使用Python OpenCV检测图像中的所有圆形(光学标记识别)。

3
我需要使用Python制作一个OMR检测系统,作为我的高中暑期项目(如果它足够可靠,学校可能会在一定程度上使用它)。我已经进行了很多研究,并尝试了从轮廓到模板匹配的所有东西。我觉得模板匹配可以工作,但它只能检测OMR表中的一个圆圈。有人可以帮助我找出如何检测OMR表中的多个(全部)圆圈(无论它们是否被涂满),以及它们各自的坐标,这对我来说就足够了。
我尝试过的方法:
import numpy as np
import cv2

img = cv2.resize(cv2.imread('assets/omr_match1.jpg', 0), (0, 0), fx=0.2, fy=0.5)
template = cv2.resize(cv2.imread('assets/circle.jpg', 0), (0, 0), fx=0.2, fy=0.5)
h, w = template.shape

methods = [cv2.TM_CCOEFF, cv2.TM_CCOEFF_NORMED, cv2.TM_CCORR,
            cv2.TM_CCORR_NORMED, cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]

methods=methods[0] 
# This is one among the above which works perfectly

for method in methods:
    img2 = img.copy()

    result = cv2.matchTemplate(img2, template, method)
    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
    if method in [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]:
        location = min_loc
    else:
        location = max_loc

    bottom_right = (location[0] + w, location[1] + h)
    cv2.rectangle(img2, location,bottom_right, 0, 1)
    cv2.imshow('Match', img2)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

Circle.jpg # 圆形.jpg

Result

请看上图,只有一个随机的圆被标记了出来,而不是所有的圆。


2
可能需要发布一些代码或sudo代码来描述您所尝试的内容。如果您找到了一个黑色圆圈的像素宽度,可以通过制作网格来找到每个人。您是否将其转换为灰度并进行蒙版处理,只留下黑色圆圈?https://stackoverflow.com/questions/63730808/golf-ball-tracking-in-python-opencv-with-different-color-balls - Cary H
3
通常,它是一张有注册标记(易于检测和定位)和一些条形码(或其他东西)以识别表格的纸张。有了这些标记,您就可以将扫描对齐到“模型”,然后“盲目”地将掩蔽应用于矫正后的扫描...并采样圆圈应该在的区域。您甚至可以尝试将整个扫描页面与整个模型页面(空白、干净、从PDF栅格化的图像)进行特征匹配。 - Christoph Rackwitz
2
你只获取了一个匹配项 - 最佳得分的那个。你没有获取到所有的匹配项。请参考 https://www.pyimagesearch.com/2021/03/29/multi-template-matching-with-opencv/ 了解如何获取多个匹配项。 - fmw42
2
另一种方法是使用cv2.HoughCircles来获取所有的圆。 - fmw42
3
然后需要告诉他们将纸张展开并尽可能地平整。如果这是个问题,你可以在纸张上放置许多注册标记,并逐块地展平它。我认为可以使用页面本身而不是特殊标记。展平会很困难。OpenCV 没有单独的函数来进行网格变形,你需要自己编写代码。从拍照中产生的透视畸变不是问题,可以进行校正。 - Christoph Rackwitz
显示剩余9条评论
1个回答

3

我们开始吧:

import cv2
import numpy as np
from matplotlib import pyplot as plt


img = cv2.imread('/path/tabela_circle.jpg', 0)

template = cv2.imread('/path/circle.jpg', 0)
h, w = template.shape

res = cv2.matchTemplate(img,template,cv2.TM_CCOEFF_NORMED)
threshold = 0.8
loc = np.where( res >= threshold)
for pt in zip(*loc[::-1]):
    cv2.rectangle(img, pt, (pt[0] + w, pt[1] + h), (0,0,255), 2)

cv2.imwrite('res.png',img)

解决方案

同样适用于只检测答案:

解决方案2


你好,做得很好。我正在尝试应用OMR来检测和定位打勾的方框,但是你的方法对我不起作用。你知道如何解决这个问题吗?链接:https://stackoverflow.com/questions/69706170/detect-and-possibly-localize-ticked-boxes-in-an-image-optical-mark-recognition谢谢。 - Mobassir Hossen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接