Opencv 可以在同一张论文中检测出两个不同大小的矩形中的一个

Posted

技术标签:

【中文标题】Opencv 可以在同一张论文中检测出两个不同大小的矩形中的一个【英文标题】:Opencv can detect one out of two different size rectangles in the same paper 【发布时间】:2020-03-21 13:28:36 【问题描述】:

我是 OpenCV 的新手,我正在 Java 中创建一个 OMR(光学标记识别)系统,以便检测多项选择纸上的答案。我创建了一个由一个大矩形组成的表格,用于通过绘制正确的圆圈来回答问题,以及一个较小的矩形,用于检测一个唯一数字,该数字是一个答案的身份。 这是表格的图片:

现在我的程序正在检测 AM 的上部矩形,但无法检测到更大的矩形。我的图像通过 6 个阶段:第 1 膨胀、第 2 灰度、第 3 阈值、第 4 模糊、第 5 和第 6 自适应阈值。在这里你可以看到

    dilated1 = new Mat(source1.size(), CV_8UC1);
    dilate(source1, dilated1, getStructuringElement(MORPH_RECT, new Size(3, 3)));
    
    gray1 = new Mat(dilated1.size(), CV_8UC1);
    cvtColor(dilated1, gray1, COLOR_BGR2GRAY);

    thresh1 = new Mat(gray1.rows(), gray1.cols(), gray1.type());
    threshold(gray1, thresh1, 0, 255, THRESH_BINARY + THRESH_OTSU );

    blur1 = new Mat(thresh1.size(), CV_8UC1);
    blur(gray1, blur1, new Size(5.,5.));

    canny1 = new Mat(blur1.size(), CV_8UC1);
    Canny(blur1, canny1,160, 80);

    adaptiveThresh1 = new Mat(canny1.rows(), gray1.cols(), gray1.type());
    adaptiveThreshold(canny1, adaptiveThresh1, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 11,2);

我也在使用这样的 findContours

findContours(adaptiveThresh1.clone(), contours1, hierarchy1, RETR_TREE, CHAIN_APPROX_SIMPLE);

我创建了两个不同的 java 类,因为在小矩形和更大的矩形中还有其他要检测的东西。上面的代码是我用来尝试检测更大的矩形的代码。我在所有步骤中尝试了许多不同的数字,但仍然没有。

当我只在图像中使用较大的矩形时,它工作得很好,但与另一个矩形结合时,它无法检测到它。这是为了我的论文,对我来说真的很重要。感谢您提供任何帮助,如果您希望我添加任何内容以帮助您,请告诉我。

【问题讨论】:

【参考方案1】:

您可以找到最大轮廓和第二大轮廓。

建议阶段:

将图像转换为灰度(与您一样)。 在图像周围绘制白色粗矩形 - 确保图像周围没有黑色轮廓。 应用阈值并转换为二进制(与您一样)。 我发布的代码也是反极性的,因为轮廓是白色的。 寻找轮廓。 使用RETR_EXTERNAL 而不是RETR_TREE,因为您不需要在轮廓中查找轮廓。 迭代等高线,找到面积最大的和面积第二大的。 面积最大的等高线是下面的矩形。 面积第二大的轮廓是上面的矩形。

这是一个 Python 实现(不是 JAVA,但足够接近):

import cv2

# Read input image
img = cv2.imread('image.png')

# Draw thick rectangle around the image - making sure there is not black contour around the image
cv2.rectangle(img, (0, 0), (img.shape[1], img.shape[0]), (255, 255, 255), thickness = 5)

# Convert from BGR to Grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# Apply threshold on gray image - use automatic threshold algorithm (use THRESH_OTSU) and invert polarity.
ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)

# Find contours
cnts, heir = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)


max_a = 0  # Maximum area
smax_a = 0 # Second maximum area

max_c = []  # Contour with maximum area
smax_c = [] # Contour with second maximum area (maximum excluding max_c)

# Iterate contours
for c in cnts:
    area = cv2.contourArea(c)
    if area > max_a:    # If area is grater than maximum, second max = max, and max = area
        smax_a = max_a
        smax_c = max_c  # Second max contour gets maximum contour
        max_a = area
        max_c = c       # Maximum contour gets c
    elif area > smax_a: # If area is grater than second maximum, replace second maximum
        smax_a = area
        smax_c = c

#Get bounding rectangle of contour with maximum area, and mark it with green rectangle
x, y, w, h = cv2.boundingRect(max_c)
cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), thickness = 2)

#Get bounding rectangle of contour with second maximum area, and mark it with blue rectangle
x, y, w, h = cv2.boundingRect(smax_c)
cv2.rectangle(img, (x, y), (x+w, y+h), (255, 0, 0), thickness = 2)

# Show result (for testing).
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

结果:

【讨论】:

太好了,这就是我想要的,我要感谢你帮助我,我真的很感激。祝贺你! @Rotem

以上是关于Opencv 可以在同一张论文中检测出两个不同大小的矩形中的一个的主要内容,如果未能解决你的问题,请参考以下文章

opencv怎么把一张图片上的人头框出来,(假设该图片上只有一个人)

OpenCV检测轮廓相交

经典论文解读YOLOv2 目标检测

在 OpenCV 中自动检测和裁剪 ROI

使用 OpenCV c++ 裁剪图像

教你用OpenCV 和 Python实现圆物检测