为OCR准备复杂的图像

val*_*tin 12 ocr image-processing edge-detection

我想识别信用卡上的数字.更糟糕的是,源图像不能保证高质量.OCR将通过神经网络实现,但这不应该是这里的主题.

当前的问题是图像预处理.由于信用卡可以具有背景和其他复杂图形,因此文本不像扫描文档那样清晰.我用边缘检测(Canny Edge,Sobel)进行了实验,但并没有那么成功.同时计算灰度图像和模糊图像之间的差异(如OCR图像处理中的删除背景颜色所述)不会导致OCRable结果.

我认为大多数方法都失败了,因为特定数字与其背景之间的对比不够强.可能需要将图像分割成块并为每个块找到最佳的预处理解决方案?

您对如何将源转换为可读二进制图像有任何建议吗?边缘检测是要走的路还是我应该坚持基本的颜色阈值?

这是一个灰度阈值方法的示例(我显然对结果不满意):

原始图片:

原始图像

灰度图像:

灰度图像

阈值图像:

阈值图像

感谢任何建议,Valentin

Ale*_*xey 5

我如何解决问题的方法是将卡片分成不同的部分.开始时没有很多独特的信用卡(万事达卡,维萨卡,列表由您决定),因此您可以像下拉菜单一样指定信用卡.这样,您可以消除并指定像素区域:

例:

仅适用于从底部20像素,从左边30像素到右边10像素到底部30像素的区域(创建一个矩形) - 这将涵盖所有万事达卡

当我使用图像处理程序(有趣的项目)时,我调高了图像的对比度,将其转换为灰度,将每个RGB值的平均值取为1像素,并将其与周围像素进行比较:

例:

PixAvg[i,j] = (Pix.R + Pix.G + Pix.B)/3
if ((PixAvg[i,j] - PixAvg[i,j+1])>30)
    boolEdge == true;
Run Code Online (Sandbox Code Playgroud)

30你想要你的形象是多么独特.差异越小,容差越低.

在我的项目中,为了查看边缘检测,我制作了一个单独的布尔数组,其中包含来自boolEdge和像素数组的值.像素阵列仅填充黑色和白色点.它得到了布尔数组中的值,其中boolEdge = true是一个白点,boolEdge = false是一个黑点.所以最后,你最终会得到一个只包含白点和黑点的像素阵列(全图).

从那里,可以更容易地检测数字的开始位置和数字的完成位置.


Ret*_*unk 5

如果可能的话,请求使用更好的照明来捕获图像.低角度灯光会照亮凸起(或凹陷)字符的边缘,从而大大提高图像质量.如果要通过机器分析图像,则应针对机器可读性优化照明.

也就是说,您应该研究的一个算法是笔划宽度变换,它用于从自然图像中提取字符.

笔画宽度变换(SWT)实现(Java,C#...)

全局阈值(用于二值化或削波边缘强度)可能不会为此应用程序削减它,而是应该查看本地化阈值.在您的示例图像中,"31"之后的"02"特别弱,因此在该区域中搜索最强的局部边缘将比使用单个阈值过滤字符串中的所有边缘更好.

如果您可以识别部分字符段,则可以使用某些方向形态操作来帮助连接段.例如,如果你有两个几乎水平的段,如下所示,其中0是背景,1是前景......

0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 1 1 1 0 0 1 1 1 1 1 1 0 0 0
0 0 0 1 0 0 0 1 0 1 0 0 0 0 1 0 0 0
Run Code Online (Sandbox Code Playgroud)

那么你可以沿水平方向执行形态学"关闭"操作,只是为了加入这些段.内核可能是这样的

x x x x x
1 1 1 1 1
x x x x x
Run Code Online (Sandbox Code Playgroud)

有更复杂的方法可以使用Bezier拟合甚至欧拉螺旋(也称为回旋曲线)来完成曲线完成,但是预处理以识别要连接的段和后处理以消除不良连接可能会变得非常棘手.