如何使用OpenCV获取数独网格的单元格?

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

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

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

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

The sudoku grid I'm working with

python image opencv image-processing sudoku
2个回答
1
投票

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

  1. 获得二进制图像。将图像转换为灰度和自适应阈值
  2. 过滤掉所有数字和噪声以仅隔离框。我们使用轮廓区域进行过滤以去除数字,因为我们只需要每个单元格
  3. 修复网格线。使用水平和垂直内核执行形态学闭合以修复网格线。
  4. 按照从上到下和从左到右的顺序对每个单元格进行排序。我们使用imutils.sort_contours()top-to-bottomleft-to-right参数将每个单元格按顺序组织起来

这是初始二进制图像(左),并过滤掉数字和修复的网格线+反转图像(右)

<< img src =“ https://image.soinside.com/eyJ1cmwiOiAiaHR0cHM6Ly9pLnN0YWNrLmltZ3VyLmNvbS9IVUN1Mi5wbmcifQ==” width =“ 325”>

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

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

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

0
投票

如果图像仅包含紧密匹配的数独网格,则实现此目标的一种粗略方法是将图像划分为相等的9X9网格,然后尝试在每个网格中提取数字。

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