提高图像中字母的质量

5
我正在处理带有文本的图像。问题是这些图像是收据,在经过大量转换后,文本失去了质量。我使用Python和OpenCV。我尝试了很多形态学变换的组合,来自形态学变换文档,但我没有得到令人满意的结果。我目前正在进行以下操作(我将注释我尝试过的内容,并让未注释的内容保持不变):
kernel = np.ones((2, 2), np.uint8)
# opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
# closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
# dilation = cv2.dilate(opening, kernel, iterations=1)
# kernel = np.ones((3, 3), np.uint8)
erosion = cv2.erode(img, kernel, iterations=1)
# gradient = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel)
#
img = erosion.copy()

通过这个,从原始图像:

enter image description here

我得到了这个:

enter image description here

你可以看到它有一点改善。但是依然不够好。OCR(tesseract)不能很好地识别这里的字符。我进行过训练,但正如你所看到的,每个“e”都是不同的。
我得到了不错的结果,但如果解决这个问题,结果将更好。也许我可以做另一件事情,或者使用更好的形态学变换组合。如果有其他工具(PIL,imagemagick等),我可以使用它们。
这是整张图片,你可以看到它的样子:

enter image description here

就像我说的,它并不差,但对字母进行更多的“优化”将是完美的。

1
尝试使用形态学闭合而不是腐蚀。至于字母,它们似乎从一开始就不同,所以我认为你不能仅仅使用简单的算法来解决这个问题。一些扫描仪会用完全相同的位图替换类似的字母,因此您可以复制此行为。但要小心:施乐机器中有一个非常丑陋的错误,使图书管理员的生活非常不舒服。 - meetaig
4个回答

3
经过多年的工作,我可以告诉你,我想做的事情需要付出很大的努力,速度相当缓慢,并且从未像我预期的那样工作。字符中像素的不规则性总是不可预测的,这就是为什么“简单的算法”行不通的原因。
问题:那么,有没有可能拥有一个可以读取损坏字符的体面OCR呢?
答案:不是不可能,但需要比使用腐蚀、形态学闭合或类似方法“多一点”。
那么,怎么做?神经网络 :)
这里有两篇非常棒的论文,对我非常有帮助: 我们能否使用LSTM网络构建语言无关的OCR? 在深度卷积序列中阅读场景文本 对于那些不熟悉RNN的人,我可以建议这个: 理解LSTM网络

还有一个Python库,它的表现相当不错(遗憾的是,对于C++来说甚至更好):

ocropy

我真的希望这能帮助到某些人。


0

0
在我的经验中,腐蚀会影响OCR的质量。如果您有灰度图像(而不是二进制图像),则可以使用更好的二值化算法。我使用SAUVOLA算法进行二值化处理。如果您只有二进制图像,最好的方法是去除噪点(删除所有小点)。

谢谢你的回答。你如何使用Sauvola?使用Leptonica吗?我使用OpenCV提供的Otsu二值化,但如果我找到如何在Python中实现(或使用)它,也可以尝试使用Sauvola。 - Chuck Aguilar
我使用SAUVOLA算法的C++实现。https://github.com/benob/opencv-utils/blob/master/include/binarize.h此外,您也可以尝试使用MEAN的自适应阈值(http://docs.opencv.org/3.1.0/d7/d4d/tutorial_py_thresholding.html)。这种二值化方法显示出与SAUVOLA类似的结果。 - Andrey Macritskiy

0

你考虑了相邻的像素并将它们的总和加起来吗?

例如:

n = numpy.zeros((3,3))
s = numpy.zeros((3,3))
w = numpy.zeros((3,3))
e = numpy.zeros((3,3))

n[0][1] = 1
s[2][1] = 1
w[1][0] = 1
e[1][2] = 1

img_n = cv2.erode(img, n, iterations=1)
img_s = cv2.erode(img, s, iterations=1)
img_w = cv2.erode(img, w, iterations=1)
img_e = cv2.erode(img, e, iterations=1)

result = img_n + img_s + img_w + img_e + img

另外,您可以使用numpy或cv2来添加数组。


谢谢,我会寻找“邻近像素算法”之类的东西。 但是,在你提供给我的答案中,我认为你用 n[4] 指的是 n[1][0],对吗?因为 n 是一个有 3 行 3 列的矩阵。 然而,它并没有起作用。结果看起来和 img 完全一样。也许需要做出一些改变。 - Chuck Aguilar
更新了答案并修改了掩模。基本上是'n'在北方方向上更加重要,'s'在南方方向上更加重要,依此类推。你能否增加卷积掩模的大小并尝试一下呢? - v.coder

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