Есть ли лучший способ отделить текст от фона? [Python] [Opencv]

Я работаю над проектом, в котором мне нужно подать заявление и OCR на некоторые документы.
Первым шагом является пороговое изображение и разрешить только написание (отбелить фон).

Пример входного изображения: (по соображениям GDPR и конфиденциальности это изображение из Интернета)

введите описание изображения здесьВот мой код:

import cv2
import numpy as np


image = cv2.imread('b.jpg')
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
h = image.shape[0]
w = image.shape[1]
for y in range(0, h):
    for x in range(0, w):
        if image[y, x] >= 120:
            image[y, x] = 255
        else:
            image[y, x] = 0
cv2.imwrite('output.jpg', image)

Вот результат, который я получил:

введите описание изображения здесь

Когда я применил pytesseract к выходному изображению, результаты не были удовлетворительными (я знаю, что OCR не идеален). Хотя я пытался отрегулировать пороговое значение (в этом коде оно равно 120), результат оказался не таким ясным, как я хотел.

Есть ли способ сделать лучший порог, чтобы надпись была только черной, а остальные отбеливали?

3 ответа

Решение

Вы можете использовать адаптивный порог. Из документации:

При этом алгоритм вычисляет порог для небольших областей изображения. Таким образом, мы получаем разные пороговые значения для разных областей одного и того же изображения, и это дает нам лучшие результаты для изображений с разной освещенностью.

import numpy as np
import cv2



image = cv2.imread('b.jpg')
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
image = cv2.medianBlur(image ,5)

th1 = cv2.adaptiveThreshold(image,255,cv2.ADAPTIVE_THRESH_MEAN_C,\
            cv2.THRESH_BINARY,11,2)
th2 = cv2.adaptiveThreshold(image,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,\
            cv2.THRESH_BINARY,11,2)
cv2.imwrite('output1.jpg', th1 )
cv2.imwrite('output2.jpg', th2 )

После глубокого изучения вопросов переполнения стека я нашел ответ, который касается удаления водяных знаков с помощью opencv. Я адаптировал код под свои нужды, и вот что я получил:

import numpy as np
import cv2


image = cv2.imread('a.png')
img = image.copy()

alpha =2.75
beta = -160.0

denoised = alpha * img + beta
denoised = np.clip(denoised, 0, 255).astype(np.uint8)

#denoised = cv2.fastNlMeansDenoising(denoised, None, 31, 7, 21)

img = cv2.cvtColor(denoised, cv2.COLOR_BGR2GRAY)

h = img.shape[0]
w = img.shape[1]

for y in range(0, h):
    for x in range(0, w):
        if img[y, x] >= 220:
            img[y, x] = 255
        else:
            img[y, x] = 0

cv2.imwrite('outpu.jpg', img)

Вот выходное изображение:

введите описание изображения здесь

Хорошая вещь в этом коде в том, что он дает хорошие результаты не только с этим изображением, но и со всеми изображениями, которые я тестировал.

Надеюсь, это поможет любому, у кого была такая же проблема.

OpenCV имеет пороговую функцию.

image = cv2.imread('b.jpg', 0)
image = cv2.medianBlur(image, 5)
ret,th = cv2.threshold(image, 125, 255, cv2.THRESH_BINARY)

th пороговое изображение видно здесь

Изменить: Обратите внимание, что предложенный адаптивный порог не будет работать, потому что он будет подбирать фоновые функции.

Другие вопросы по тегам