Есть ли лучший способ отделить текст от фона? [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
пороговое изображение видно здесь
Изменить: Обратите внимание, что предложенный адаптивный порог не будет работать, потому что он будет подбирать фоновые функции.