Правильное определение порога изображения для подготовки к OCR в python с использованием opencv - PullRequest
0 голосов
/ 22 сентября 2018

Я действительно новичок в opencv и новичок в python.

У меня есть это изображение:

original bmp 24bit image

Я хочукаким-то образом применить правильное пороговое значение, чтобы оставить только 6 цифр.

В целом я намерен попытаться выполнить ручное распознавание изображений для каждой цифры отдельно, используя алгоритм k-ближайших соседей для каждой цифрыlevel (kNearest.findNearest)

Проблема в том, что я не могу достаточно почистить цифры, особенно цифру '7', через которую проходит этот синий водяной знак.

Шаги Iдо сих пор пробовал следующее:

Я читаю изображение с диска

# IMREAD_UNCHANGED is -1
image = cv2.imread(sys.argv[1], cv2.IMREAD_UNCHANGED)

Тогда я оставляю только синий канал, чтобы избавиться от синего водяного знака вокруг цифры '7', эффективно преобразуя его в одноканальное изображение

image = image[:,:,0] 
# openned with -1 which means as is, 
# so the blue channel is the first in BGR

single channel - red only - image

Затем я немного умножаю его, чтобы увеличить контраст между цифрами ифон:

image = cv2.multiply(image, 1.5)

multiplied image to increase contrast

Наконец я выполняю бинарный + отсечение порога:

_,thressed1 = cv2.threshold(image,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

binary Oahu thresholded image

Как вы видите конечный результатдовольно хорошо, за исключением цифры «7», которая сохранила много шума.

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

Ответы [ 4 ]

0 голосов
/ 23 сентября 2018

Вы можете попытаться создать среднеквадратическое размытие серого (размытого) изображения с разными ядрами (например, 3, 51), разделить размытые результаты и пороговое значение.Примерно так:

enter image description here


#!/usr/bin/python3
# 2018/09/23 17:29 (CST) 
# (中秋节快乐)
# (Happy Mid-Autumn Festival)

import cv2 
import numpy as np 

fname = "color.png"
bgray = cv2.imread(fname)[...,0]

blured1 = cv2.medianBlur(bgray,3)
blured2 = cv2.medianBlur(bgray,51)
divided = np.ma.divide(blured1, blured2).data
normed = np.uint8(255*divided/divided.max())
th, threshed = cv2.threshold(normed, 100, 255, cv2.THRESH_OTSU)

dst = np.vstack((bgray, blured1, blured2, normed, threshed)) 
cv2.imwrite("dst.png", dst)

Результат:

enter image description here

0 голосов
/ 23 сентября 2018

Кажется нелегко полностью удалить надоедливую печать.

Что вы можете сделать, это сгладить интенсивность фона с помощью

  • , вычисляя низкочастотное изображение (гауссовофильтр, морфологическое закрытие);размер фильтра должен быть немного больше размера символа;

  • , делив исходное изображение на изображение нижних частот.

Тогда вы можете использоватьОцу.

enter image description here

Как видите, результат не идеален.

0 голосов
/ 23 сентября 2018

Я попробовал немного другой подход, чем Ив на синем канале: Blue channel

  • Применить медианный фильтр (r = 2):

Filtered image

  • Использовать обнаружение краев (например, оператор Собеля):

Edges detected

  • Автоматическое установление порога (Оцу)

Thresholded image

  • Закрытие изображения

Closed image

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

0 голосов
/ 22 сентября 2018

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

Примерно так:

import cv2
import numpy as np

img = cv2.imread("./a.png")[:,:,0]  # the last readable image

new_img = []
for line in img:
    new_img.append(np.array(list(map(lambda x: 0 if x < 100 else 255, line))))

new_img = np.array(list(map(lambda x: np.array(x), new_img)))

cv2.imwrite("./b.png", new_img) 

Отлично выглядит:

Вероятно, вы могли бы играть с порогом еще больше и получить лучшие результаты.

...