Предварительная обработка плохо отсканированных рукописных цифр

У меня есть несколько тысяч PDF файлов, содержащих B & W-изображения (1 бит) из оцифрованных бумажных форм. Я пытаюсь OCR некоторых полей, но когда-то написание слишком слабый:

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

Я только что узнал о морфологических трансформациях. Они действительно классные!!! Я чувствую, что я злоупотребляю ими (например, я делал это с регулярными выражениями, когда узнал Perl).

Меня интересует только дата, 07-06-2017:

im = cv2.blur(im, (5, 5))
plt.imshow(im, 'gray')

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

ret, thresh = cv2.threshold(im, 250, 255, 0)
plt.imshow(~thresh, 'gray')

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

Люди, заполняющие эту форму, похоже, не обращают внимания на сетку, поэтому я попытался избавиться от нее. Я могу выделить горизонтальную линию с помощью этого преобразования:

horizontal = cv2.morphologyEx(
    ~thresh, 
    cv2.MORPH_OPEN, 
    cv2.getStructuringElement(cv2.MORPH_RECT, (100, 1)),
)
plt.imshow(horizontal, 'gray')

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

Я могу получить и вертикальные линии:

plt.imshow(horizontal ^ ~thresh, 'gray')

ret, thresh2 = cv2.threshold(roi, 127, 255, 0)
vertical = cv2.morphologyEx(
    ~thresh2, 
    cv2.MORPH_OPEN, 
    cv2.getStructuringElement(cv2.MORPH_RECT, (2, 15)), 
    iterations=2
)
vertical = cv2.morphologyEx(
    ~vertical, 
    cv2.MORPH_ERODE, 
    cv2.getStructuringElement(cv2.MORPH_RECT, (9, 9))
)
horizontal = cv2.morphologyEx(
    ~horizontal, 
    cv2.MORPH_ERODE, 
    cv2.getStructuringElement(cv2.MORPH_RECT, (7, 7))
)
plt.imshow(vertical & horizontal, 'gray')

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

Теперь я могу избавиться от сетки:

plt.imshow(horizontal & vertical & ~thresh, 'gray')

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

Лучшее, что я получил, было это, но 4 все еще разделены на 2 части:

plt.imshow(cv2.morphologyEx(im2, cv2.MORPH_CLOSE, 
    cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))), 'gray')

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

Вероятно, в этот момент лучше использовать cv2.findContours и некоторую эвристику, чтобы найти каждую цифру, но мне было интересно:

  • Должен ли я отказаться и потребовать повторного сканирования всех документов в оттенках серого?
  • существуют ли более эффективные методы для выделения и определения слабых цифр?
  • Знаете ли вы какое-либо морфологическое преобразование, чтобы присоединиться к случаям типа "4"?

[обновление]

Является ли повторное сканирование документов слишком требовательным? Если нет больших проблем, я считаю, что лучше получить более качественные входы, чем обучение, и попытаться усовершенствовать вашу модель, чтобы выдерживать шумные и нетипичные данные.

Немного контекста: Я не работаю в государственном агентстве в Бразилии. Цена на решения ICR начинается с 6 цифр, поэтому никто не верит, что один парень может написать решение ICR на дому. Я достаточно наивен, чтобы поверить, что могу доказать, что они неправы. Эти документы PDF сидели на FTP-сервере (около 100 тыс. Файлов) и были отсканированы только для того, чтобы избавиться от мертвой версии дерева. Вероятно, я могу получить оригинальную форму и снова просмотреть ее, но я должен был бы попросить некоторую официальную поддержку - так как это государственный сектор, я хотел бы как можно больше сохранить этот проект под землей. У меня сейчас частота ошибок 50%, но если этот подход является тупиком, нет смысла пытаться его улучшить.

Ответы

Ответ 1

Может быть, с активная модель контура? Например, я нашел эту библиотеку: https://github.com/pmneila/morphsnakes

Взял свой последний номер "4":

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

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

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

со следующим кодом (я также немного взломал в morphsnakes.py, чтобы сохранить изображения):

import morphsnakes

import numpy as np
from scipy.misc import imread
from matplotlib import pyplot as ppl

def circle_levelset(shape, center, sqradius, scalerow=1.0):
    """Build a binary function with a circle as the 0.5-levelset."""
    grid = np.mgrid[list(map(slice, shape))].T - center
    phi = sqradius - np.sqrt(np.sum((grid.T)**2, 0))
    u = np.float_(phi > 0)
    return u

#img = imread("testimages/mama07ORI.bmp")[...,0]/255.0
img = imread("four.png")[...,0]/255.0

# g(I)
gI = morphsnakes.gborders(img, alpha=900, sigma=3.5)

# Morphological GAC. Initialization of the level-set.
mgac = morphsnakes.MorphGAC(gI, smoothing=1, threshold=0.29, balloon=-1)
mgac.levelset = circle_levelset(img.shape, (39, 39), 39)

# Visual evolution.
ppl.figure()
morphsnakes.evolve_visual(mgac, num_iters=50, background=img)