现在的位置: 首页 > 综合 > 正文

基于RGB空间的交通标志检测

2013年10月12日 ⁄ 综合 ⁄ 共 5627字 ⁄ 字号 评论关闭

主要思想来自颜色分类论文《Goal Evaluation of Segmentation Algorithms for Traffic Sign Recognition》

RGB空间是通常的初始的空间,如果简单的分割过程是其目的,使用RGB空间是比较好的选择。然而,三个颜色之间的高相关性组件和光照变化颜色的效果信息,使得它很难找到正确的阈值。在这个空间上,一个解决办法是使用RGB的相对于归一化,即除以R + G+ B。



这种方式,阈值在这个空间里很容易地找到。然而,出现了一些问题:这个标准化的空间,因为照度低(低RGB值),该转换是不稳定的,并在接近零的值,噪声被放大。

检测所用的阈值如下



其中ThR=0.4;ThG=0.3,ThB=0.4,thy=0.85



程序代码为



// 交通标志检测.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"

#include "stdafx.h"
#include "cv.h"
#include "cv.h"
#include "highgui.h"
#include <stdio.h>
#include <iostream>//这里不要.h!
#include <string>
#include<windows.h>

using namespace std;
int ifred=0;
int ifgreen=0;
int ifblue=0;
int whetherRed(int rData,int gData,int bData,int T);
int whetherBlue(int rData,int gData,int bData,int T);
int whetherYellow(int rData,int gData,int bData,int T);
int rednum=0;
int bluenum=0;
int yellownum=0;
float rij,bij,gij;

CvRect processImg(IplImage* img);//函数初始化
int main( )
{

cvNamedWindow( "window1", 1 ); //创建窗口
cvNamedWindow( "window2", 1 ); //创建窗口

    IplImage* pImg; //声明IplImage指针

pImg = cvLoadImage( "P6250063.TIF"/*argv[1]*/, 1);//需要检测的图片名称
IplImage *RChannel,*GChannel,*BChannel,*tempImg,*middleImg;
CvSize Size1;//OpenCV的基本数据类型之一。表示矩阵框大小,以像素为精度。与CvPoint结构类似,但数据成员是integer类型的width和height。
Size1 = cvGetSize(pImg);//OpenCV提供的一种操作矩阵图像的函数。得到二维的数组的尺寸,以CvSize返回。
RChannel = cvCreateImage(Size1, IPL_DEPTH_8U, 1);//创建头并分配数据,IPL_DEPTH_8U - 无符号8位整型
GChannel = cvCreateImage(Size1, IPL_DEPTH_8U, 1);
BChannel = cvCreateImage(Size1, IPL_DEPTH_8U, 1);
cvSplit(pImg, BChannel, GChannel, RChannel, NULL);//分割多通道数组成几个单通道数组或者从数组中提取一个通道
tempImg = cvCreateImage(Size1, IPL_DEPTH_8U, 1);//CreateImage创建头并分配数据
CvMat mat = cvMat(Size1.height,Size1.width,IPL_DEPTH_8U,NULL);//CvMat 多通道矩阵 

CvMat mat2 = cvMat(Size1.height,Size1.width,IPL_DEPTH_8U,NULL);
CvMat mat3 = cvMat(Size1.height,Size1.width,IPL_DEPTH_8U,NULL);
CvMat* Rmat;//指针
CvMat* Gmat;
CvMat* Bmat;
int rData;
int gData;
int bData;
int temp=0;

CvRect resultRect;//矩形框的偏移和大小 
Rmat = cvGetMat(RChannel, &mat, 0, 0);//转换成向量

Gmat = cvGetMat(GChannel, &mat2, 0, 0);

Bmat = cvGetMat(BChannel, &mat3, 0, 0);

for (int i = 0;i<pImg->height;i++)
{
for (int j = 0;j<pImg->width;j++)
{   int ifred=0;//重新赋值!坑爹啊!
            int ifgreen=0;
            int ifyellow=0;
            int temp=0;
rData = (int)CV_MAT_ELEM(*Rmat, uchar, i, j);//opencv中用来访问矩阵每个元素的宏,这个宏只对单通道矩阵有效,多通道会报错
gData = (int)CV_MAT_ELEM(*Gmat, uchar, i, j);
bData = (int)CV_MAT_ELEM(*Bmat, uchar, i, j);
float sum=rData+gData+bData;
float rr=rData;
float gg=gData;
float bb=bData;
 rij=rData/sum;
 gij=gData/sum;
 bij=bData/sum;

ifred=whetherRed(rData,gData,bData,50);
        ifblue=whetherBlue(rData,gData,bData,50);
        ifyellow=whetherYellow(rData,gData,bData,50);

if((ifred==255)||(ifblue==255)||(ifyellow==255))
{
temp=255;

}

cvSet2D(&mat,i,j,cvScalar(temp));//Set*D修改指定的数组 cvSet2D 给某个点赋值。cvGet2D 获得某个点的值, idx0=hight 行值, idx1=width 列值。函数返回的是一个CvScalar 容器,其参数中也有两个方向的坐标;CvScalar定义可存放1—4个数值的数值,

}
}
middleImg = cvGetImage(&mat,tempImg);//GetImage从不确定数组返回图像头 

    cvShowImage( "window2",  middleImg ); //显示图像

resultRect = processImg(middleImg);
if((rednum>=yellownum)&&(rednum>=bluenum))
cout<<"检测到红色标志!"<<endl;
if((bluenum>=yellownum)&&(bluenum>=rednum))
cout<<"检测到蓝色标志!"<<endl;
if((yellownum>=bluenum)&&(yellownum>=rednum))
cout<<"检测到黄色标志!"<<endl;

cvRectangle( pImg, cvPoint(resultRect.x,resultRect.y), cvPoint(resultRect.x + resultRect.width,resultRect.y + resultRect.height), CV_RGB(0,255,0),1, 8, 0 );//Rectangle绘制简单、指定粗细或者带填充的 矩形 

    cvShowImage( "window1",  pImg ); //显示图像
    cvWaitKey(0); //等待按键
    cvDestroyWindow( "window1" );//销毁窗口
    cvDestroyWindow( "window2" );//销毁窗口
    cvReleaseImage( &pImg ); //释放图像

    return 0;
}
int whetherRed(int rData,int gData,int bData,int T)

