猿问

删除数独图像中的水平和垂直网格

这是我的输入图像:

这是一个带有网格和 81 个数字的灰度数独图像。


我尝试通过参考一些网站使用opencv从该图像中删除水平和垂直网格。


import cv2

import math

import numpy as np

import matplotlib.pyplot as plt

gray = cv2.imread('gray.png', cv2.IMREAD_GRAYSCALE)


thresh = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY_INV, 5, 5 )

horizontal = np.copy(thresh)

vertical = np.copy(thresh)


# Specify size on horizontal axis

cols = horizontal.shape[1]

horizontal_size = math.ceil(cols / 20)


# Create structure element for extracting horizontal lines through morphology operations

horizontalStructure = cv2.getStructuringElement(cv2.MORPH_RECT, (horizontal_size, 1))


# Apply morphology operations

horizontal = cv2.erode(horizontal, horizontalStructure)

horizontal = cv2.dilate(horizontal, horizontalStructure)


# Show extracted horizontal lines

cv2.imwrite("horizontal.jpg", horizontal)


# Specify size on vertical axis

rows = vertical.shape[0]

verticalsize = math.ceil(rows / 20)


# Create structure element for extracting vertical lines through morphology operations

verticalStructure = cv2.getStructuringElement(cv2.MORPH_RECT, (1, verticalsize))


# Apply morphology operations

vertical = cv2.erode(vertical, verticalStructure)

vertical = cv2.dilate(vertical, verticalStructure)


thresh_ = thresh - horizontal - vertical

这是我当前的输出图像:

http://img3.mukewang.com/64c20c630001c57502420244.jpg

我面临两个问题:

  • 并非所有水平和垂直网格都被删除。

  • 该代码还删除了数字 4 的一部分。

我该如何更正我的代码?


弑天下
浏览 155回答 3
3回答

交互式爱情

我不知道这种方法是否适用于您的所有图像,但我注意到您想要删除网格的所有位置都有白线,并且图像的所有其余部分都是黑色的,因此它们似乎是一个有用的地方处理的目标。我使用ImageMagick,但该方法可以轻松转换为 OpenCV。因此,步骤如下:克隆图像和阈值,使浅色线条变为白色,其余线条变为黑色将白色区域扩大为 3 个正方形,这样白线就会扩大以覆盖附近的黑色网格将白色替换为灰色(171)以匹配您的背景使黑色透明将结果合成到原始图像上,以用灰色隐藏白线和附近的黑色区域magick sudoku.png \( +clone -threshold 80% -fill "gray(171)" -morphology dilate square:3 -opaque white -transparent black \) -composite result.png

慕神8447489

检测线路,使用fastLineDetector设置长度阈值绘制与背景相同的线条。输出:代码:import cv2gray = cv2.imread("gray.png", cv2.IMREAD_GRAYSCALE)lines = cv2.ximgproc.createFastLineDetector(_length_threshold=15).detect(gray)if lines is not None:    for line in lines:        (x_start, y_start, x_end, y_end) = line[0]        cv2.line(gray, (x_start, y_start), (x_end, y_end), (172, 172, 172), thickness=4)    cv2.imwrite("gray_result.png", gray)    cv2.imshow("result", gray)    cv2.waitKey(0)    cv2.destroyAllWindows()我们首先检查是否检测到这些行:if lines is not None:如果检测到线条,则获取坐标:(x_start, y_start, x_end, y_end) = line[0]然后画线:cv2.line(gray, (x_start, y_start), (x_end, y_end), (172, 172, 172), thickness=4)您可以更改线条的粗细,例如,如果将粗细设置为 10。cv2.line(gray, (x_start, y_start), (x_end, y_end), (172, 172, 172), thickness=10)输出:

慕的地6264312

有多种方法可以完成此类任务。除了其他答案之外,我还制作了另外两个示例来说明如何使用 numpy 和 OpenCV 来实现这一目标。选择正确的方式与您希望用什么来替换网格有关。方法1:使用cv2.inpaint()函数方法2:找到白色像素并将其绘制出来# importsimport cv2import numpy as npimg = cv2.imread("sudoku.png")  # read imagecolor = img[3, 3]  # color of pixel in (3,3) coordinatecolor = [int(i) for i in color]  # list of integer values of colorgray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # convert to grayscalethresh = cv2.threshold(gray, 250, 255, cv2.THRESH_BINARY)[1]  # threshold image so that only white grid is leftdst = cv2.inpaint(img.copy(), thresh, 3, cv2.INPAINT_TELEA)  # Method 1: perform inpaintcoords = np.argwhere(gray==255)  # Method 2: find all coordinates of white pixelsdst2 = img.copy()  # hard copy of original imagedst3 = img.copy()  # hard copy of original image# iterate through pixels and draw out the grid (Method 2)for i in coords:    cv2.circle(dst2, (i[0], i[1]), 3, color, -1)  # cirle with radius 3    cv2.circle(dst3, (i[0], i[1]), 1, color, -1)  # circle only one pixel# Write and display imagescv2.imwrite("dst.png", dst)cv2.imwrite("dst2.png", dst2)cv2.imwrite("dst3.png", dst3)cv2.imshow("dst", dst)cv2.imshow("dst2", dst2)cv2.imshow("dst3", dst3)cv2.waitKey(0)cv2.destroyAllWindows()结果:.方法一方法2(5像素半径)
随时随地看视频慕课网APP

相关分类

Python
我要回答