如何使用OpenCV获取数独网格的单元格? [英] How to get the cells of a sudoku grid with OpenCV?

查看:86
本文介绍了如何使用OpenCV获取数独网格的单元格?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最近几天,我一直在尝试从图片中获取数独网格,而我一直在努力获取网格的较小正方形. 我正在处理下面的图片.我以为用Canny滤镜处理图像会很好,但是没有,而且我无法获得每个正方形的每个轮廓.然后,我将自适应阈值,otsu和经典阈值进行了测试,但是每次似乎都无法捕捉到每个小方块.

I've been trying for the last few days to get a sudoku grid from a picture, and I have been struggling on getting the smaller squares of the grid. I am working on the picture below. I thought processing the image with a canny filter would work fine, but it didn't and I couldn't get every contour of each square. I then put adaptive threshold, otsu, and a classic thresholding to the test, but every time, it just could not seem to capture every small square.

最终的目标是获取包含数字的单元格,并使用pytorch识别数字,所以我真的很想获得一些清晰的数字图像,以使识别不会出错:)

The final goal is to get the cells containing a number, and recognize the numbers with pytorch, so I would really like to have some clean images of the numbers, so the recognition doesn't screw up :)

有人会对如何实现这一目标有想法吗? 在此先多谢! :D

Would anyone have an idea on how to achieve this? Thanks a lot in advance! :D

推荐答案

这是一个潜在的解决方案:

Here's a potential solution:

  1. 获取二进制图像.将图像转换为灰度图像并

  1. Obtain binary image. Convert image to grayscale and adaptive threshold

过滤掉所有数字和噪音以仅隔离盒子.我们使用

Filter out all numbers and noise to isolate only boxes. We filter using contour area to remove the numbers since we only want each individual cell


这是初始二进制图像(左),并过滤出数字+修复的网格线+倒置图像(右)


Here's the initial binary image (left) and filtered out numbers + repaired grid lines + inverted image (right)

这是每个单元格迭代的可视化视图

Here's a visualization of the iteration of each cell

在每个单元格中检测到的数字

The detected numbers in each cell

代码

import cv2
from imutils import contours
import numpy as np

# Load image, grayscale, and adaptive threshold
image = cv2.imread('1.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.adaptiveThreshold(gray,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV,57,5)

# Filter out all numbers and noise to isolate only boxes
cnts = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    area = cv2.contourArea(c)
    if area < 1000:
        cv2.drawContours(thresh, [c], -1, (0,0,0), -1)

# Fix horizontal and vertical lines
vertical_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1,5))
thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, vertical_kernel, iterations=9)
horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,1))
thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, horizontal_kernel, iterations=4)

# Sort by top to bottom and each row by left to right
invert = 255 - thresh
cnts = cv2.findContours(invert, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
(cnts, _) = contours.sort_contours(cnts, method="top-to-bottom")

sudoku_rows = []
row = []
for (i, c) in enumerate(cnts, 1):
    area = cv2.contourArea(c)
    if area < 50000:
        row.append(c)
        if i % 9 == 0:  
            (cnts, _) = contours.sort_contours(row, method="left-to-right")
            sudoku_rows.append(cnts)
            row = []

# Iterate through each box
for row in sudoku_rows:
    for c in row:
        mask = np.zeros(image.shape, dtype=np.uint8)
        cv2.drawContours(mask, [c], -1, (255,255,255), -1)
        result = cv2.bitwise_and(image, mask)
        result[mask==0] = 255
        cv2.imshow('result', result)
        cv2.waitKey(175)

cv2.imshow('thresh', thresh)
cv2.imshow('invert', invert)
cv2.waitKey()

注意:排序思想是根据 查看全文

登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