Как найти углы на бумаге, если на самой бумаге есть напечатанные углы / линии? - PullRequest
2 голосов
/ 31 марта 2020

Я использую openCV в Python, чтобы найти углы листа бумаги, чтобы развернуть его.

img = cv2.imread(images[i])

        corners = cv2.goodFeaturesToTrack(cv2.cvtColor(img,cv2.COLOR_BGR2GRAY),4,.01,1000,useHarrisDetector=True,k=.04)
        corners = np.float32(corners)
        print(corners)
        ratio = 1.6
        cardH = math.sqrt((corners[2][0][0] - corners[1][0][0]) * (corners[2][0][0] - corners[1][0][0]) + (corners[2][0][1] - corners[1][0][1]) * (
                    corners[2][0][1] - corners[1][0][1]))
        cardW = ratio * cardH;
        pts2 = np.float32(
            [[corners[0][0][0], corners[0][0][1]], [corners[0][0][0] + cardW, corners[0][0][1]], [corners[0][0][0] + cardW, corners[0][0][1] + cardH],
             [corners[0][0][0], corners[0][0][1] + cardH]])

        M = cv2.getPerspectiveTransform(corners, pts2)

        offsetSize = 500
        transformed = np.zeros((int(cardW + offsetSize), int(cardH + offsetSize)), dtype=np.uint8);
        dst = cv2.warpPerspective(img, M, transformed.shape)

До: https://imgur.com/a/H7HjFro

После: https://imgur.com/a/OA6Iscq

Как вы можете видеть на этих изображениях, они обнаруживают края внутри самой бумаги, а не ее угла. Стоит ли полностью использовать другой алгоритм? Я совсем растерялся.

Я пытался увеличить минимальное евклидово расстояние до 1000, но это действительно ничего не сделало.

Обратите внимание, это не чья-то реальная информация, это поддельный набор данных, найденный на Kaggle.

Набор данных kaggle можно найти https://www.kaggle.com/mcvishnu1/fake-w2-us-tax-form-dataset

1 Ответ

1 голос
/ 31 марта 2020

Вот один из способов сделать это в Python / OpenCV.

Обратите внимание, что найденные углы перечислены против часовой стрелки от самого верхнего угла.

  • Считайте ввод
  • Преобразовать в серый
  • размытие по Гауссу
  • порог Оцу
  • морфология открытия / закрытия для очистки порога
  • получение наибольшего контура
  • Приблизительный многоугольник из контур
  • Получить углы
  • Нарисовать многоугольник на входе
  • Вычислить длины сторон
  • Вычислить выходные значения соответствующих углов
  • Получить перспективу матрица преобразования из соответствующих угловых точек
  • Деформация входного изображения в соответствии с матрицей
  • Сохранение результатов

Ввод:

enter image description here

import cv2
import numpy as np

# read image
img = cv2.imread("efile.jpg")

# convert img to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# blur image
blur = cv2.GaussianBlur(gray, (3,3), 0)

# do otsu threshold on gray image
thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)[1]

# apply morphology
kernel = np.ones((7,7), np.uint8)
morph = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
morph = cv2.morphologyEx(morph, cv2.MORPH_OPEN, kernel)

# get largest contour
contours = cv2.findContours(morph, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
area_thresh = 0
for c in contours:
    area = cv2.contourArea(c)
    if area > area_thresh:
        area_thresh = area
        big_contour = c

# draw white filled largest contour on black just as a check to see it got the correct region
page = np.zeros_like(img)
cv2.drawContours(page, [big_contour], 0, (255,255,255), -1)

# get perimeter and approximate a polygon
peri = cv2.arcLength(big_contour, True)
corners = cv2.approxPolyDP(big_contour, 0.04 * peri, True)

# draw polygon on input image from detected corners
polygon = img.copy()
cv2.polylines(polygon, [corners], True, (0,0,255), 1, cv2.LINE_AA)
# Alternate: cv2.drawContours(page,[corners],0,(0,0,255),1)

# print the number of found corners and the corner coordinates
# They seem to be listed counter-clockwise from the top most corner
print(len(corners))
print(corners)

# for simplicity get average of top/bottom side widths and average of left/right side heights
# note: probably better to get average of horizontal lengths and of vertical lengths
width = 0.5*( (corners[0][0][0] - corners[1][0][0]) + (corners[3][0][0] - corners[2][0][0]) )
height = 0.5*( (corners[2][0][1] - corners[1][0][1]) + (corners[3][0][1] - corners[0][0][1]) )
width = np.int0(width)
height = np.int0(height)

# reformat input corners to x,y list
icorners = []
for corner in corners:
    pt = [ corner[0][0],corner[0][1] ]
    icorners.append(pt)
icorners = np.float32(icorners)

# get corresponding output corners from width and height
ocorners = [ [width,0], [0,0], [0,height], [width,height] ]
ocorners = np.float32(ocorners)

# get perspective tranformation matrix
M = cv2.getPerspectiveTransform(icorners, ocorners)

# do perspective 
warped = cv2.warpPerspective(img, M, (width, height))

# write results
cv2.imwrite("efile_thresh.jpg", thresh)
cv2.imwrite("efile_morph.jpg", morph)
cv2.imwrite("efile_polygon.jpg", polygon)
cv2.imwrite("efile_warped.jpg", warped)

# display it
cv2.imshow("efile_thresh", thresh)
cv2.imshow("efile_morph", morph)
cv2.imshow("efile_page", page)
cv2.imshow("efile_polygon", polygon)
cv2.imshow("efile_warped", warped)
cv2.waitKey(0)


пороговое изображение:

enter image description here

морфологически очищенное изображение:

enter image description here

Многоугольник на входе:

enter image description here

Извлеченные углы (против часовой стрелки из правого верхнего угла)

4

[[[693  67]]
 [[ 23  85]]
 [[ 62 924]]
 [[698 918]]]


Деформированный результат:

enter image description here

...