0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

基于视觉的交通标识牌检测与识别

ADAS 来源:djl 作者:ADAS 2019-08-08 08:46 次阅读

一、要求

首先要明确一下本文到底是要干什么。本文要完成基于视觉的交通标识牌检测与识别,说白了,就两个事:1)在一张图中找到交通标识牌在哪里(检测);2)认清楚这个标识牌是啥,表达的什么意思(识别)。那么最后得到的结果预览如下:

二、使用数据

交通标识牌种类数不胜数,我国的交通标志一共有一百余种,按类别可分为黄底黑边的警告标志、白底红圈的禁令标志、蓝底白字的指示标志,形状上以三角形、圆形和矩形为主。本文主要是为了介绍一下交通标识牌的识别流程和一些主要方法的实现,为了简化工作,本文挑选了以下五类交通标识牌。

可以看出来,博主用心良苦,选择的交通标识牌具有很清楚的特征:1)颜色上,这五类交通标识牌的外边框都是红色的;2)形状上,标识牌都是标准的圆形。这事实上也表明了,交通标识牌具有着鲜明的特征,故无论是人眼还是机器,都较易识别。(其他种类的交通标志牌也是一样,利用形状和颜色特征来处理)

三、使用方法
在我看来,目前处理交通标牌识别的主要有两种方法,1)传统的图像处理+机器学习办法;2)最近很火的深度学习。那么本文采用的是前者,后者后续再进行介绍。

1>检测:颜色和形状。

交通标志牌为了起到其警示作用,在颜色和形状上都有着易区分性,如本文所讨论的五类标志牌,颜色特征为外框均为鲜艳的红色;形状特征为均为圆形。于是,检测的思路如下,最终得到了圆形部分的交通标牌:

基于视觉的交通标识牌检测与识别

接下来,主要分为颜色分割和形状检测两部分进行讨论:

基于颜色分割的图像二值化处理:

最直观、简单的是利用RGB颜色空间来描述图像的色彩情况,但是,RGB色彩空间极易受到光线情况的影响,鲁棒性并不是很好,所以在相关论文中,你会发现,很少有人直接使用RGB色彩空间进行色彩分割。而实际上,本人拿有限的样本和测试集进行测试,RGB色彩分割效果在图像成像质量较理想的时候效果极佳,但是的确容易受到干扰。本文此处选择了HSI色彩空间模型进行色彩分割。先来点理论知识:

色调H(Hue):与光波的波长有关,它表示人的感官对不同颜色的感受,如红色、绿色、蓝色等,它也可表示一定范围的颜色,如暖色、冷色等。

饱和度S(Saturation):表示颜色的纯度,纯光谱色是完全饱和的,加入白光会稀释饱和度。饱和度越大,颜色看起来就会越鲜艳,反之亦然。

亮度I(Intensity):对应成像亮度和图像灰度,是颜色的明亮程度。

从理论上看,HSI色彩空间将饱和度和亮度信息独立了出来,这样一定程度上就降低了光线带来的影响。听上去很有道理,但是,实际上,这也仅仅是一定程度上降低了亮度和色彩的耦合关系,并不是完全地进行了解耦,所以,效果会有提升,但是很难带来质的改变(这是笔者自己的体验,也许是笔者能力不足,实现得不是很理想)

那么从RGB色彩空间转换到HSI空间的转换公式如下:

基于视觉的交通标识牌检测与识别

函数RGB2HSI是将RGB色彩空间转换到HSI色彩空间,其转换的过程参照式(2.2),最后将饱和度S和强度I均放大100倍,便于操作。 最后得到的H、 S、 I的取值范围分别为[0,360]、 [0,100]、 [0,100]。

Cpp代码

voidRGB2HSV(doublered,doublegreen,doubleblue,double&hue,double&saturation,

double&intensity)

