基于RGB差值法的颜色分割

xiaoxiao2021-10-27  53

主要思想来自颜色分类论文《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; }

转载自:https://blog.csdn.net/kobesdu/article/details/8142068

转载请注明原文地址: https://www.6miu.com/read-4832015.html

最新回复(0)