今天,我们将介绍使用(opencv/python ) OCR处理银行票据的方法。 文末有代码和相关文档的下载!
第一部分介绍两个主题。
1 .首先,对MICR E-13B字体、美国、英国、加拿大等国家支票中使用的字体进行说明。
2 .接着,讨论从MICR E-13B参考图像中提取数字和符号的方法。 这样可以提取每个字符的ROI,并将其用于OCR银行支票。
MICR E-13B字体:
MICR (磁性墨水文字识别)是处理文件的金融工业技术。
MICR的E-13B变体包含14个字符。
数字:数字0-9。
过境:银行分行的隔断。
金额:交易金额的分隔符。
本公司使用客户的账户分隔符。
dash (数字分隔符)根目录和账户之间等。
银行支票的文字识别似乎更难:
银行支票上使用的MICR E-13B字体中,数字有轮廓。 但是,控制符号每个角色有三个轮廓,使任务更加困难。 我们不能使用简单的轮廓和边框方法。 相反,需要设计自己的方法来确保提取数字和符号。
用OpenCV提取MICR的数字和符号:
创建一个名为bank_check_ocr.py的新文件,然后插入以下代码:
# # importthenecessarypackagesfromskimage.segmentationimportclear _ border首先,导入所需的各种软件包,以确保程序正常工作
OpenCV :从该页面中选择适合系统的安装版本。
sci工具包-图像:这是用pip安装的pip安装- usci工具包-图像
numpy :通过pipinstallnumpy。
imutils :这是一个可以通过pip安装: pip安装--upgradeimutils的地方。
然后,构建从MICR字体中提取字符的函数。
对于ef extract _ digits _ and _ symbols (图像,字符,最小值=5,最小值=15 ) :初学者,我们的功能需要四个参数。
image:MICR E-13B字体图像(代码下载提供)。
charCnts :包含参照图像中文字轮廓的列表。
minW :表示最小字符宽度的可选参数。 默认值为5像素宽。
minH :最小文字高度。 默认值为15像素。
然后,初始化charCnts列表中的迭代者。 列表对象本质上是“可重复的”,这意味着__iter__方法由生成器执行。
最后初始化空列表,保存我们的rois (感兴趣的区域)和LOC )的位置。 在函数的最后一个元组中返回这些列表。
让我们来看看迭代器的工作原理:
while True:在我们的函数中,我们开始了无限循环。 我们的退出条件是捕捉到停止迭代器异常的时候。 为了捕捉该异常,需要设定try-catch块。 每次循环迭代时,调用next(Chariter )获取下一个字符的轮廓。 可以从该函数调用中提取矩形的(x,y )坐标和宽度/高度。 然后初始化roi,在短时间内保存文字图像。
然后,确认边框的宽度和高度大小,并采取适当的措施。
if cW=minW and cH=minH:字符计数器的大小分别在最小宽度和高度以上时,请采取以下措施。
1 .使用在我们的边界矩形中调用的坐标和width/height从图像中提取roi。 将roi添加到rois中。
向locs添加元组。 元组由矩形两个角的(x,y )坐标组成。 稍后返回这个地方的列表。
否则,假设您使用的是MICRE-13B字符符号,需要应用一组更高级的处理操作。
else:if-else中的else块包含用于分析MICR E-13B字体中多个轮廓的特殊符号的逻辑。 我们做的第一件事是做符号的部分。 为了了解有轮廓的角色的边框,需要了解有三个轮廓的角色的边框。 为了实现这一点,需要在sYB中初始化四个包围盒参数sXA。
在此,循环使用表示字符/符号的列表的一部分。 使用边界矩形参数比较和计算与先前值相关的最小值和最大值。 这是首先在sYB中将sXA初始化为正/负无限值的理由。
现在找到了包围符号的框的坐标。 从图像中提取roi,将roi添加到rois中,将长方体坐标元组添加到locs中
我们函数剩下的代码块处理我们的while循环结束条件和return语句。
Ex
cept StopIteration:如果在charIter(我们的iterator对象)上调用next来抛出一个StopIteration异常,那么说明我们已经到达了最后一个轮廓。
现在我们已经准备好解析命令行参数并继续执行脚本:
ap = argparse.ArgumentParser()在上面的代码中,我们建立了两个必需的命令行参数:
·- image:我们的查询图像。
·- reference:我们的参考MICR E-13B字体图像。
接下来,我们将为每个符号/字符创建“名称”,并将其存储在列表中。
charNames = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "T", "U", "A", "D"]上面的代码很简单,我们只是在参考图像中从左到右建立了我们遇到的符号的名称。
注意:由于OpenCV不支持unicode中的绘图字符,因此需要定义“T”表示transit,“U”表示“on-us”,“A”表示amount,“D”表示dash。
接下来,我们将参考图像加载到内存中,并执行一些预处理:
ref = cv2.imread(args["reference"])ref = cv2.cvtColor(ref, cv2.COLOR_BGR2GRAY)ref = imutils.resize(ref, width=400)ref = cv2.threshold(ref, 0, 255, cv2.THRESH_BINARY_INV |cv2.THRESH_OTSU)[1]在上面的代码中,我们完成了四个任务:
1.加载图像到存储器中作为参考。
2.图片转换为灰度级。
3.调整width=400。
4.使用Otsu方法的二进制逆阈值。
这些简单操作的结果可以在下图中看到:
其余的代码遍历分为两部分。首先,我将向您展示一个逻辑和简单的轮廓方法以及生成的图像。
然后,我们将继续使用更高级的方法,利用我们在脚本顶部写的函数extract_digits_and_symbols。
对于这两个部分,我们将使用一些常见的数据,包括ref(参考图像,我们刚刚预处理的)和refCnt(参考轮廓,我们即将提取)。
refCnts = cv2.findContours(ref.copy(), cv2.RETR_EXTERNAL,要从参考图像中提取轮廓,我们利用OpenCV的cv2 .findContours函数
接下来,我们要绘制图像,所以我们将所有频道复制到上称为克隆的图像。在显示结果之前,简单轮廓方法的最后一步是循环遍历排序轮廓。在这个循环中,我们计算每个轮廓的边界框,然后在其周围绘制一个矩形。通过显示图像显示结果并在此处暂停直到按下一个键参见图4
你看到这种方法的问题吗?问题是我们有22个边框,而不是所需的14个边界轮廓(每个角色一个)。显然,这个问题可以通过更先进的方法来解决。
更先进的方法如下所示和描述
(refROIs, refLocs) = extract_digits_and_symbols(ref, refCnts,我们初始化一个空字典,chars,它将保存每个符号的name和roi。我们通过用新的ref副本覆盖clone图像来执行此操作(以摆脱刚刚绘制的矩形)。
最后在for循环的主体中,首先我们为clone图像中的每个角色绘制一个矩形。
其次,我们调整roi到36像素和从词典的roi和name的键值对,更新我们的chars。最后一步(主要用于调试/开发目的)是在屏幕上显示每个roi,直到按下一个键。所产生的“更好的方法”图像显示在屏幕,直到按下一个键,并且结束了我们的脚本。
数字和符号提取结果:
现在我们已经编码了我们的MICR E-13B数字和符号提取器,让我们试一试。
从那里执行以下脚本:
$ python bank_check_ocr.py --image example_check.png总结
我们可以看到OCR的银行支票比OCR的信用卡更难识别,主要是由于银行支票符号由多个部分组成。我们不能假设我们的引用字体图像中的每个轮廓映射到一个单独的角色。
相反,我们需要插入额外的逻辑来检查每个轮廓的尺寸,并确定我们正在检查数字或符号。在我们找到一个符号的情况下,我们需要抓住下两个轮廓来构建我们的边界框(因为银行检查控制字符由三个不同的部分组成)。
希望上述的介绍能够帮助到你!
本文由北邮@爱可可-爱生活老师推荐,@阿里云云栖社区组织翻译。
文章原标题《Bank check OCR with OpenCV and Python | PyImageSearch》
作者:Adrian Rosebrock译者:xlddm