Reputation: 675
I am working on an OMR sheet processing system where users bubble answers in four columns (A, B, C, D). My goal is to detect each individual bubble inside each column.
I am successfully detecting all four columns, but there is an issue:
My code for the same is
from imutils.perspective import four_point_transform
from imutils import contours
import numpy as np
import imutils
import cv2
import matplotlib.pyplot as plt
# Define Answer Key (Correct Answers for Each Question)
counter_needed = 2
# Load the image
image_name = "omr_image_dummy.jpg"
image = cv2.imread(image_name)
ANSWER_KEY = {0: 1, 1: 1, 2: 1, 3: 3, 4: 1, 5: 0, 6: 2, 7: 1, 8: 3, 9: 2}
# Convert the image to grayscale
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# Apply Gaussian Blur
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
# Apply Canny edge detection
edged = cv2.Canny(blurred, 75, 200)
# Find contours
cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
docCnt = None
count_counter = 0
# Ensure that at least one contour was found
if len(cnts) > 0:
# Sort contours by area in descending order
cnts = sorted(cnts, key=cv2.contourArea, reverse=True)
# Loop over sorted contours
for c in cnts:
# Approximate the contour
peri = cv2.arcLength(c, True)
approx = cv2.approxPolyDP(c, 0.02 * peri, True)
# If the approximated contour has four points, we assume it's the document
if len(approx) == 4 and count_counter < 6:
if count_counter == counter_needed:
print(count_counter)
docCnt = approx
break
count_counter += 1
paper = four_point_transform(image, docCnt.reshape(4, 2))
warped = four_point_transform(gray, docCnt.reshape(4, 2))
# apply Otsu's thresholding method to binarize the warped piece of paper
thresh = cv2.threshold(warped, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
show_image("Threshold Image 2", thresh)
contour_image = cv2.cvtColor(thresh, cv2.COLOR_GRAY2BGR) # Convert to BGR for colored visualization
# Apply thresholding (assuming `thresh` is already computed)
cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
# print(cnts)
for idx, c in enumerate(cnts):
color = (np.random.randint(0, 255), np.random.randint(0, 255), np.random.randint(0, 255))
cv2.drawContours(contour_image, [c], -1, color, 2) # Random color for each contour
# Get bounding box for labeling
x, y, w, h = cv2.boundingRect(c)
# print(x, y, w, h)
# Add index number to each contour
cv2.putText(contour_image, f"{idx}", (x, y - 5),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2)
# Display the image with all contours
show_image("Counter 1", contour_image)
Upvotes: 2
Views: 92