用于对数独的轮廓进行排序的功能,从上到下、从左到右?

问题描述 投票:0回答:1

我正在尝试对该图像中找到的轮廓进行排序:

框结果:

Box Result

暂时找到这样的轮廓:

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 坐标:

Sorting Failure

所以我只想选取 81 个红色和正方形的区域。然后从上到下,再从左到右排序。所以取出第一行的前9个盒子,用y坐标排序。

非常感谢。

BR卡米

显示在问题中。

python sorting opencv computer-vision
1个回答
0
投票

我的方法适用于任何数独图像,无需任何绘制轮廓的过程。在我的示例中,我将使用 sudoku.com 网站上的数独,但它也与您的图像完美配合。

在我的方法中,我将使用更可靠的方法来检测和提取任何数独图片中数独的 81 个方格。

我将使用的数独图像:

Sudoku example

  1. 读取灰度图像:
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)
  1. 检测边缘并将图像从灰色调转换为二值黑白图像
# 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结果:

Dilated sudoku result

  1. 仅选择水平边缘
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的结果:

horizontal lines

  1. 仅选择垂直边缘
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的结果:

vertical lines

  1. 合并垂直线和水平线
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的结果:

Sudoku grid

  1. 在数独网格中划分不同区域
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结果:

Regions

  1. 仅选择 81 个数独方块
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')
  1. 最后对所有方块进行排序。结果将是一个矩阵,其中包含每个数独位置对应的平方
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]
将返回第一行第二列中的正方形。

希望有帮助!

© www.soinside.com 2019 - 2024. All rights reserved.