OpenCV 入门系列:
OpenCV 入门(一)—— OpenCV 基础 OpenCV 入门(二)—— 车牌定位 OpenCV 入门(三)—— 车牌筛选 OpenCV 入门(四)—— 车牌号识别 OpenCV 入门(五)—— 人脸识别模型训练与 Windows 下的人脸识别 OpenCV 入门(六)—— Android 下的人脸识别 OpenCV 入门(七)—— 身份证识别
从本篇文章开始我们进入 OpenCV 的 Demo 实战。首先,我们会用接下来的三篇文章介绍车牌识别 Demo。
识别图片中的车牌号码需要经过三步:
本节是 OpenCV 车牌识别的第一节课,主要完成了车牌定位的工作。具体流程:
Demo 使用 Visual Studio 开发,有关 Visual Studio 配置 OpenCV 项目的详细过程在上一篇文章中已经介绍过,这里就只是再简单提一下。
在 Visual Studio 中创建一个 CMake 项目 LicensePlateRecognition,配置 CMakeLists.txt 如下:
如果运行时说找不到 opencv_world410d.dll,请将库目录添加到环境变量并重启 VS 再试。
说一下被添加到 add_executable() 中编译的源码的功能:
LicensePlateRecognizer 是车牌识别器,传入一个车牌图像会返回车牌号:
PlateLocator 是车牌定位器,用于定位车牌的。由于车牌定位有多种算法,因此具体的识别工作不由 PlateLocator 完成,而是交给使用了某一种算法的子类完成,如 SobelLocator(使用 Sobel 算法)或 ColorLocator(使用 HSV 颜色模型)
由于本节我们只进行车牌定位,因此文件暂时就这么多,后续随着功能的添加,源码文件也会随之增加。
注意事项与小技巧:
- 头文件内不建议使用 # pragma once 的形式,兼容性不如宏定义的方式好
- 使用 Visual Studio 时,如果在 CMakeLists 中通过 *.cpp 这种形式设置所有 cpp 文件都添加到可执行文件中,那么在新建 cpp 文件后,需要在 Visual Studio -> Project -> CMake 缓存 -> 删除缓存,然后在 CMakeLists 通过 Ctrl + S 重新生成可执行文件,否则新建的 cpp 不会自动被添加到可执行文件中
我们使用 Sobel 算法实现 SobelLocator 定位器的 locate(),3.1 ~ 3.8 节的标题就是根据前面给出的流程图做出的实现步骤。
高斯模糊算法本质上是一种数据平滑技术,图像处理恰好是一个直观的应用实例,具体内容可以参考阮一峰大神的博客:高斯模糊的算法。
我们这里需要了解 OpenCV 的高斯模糊函数 GaussianBlur 如何使用:
调用 GaussianBlur() 对原图进行高斯模糊:
对比效果如下:
实际上,色彩对于图像识别是有干扰的,因此需要通过灰度化对图像“降噪”,为 Sobel 边缘检测算法(该算法只接受灰度图)做准备:
灰度化效果:
可否先对原图灰度化后再高斯模糊呢?没有硬性规定,但是高斯模糊接收彩色图的模糊效果更好。
Sobel Derivatives —— Sobel 导数是一种用于计算图像梯度的算子。它是一种线性滤波器,用于检测图像中的边缘。Sobel 算子结合了水平和垂直方向的差分操作,从而可以同时计算图像在水平和垂直方向上的梯度。这使得 Sobel 算子在图像处理中广泛应用于边缘检测、图像增强和特征提取等任务中。
Sobel 算子的计算过程涉及对图像进行卷积操作,具体而言,它使用一个 3 × 3 的卷积核分别对图像进行水平和垂直方向的卷积。通过计算卷积结果的导数,可以得到图像在水平和垂直方向上的梯度强度。这些梯度信息可以用来检测图像中的边缘,因为边缘通常表示图像中灰度值的剧烈变化。
Sobel 算子在图像处理和计算机视觉领域具有广泛的应用,例如边缘检测、角点检测、图像平滑和模糊等。它是一种简单而有效的方法,可用于提取图像的结构信息并进行特征提取。更详细的信息与公式可参考 OpenCV 官方文档 Sobel Derivatives。
我们通过 Sobel 运算可以得到图像一阶水平方向导数,目的是检测图像中的垂直边缘,便于区分车牌(注意 Sobel 运算只能对灰度图像有效,因此进行 Sobel 运算前必须先进行灰度化工作):
Sobel 运算后的效果:
可以看到,经过 Sobel 运算后,物体轮廓要比灰度图明显了。
二值化的通俗说法就是非黑即白。对图像的每个像素做一个阈值处理,为后续的形态学操作准备。
具体来讲,就是灰度图中每个像素值是 0 ~ 255,表示灰暗程度。现在我们设定一个阈值 t,像素值小于 t 的设为 0,否则设为 1,这样所有的像素就只有 0 或 1 两个值。
在 OpenCV 中,二值化使用 threshold() 函数:
使用 threshold() 进行二值化:
效果:
可以看出对比度更明显,轮廓更清晰了。
形态学操作的目的是将车牌字符连接成一个连通区域,便于取轮廓。
形态学操作的对象是二值化图像,操作有多种类型,腐蚀,膨胀是许多形态学操作的基础。我们先来了解部分操作类型:
假如按照从上至下、从左至右的顺序逐个检查像素点,现在检查到第一排最右侧,设该像素点为 X,让 X 位于模板中心:
那么原图像被模板覆盖的除了 X 还有 1、2、3 共 4 个像素点,只要有 1 个是黑色,X 就要被涂成黑色。整个原图中只有 A、B、C 三个像素作为中心的 3 * 3 矩形全部为白色,因此腐蚀后的效果就像右边的图那样。
可以看到,闭操作将两个分开的部分融合成一个部分,这正是我们要做的把车牌字符的各个部分融合为整个车牌的轮廓:
效果如下:
可以看到原本车牌字符是分开的,现在都融合到一个车牌轮廓之中。
将连通域的外围画出来,便于形成外接矩形。这个矩形我们认为是可以有旋转角度的矩形,不一定是与 X 或 Y 正方向垂直的矩形。
在找轮廓的过程中会用到如下几个 API:
findContours() 用于查找轮廓:
minAreaRect() 用于查找最小面积旋转矩形:
函数用于找到能够包围给定的 2D 点集的最小面积旋转矩形。
该函数计算并返回一个最小面积的包围矩形(可能是旋转的),用于指定的点集。开发者应该注意,返回的对象可能包含负索引,当数据接近元素边界时。
函数接受一个输入参数,表示 2D 点的输入向量或矩阵。这些点可以使用或来存储。
函数返回一个类型的对象,表示最小面积的旋转矩形。是一个包含旋转矩形相关信息的类,包括旋转矩形的中心坐标、宽度、高度和旋转角度等。
需要注意的是,当数据接近元素边界时,返回的对象可能包含负索引。开发者在使用返回的旋转矩形时需要注意这一点。
可以看到,在原图中找出了大大小小 N 多个轮廓:
从上图看出,经过轮廓查找,一张图片中可以找出很多个轮廓,但是有很多从大小上判断,就明显就不可能是车牌。所以我们通过尺寸判断的方式,初步筛选排除不可能是车牌的矩形(中国车牌的一般大小是 440mm * 140mm,宽高比为 3.14)。
由于尺寸判断对于车牌定位而言是一个通用操作,因此将其放在基类 PlateLocator 作为一个 protected 成员(方便特定算法子类覆盖):
在找轮廓的过程中会遍历形成矩形,用 verifySizes() 判断这些矩形是否符合规格,符合的存入 vec_sobel_rects 中:
经过尺寸判断,有可能为车牌的矩形被画成绿色:
由于图片中的车牌不可能都像上面那样是正向的,也有可能是斜向的,比如下面这种:
那么在车牌定位阶段,就势必要对车牌轮廓的矩形进行旋转调整到水平正向位置,在旋转时还要注意不能超出原图的范围,最后还要将车牌图片调整到合适的大小方便后续识别。因此矩形矫正主要包括三方面内容:
进入代码。上一步我们得到了尺寸校验合格的矩形 vec_sobel_rects,接下来就对这些矩形进行校正,并将校正结果存入 SobelLocator::locate() 的参数 dst_plates 中:
tortuosity() 是校正操作的入口,包含了上面提到的三种矫正方法:
136 * 36 是我们训练车牌识别模型时使用的车牌样本图片宽高,为了提高识别率,我们在最后输出车牌定位结果时,也将图片宽高设置为 136 * 36。
计算范围安全的矩形:
旋转:
旋转过程用到了仿射变换,可以参考 OpenCV 官方的仿射变换教程。
至此,车牌定位完成,我们可以运行 Demo 来看一下效果:
四张图从左至右依次是原图、旋转前、旋转后、截取后的图片效果,可以看到第一组并没有得到正确的车牌。结果一共有三组,后两组效果如下:
可以看到第二组是正确地定位了车牌的。
我们使用手中现有的车牌图片进行车牌定位,发现 HSV 颜色模型的定位准确性要比 Sobel 好一些,因此我们也介绍一下这种定位方式。
利用 HSV 模型定位的要点:识别车牌的蓝色底色,将蓝色亮度调到最高,其余颜色亮度调低,以实现车牌定位的效果。
为了找出图像中的蓝色部分,需要检查 RGB 分量中的 Blue 分量就可以了。一般 Blue 分量是 0~255 的值,即便蓝色分量是 255 了,由于另外两个分量的影响,需要考虑各个分量的配比问题,RGB 作为颜色判断很难实现,于是就有了 HSV 模型和 Photoshop 中的 HSB 模型。
HSV(Hue, Saturation, Value)模型和 HSB(Hue, Saturation, Brightness)模型是描述颜色的模型,它们在表示颜色的方式上是相似的,但在数学计算上有细微的差异。
HSV 模型是根据颜色的直观特性由 A. R. Smith 在 1978 年创建的一种颜色空间,也称六角锥体模型(Hexcone Model)。这个模型中颜色的参数分别是:色调(H),饱和度(S),明度(V):
HSB 模型:
HSV 模型和 HSB 模型在实际应用中可以互换使用,但需要注意它们之间的命名差异和数值范围的不同。
OpenCV 中 HSV 数据与原始定义略有不同,数据类型为 8UC,取值分别为 0 ~ 180、0 ~ 255、0 ~ 255,蓝色的范围是 100 ~ 124:
Sobel 算法实现车牌定位的前三步为高斯模糊、灰度化、Sobel 运算,然后进行二值化运算。HSV 与 Sobel 的不同之处就在于前三步,从第四步二值化开始的后续步骤是相同的。
HSV 的前三步为:
参考代码如下:
原图、转换为 HSV、凸显蓝色的效果图如下:
对图像按通道进行分离可以是对 BGR 进行分离,也可以是对 HSV 进行分离。以 BGR 为例,分离的示意图如下:
对于 HSV 而言,分离结果就是将像素中每个点的 H、S、V 分量提取到各自的数组中,代码中的 hsv_split[2] 就是 V 分量的数组。
虽然 HSV 后续步骤与 Sobel 相同,但是 HSV 的定位效果却要比 Sobel 好。HSV 的闭操作、找轮廓都要比 Sobel 更准确,并且最后得出的候选车牌,Sobel 有三组,而 HSV 直接就是车牌的那一组:
本网信息来自于互联网,目的在于传递更多信息,并不代表本网赞同其观点。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,并请自行核实相关内容。本站不承担此类作品侵权行为的直接责任及连带责任。如若本网有任何内容侵犯您的权益,请及时联系我们,本站将会在24小时内处理完毕,E-mail:975644476@qq.com
本文链接:http://www.gawce.com/tnews/1562.html