//int deltaRG, deltaRB;
//deltaRG = rData - gData;
//deltaRB = rData - bData;

if ((rij >= 0.4)&&(gij <= 0.3))
{
rednum++;
return 255;
}
//return 0;

}
int whetherYellow(int rData,int gData,int bData,int T)
{   
//int deltaGR, deltaGB;
//deltaGR = gData - rData;
//deltaGB = gData - bData;

if ((rij+gij)>=0.85)
{
yellownum++;
return 255;
}
//return 0;

}
int whetherBlue(int rData,int gData,int bData,int T)
{  
//int deltaBR, deltaBG;
//deltaBR = bData - rData;
//deltaBG = bData - gData;

if (bij>=0.4 )
{
bluenum++;
return 255;
}
//return 0;

}

CvRect processImg(IplImage* img)
{
CvMemStorage *stor = 0;//内存存储器是一个可用来存储诸如序列,轮廓,图形,子划分等动态增长数据结构的底层结构。它是由一系列以同等大小的内存块构成,呈列表型
CvSeq * cont = NULL,*conttmp = NULL;//CvSeq可动态增长元素序列
CvSeq * contMax=NULL;
int Number_Object =0;
int contour_area_tmp = 0;
int contour_area_max = 0;

CvRect resultRect = {0,0,0,0};

cvSmooth(img,img,CV_MEDIAN,3);//各种方法的图像平滑


stor = cvCreateMemStorage(0);//存储块的大小以字节表示。如果大小是 0 byte, 则将该块设置成默认值
cont = cvCreateSeq(CV_SEQ_ELTYPE_POINT, sizeof(CvSeq), sizeof(CvPoint), stor);
//存储面积最大轮廓数组
contMax = cvCreateSeq(CV_SEQ_ELTYPE_POINT, sizeof(CvSeq), sizeof(CvPoint), stor);
Number_Object = cvFindContours( img, stor, &cont, sizeof(CvContour),
CV_RETR_EXTERNAL , CV_CHAIN_APPROX_NONE , cvPoint(0,0) );//在二值图像中寻找轮廓

conttmp = cont;
bool check = TRUE;//bool是布尔型变量,也就是逻辑型变量的定义符,类似于float,double等
CvPoint* pointTmp;//二维坐标系下的点,类型为整型 

int mostLeft = img->width - 1,mostRight = 0,mostHigh = img->height-1,mostlow=0;
for(;cont;cont = cont->h_next)//h_next???????

{
if (CV_IS_SEQ_POLYGON( cont ))//POLYGON多边形;多角形物体
{
for (int i = 0; cvGetSeqElem(cont, i)!=0;i++)//返回索引所指定的元素指针
{
pointTmp = (CvPoint*)cvGetSeqElem(cont, i);
if (pointTmp->y < 2||pointTmp->x < 2||pointTmp->y > img->height-3||pointTmp->x > img->width)
{
check = FALSE;break;
}

}
}
if (check)
{
contour_area_tmp = (int)fabs(cvContourArea( cont, CV_WHOLE_SEQ ));
//计算整个轮廓或部分轮廓的面积 

if(contour_area_tmp > contour_area_max)
{
contour_area_max = contour_area_tmp;
contMax = cont;//把最大面积的轮廓赋值给conmax
}

}
}
if (conttmp&&contMax)
{
if (CV_IS_SEQ_POLYGON( contMax ))
{
for (int i = 0; cvGetSeqElem(contMax, i)!=0;i++)
{
pointTmp = (CvPoint*)cvGetSeqElem(contMax, i);
if (pointTmp->x < mostLeft)
{
mostLeft = pointTmp->x;
}
if (pointTmp->x > mostRight)
{
mostRight = pointTmp->x;
}
if (pointTmp->y < mostHigh)
{
mostHigh = pointTmp->y;
}
if(pointTmp->y>mostlow)
{
                       mostlow=pointTmp->y;
}

}
resultRect.x = mostLeft;
resultRect.y = mostHigh;
resultRect.width = mostRight - mostLeft;
resultRect.height= mostlow -  mostHigh;

}
}
return resultRect;

}


抱歉!评论已关闭.