{

doubler,g,b;

doubleh,s,i;

doublesum;

doubleminRGB,maxRGB;

doubletheta;

r=red/255.0;

g=green/255.0;

b=blue/255.0;

minRGB=((r

minRGB=(minRGB

maxRGB=((r>g)?(r):(g));

maxRGB=(maxRGB>b)?(maxRGB):(b);

sum=r+g+b;

i=sum/3.0;

if(i<0.001 || maxRGB-minRGB<0.001 )  

{

h=0.0;

s=0.0;

}

else

{

s=1.0-3.0*minRGB/sum;

theta=sqrt((r-g)*(r-g)+(r-b)*(g-b));

theta=acos((r-g+r-b)*0.5/theta);

if(b<=g)  

h=theta;

else

h=2*PI-theta;

if(s<=0.01)  

h=0;

}

hue=(int)(h*180/PI);

saturation=(int)(s*100);

intensity=(int)(i*100);

}

在得到HSI空间的基础上,分割出红色像素,事实上这个阈值最好时自己调出来,无论是基于哪个色彩空间,网上的代码或者论文中的数值都是个参考,自己调出来的才靠谱嘛,代码如下:

Cpp代码

//得到图像参数

intwidth=src.cols;//图像宽度

intheight=src.rows;//图像高度

//色彩分割

doubleB=0.0,G=0.0,R=0.0,H=0.0,S=0.0,I=0.0;

MatMat_rgb=Mat::zeros(src.size(),CV_8UC1);

intx,y,px,py;//循环

for(y=0;y

{

for(x=0;x

{

//获取BGR值

B=src.at(y,x)[0];

G=src.at(y,x)[1];

R=src.at(y,x)[2];

RGB2HSV(R,G,B,H,S,I);

//红色:337-360

if((H>=337&&H<=360||H>=0&&H<=10)&&  

S>=12&&S<=100&&V>20&&V<99)  

{

Mat_rgb.at(y,x)=255;//分割出红色

}

}

}

分割效果可见如下组图,由近至远:

注意:有一个很严肃的问题我这里没有提,那就是图像预处理!做图像处理的很重要的一个步骤就是图像预处理,预处理做好了,后面的问题复杂度也就降低了许多。实际上,用颜色分割来二值化图像也可以看作一种预处理。那么颜色分割之前有不有必要做图像预处理呢?是有的。举个例子,我那我的MATE8在学校里拍了一张照,然后使用手机相机自带的功能,调整其色彩饱和度,亮度等,得到以下两种图片:

相机拍的原图

手机调整饱和度、亮度后

这两种图片,显然右边的将更有利于颜色分割!(不信可以试试哦)。本文主要以介绍交通标牌的主要流程为主,预处理的方法包括直方图均衡化、白平衡、亮度调节等等这些就不仔细纠结了,但是,不代表这部分不重要,图像预处理往往一定程度上决定了最后的效果。

基于形状(圆形)检测的ROI提取
在进行颜色分割之后,得到的只是一个粗略的交通标志牌ROI区域, 还会留下一些噪声以及一些和目标区域面积相当或者比目标面积略大的区域,这时候就还需要进行一些图像预处理,为准确检测交通标志牌打下坚实基础。由于交通标志最明显的特征是其颜色和形状,在用颜色分割之后,我们可以通过形状特征来去除其余的干扰。对于本文的研究对象而言,交通标志牌的形状为圆形,可以采用经典的Hough变换进行圆检测,该方法准确性高,但是计算量大,耗时且占用较大内存;也可以采用圆度的方法来提取圆形,该方法原理简单,计算量小,准确率高。综合考虑,本文使用基于圆度的圆检测算法。大概流程如下,后文还会详细介绍:

基于视觉的交通标识牌检测与识别

图有点不太清楚,下文中对于关键的部分会再次给出效果图。

中值滤波,这个没啥好说的,图上效果不是很明显,但是实际上可以一定程度上滤掉单个噪点,对得到准确的结果会有一定的帮助;

形态学处理,最后我们的目的是要得到一个封闭的区域,所以,颜色分割后的结果很可能不会是比较理想封闭的圆形,那么选用的3×3腐蚀模板,7×7膨胀模板,这样检测到的圆形将基本不会产生缺口,保证是一个封闭的形状。

图像填充,有了上述步骤得到的封闭圆形,我们接下来就可以填充封闭图形了(这里你可能会问,为啥要这样做。实际上直接进行Hough圆检测可以得到ROI结果,但是本文是换了一个思路,使用圆度来判断圆形,所以算法需要一个实心区域),代码如下:

Cpp代码

voidfillHole(constMatsrcBw,Mat&dstBw)

{

Sizem_Size=srcBw.size();

MatTemp=Mat::zeros(m_Size.height+2,m_Size.width+2,srcBw.type());//延展图像

srcBw.copyTo(Temp(Range(1,m_Size.height+1),Range(1,m_Size.width+1)));

cv::floodFill(Temp,Point(0,0),Scalar(255));//填充区域

MatcutImg;//裁剪延展的图像

Temp(Range(1,m_Size.height+1),Range(1,m_Size.width+1)).copyTo(cutImg);

dstBw=srcBw|(~cutImg);

}

轮廓检测,初步筛选ROI,要想使用基于圆度的圆检测算法,则需要从图像中提取初步的ROI来进行筛选。这里使用轮廓检测法来检测图片中的ROI区域。可以看到,一些细小的噪声也被检测进来。

所以,本文先通过对检测区域的宽高比、面积大小进行限制,筛选出有效的检测区域,经过实验,可以确定宽高比限制在0.5-2之间,面积最小值设定为400,可以进一步得到下图的检测效果,可以看到,此时小面积的噪声已经被排除。

代码如下:

Cpp代码

//找轮廓

vector>contours;

vectorhierarchy;

findContours(Mat_rgb,contours,hierarchy,CV_RETR_EXTERNAL,

CV_CHAIN_APPROX_SIMPLE,Point(0,0));

///多边形逼近轮廓+获取矩形和圆形边界框

vector>contours_poly(contours.size());

vectorboundRect(contours.size());

vectorcenter(contours.size());

vectorradius(contours.size());

//得到轮廓矩形框

for(inti=0;i< contours.size(); i++ )  

{

approxPolyDP(Mat(contours[i]),contours_poly[i],3,true);

boundRect[i]=boundingRect(Mat(contours_poly[i]));

minEnclosingCircle(contours_poly[i],center[i],radius[i]);

}

///画多边形轮廓+包围的矩形框

Matdrawing=Mat::zeros(Mat_rgb.size(),CV_8UC3);

for(inti=0;i< contours.size(); i++ )  

{

Rectrect=boundRect[i];

//首先进行一定的限制,筛选出区域

//高宽比限制

floatratio=(float)rect.width/(float)rect.height;

//轮廓面积

floatArea=(float)rect.width*(float)rect.height;

floatdConArea=(float)contourArea(contours[i]);

floatdConLen=(float)arcLength(contours[i],1);

if(dConArea<400)//ROI 区域面积限制  

continue;

if(ratio>2||ratio<0.5)//ROI 区域宽高比限制  

continue;

//检测到了!

Scalarcolor=Scalar(rng.uniform(0,255),rng.uniform(0,255),rng.uniform(0,255));

//绘制轮廓和检测到的轮廓外接矩形

drawContours(drawing,contours_poly,i,color,1,8,vector(),0,Point());

rectangle(drawing,boundRect[i].tl(),boundRect[i].br(),color,2,8,0);

rectangle(src,boundRect[i].tl(),boundRect[i].br(),color,2,8,0);

}

圆度算法检测,实际上这是利用了非常简单的数学约束,来对检测到的区域进行圆形验证。圆度定义如下:

其中,S为圆的面积,L为圆的周长,C为圆度。圆度值越接近1,则表示该图形与圆形的契合程度越高。经过大量的实验,可以得出圆度大于0.5时,即 4 . 0  C 时,可以筛选出巨大部分的圆形。

ROI区域无效像素面积约束,这是进一步确定筛选后的ROI区域是目标圆形区域。该约束条件是基于ROI区域中圆形的缺失面积而得到的。前文中得到的ROI区域是包含圆形交通标志牌的矩形区域,如下图所示,可以将整个ROI区域分成1、2、3、4四块,其中红色部分为交通标志牌,灰色部分为ROI区域中的无效像素。可以直观地看到,1、2、3、4四块的无效像素满足一定的数学关系,

基于视觉的交通标识牌检测与识别

有如下约束

基于视觉的交通标识牌检测与识别

圆度代码即为一个约束条件,对面个轮廓检测得到的ROI进行验证,无效像素面积约束则代码如下:

Cpp代码

boolisCircle(constMatsrcBw,Mat&mytemp)//(待改进)

{//输入的是一个灰度图像

Mattemp=Mat::zeros(srcBw.size(),CV_8UC1);;

booliscircle=false;

//获得srcBw信息

intw=srcBw.cols;

inth=srcBw.rows;

intcount1=0;//各部分的缺失像素计数器

intcount2=0;

intcount3=0;

intcount4=0;

//将srcBw平均分成四份,进行访问缺失的像素个数、所占比重

//先访问左上

for(inti=0;i< h/2;i ++)  

{

for(intj=0;j< w/2;j ++)  

{

if(srcBw.at(i,j)==0)

{

temp.at(i,j)=255;

mytemp.at(i,j)=255;

count1++;

}

}

}

//右上

for(inti=0;i< h/2;i ++)  

{

for(intj=w/2-1;j< w;j ++)  

{

if(srcBw.at(i,j)==0)

{

temp.at(i,j)=255;

mytemp.at(i,j)=255;

count2++;

}

}

}

//左下

for(inti=h/2-1;i< h;i ++)  

{

for(intj=0;j< w/2;j ++)  

{

if(srcBw.at(i,j)==0)

{

temp.at(i,j)=255;

mytemp.at(i,j)=255;

count3++;

}

}

}

//右下

for(inti=h/2-1;i< h;i ++)  

{

for(intj=w/2-1;j< w;j ++)  

{

if(srcBw.at(i,j)==0)

{

temp.at(i,j)=255;

mytemp.at(i,j)=255;

count4++;

}

}

}

floatc1=(float)count1/(float)(w*h);//左上

floatc2=(float)count2/(float)(w*h);//右上

floatc3=(float)count3/(float)(w*h);//左下

floatc4=(float)count4/(float)(w*h);//右下

cout<< "result: " << c1 << "," << c2  

<< "," << c3 << "," << c4 << endl;  

//限定每个比率的差值范围

if((c1>0.037&&c1<0.12)&&(c2>0.037&&c2<0.12)&&(c2>0.037&&c2<0.12)&&(c2>0.037

&&c2<0.12))  

{

//限制差值,差值比较容错,相邻块之间差值相近,如左上=右上&&左下=右下或左上=左下&&右上=右下

if((abs(c1-c2)<0.04&&abs(c3-c4)<0.04)||(abs(c1-c3)<0.04&&abs(c2-c4)<0.04))  

{

iscircle=true;

}

}

returniscircle;

}

利用轮廓检测、圆度约束和无效面积约束,可以测试得到如下效果图,


最后,目标区域提取的效果如下:


2>识别:SVM分类。

有了上文提取ROI的基础,分类过程实际上和我之前写过的箭头分类如出一辙。

图像预处理,首先将无效像素全部去除,只留下圆形ROI有效区域

然后进行二值化处理,二值化后的图像特征更为清晰

可以选择所有像素作为特征,当然更科学的是Hu不变矩、Zernike不变矩、二者混合矩等特征。关于Hu、Zernike特征的代码网上比比皆是,这里仅推荐一个作为参考。本文为了简单实现框架,拿全部像素特征进行训练。准备好样本和测试集,并给这五类交通标牌设置标签“stop”,“20t”,“car forbidden”,“5”,“stop2”

SVM代码框架如下。

SVM训练

Cpp代码

//*********************SVM训练部分***********************

//准备开始训练

CvSVMclassifier;

CvSVMParamsSVM_params;

SVM_params.kernel_type=CvSVM::LINEAR;//使用RBF分类非线性问题

SVM_params.svm_type=CvSVM::C_SVC;

SVM_params.degree=0;

SVM_params.gamma=0.01;

SVM_params.term_crit=cvTermCriteria(CV_TERMCRIT_ITER,1000,FLT_EPSILON);

SVM_params.C=100;

SVM_params.coef0=0;

SVM_params.nu=0;

SVM_params.p=0.005;

classifier.train(train,labels,Mat(),Mat(),SVM_params);//SVM训练,线性核上述参数C起作用

SVM保存

Cpp代码

classifier.save("model180.txt");

SVM读取

Cpp代码

//这里载入分类器,方便直接训练

CvSVMclassifier;

classifier.load("model180.txt");

SVM预测

Cpp代码

for(inti=0;i< testdata.size() ; ++i)  

{

intresult=(int)classifier.predict(testdata[i]);

std::cout<<"测试样本"<"的测试结果为:"  

<" " << labelname[result-1] << " ";  

}

最后得到了文中开始展示的效果。
本文完整代码和数据,已托管在Github上https://github.com/lps683/TrafficsSignDetection。这些东西也许在高手看来不值一提,但是,若能给一部分人带来一些哪怕一点点收获,那么花这么多功夫写这篇文章也不算白费。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 图像采集
    +关注

    关注

    2

    文章

    280

    浏览量

    41075
  • 智能汽车
    +关注

    关注

    30

    文章

    2615

    浏览量

    106388
  • 交通标志识别

    关注

    0

    文章

    4

    浏览量

    3245
收藏 人收藏

    评论

    相关推荐

    安全标识牌|夜光标识|管道标识|反光胶带|警示胶带

    安赛-安全标识专家。我们帮助客户加强工作中的安全性,提高安全意识,主要产品包括:安全标识牌|夜光标识|管道标识|反光胶带|警示胶带|防滑胶带|防滑地贴|划线胶带|消防逃生
    发表于 12-15 09:02

    LED标识标牌全解

    来公布某些信息的。  从交通标识来讲:城市中汽车的数量每天都有几百辆增加,道路资源越来越少,对于交通标识合理布局,增加交通监控,单行道以及时
    发表于 10-17 15:18

    一套基于RFID的交通检测方法介绍

    无线射频识别技术(RFID)是一项非接触式自动识别技术,具有信息量大,抗干扰能力强,操作快捷等许多优点。特别是RFID技术在高速运动物体识别、多目标识别和非接触
    发表于 07-26 06:31

    多功能杆的系统组成与功能要求

    传感器等设备,实现智能照明、视频监控、信息发布、环境监测等功能,进而推动智慧城市的发展和运营模式探索建设。多功能杆杆同时支持交通信号灯、道路指示交通标识牌等道路杆件设施的挂载,实现
    发表于 11-10 17:12

    基于图像轮廓识别技术在交通路标识别应用

    针对现有计算机视觉交通路标识别的复杂性和不稳定性的问题,通过运用图像轮廓识别技术,提出了由全局特征到局部特征再到结构特征的多层次轮廓识别,在交通
    发表于 11-03 16:16 8次下载
    基于图像轮廓<b class='flag-5'>识别</b>技术在<b class='flag-5'>交通路标识别</b>应用

    基于SIFT视觉词汇的目标识别算法

    算法的目标识别算法。结合在无遮挡与被局部遮挡的交通工具全方位姿态模型库上进行的目标识别试验,得出结果:算法对无遮挡目标的平均识别率能到达83%以上,具有良好的
    发表于 11-14 11:04 5次下载
    基于SIFT<b class='flag-5'>视觉</b>词汇的目<b class='flag-5'>标识别</b>算法

    基于机器视觉识别交通灯控制系统

    本文主要介绍了一种基于机器视觉识别交通灯控制系统,对交通信号灯的颜色及其数字进行自动识别。对于交通
    发表于 01-09 15:22 1.1w次阅读
    基于机器<b class='flag-5'>视觉</b><b class='flag-5'>识别</b>的<b class='flag-5'>交通</b>灯控制系统

    交通标识识别流程解析

    交通标识识别算法一方面采用了基于卷积神经网络的训练和识别方法,极大地提高了交通标识
    的头像 发表于 08-08 10:04 6384次阅读

    基于YOLO改进的轻量级交通标识检测模型

    在车载边缘计算单元中,由于其硬件设备的资源受限,开发适用于车载边缘计算的轻量级、高效的交通标识检测模型变得越来越迫切。文中提出了一种基于 Tiny YOLO改进的轻量级交通
    发表于 04-19 15:01 12次下载
    基于YOLO改进的轻量级<b class='flag-5'>交通</b><b class='flag-5'>标识</b><b class='flag-5'>检测</b>模型

    路灯RFID智能标识牌简介

    路灯RFID智能标识牌型号HY-WS05,采用超高频UHF远距离芯片、灯光交互技术、专利天线设计和聚乙烯灌注密封。
    的头像 发表于 05-08 10:26 668次阅读
    路灯RFID智能<b class='flag-5'>标识牌</b>简介

    RFID标识牌手持识别终端简介

    RFID标识牌手持识别终端型号 HY-SD1701是为RFID智能交互标识牌专业定制开发的专业识读设备,专利的盾牌UHF识读模块,采用Android 5.1.1 操作系统,5.0寸IPS屏,8000mAh锂聚合物电池,4G通讯模
    的头像 发表于 05-08 11:16 613次阅读

    超详细!一文讲透机器视觉常用的 3 种“目标识别”方法

    来源:机器视觉沙龙随着机器视觉技术的快速发展,传统很多需要人工来手动操作的工作,渐渐地被机器所替代。传统方法做目标识别大多都是靠人工实现,从形状、颜色、长度、宽度、长宽比来确定被识别
    的头像 发表于 12-15 10:44 709次阅读
    超详细!一文讲透机器<b class='flag-5'>视觉</b>常用的 3 种“目<b class='flag-5'>标识别</b>”方法

    机器视觉的图像目标识别方法操作要点

    通过加强图像分割,能够提高机器视觉的图像目标识别的自动化水平,使得图像目标识别效果更加显著。图像分割的方法有很多种,不同方法分别适用于不同领域,这里重点介绍以下3种分割方法。
    发表于 01-15 12:17 149次阅读

    机器视觉的图像目标识别方法综述

    文章来源:MEMS引言从20世纪80年代开始,机器视觉技术的发展速度不断加快,已经走进了人们的日常生活与工作之中。机器视觉的图像目标识别系统的自动化程度较高,应用范围广,尤其在危险场所的运用,采用
    的头像 发表于 02-23 08:26 347次阅读
    机器<b class='flag-5'>视觉</b>的图像目<b class='flag-5'>标识别</b>方法综述

    机器视觉常用的三种目标识别方法解析

    随着机器视觉技术的快速发展,传统很多需要人工来手动操作的工作,渐渐地被机器所替代。传统方法做目标识别大多都是靠人工实现,从形状、颜色、长度、宽度、长宽比来确定被识别的目标是否符合标准,最终定义出
    的头像 发表于 03-14 08:26 282次阅读
    机器<b class='flag-5'>视觉</b>常用的三种目<b class='flag-5'>标识别</b>方法解析