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

Opencv can detect one out of two different size rectangles in the same paper

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

现在我的程序正在检测 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 类 因为在小矩形和大矩形中还有其他要检测的东西。上面的代码是我用来尝试检测更大矩形的代码。我在所有步骤中尝试了很多不同的数字,但仍然没有。

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

您可以找到最大 等高线和第二大 等高线。

建议阶段:

  • 将图像转换为灰度(就像您所做的那样)。
  • 在图像周围绘制白色粗矩形 - 确保图像周围没有黑色轮廓。
  • 应用阈值并转换为二进制(就像您所做的那样)。
    我发布的代码也是反极性的,因为轮廓是白色的。
  • 寻找轮廓。
    使用 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()

结果: