Удалить не прямые линии из текстового изображения - PullRequest
5 голосов
/ 24 октября 2019

У меня есть изображение, содержащее текст, но на нем нарисованы не прямые линии.

enter image description here

Я хочу удалить эти строки, не затрагивая и не удаляя что-либо из текста.
Для этого я использовал вероятностное преобразование Хау:

import cv2
import numpy as np


def remove_lines(filename):
    img = cv2.imread(filename)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    edges = cv2.Canny(gray, 50, 200)
    lines = cv2.HoughLinesP(edges, rho=1, theta=1*np.pi/180,
                            threshold=100, minLineLength=100, maxLineGap=5)
    # Draw lines on the image
    for line in lines:
        x1, y1, x2, y2 = line[0]
        cv2.line(img, (x1, y1), (x2, y2), (0, 0, 255), 3)

    cv2.imwrite('result', img) 

Результат оказался не таким хорошим, как я ожидал:

enter image description here

Линии не были полностью обнаружены (только некоторые сегменты, прямыебыли обнаружены сегменты линий).
Я внес некоторые изменения в параметры cv2.Canny и cv2.HoughLinesP, но это тоже не сработало.

Я также пытался cv2.createLineSegmentDetector (недоступно в последней версии opencv из-за проблемы с лицензией, поэтому мне пришлось понизить версию opencv до версии 4.0.0.21):

import cv2
import numpy as np
def remove_lines(filename):
    im = cv2.imread(filename)
    gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
    # Create default parametrization LSD
    lsd = cv2.createLineSegmentDetector(0)

    # Detect lines in the image (Position 0 of the returned tuple are the
    # detected lines)
    lines = lsd.detect(gray)[0]

    # drawn_img = lsd.drawSegments(res, lines)
    for element in lines:
        if (abs(int(element[0][0]) - int(element[0][2])) > 70 or
                abs(int(element[0][1]) - int(element[0][3])) > 70):
            cv2.line(im, (int(element[0][0]), int(element[0][1])), (int(
                element[0][2]), int(element[0][3])), (0, 0, 255), 3)
    cv2.imwrite('lsd.jpg', im)  

Результатбыло немного лучше, но не обнаружил целые строки.

enter image description here

Есть идеи, как сделать обнаружение линий более эффективным?

Ответы [ 2 ]

3 голосов
/ 25 октября 2019

Типичные методы удаления линий - использование горизонтальных / вертикальных ядер или cv2.HoughLinesP(), но эти методы работают, только если линии прямые. В этом случае линии не являются прямыми, поэтому идея состоит в том, чтобы использовать диагональное ядро, морфологические преобразования и контурную фильтрацию для удаления линий из текста. Я буду использовать подход предыдущего ответа, найденный в удалении горизонтальных линий в изображении , но с диагональным ядром


Мы начнем с преобразования изображения в оттенки серого и выполним порог Оцу, чтобы получитьдвоичное изображение. Затем мы создаем диагональное ядро, затем выполняем морфологическое закрытие, чтобы обнаружить / отфильтровать диагональные линии. Поскольку cv2.getStructuringElement() не имеет встроенного диагонального ядра, мы создаем свое собственное

image

# Read in image, grayscale, and Otsu's threshold
image = cv2.imread('1.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255,cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]

# Create diagonal kernel
kernel = np.array([[0, 0, 1],
                   [0, 1, 0],
                   [1, 0, 0]], dtype=np.uint8)
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=1)

Изображение изолировало основные диагональные линии, но онотакже включены небольшие строки из текста. Чтобы удалить их, мы находим контуры и фильтруем, используя область контура. Если контур проходит через наш фильтр, мы эффективно удаляем шум, «заполняя» контур с помощью cv2.drawContours(). Это оставляет нам желаемые диагональные линии для удаления

image

# Find contours and filter using contour area to remove noise
cnts = cv2.findContours(opening, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    area = cv2.contourArea(c)
    if area < 500:
        cv2.drawContours(opening, [c], -1, (0,0,0), -1)

Отсюда мы просто cv2.bitwise_xor() с исходным изображением, чтобы получить наш результат

image

# Bitwise-xor with original image
opening = cv2.merge([opening, opening, opening])
result = cv2.bitwise_xor(image, opening)

Примечания: Трудно удалить строки, не затрагивая текст, хотя это возможно и потребует некоторых хитрых уловок, чтобы «исправить» текст. Взгляните на удаление границ с изображения, но оставьте текст написанным на границах , чтобы найти способ восстановить отсутствующий текст. Другим методом выделения диагональных линий может быть противоположный подход;вместо того, чтобы пытаться обнаружить диагностические линии, почему бы не попытаться определить, что не является диагностической линией. Возможно, вы могли бы сделать это с помощью простых методов фильтрации. Для создания динамических диагональных ядер вы можете использовать np.diag() для различной ширины диагональной линии

Полный код для полноты

import cv2
import numpy as np

# Read in image, grayscale, and Otsu's threshold
image = cv2.imread('1.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255,cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]

# Create diagonal kernel
kernel = np.array([[0, 0, 1],
                   [0, 1, 0],
                   [1, 0, 0]], dtype=np.uint8)
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=1)

# Find contours and filter using contour area to remove noise
cnts = cv2.findContours(opening, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    area = cv2.contourArea(c)
    if area < 500:
        cv2.drawContours(opening, [c], -1, (0,0,0), -1)

# Bitwise-xor with original image
opening = cv2.merge([opening, opening, opening])
result = cv2.bitwise_xor(image, opening)

cv2.imshow('thresh', thresh)
cv2.imshow('opening', opening)
cv2.imshow('result', result)
cv2.waitKey()
0 голосов
/ 24 октября 2019

Используйте connectedComponentsWithStats, чтобы найти два самых длинных подключенных компонента на изображении.

...