Как найти контур готовой формы отсканированного изображения? - PullRequest
2 голосов
/ 04 февраля 2020

Я хотел бы определить контур заполненной формы в этом скане.

В идеале я хотел бы найти углы стола, окрашенные красным.

Моя последняя цель - обнаружить, что весь документ был отсканирован и что четыре угла находятся в границах сканирования.

Я использовал OpenCV из python - но он не смог найти контур большого контейнера.

Есть идеи?

image

image

Ответы [ 2 ]

1 голос
/ 05 февраля 2020

С учетом того, что форму можно идентифицировать с помощью таблицы, вот простой подход:

  1. Получить двоичное изображение. Загрузить изображение в градациях серого, Размытие по Гауссу, затем порог Оцу, чтобы получить двоичное изображение

  2. Найти горизонтальные сечения. Мы создаем ядро ​​горизонтальной формы, находим горизонтальные линии таблицы и рисуем на маске

  3. Найти вертикальные сечения. Мы создаем вертикальное ядро ​​в форме, находим вертикальные линии таблицы и рисуем на маске

  4. Заполнить текстовое тело документа и открыть морф. Мы выполняем операции морфинга, чтобы закрыть таблицу, затем находим контуры и заполняем маску, чтобы получить контур фигуры. Этот шаг удовлетворяет вашим потребностям, поскольку вы можете просто найти контуры на маске, но мы можем go продолжить и извлечь только нужные сечения.

  5. Выполнить четырехточечное перспективное преобразование. Мы находим контуры, сортируем по наибольшему контуру, сортируем, используя аппроксимацию контуров, затем выполняем четырехточечное перспективное преобразование , чтобы получить изображение с высоты птичьего полета.


Вот результаты:

Входное изображение

image

Обнаруженный контур для выделения выделен зеленым цветом

image

Вывод после 4-точечного перспективного преобразования

image

Код

import cv2
import numpy as np
from imutils.perspective import four_point_transform

# Load image, create mask, grayscale, and Otsu's threshold
image = cv2.imread('1.jpg')
mask = np.zeros(image.shape, dtype=np.uint8)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (3,3), 0)
thresh = cv2.adaptiveThreshold(blur,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV,11,3)

# Find horizontal sections and draw on mask 
horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (80,1))
detect_horizontal = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, horizontal_kernel, iterations=2)
cnts = cv2.findContours(detect_horizontal, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    cv2.drawContours(mask, [c], -1, (255,255,255), -1)

# Find vertical sections and draw on mask 
vertical_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1,50))
detect_vertical = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, vertical_kernel, iterations=2)
cnts = cv2.findContours(detect_vertical, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    cv2.drawContours(mask, [c], -1, (255,255,255), -1)

# Fill text document body
mask = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY)
close_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9,9))
close = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, close_kernel, iterations=3)
cnts = cv2.findContours(close, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    cv2.drawContours(mask, [c], -1, 255, -1)

# Perform morph operations to remove noise
# Find contours and sort for largest contour
opening = cv2.morphologyEx(mask, cv2.MORPH_OPEN, close_kernel, iterations=5)
cnts = cv2.findContours(opening, cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
cnts = sorted(cnts, key=cv2.contourArea, reverse=True)
displayCnt = None

for c in cnts:
    # Perform contour approximation
    peri = cv2.arcLength(c, True)
    approx = cv2.approxPolyDP(c, 0.02 * peri, True)
    if len(approx) == 4:
        displayCnt = approx
        break

# Obtain birds' eye view of image
warped = four_point_transform(image, displayCnt.reshape(4, 2))

cv2.imwrite('mask.png', mask)
cv2.imwrite('thresh.png', thresh)
cv2.imwrite('warped.png', warped)
cv2.imwrite('opening.png', opening)
0 голосов
/ 04 февраля 2020

Как насчет использования преобразования Хафа с узким диапазоном направлений, чтобы найти вертикали и горизонтали? Если вам повезет, то те, которые вам нужны, будут самыми длинными, и после их выбора вы сможете восстановить прямоугольник.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...