1

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

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

4

1 回答 1

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()

结果:
在此处输入图像描述

于 2020-03-22T17:26:10.323 回答