NoobCoder
NoobCoder

Reputation: 675

Issue in detecting the bubble of OMR sheet

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:

This is the thresh image for counter 1

Corresponding Bubble Detection from Thresh 1

THresh Image for Counter 2

Corresponding Bubble Detection from Thresh 2

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

Answers (0)

Related Questions