1. 程式人生 > >基於RGB差值法的顏色分割

基於RGB差值法的顏色分割

主要思想來自顏色分類論文《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