我正在尝试对该图像中找到的轮廓进行排序:
框结果:
暂时找到这样的轮廓:
img_bw=cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
(thresh, im_bw) = cv2.threshold(img_bw, 128, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
ctrs, hier = cv2.findContours(im_bw.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
boundingBoxes = [cv2.boundingRect(c) for c in ctrs]
(cnts, boundingBoxes) = zip(*sorted(zip(ctrs, boundingBoxes),key=lambda b:b[1][0], reverse=False))
但我想从上到下、从左到右排序。 问题是,一些轮廓较小,如图所示:
这是 x,y 坐标:
所以我只想选取 81 个红色和正方形的区域。然后从上到下,再从左到右排序。所以取出第一行的前9个盒子,用y坐标排序。
非常感谢。
BR卡米
显示在问题中。
我的方法适用于任何数独图像,无需任何绘制轮廓的过程。在我的示例中,我将使用 sudoku.com 网站上的数独,但它也与您的图像完美配合。
在我的方法中,我将使用更可靠的方法来检测和提取任何数独图片中数独的 81 个方格。
我将使用的数独图像:
import cv2
import numpy as np
from matplotlib import pyplot as plt
# reading the image directly in grayscale
image = cv2.imread(image, cv2.IMREAD_GRAYSCALE)
# Edge detection with Canny function
img_bin = cv2.Canny(image,50,110)
dil_kernel = np.ones((3,3), np.uint8)
# dilatation of the edges
img_bin=cv2.dilate(img_bin,dil_kernel,iterations=1)
img_bin结果:
line_min_width = 40 # minimum width of the selected lines
kernel_hprizontal = np.ones((1,line_min_width), np.uint8) # mask
img_bin_h = cv2.morphologyEx(img_bin, cv2.MORPH_OPEN, kernel_hprizontal)
img_bin_h的结果:
kernel_vertical = np.ones((line_min_width,1), np.uint8)
img_bin_v = cv2.morphologyEx(img_bin, cv2.MORPH_OPEN, kernel_vertical)
img_bin_v的结果:
img_bin_final=img_bin_h|img_bin_v
final_kernel = np.ones((3,3), np.uint8)
# Dilatting the edges for easier shape detection
img_bin_final=cv2.dilate(img_bin_final,final_kernel,iterations=1)
img_bin_final的结果:
ret, labels, stats, centroids = cv2.connectedComponentsWithStats(~img_bin_final, connectivity=8, ltype=cv2.CV_32S)
# THIS CODE IS ONLY USED TO SHOW THE REGIONS IN DIFERENT COLORS ########
# Map component labels to hue val
label_hue = np.uint8(179*labels/np.max(labels))
blank_ch = 255*np.ones_like(label_hue)
labeled_img = cv2.merge([label_hue, blank_ch, blank_ch])
# cvt to BGR for display
labeled_img = cv2.cvtColor(labeled_img, cv2.COLOR_HSV2BGR)
# set bg label to black
labeled_img[label_hue==0] = 0
########################################################################
labeled_img结果:
percentage_limit = 0.15 # percentatge of error for the area of the sudoku squares
# Selecting the shapes with more than 1000 of area and with a square shape (height and width (h and w) must be similar by and error of 10)
boxes = [[x,y,w,h, w*h] for x,y,w,h,_ in stats if w*h>1000 and abs(w - h) < 10]
# median of the areas of the selected squares
median = np.median(np.array(boxes)[:,4])
# using the median to choose the 81 squares corresponding to each cell of the sudoku with an error of 'percentage_limit'
boxes = [x for x in boxes if x[4] > median*(1-percentage_limit) and x[4] < median*(1+percentage_limit)]
if len(boxes) != 81: # Simple error check
print('Error: The number of cells is not 81')
boxes = sorted(boxes, key=lambda x: x[0])
result = []
for row in range(9):
result.append(sorted(boxes[row*9:(row+1)*9], key=lambda x: x[1]))
例如
box[0]
将返回数独的第一行,box[0][1]
将返回第一行第二列中的正方形。
希望有帮助!