基于OpenCV的交通标志识别

37次阅读

共计 3002 个字符,预计需要花费 8 分钟才能阅读完成。

前几天看新闻得知微软为美国执法机关研发了一套基于 AI 识别,追踪并提取编辑视频中出现的人脸的算法,只要输入一段带人脸信息的视频文件,运行后即可输出一段所有人脸已被提取并且按要求编辑好的视频文件。当然该算法目前仍然存在局限,在人脸被部分遮挡、快速移动等情况下,无法正确识别,同时,执法机关也并非想要一个视频文件中相关不相关的所有人的人脸被获取出来,算法真正应用于实际也许还需经过一番优化。
类似上述新闻中从视频或图像中提取人脸或其它信息的学科称为计算机图形学(Computer Graphics),该门学科涵盖面很广,对于游戏爱好者来说,所看到的游戏画面精美流畅与否,与计算机的实时渲染有很大关系。另外 3D 游戏中模型为了呈现得更逼真的模拟现实的光照效果,AR/VR 中的实时建模 / 渲染,都与 CG 悉悉相关。
于是本着学无止境的思想,尝试对计算机图形学入个门。该项目使用的是 OpenCV2.4.9 的库,至于为什么用这么老的库是因为我大学时下好了这个库在电脑里,并且这个项目比较初级用 3 + 版本和 2 + 版本没有差别。

OpenCV 是一个基于 BSD 许可(开源)发行的跨平台计算机视觉库,可以运行在 Linux、Windows、Android 和 MacOS 操作系统上。它轻量级而且高效——由一系列 C 函数和少量 C++ 类构成,同时提供了 Python、Ruby、MATLAB 等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。OpenCV 用 C ++ 语言编写,它的主要接口也是 C ++ 语言,但是依然保留了大量的 C 语言接口。该库也有大量的 Python、Java andMATLAB/OCTAVE(版本 2.5)的接口。这些语言的 API 接口函数可以通过在线文档获得。如今也提供对于 C#、Ch、Ruby 的支持。

【百度百科如是说】
当然,一开始不能直接识别人脸等比较复杂多变的图形,本文是通过实现交通标志识别来做一个简单的讲解,至于更进一步的图象识别大家有兴趣可以继续学习。本次项目实现的交通标志识别主要是给予一张待识别图片,运行代码,系统提取到图中的交通标志内容并使用霍夫圆变换将其位置圈出。
识别交通标志位置的方法步骤如下:
1. 提取特征颜色 — 对图片去噪 — 提取边缘信息
2. Canny 边缘检测 — Hough 变换找出圆形区域
交通标志牌通常规定为红、蓝、黄三种颜色,其含义为:
1. 红色:表示禁止、停止 2. 蓝色:表示指令、必须遵守的规定 3. 黄色:表示警告、注意
一、提取特征颜色
根据这三种交通标志牌的颜色,初步确定待识别图片所要提取图片信息的颜色范围,代码中使用的是 RGB 颜色模型。RGB 颜色模型是位于空间中的一个立体模型,如下图所示为 RGB 的色度坐标示意图
在特征颜色提取中,确定颜色的阈值是其中最重要的一点(HSV 颜色模型可以避免光 照不同的影响,此处不讨论),经过查询资料,得到红、蓝、黄对应的阈值如下:
其中 ThR=0.4;ThG=0.3,ThB=0.4,ThY=0.85
在这种情况下,G 分量的值比 R 分量和 B 分量大 50 则判定绿色,:B 分量的值比 G 分量和 R 分量大 50 则判定蓝色,R 分量的值比 G 分量和 B 分量大 50 则判定为红色,找到满足条件的区域后在原图中标出,不满足条件的部分标为黑色。
首先读取图片文件代码如下:

提取颜色区域代码:

上述三个被调用的函数,作用是根据我们查得的阀值进行判断并返回值,如果在阀值范围内,则返回 255:

在这种由阀值提取颜色区域的情况下,绿色极有可能混入被提取的颜色中,在背景绿叶过多的情况下,检测会比较困难。
二、图片去噪
经过上一步的提取后,留下的区域则为感兴趣的区域,由于阈值范围的问题,留下的区域并不一定都是我们所需要的区域。在现实情况中,经常会有一部分我们不需要,极容易使实验结果出错的图片部分混入颜色提取范围。这种不应该,也最好不要出现在被提取区域上的像素点,称为噪点。
前人在去噪方面也有着杰出的作为,方框滤波、中值滤波以及高斯滤波,都能或多或少地起到去噪作用。为了接下来的边缘检测,我们一般采用能得到较好图像边缘的高斯滤波来对图片进行去噪,对图片信号进行平滑处理。
对于图像处理来说,常用二维零均值离散高斯函数作平滑滤波器。
二维高斯函数为:

使用去噪函数的代码如下:
该函数是 OpenCV 库中自带的滤波函数,可以直接调用
三、提取边缘信息
Canny 边缘检测算子是 John F.Canny 于 1986 年开发出来的一个多级边缘检测算法。Canny 边缘检测算法以 Canny 的名字命名,被很多人推崇为当今最优的边缘检测的算法。
Canny 边缘检测的步骤一般分为下列 4 步:

消除噪声(一般情况下,使用高斯平滑滤波器卷积降噪)
计算梯度幅值和方向(略复杂不做详述)
非极大值抑制(这一步排除非边缘像素,仅仅保留了一些细线条,做为候选边缘)

滞后阈值(滞后阈值需要两个阈值 (高阈值和低阈值)):
如果某一像素位置的幅值超过高阈值, 该像素被保留为边缘像素。

如果某一像素位置的幅值小于低阈值, 该像素被排除。

如果某一像素位置的幅值在两个阈值之间, 该像素仅仅在连接到一个高于高阈值的像素时被保留。

对于 Canny 函数的使用,推荐的高低阈值比在 2:1 到 3:1 之间

四、Hough 圆变换
霍夫圆变换的基本原理和上面讲的霍夫线变化大体上是很类似的,只是点对应的二维极径极角空间被三维的圆心点 x, y 还有半径 r 空间取代。
对直线来说, 一条直线能由参数极径极角表示. 而对圆来说, 我们需要三个参数来表示一个圆, 也就是:

在 open_cv 中一般通过霍夫梯度法来解决圆变换问题,原理如下:

首先对图像应用边缘检测,用 canny 边缘检测。
然后,对边缘图像中的每一个非零点,考虑其局部梯度,即用 Sobel()函数计算 x 和 y 方向的 Sobel 一阶导数得到梯度
利用得到的梯度,由斜率指定的直线上的每一个点都在累加器中被累加,这里的斜率是从一个指定的最小值到指定的最大值的距离
标记边缘图像中每一个非 0 像素的位置
从二维累加器中这些点中选择候选的中心,这些中心都大于给定阈值并且大于其所有近邻。这些候选的中心按照累加值降序排列,以便于最支持像素的中心首先出现
对每一个中心,考虑所有的非 0 像素
这些像素按照其与中心的距离排序,从到最大半径的最小距离算起,选择非 0 像素最支持的一条半径
如果一个中心收到边缘图像非 0 像素最充分的支持,并且到前期被选择的中心有足够的距离,那么它就会被保留下来

这个实现可以使算法执行起来更高效,或许更加重要的是,能够帮助解决三维累加器中会产生许多噪声并且使得结果不稳定的稀疏分布问题,但该算法同样不完美。
在程序中使用的函数为 HoughCircles(), 使用此函数可以很容易地检测出圆的圆心,但是它可能找不到合适的圆半径:

通过以上这几步,基本能在一张图片中找到交通标志牌的位置了,下面是示例效果:
A. 原图

B. 提取颜色区域后
[如图所示,代码中所要实现的提取红蓝黄区域已经实现,而不足之处在于,无关的区域也被提取了进来,例如蓝色的天空,红色的交通柱,以及少部分绿叶和车辆轮廓,但对于识别交通标志颜色而言是没有影响的]
C. 边缘检测

[该图是对提取颜色区域后的图进行了边缘检测,清晰地把交通标志牌和其它的一些图片轮廓给勾勒出来。这近一步地方便了下一步进行圆变换的操作]
D. 霍夫圆变换

[在对边缘检测后的图进行了高斯滤波去噪之后,对图片进行了 HoughCircles() 的操作,可以看出,交通标志的位置被很准确地勾勒出来 ]

正文完
 0