#python #python-3.x #opencv #computer-vision
#python #python-3.x #opencv #компьютерное зрение
Вопрос:
Это мое входное изображение:
Это изображение судоку в оттенках серого с сетками и 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
Это мое текущее выходное изображение:
Я сталкиваюсь с 2 проблемами :
-
Не все горизонтальные и вертикальные сетки удалены.
-
Код также удаляет часть числа 4.
Как я могу исправить свой код?
Комментарии:
1. Вау, круто! @nathancy
Ответ №1:
Я не знаю, будет ли этот подход работать для всех ваших изображений, но я замечаю, что во всех местах, где вы хотите удалить сетки, есть белые линии, а все остальное изображение темное, поэтому они кажутся полезным местом для обработки.
Я использовал ImageMagick, но этот подход можно легко преобразовать в OpenCV. Итак, вот шаги:
-
клонируйте изображение и пороговое значение, чтобы светлые линии были белыми, а остальные черными
-
расширьте белые области квадратом размером 3, чтобы белые линии расширились и покрыли близлежащие черные сетки
-
замените белый на серый (171), чтобы соответствовать вашему фону
-
сделать черный прозрачным
-
объедините результат поверх оригинала, чтобы скрыть белые линии и близлежащие черные области серым
magick sudoku.png ( clone -threshold 80% -fill "gray(171)" -morphology dilate square:3 -opaque white -transparent black ) -composite result.png
Ответ №2:
-
- Определите линию, используя
fastLineDetector
- Определите линию, используя
-
- Установите пороговое значение длины
-
- Нарисуйте линию так же, как фон.
Вывод:
Код:
import cv2
gray = 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)
Вывод:
Ответ №3:
Есть несколько способов выполнить такую задачу. В дополнение к другим ответам я привел два других примера о том, как добиться этого с помощью numpy и OpenCV. Выбор правильного способа зависит от того, чем вы хотите заменить эту сетку.
Метод 1: использование cv2.inpaint()
функции Метод 2: найдите белый пиксель и вытяните их
# imports
import cv2
import numpy as np
img = cv2.imread("sudoku.png") # read image
color = img[3, 3] # color of pixel in (3,3) coordinate
color = [int(i) for i in color] # list of integer values of color
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # convert to grayscale
thresh = cv2.threshold(gray, 250, 255, cv2.THRESH_BINARY)[1] # threshold image so that only white grid is left
dst = cv2.inpaint(img.copy(), thresh, 3, cv2.INPAINT_TELEA) # Method 1: perform inpaint
coords = np.argwhere(gray==255) # Method 2: find all coordinates of white pixels
dst2 = img.copy() # hard copy of original image
dst3 = 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 images
cv2.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()
Результаты:
Способ 1
Метод 2 (радиус 5 пикселей)
Метод 2 (радиус 1 пиксель)