Building an OMR Scanner and Test Grader with OpenCV

Building an OMR Scanner and Test Grader with OpenCV Building an OMR Scanner with OpenCV

๐Ÿ“„ Building an OMR Scanner and Test Grader with OpenCV

๐Ÿง  Introduction

Optical Mark Recognition (OMR) technology detects and captures human-marked data from documents like surveys, tests, and assessments. It is widely used in education and professional fields to automate grading, making it fast, accurate, and cost-effective.

๐ŸŽฏ Why Use OMR?
✅ Fast
✅ Accurate
✅ Cost-effective

In this article, we’ll walk through building an OMR scanner and test grader using OpenCV, a powerful computer vision library in Python.

๐Ÿ” Understanding OMR Technology

OMR enables machines to recognize marks on paper and convert them into digital data.

  • Accuracy: Ensures minimal grading errors
  • Speed: Processes data rapidly
  • Cost-effectiveness: No manual data entry

๐Ÿงพ Designing the OMR Sheet

  • Marking Areas: Bubbles or boxes for answers
  • Identification Areas: Student ID/test ID
  • Calibration Marks: Small dots for alignment

๐ŸŽฏ Project Overview and Purpose

The goal is to automate grading by scanning OMR sheets, identifying marked answers, and calculating scores.

✅ Improves efficiency and reduces manual errors.

⚙️ Implementation and Workflow

๐Ÿ› ️ Step 1: Setting Up the Environment

Required libraries: OpenCV, NumPy

pip install opencv-python numpy

๐Ÿงผ Step 2: Image Preprocessing

a) Convert Image to Grayscale

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

b) Error Handling for Image Loading

⚠️ Always check if image loaded correctly using if image is None:

๐Ÿ“ Step 3: Detecting the OMR Sheet

edges = cv2.Canny(gray, 30, 100)

๐Ÿ”„ Step 4: Perspective Transformation

def get_warped_image(image, contour):
    pts = contour.reshape(4, 2)
    rect = np.zeros((4, 2), dtype="float32")
    s = pts.sum(axis=1)
    rect[0] = pts[np.argmin(s)]
    rect[2] = pts[np.argmax(s)]
    diff = np.diff(pts, axis=1)
    rect[1] = pts[np.argmin(diff)]
    rect[3] = pts[np.argmax(diff)]
    (tl, tr, br, bl) = rect
    widthA = np.linalg.norm(br - bl)
    widthB = np.linalg.norm(tr - tl)
    maxWidth = max(int(widthA), int(widthB))
    heightA = np.linalg.norm(tr - br)
    heightB = np.linalg.norm(tl - bl)
    maxHeight = max(int(heightA), int(heightB))
    dst = np.array([[0, 0], [maxWidth - 1, 0],
                    [maxWidth - 1, maxHeight - 1], [0, maxHeight - 1]], dtype="float32")
    M = cv2.getPerspectiveTransform(rect, dst)
    warped = cv2.warpPerspective(image, M, (maxWidth, maxHeight))
    return warped

✏️ Step 5: Answer Detection

thresh = cv2.threshold(warped, 0, 255,
    cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]

def find_bubbles(thresh_image):
    contours, _ = cv2.findContours(thresh_image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    bubble_contours = [c for c in contours if cv2.contourArea(c) > 100]
    return bubble_contours

bubbles = find_bubbles(thresh)
๐Ÿ“Œ Use a contour area threshold (e.g., >100) to filter out noise.

✅ Step 6: Grading

correct_answers = ['A', 'B', 'C', 'D', 'A']
student_answers = []

for bubble in bubbles:
    (x, y, w, h) = cv2.boundingRect(bubble)
    roi = thresh[y:y + h, x:x + w]
    total = cv2.countNonZero(roi)
    student_answers.append('A' if total > 500 else 'B')

score = sum([1 for student, correct in zip(student_answers, correct_answers) if student == correct])
print(f'Score: {score}/{len(correct_answers)}')

๐ŸŒŸ Features and Capabilities

  • ✅ Automatic OMR sheet detection
  • ✅ High grading accuracy
  • ✅ Customizable answer formats
  • ✅ Fast processing of test batches

๐Ÿงฑ Challenges and Solutions

Challenge Solution
Noise in Images Apply preprocessing like thresholding & edge detection
Varying Sheet Layouts Use perspective transformation
Inconsistent Markings Apply adaptive thresholding & filtering

๐Ÿซ Real-World Application Example

This OMR scanner can be used in schools, colleges, and training centers for automated grading of exams, saving manual effort and increasing accuracy.

๐Ÿงพ Conclusion

Using OpenCV, you can build a scalable, accurate OMR test grading system that dramatically simplifies the grading process for institutions.

❓ FAQs

Q: Can this system handle different OMR sheet formats?
A: Yes, by adjusting the preprocessing logic and contours detection.

Q: What are the limitations?
A: It might struggle with low-resolution or damaged images.

Q: Can this be improved with ML?
A: Yes! ML models can enhance bubble detection and grading accuracy.

Comments

Popular posts from this blog

Python for IoT Development: Secure and Scalable Solutions Guide