Как определить текст над строками, используя OpenCV в Python - PullRequest
0 голосов
/ 14 апреля 2020

Я заинтересован в обнаружении линий (которые мне удалось выяснить с помощью грубого преобразования) и текста над ним.

Мое тестовое изображение ниже: Test Image

Код, который я написал ниже. (Я отредактировал так, чтобы я мог l oop через координаты каждой линии)

import cv2
import numpy as np

img=cv2.imread('test3.jpg')
#img=cv2.resize(img,(500,500))
imgGray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
imgEdges=cv2.Canny(imgGray,100,250)
imgLines= cv2.HoughLinesP(imgEdges,1,np.pi/180,230, minLineLength = 700, maxLineGap = 100)
imgLinesList= list(imgLines)

a,b,c=imgLines.shape
line_coords_list = []
for i in range(a):
    line_coords_list.append([(int(imgLines[i][0][0]), int(imgLines[i][0][1])), (int(imgLines[i][0][2]), int(imgLines[i][0][3]))])

print(line_coords_list)#[[(85, 523), (964, 523)], [(85, 115), (964, 115)], [(85, 360), (964, 360)], [(85, 441), (964, 441)], [(85, 278), (964, 278)], [(85, 197), (964, 197)]]

roi= img[int(line_coords_list[0][0][1]): int(line_coords_list[0][1][1]), int(line_coords_list[0][0][0]) : int(line_coords_list[0][1][0])]
print(roi) # why does this print an empty list?
cv2.imshow('Roi NEW',roi) 




Теперь я просто не знаю, как определить интересующую область над этими линиями. Можно ли сказать обрезать каждую строку и иметь изображения, например, roi_1, roi_2, roi_n, где каждый roi - это текст над первой строкой, текст над второй строкой et c?

Мне бы хотелось вывод будет примерно таким.

Ответы [ 2 ]

1 голос
/ 14 апреля 2020

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

  • Считать ввод
  • Преобразовать в серый
  • Порог (OTSU), чтобы текст белый на черном фоне
  • Применение морфологии с горизонтальным ядром для размытия текста в одной строке вместе
  • Применение морфологии с вертикальным ядром для удаления тонких линий из пунктирных линий
  • Получить контуры
  • Найти контур, который имеет наименьшее значение Y ограничивающего прямоугольника (самый верхний прямоугольник)
  • Нарисовать все ограничивающие прямоугольники на входе, кроме самого верхнего
  • Сохранить результаты

Ввод:

enter image description here

import cv2
import numpy as np

# load image
img = cv2.imread("text_above_lines.jpg")

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

# threshold the grayscale image
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]

# use morphology erode to blur horizontally
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (151, 3))
morph = cv2.morphologyEx(thresh, cv2.MORPH_DILATE, kernel)

# use morphology open to remove thin lines from dotted lines
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 17))
morph = cv2.morphologyEx(morph, cv2.MORPH_OPEN, kernel)

# find contours
cntrs = cv2.findContours(morph, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cntrs = cntrs[0] if len(cntrs) == 2 else cntrs[1]

# find the topmost box
ythresh = 1000000
for c in cntrs:
    box = cv2.boundingRect(c)
    x,y,w,h = box
    if y < ythresh:
        topbox = box
        ythresh = y

# Draw contours excluding the topmost box
result = img.copy()
for c in cntrs:
    box = cv2.boundingRect(c)
    if box != topbox:
        x,y,w,h = box
        cv2.rectangle(result, (x, y), (x+w, y+h), (0, 0, 255), 2)

# write result to disk
cv2.imwrite("text_above_lines_threshold.png", thresh)
cv2.imwrite("text_above_lines_morph.png", morph)
cv2.imwrite("text_above_lines_lines.jpg", result)

#cv2.imshow("GRAY", gray)
cv2.imshow("THRESH", thresh)
cv2.imshow("MORPH", morph)
cv2.imshow("RESULT", result)
cv2.waitKey(0)
cv2.destroyAllWindows()


Предел изображения:

enter image description here

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

enter image description here

Результат:

enter image description here

1 голос
/ 14 апреля 2020

Вы обнаружили линии. Теперь вам нужно разделить изображение на области между строками, используя координаты y, а затем выполнить поиск черных пикселей (слов) на белом фоне (бумаге).

Построение гистограммы вдоль x и y Оси, скорее всего, дадут вам интересующую вас область.


Просто для ответа на ваши вопросы в комментариях, например, если у вас есть изображение img и область интерес с y координатами (100,200), охватывающими всю ширину изображения, вы можете обрезать эту область вниз и искать там что-нибудь вроде этого:

cropped = img[100:200,5:-5]  # crop a few pixels off in x-direction just in case

Теперь поиск:

top, left = 10000, 10000
bottom, right = 0, 0
for i in range(cropped.shape[0]) :
    for j in range(cropped.shape[1]) :
        if cropped[i][j] < 200 :    # black?
            top = min( i, top)
            bottom = max( i, bottom)
            left = min( j, left)
            right = max( j, right)

Или что-то в этом роде ...

...