目录
个人感悟
一直以来对图像识别很感兴趣,再加上这段时间系统地自学了下机器学习的相关知识,所以想自己找实践项目做一下。至于为什么选择车牌识别,一方面是以前学习Opencv的时候也尝试做过,可能受限于当时的知识面,效果惨不忍睹;另一方面车牌识别的方案相对比较成熟,网上也有相关的经验可以借鉴。毕竟要靠自己一个人从0到1完成一个项目还是有难度,别人好的思路自己消化后不就是自己的想法嘛!关于自学机器学习再啰嗦几句吧,我觉得入门机器学习最快的方法是看别人发布的系列视频。我学习了两套视频,第一套是网上买的,对于数学公式的推导比较详细,实践代码也比较丰富;另一套是网易云课堂吴恩达的机器学习系列视频,获益良多,很多知识最后多记笔记,这样在调试代码中就能运用的上了。
模块分解
图像预处理
关于车牌预处理,网上有很多说法,不过都差不太多。预处理的目的在于找到“疑似车牌”的大概位置,为下一步定位车牌做准备。
- 加载原始图片
- RGB图片转灰度图:减少数据量
- 均值模糊:柔化一些小的噪声点
- sobel获取垂直边缘:因为车牌垂直边缘比较多
- 原始图片从RGB转HSV:车牌背景色一般是蓝色或黄色(至于h、s、v的设置参考这里:https://blog.csdn.net/taily_duan/article/details/51506776)
- 从sobel处理后的图片找到蓝色或黄色区域:从HSV中取出蓝色、黄色区域,和sobel处理后的图片相乘
- 二值化:最大类间方差法
- 闭运算:将车牌垂直的边缘连成一个整体,注意核的尺寸
车牌定位
从上图可以看出虽然车牌被相对完整的找出来了,但是整个图片还有太多干扰项,接下来就是排除干扰项,尽可能地只保留车牌区域
- 获取轮廓
- 求得轮廓外接矩形
- 通过外接矩形的长、宽、长宽比三个值排除一部分非车牌的轮廓:绿色为疑似车牌区域
4. 通过背景色进一步排除非车牌区域
这里主要用到漫水填充算法(类似PS的魔术棒),通过在矩形区域生成种子点,种子点的颜色必须是蓝色或黄色,在填充后的掩模上绘制外接矩形,再依次判断这个外接矩形的尺寸是否符合车牌要求,最后再把矩形做仿射变换校准位置。做漫水填充的目的有两个,第一个是预处理的时候车牌轮廓可能有残缺,做完漫水填充后可以把剩余的部分补全,第二个目的是进一步排除非车牌区域。
上面的漫水填充算法对于种子点的选取比较关键,因为一旦选取不好前面的努力白费,后面也别想得到车牌区域了。一般情况下得到的车牌多少会存在倾斜的情况,如上图(1)所示,我将矩形4个顶点的x、y值做了排序,分别取x和y中间两个值作为水平、垂直的上下限来生成随机种子点,这样能比较好的覆盖整个车牌区域;另一种情况是车牌倾斜太严重如图(2)所示,对于这种情况我想了个笨办法,直接在矩形的两条对角线上生成种子点,也能比较好的覆盖整个车牌区域。另外在生成种子点的时候还可以加调节系数,不要让生成的种子点太靠近矩形边缘。
通过漫水填充在背景色的排除后仍然还有2块疑似车牌区域,不过看起来距离提取真正的车牌目标很接近了。
车牌过滤
这一步的目标就是从上面两张疑似车牌图片中选出真正的车牌。这里我用卷积神经网络来处理是否为车牌的二分类问题,数据集用的是别人的(https://github.com/zeusees/HyperLPR),他的车牌过滤貌似用的支持向量机,还没看他的代码,有时间拜读下),这里要注意模型参数的标准差设置小一些,模型收敛还是比较快,效果也还不错。当然模型也有可能会误判,比如模型把两张疑似车牌图片都判定为车牌,那就取和车牌相似度最高的作为最终选择。
字符分割
- 水平投影:将二值化的车牌图片水平投影到Y轴,得到连续投影最长的一段作为字符区域,因为车牌四周有白色的边缘,这里可以把水平方向上的连续白线过滤掉。
- 垂直投影:因为字符与字符之间总会分隔一段距离,因此可以作为水平分割的依据,分割后的字符宽度必须达到平均宽度才能算作一个字符,这里可以排除车牌第2、3字符中间的“.”。
得到分割后的字符如下所示:
字符识别
这一步的目的是把上面的字符图像块识别出来并输出车牌文本字符,这里我依然用了卷积神经网络,这里的类别比较多,包括数字、字母、汉字,但是做法和车牌过滤的二分类差不多,网络输出67维向量,取概率最大的作为输出结果,测试后发现识别率还可以。
操作步骤
- 从github下载代码和图片数据集,代码有3个文件,charNeuralNet.py用来训练和测试字符识别模型,plateNeuralNet.py用来训练和测试车牌检测模型,carPlateIdentity.py是最终的测试程序,会调用前面2个训练好的模型识别图片中的车牌字符。数据集包括cnn_char_train(字符数据集)、cnn_plate_train(车牌数据集)、pictures(最终测试图片,仅供参考)、opencv_output(这是我测试的结果),字符数据集和车牌数据集没有划分训练集和测试集,自行按比例切分;
- 将charNeuralNet.py在main函数的train_flag改成1,在当前工程目录下创建carIdentityData/cnn_char_train和carIdentityData/model/char_recongnize目录,取字符训练集放在carIdentityData/cnn_char_train路径下,执行该程序训练字符识别模型,模型保存在carIdentityData/model/char_recongnize路径下;
- 将charNeuralNet.py在main函数的train_flag改成0,在当前工程目录下创建carIdentityData/cnn_char_test目录,取字符测试集放在此路径下,将model_path修改成自己模型的路径,执行程序测试字符识别准确率;
- plateNeuralNet.py的操作步骤同2、3步骤相似,用来获取车牌检测模型;
- 将carPlateIdentity.py程序的plate_model_path、char_model_path修改成自己训练好的模型路径,下面测试图片的img路径也修改成自己图片的路径,执行该程序进行车牌字符检测。
总结
- 字符矫正我使用的仿射变换,对于倾斜严重的情况效果不是很好;
- 用颜色来获取车牌位置对于蓝色黄色的车识别率会有一定影响;
- 卷积神经网络对于车牌识别和字符识别的准确率还有待提升;
- 另外程序支持蓝色车牌的识别,对于黄色车牌可以识别车牌位置,字符识别的话因为黄牌是黑字,蓝牌是白字,这里要加个判断再提取字符,这个不难,有时间再完善。
我的开发环境:python3.6、OpenCV3.4.4、tensorflow1.12
源码和数据集已上传github,有不同想法的可以私信交流一起提高(https://github.com/simple2048/CarPlateIdentity)
转载:https://blog.csdn.net/GK_2014/article/details/84779166