基于Opencv和Tesseract的行驶证识别系统设计 | ![]() |
行驶证作为一种常用证件, 在车险理赔、二手车交易、违章处理、汽修保养等行业频繁使用, 但是行驶证不像银行卡一样可以刷卡识别, 常规采集行驶证信息的方式是手动登记, 这种方式存在低效率和易出错的问题[1]。随着光学字符识别技术(optical character recognition, OCR)[2]的迅速发展, 行驶证OCR逐渐进入市场, 帮助人们完成一些繁杂的证件录入工作。对百度、腾讯、阿里巴巴等开放平台的API进行测试, 准确率在95%左右。
由于行驶证特殊的防伪技术和套打样式, 行驶证的OCR识别存在以下难题:1)打印颜色有深浅, 有时候过深, 有时候过浅;2)信息错位, 内容信息和表格粘连;3)行驶证外套塑料薄膜反光;4)防伪底纹干扰。以上平台的OCR-API对不同程度的反光、倾斜等情况下, 准确率下降到80%左右。
该设计最终采用OpenCV[3]、Tesseract[4]、Python[5]进行算法设计, 通过改进图像处理算法, 改善了反光和倾斜的问题。
1 行驶证图像预处理 1.1 转灰度图灰度图(grey scale image)又称灰阶图, 是一幅只含亮度信息, 不含色彩信息的图像, 与原彩色图像比较, 它只有一个通道, 图像中每个像素其实就是亮度值(Intensity), 这样图像处理计算量也相应大幅减少[6]。要表示灰度图, 就需要把亮度值进行量化, 简单来说, 就是把彩色图像3个通道的分量按照一定的比例计算到灰度图像中, 通常将灰度值划分到0至255范围内, 其中0代表最暗, 255代表最亮。从RGB到灰度图转换公式为:
$ \mathit{Gray} = 0.299R + 0.587G + 0.114B $ | (1) |
行驶证的防伪底纹对于提取内芯区域影响较大, 为了排除防伪底纹的干扰, 本文对灰度图采取高斯平滑滤波处理, 使得内芯的底纹背景融为一体, 便于进行阈值分割。我们把概率密度函数服从正态分布的噪声称为高斯噪声, 底纹大致符合正态分布, 因此可以当作高斯噪声进行处理。高斯滤波是一种用来消除高斯噪声的线性平滑滤波器, 所以可以使用它来模糊内芯的防伪底纹[6], 因为高斯滤波器具有滤除高频的特性, 因此也可以理解为一个低通滤波器。
高斯滤波是用一个掩模逐行逐列地扫描图像, 掩模其实就是权重矩阵, 离掩模中心越近的像素权重越高, 其运算实质是把掩模中心像素点的灰度值设置为掩模覆盖的区域内像素的加权平均灰度值。因此高斯滤波的平滑效果比均值滤波更加柔和, 而且边缘保留效果更好。
1.3 局部高光抑制行驶证外面的薄膜极易反光, 在阳光、灯光下会形成局部镜面反射, 呈现在图像上的是高亮光斑, 一般出现在内芯边缘, 面积不大, 但是影响边缘检测, 所以可以先通过OpenCV的局部亮度改变算法(Illumination Change)削弱局部镜面反射对边缘的影响[7]。参数分别是源图(source)、掩码(mask)、结果图(result)、系数(α, β), 乘数范围在0~2之间, 0比较清晰, 2比较模糊。
1.4 图像增强由于部分图像背景和主体对比较弱, 难以设置合适的灰度阈值, 所以对灰度图像采取图像增强处理, 使内芯明显地区别于背景, 达到增强对比度的效果。
本文采用是单尺度SSR(Single Scale Retinex)图像增强算法, Retinex是一种图像增强理论的统称, 它是retina(视网膜)和cortex(皮层)两个单词的组合[8]。记一幅给定的图像为S(x, y), 单尺度SSR算法将该幅图像分解为反射图像R(x, y)和亮度图像L(x, y)两个图像, 由此可以得到单尺度SSR的公式为:
$ S(x, y) = R(x, y) \cdot L(x, y) $ | (2) |
定义一个高斯函数G(x, y), C为高斯环绕尺度, λ是一个尺度且满足以下条件。
$ G(x, y)=\lambda {{\ell }^{\frac{-\left( {{x}^{2}}+{{y}^{2}} \right)}{2}}}, \iint{G}(x, y)dxdy=1 $ | (3) |
得到增强后的图像, R(x, y)是输出图像, *代表卷积符号:
$ R(x, y) = \log S(x, y) - \log \left[ {F(x, y)*S(x, y)} \right] $ | (4) |
本文的SSR算法通过OpenCV for Python实现, 图像增强对比效果图如图 1所示, 单尺度SSR算法能在保持原始图像平均亮度的同时较好地增强灰度图对比度, 使得行驶证内芯背景与边缘黑白分明, 便于进一步阈值分割。
![]() |
图 1 图像增强对比图 |
2 提取证件内芯区域 2.1 OTSU阈值分割
行驶证经过以上图像预处理之后, 内芯和背景的对比度明显, 分界线清晰, 但是受不均匀光照影响, 直接采取阈值分割, 无法适用于多样的拍摄环境, 本文采取分块最大类间差法(OTSU)算法, OTSU阈值分割算法是根据灰度图像的全局特性, 找到一个合适的阈值将图像划分为背景和前景, 也就是求取直方图中两个峰值之间的最小值[9]。类间方差越大代表图像的背景和前景的差别越大。本设计将灰度图像分成9块, 逐个采用OTSU算法进行阈值分割, 经过二值化的图像如图 2所示。
![]() |
图 2 采用分块OTSU算法的二值化对比图 |
然后采取无级别寻找轮廓, 并选取最大轮廓。在opencv里对应的函数为:findContours, 通过for循环对每个轮廓的面积(contourArea)比较, 找到最大轮廓。
2.2 直线拟合通过drawcontours对轮廓内外所有区域均填充0(全黑), 并绘制宽6 pixl的白色轮廓线。通过arcLength和approxPolyDP找到四个轮廓拟合点, 将轮廓断开, 筛选出最长的四条轮廓线, 把白色的轮廓线看成一组点, 对每条实线分别直线拟合(fitLine), 拟合出四条直线。在OpenCV中采用的直线拟合是HUBER算法。公式(5)中, 记点到直线的距离函数ρ(r), 一个点(x, y)到直线的距离为r, 其中C=1.345。
$ \rho (r) = \left\{ {\begin{array}{*{20}{c}} {\frac{{{r^2}}}{2}}&{{\rm{ }}\mathit{if }r < C, }\\ {C\left( {r - \frac{r}{2}} \right)}&{{\rm{ }}\mathit{oterwise}\mathit{.}{\rm{ }}} \end{array}} \right. $ | (5) |
![]() |
图 3 直线拟合 |
直线拟合效果如图 3所示。在获取四条拟合直线后, 利用getCrossPoint获取四条直线的交点(a, b, c, d)并排序, 行驶证内芯比例宽高比为8.8:6, 本文将内芯尺寸设置为1 760*1 200 pix。
2.3 透视矫正OpenCV提供了两种图片变换的方式:仿射变换和透视变换, 两者的区别很容易区分, 前者是将矩形的图片变成平行四边形, 而后者是将图片变成梯形。这两种变换虽然都有各自的应用场景, 但在实际的图片变换中由于透视效应的存在, 后者的使用更加普遍[10]。
采用手机拍摄行驶证照片的时候, 受相机角度和高度的影响往往会拍出梯形的照片, 如图 4左图所示, 这样的照片不仅不够美观而且给文字识别带来较大难度, 将梯形的图片转换成标准的矩形就要对图片进行透视变换。透视变换实质上就是通过矩阵运算将图像投影到一个新的平面上, 通用的变换公式为:
$ \left[ {x', y', z'} \right] = [u, v, w]\left[ {\begin{array}{*{20}{l}} {{T_1}}&{{T_2}}\\ {{T_3}}&{{a_{33}}} \end{array}} \right] $ | (6) |
$ T = \left[ {\begin{array}{*{20}{l}} {{T_1}}&{{T_2}}\\ {{T_3}}&{{a_{33}}} \end{array}} \right] = \left[ {\begin{array}{*{20}{l}} {{a_{11}}}&{{a_{12}}}&{{a_{13}}}\\ {{a_{21}}}&{{a_{22}}}&{{a_{23}}}\\ {{a_{31}}}&{{a_{32}}}&{{a_{33}}} \end{array}} \right] $ | (7) |
T1、T2、T3分别对应线性变换、透视变换、图像平移。透视变换的数学表达式为:
$ x = \frac{{x'}}{{w'}} = \frac{{{a_{11}}u + {a_{21}}v + {a_{31}}}}{{{a_{13}}u + {a_{23}}v + {a_{33}}}} $ | (8) |
$ y = \frac{{y'}}{{w'}} = \frac{{{a_{12}}u + {a_{22}}v + {a_{32}}}}{{{a_{13}}u + {a_{23}}v + {a_{33}}}} $ | (9) |
由2.2直线拟合求得的(a, b, c, d)和(a′, b′, c′, d′)四对像素点坐标, 即可求得透视变换矩阵。透视变换效果图如图 4所示。
![]() |
图 4 透视变换 |
3 字符裁剪与分割 3.1 二值化
在数字图像处理中, 图像的二值化(Image Binarization)主要是为了凸显感兴趣区域的轮廓, 方便进一步便于检测轮廓。灰度图的0代表全黑, 255代表最亮, 二值化就是要将图像像素点的灰度值比阈值小的置为0, 比阈值大的置为255, 使得灰度图呈现出黑白分明效果。有时为了选择暗处会设置反向(INV)。二值化包括全局二值化和局部二值化两大类。
全局二值化方法(Global Binariztion Method)只设置一个阈值划分整张图的前景和背景, 是否将像素点判定为前景点取决于该点的灰度值是否大于给定的阈值。平均灰度法、固定阈值法、OSTU方法和直方图法是常用的全局二值化方法。
局部二值化方法(Local Adaptive Binarization Method)又称为自适应二值化, 是通过分析像素点的邻域来计算该点的阈值[11]。如果灰度级高于阈值则将点视为背景点处理, 否则作为前景点处理。常见的局部二值化有自适应中值阈值分割、自适应高斯阈值分割。
采取局域自适应高斯阈值分割, 可以排除底纹的干扰, 如图 5所示, 自适应高斯阈值分割的效果明显好于自适应中值阈值分割和全局阈值分割。
![]() |
图 5 局部阈值分割效果图 |
3.2 字条裁剪
行驶证打印的信息共有十条, 它们在行驶证上的范围是一定的, 所以可以根据相对原点的位置坐标定位文本行, 本设计中采用数组记录字条坐标, 通过for循环将文本行逐一裁剪成字条并保存到一个文件夹中, 按顺序命名, 便于查找。在Python中裁剪图片只需要知道字条相对于原点的左上角坐标(x0, y0)和右下角坐标(x1, y1), 最终裁剪效果图如图 6所示, 在这里为了节省空间, 特意将字条组合在了一起。
![]() |
图 6 裁剪效果图 |
3.3 字符分割
由于行驶证印刷质量不统一, 颜色过浅会导致阈值分割的时候产生底纹噪点, 位置偏移会造成文字和虚线粘连, 这两个问题对文字识别的准确度影响较大, 处理起来也比较困难。
经验发现, 虚线点在文字下方, 并且比字符小, 所以可以判断面积大小筛选掉, 尽可能地将孤立的虚线点清除, 同时也可以清除掉底纹噪点, 这样可以排除虚线粘连的干扰。但是还是会有一小部分粘连, 所以后续采用单个文符识别的模式进行识别。
![]() |
图 7 汉字、英文、数字的分割效果图 |
字符分割前先进行8*8的闭运算, 以避免左右结构的汉字被分割成两个字符。先采取竖向垂直投影分割[12], 然后再对单个字符采取横向垂直投影分割, 在分割前都需要进行一次闭运算, 主要是为了避免单个字符被误判为两个字符, 分割效果图如图 7所示。
4 文字识别 4.1 Tesseract和LSTM介绍本文使用的Tesseract4.0是一款文字识别引擎, 它的核心是长短时记忆网络(LSTM)[13]。LSTM是一种改进的循环神经网络(RNN), 它在实践中不需要付出很大代价就可以记住长期的信息, 完美解决了普通RNN在实际应用中很难处理长距离文本的缺陷, 这也是它本身具有的能力。LSTM示意图如图 8所示, LSTM设计思路简单, 但结构复杂, 基础LSTM网络一般包含三个门(输入门、遗忘门、输出门)和一个神经元细胞。LSTM示意图如图 8所示, t时刻, LSTM有三个输入:当前时刻输入值xt、上一时刻输出值ht-1和上一时刻的细胞状态ct-1;LSTM有两个输出:当前时刻输出值ht和当前时刻的细胞状态ct。
![]() |
图 8 LSTM示意图 |
4.2 训练字符识别库
行驶证上的字体和一般字体不同, 数字和英文是专用防伪字体, 汉字是宋体, 但是由于各个地方印刷质量不同, 有深有浅, 有粗有细, 经过二值化处理后的字体和常规字体差别较大, 表现为轮廓粗糙、断点、粘连等, 所以只有选择单独训练库。通过程序批量二值化1万张图片, 并将裁剪的字条保存作为训练样本, 最终将样本训练成两个库, 一个是汉字库, 一个是英文数字库。
在实验中, 采用jtessboxeditor训练文字库。如图 9所示, 训练过程相对简单, 但工作量大, 耗时两个多星期, 主要是对box文件进行逐一矫正。最终将几个文件合并为trainddata文件, 也就是训练的库。将trainddata文件放置到tessdata文件夹, 就可以正常引用此文字识别库了。
![]() |
图 9 训练和矫正过程示意图 |
4.3 识别过程与效果
Tesseract对于中文字符的识别不太友好, 经常将1个汉字识别为两个汉字, 造成识别信息错乱, 本文将头文件(tovars.h)里的文字间距变量(textord_dotmatrix_gap)设置为合适的数值。中文字符和汉字和英文的区别是汉字为趋近方形, 英文和数字为瘦长型, 因此可以根据轮廓的长宽判断是哪一类, 对于汉字采用汉字库进行识别, 英文和数字采用数字和英文识别库判断, 增加识别成功率。
从表 1识别率对比看出, Tesseract自带库识别率极低。经过训练后的库与百度API开放平台的API进行对比测试, 训练库和算法结合的识别效果在边缘反光和倾斜方面比百度API略高, 但是对于打印偏移和字体过浅问题识别效果较差。正常情况下识别率达到94.1%。图 2的最终识别结果保存到文本文件中, 结果如图 10所示。
表 1 识别率对比 |
![]() |
![]() |
图 10 最终识别效果图 |
5 结论
本文设计了一种行驶证识别系统, 主要包括四部分:图像预处理, 图像矫正, 字符切割, 字符识别。经过测试, 本文采取的文字定位和识别方法效果良好, 能适用于普通手机拍摄的照片, 平均识别率达到94.1%。但是对于一些恶劣情况, 例如:打印颜色浅、文字偏移严重、边缘不全等, 无法精确识别, 后续将针对这些问题对系统加以改进。
[1] |
李亮.基于Tesseract_OCR的驾驶证识别系统设计与实现[D].成都: 电子科技大学, 2018. http://kns.cnki.net/KCMS/detail/detail.aspx?dbcode=CMFD&filename=1018708658.nh
|
[2] |
IMAD Q H, ZEYAD Q A. Enhanced ensemble technique for optical character recognition[M]. Switzerland: Springer International Publishing, 2018: 23-30.
|
[3] |
AMIN A T. Computer vision with opencv3 and qt5[M]. Iran: Packt Publishing, 2018: 89-99.
|
[4] |
FLORIAN R, THOMAS S. Time-drifts in event streams using series of evolving rolling averages of completion times[J]. Information Systems, 2018, 15(3): 130-135. |
[5] |
韩晓冬, 王浩森, 王硕, 等. Python在图像处理中的应用[J]. 北京测绘, 2018, 32(03): 312-317. |
[6] |
RAFAEL C, GONZALE Z. Digital image processing[M]. Beijing: Publishing House of Electronics Industry, 2008: 110-117.
|
[7] |
郑红波, 石豪. 光照不均匀的结构光图像的条纹快速提取方法[J]. 计算机科学, 2019, 46(05): 272-278. |
[8] |
张诗.基于Retinex理论的图像与视频增强算法研究[D].南京: 南京邮电大学, 2018.
|
[9] |
赵世峰, 何皙健. 基于OpenCV的复杂环境下图像二值化方法[J]. 电子测量技术, 2018, 41(06): 55-59. |
[10] |
MIKKO H, LASSE M, STEPHEN K. Multi-sided market places and the transformation of retail:A service systems perspective[J]. Journal of Retailing and Consumer Services, 2019, 49(1): 380-388. |
[11] |
BILAL B, SITI N. An adaptive local binarization method for document images based on a novel thresholding method and dynamic windows[J]. Pattern Recognition Letters, 2011, 32(14): 1803-1805. |
[12] |
冉令峰. 基于垂直投影的车牌字符分割方法[J]. 通信技术, 2012, 45(04): 89-91. DOI:10.3969/j.issn.1002-0802.2012.04.029 |
[13] |
YU L Z, REN J H. Long short-term memory networks for CSI300 volatility prediction with baidu search volume[J]. Concurrency and Computation:Practice andExperience, 2019, 31(10): 1-7. |