如何使用OpenCV检测多个外部边界中的数独确切边界?

0 投票
1 回答
63 浏览
提问于 2025-04-12 02:59

我在用OpenCV提取数独网格的时候,想找到面积最大的方形轮廓。但是有些数独的外边界不止一个,所以程序只检测到了最外面的边界。这影响了后面的程序,因为数独是按行和列分成9个部分的,目的是从每个单元格中提取数字。

我该怎么修改main_outline()函数,才能检测到数独的实际边界,而不是那些额外的外边界呢?

def main_outline(contour):
                biggest = np.array([])
                max_area = 0
                for i in contour:
                    area = cv2.contourArea(i)
                    if area >50:
                        peri = cv2.arcLength(i, True)
                        approx = cv2.approxPolyDP(i , 0.02* peri, True)
                        if area > max_area and len(approx) ==4:
                            biggest = approx
                            max_area = area
                return biggest ,max_area

su_contour_1= su_puzzle.copy()
su_contour_2= su_puzzle.copy()
su_contour, hierarchy = cv2.findContours(preprocess(su_puzzle),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(su_contour_1, su_contour,-1,(0,255,0),3)
            
black_img = np.zeros((450,450,3), np.uint8)
su_biggest, su_maxArea = main_outline(su_contour)

这个问题可以通过以下图片来解释:

输入图片:

输入图片

当前程序提取的图片:

当前程序提取的图片

期望提取的图片:

期望提取的图片

我尝试使用递归函数来检测内部边界,但失败了,因为在检测到确切边界后,它会继续寻找轮廓,这样就会被识别为单独的数独网格,导致结果错误。我找不到一个好的停止条件。

1 个回答

1

如果边界总是蓝色的话,这样做可能会效果很好:

im = cv2.imread("sudoku.png") # read im
b,g,r = cv2.split(im) # split to bgr
bThresh = cv2.threshold(b, 0, 1, cv2.THRESH_OTSU + cv2.THRESH_BINARY_INV)[1] # get the threshold
cnts, _ = cv2.findContours(bThresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) # find the contours
largestCnt = max(cnts, key = cv2.contourArea) # find the largest contour
x, y, w, h = cv2.boundingRect(largestCnt) # get bounding rect
croppedIm = im[y:y+h, x:x+w] # crop
cv2.imwrite("Cropped.png", croppedIm) # save

下面的代码可视化效果:

imContoured = cv2.drawContours(cv2.merge((r,g,b)).copy(), largestCnt, -1, (255,0,0), 5) # draw largest contour with thick line, red
plt.figure()
plt.imshow(imContoured)
plt.axis("off")

得到的结果是:

nice contour

最终保存的图片是:

cropped

撰写回答