Building an OMR Scanner and Test Grader 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.
✅ 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.
⚙️ 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
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)
✅ 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
Post a Comment