本文来自网易实践者社区,经作者王昕冉授权发布
1 简介
OCR即字符识别,通俗的说就是将图片中有意义的文本信息识别出来。在最近的工作中接触到OCR是有一个自动识别某网站验证码的开发需求,简单的图片验证码一般由字母数字组成,包含一些干扰线、杂色等,如图1-1所示:
对于图片验证码的识别,通常分为几个步骤:图片预处理(二值化、去除干扰点)、字符分割、字符识别。在这几个步骤中,个人认为重点与难点的是图片预处理与分割,至于识别采用Tesserocr 等库或手动进行训练识别大多都能满足需求。本文是个人在处理自动识别图片验证码中的一点经验和感想的分享。
2 图片处理与分割
下面以自动识别某网站图片验证码为例,经过初步观察,该网站图片验证码可分为两类,如图2-1所示。
可以看出一种线条较细,一种线条较粗。验证码字符部分均为黑色,干扰线条颜色较浅,可以采用较低灰度阈值进行二值化,去除部分干扰线。在处理噪点时,如果采用8邻域法处理噪点时,需要采用不同的去噪阈值。类似的去噪方法还有连通域法等。
经过初步处理的图片如图2-2所示,可以看出去除噪点后导致字符也有所缺失,后续优化可以做一定的修补。对于图片的分割,针对本文中的示例图片验证码,对于各个字符分界较易界定的,利用像素在x轴上的投影的像素空白部分即可进行分割。这样分割可能会造成某些字符被分成两部分,或者字符太近,无法分割。通过判断分割出的字符数和期望的字符数对比,再与各个字符期望的平均长度进行对比,然后将包含两个字符的字符块进行再分割,过度分割的字符进行合并。当然这一过程很容易导致分割出的字符难以辨认,是需要优化的重要部分。图2-2中的字符分割后得到的单个字符如图2-3所示。
分割字符时需要特别考虑字符l、i这种,最初采用x轴投影长度阈值来判断是否为有效字符导致出错,后修改为结合投影处像素点个数大于6个即视为有效字符,避免遗漏了细线图片验证码的某些字符。另外,在对字符上下的空白部分进行去除时,对于b、p、l这类字符,需考虑当字符突出部分存在断层空白时不能截去。其他一些细节的问题应该是针对具体情况具体对待的,采用分类识别时图片预处理对提高识别率具有相当有效的提升。
3 识别与精度提升
在字符完美分割的基础上进行识别是相对容易实现,扭曲程度比较低的直接使用字符库勉强能够识别;也可采用分类算法,机器学习等。本文中采用的svm分类算法,在python中调用libsvm进行训练识别十分方便,导入LIBSVM库并调用:
svmutil.svm_train()
就可以完成训练,训练会生成.model文件,在识别时调用:
svmutil.svm_predict()
即可完成识别,识别时使用参数”-b 1”可以查看识别准确率,具体详细参数及使用方法可以参见
https://www.csie.ntu.edu.tw/~cjlin/libsvm/
比较繁琐的部分就是打标的过程了,需要手动操作。基本上,每个字符提供10个以上的训练集就能够达到一定的识别精度,加大训练集的量是能够提高识别的准确度,图片去噪及分割处理的好坏在小的训练集的情况下能够有效提升准确度。而对于某些易混字符,例如o和0,9和q等,有时候肉眼也很容易看错,为保证识别准确率,可以在准确度大于一定值时再返回。对上文的图片,得到的识别结果为:['e8p6', [0.4247, 0.5323, 0.3458, 0.4902]]、['74wa', [0.4571, 0.4945, 0.4501, 0.1775]]。结果比较一般,尤其是字符a的识别准确率十分的低,对照字符分割处理的结果也能看出该字符的缺损较为严重,虽然对于出错的情况刷新验证码重新识别成本比较低,但重试次数过多显然是影响效率的,通过对图片处理方式的改进和加大训练集勉强完成了需求。
4 感想
图片验证码的处理过程不可避免的会导致字符的残缺,甚至有些图片验证码本身就是由断断续续的噪点所组成,对于特别样式的验证码进行特殊处理更是比较繁琐的工作。最近看到的一篇相关论文(Fast Oriented Text Spotting with a Unified Network)中提到了一种端到端的文本检测模型给了一点启示,对于图片识别有兴趣的可以研究下。个人的一点想法是,不采用传统的二值化分割识别,直接对原图片中的字符进行定位识别。这样可以满足不同场景的识别需求,采用文中的FOTS框架无疑是一个不错的选择,然而该方法源码并未公布,可以借鉴一下其思想。
相关阅读: