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

标签 python image opencv image-processing sudoku

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

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

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

The sudoku grid I'm working with

最佳答案

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

  • 获取二进制图像。 将图像转换为灰度和adaptive threshold
  • 过滤掉所有数字和噪音以仅隔离盒子。 因为我们只希望每个单元格
  • ,所以我们使用contour area进行过滤以删除数字
  • 修复网格线。 morphological closing一起执行horizontal and vertical kernel以修复网格线。
  • 按从上到下和从左到右的顺序对每个单元格进行排序。 我们使用 imutils.contours.sort_contours() top-to-bottomleft-to-right参数
  • 将每个单元格按顺序组织


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


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

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


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

    注意:排序思路是根据Rubrik cube solver color extraction中以前的旧答案改编而成的。

    关于python - 如何使用OpenCV获取数独网格的单元格?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59182827/

    相关文章:

    css - 如何使方形裁剪图像响应

    python - 无法读取UDP数据包

    python - OpenCV 错误 : (-215) scn == 3 || scn == 4 in function ipp_cvtColor

    c++ - 使用 Mingw-make 构建 OpenCV 3.3 在 47% 处出现错误 2

    python - 使用 python pandas 将现有的 excel 表 append 到新的数据框

    python - 你如何组织 Python 模块?

    python - 使用 ThreadPoolExecutor 优雅退出

    python - GeoDjango & SpatiaLite - 过滤附近的物体

    c# - 在 WPF 中操作图像控件

    wpf - 将图像添加到资源的不同方式