预处理低质量扫描的手写数字

19

我有几千个PDF文件,包含从数字化纸质表单中提取出的黑白图像(1位)。我正在尝试OCR一些字段,但有时书写太模糊:

输入图像描述

我刚刚学习了形态学变换。它们真的很酷!我感觉自己在滥用它们(就像我学Perl时滥用正则表达式一样)。

我只对日期07-06-2017感兴趣:

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

enter image description here

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')
现在我可以摆脱网格:

enter image description here

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

这里输入图片描述

我最好的结果是这个,但数字4仍然分成了两部分:

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

输入图像描述

可能此时最好使用cv2.findContours和一些启发式方法来定位每个数字,但我在思考:

  1. 我应该放弃并要求所有文档重新以灰度扫描吗?
  2. 是否有更好的方法来隔离和定位模糊的数字?
  3. 您知道任何形态学变换可以合并“4”这样的情况吗?

[更新]

重新扫描文档是否太过苛刻?如果没有太大的麻烦,我认为获取更高质量的输入比训练和尝试改进模型以承受嘈杂和非典型数据更好

背景信息:我是巴西公共机构的一个无名小卒。 ICR解决方案的价格从6位数开始,因此没有人相信一个人能在内部编写ICR解决方案。 我太天真了,以至于相信我可以证明他们是错误的。 这些PDF文件存放在FTP服务器上(约10万个文件),仅为了摆脱死树版本而进行了扫描。 可能我可以获取原始表格并自己扫描,但我必须要求一些官方支持-由于这是公共部门,因此我希望尽可能地保持这个项目的低调。 现在我有50%的错误率,但如果这种方法行不通,那么改进它就没有意义。


1
重新扫描文件是否过于费力?如果不是太麻烦的话,我认为最好获取更高质量的输入数据,而不是训练和尝试优化模型以承受嘈杂和非典型数据。 - DarkCygnus
@GrayCygnus:我可能需要穿越一片官僚主义和惯性的海洋,但这是有可能的。我可能需要亲自完成所有的手工工作。 - Paulo Scardine
1
顺便说一下,我已经成功地使用pytesseract来获取打印表格的编号。我已经成功地将70,000张图像与由专业人类打字员输入的数据库中相应的记录进行了链接。这已经很有用了,因为我发现了许多应该在数据库中但不在其中的文件。从政治上讲,这是一个冒险:如果我编写了一个揭露他们失误的系统,我会招致一些敌人,所以我希望展示其他东西。 - Paulo Scardine
手写识别是神经网络擅长的领域之一,有很多免费的.NET实现;它们通常会附带字符识别样本集作为其“示例”。 - PhillipH
@PhillipH 你说得对。这使得识别成为最容易的部分,而艰苦的工作是预处理图像以定位数字并规范化样本。例如,当一个数字像上面图片中的“4”一样被分割时,有时算法会将其视为“11”或“14”。 - Paulo Scardine
显示剩余2条评论
1个回答

8
也许可以使用某种主动轮廓模型? 例如,我找到了这个库:https://github.com/pmneila/morphsnakes 取您的最后一个“4”数字:

enter image description here

经过一些快速调整(没有真正理解参数,因此可能有更好的结果),我得到了这个:

enter image description here

使用以下代码(我还稍微修改了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)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接