票据识别的图片前处理

问题背景

在银行的票据识别的过程中,并非所有的票据都是完整的一张图,有一些票据图片是倾斜并且有背景的,这种在票据识别的版式(也称模板)粗切时,会出现大量的粗切不准现象。所以对这类OCR的票据识别的图片,有必要对其进行规整。

处理算法

这里的处理主要还是看图片本身的情况如何,我们接触到的图片,前景为浅色的矩形,大多数是整张票据,但有部分图片中的票据有某几边是存在较深颜色的背景的。并且在深颜色的背景中,还可能会有闪光灯拍照造成的高光区域,颜色基本和票据颜色相近。如果采用普通的找矩形轮廓再透视变换的方法,极可能把大多数整张票据的轮廓进行裁剪,造成处理后的票据图并非整张票据。所以这里需要对此进行特殊处理。下面进行处理算法的详细描述。

二值化图像

这里的二值化票据图像的目标就是要把票据的前景显示为白,其他为黑。

首先是把图像转为灰阶图,然后用Otsu算法进行二值化,关于Otsu算法,笔者有一篇专门的文章描述其原理- Otsu算法。在二值化之后,就可以进行形态学闭运算,把票据中的的内容进行清除,减少找轮廓的运算量。这里的闭运算采用的核为10阶。

边缘加边

这个想法是整个方案中比较特殊的一个处理。因为如果是已经整张图都是前景票据,这个时候去找轮廓基本上都会影响票据的正常大小。所以这里有一个处理方法是在上述二值化之后的图片的四边均加上一个小边,这个小边的要求是基本上比有深背景的图片的深背景宽度要小。这里取的是20个像素。

寻找轮廓

在边缘加边了之后就可以去大胆找轮廓而不用担心轮廓找错,寻找最大的轮廓即可。

多边拟合

在找到最大轮廓之后即可对其进行拟合,可以加大类似于tolerance之类的系数让其尽量为一个矩形,从而忽略掉可能会影响轮廓查找的闪光灯高光。

顶点排序

顶点排序,即把所有的轮廓点作为输入,找到矩形顶点并进行排序,方便后面透视变换。这里直接把代码打在如下,其中pts为n个二维点的numpy矩阵。

1
2
3
4
5
6
7
8
9
10
# 四边形顶点排序,[top-left, top-right, bottom-right, bottom-left]
def orderPoints(pts):
rect = np.zeros((4, 2), dtype="float32")
s = pts.sum(axis=1)
rect[0] = pts[np.argmin(s)]
rect[2] = pts[np.argmax(s)]
diff = np.diff(pts, axis=1)
rect[1] = pts[np.argmin(diff)]
rect[3] = pts[np.argmax(diff)]
return rect

透视变换

这个没什么好说的,就是把顶点排序之后的顶点对应到目标顶点直接调接口进行透视变换。目标顶点即为我们需要的分辨率的四个顶点。

遗留问题

整个方案的图片处理正确率在98%左右,其他无法处理有如下几类:1.整体亮度都非常暗,2.整体亮度都非常亮或者背景都是浅色背景和前景无法区分者。由于要兼顾效率与效果,目前处理结果已能接受。另外就是在无Opencv的环境还用skimage进行了全套实现。如果有任何问题可以在正文评论提出或者在github的repo中提出。

参考

github源码

瑾锋 wechat
心明录公众号