• 【图像算法】彩色图像分割专题五:提取彩色图像上特定色彩


    【图像算法】彩色图像分割专题五:提取彩色图像特定色彩

        SkySeraph Jun 8th 2011  HQU

    Email:zgzhaobo@gmail.com    QQ:452728574

    Latest Modified Date:Jun 8th 2011 HQU

    一 原理及说明:

    1  RGB(red,green,blue)模式是一种与设备相关的色彩空间,最常用的用途就是显示器系统。RGB下,各分量关联性太大,每个通道都编入了亮度信息,容易受周围环境影响(光照等),其与人眼认知颜色的过程不太匹配,并不适合用来对彩色图像进行分析和分割,相比下HSV空间是从人的视觉系统除法的,更适于图像分析等。更多关于各种彩色空间模型请参考http://www.cnblogs.com/skyseraph/archive/2011/05/03/2035643.html

     国内很多关于车牌识别的论文中,当利用到颜色信息时,一般都是在HSV/YIQ/Lab模式下,根据特定的车牌颜色信息(常见车牌颜色有:白底黑字、黑底白字、蓝底白字、黄底黑字等),进行车牌分割进行的。 颜色的提取方法即本文所述。 这种方法只适合特定颜色的提取,用PR术语,类似"有监督学习";反之,无监督,对任意图像进行颜色分割,属于彩色分割领域。

    3  关于HSV范围的划分:

    <1> 论文:Car color recognition from CCTV camera image:http://www.docin.com/p-211572110.html 

    作者采用的是如下方式:

    <2>论文:利用支持向量机识别汽车颜色:http://www.cnki.com.cn/Article/CJFDTotal-JSJF200405018.htm

    作者首先是在Lab空间下分出16类颜色,然后再HSV下进行样本空间分解,采用如下方式:

    <3>本文根据实验,采取划分方式如源码所示,在这种方式下,测试结果较好。

    二 源码:

    /////////////////////////////////////////////////////////////////////////////
    // Note:		颜色分割:提取特定颜色
    // Version:	5/11/2011 skyseraph  zgzhaobo@gmail.com
    /////////////////////////////////////////////////////////////////////////////
    void CColorSegDlg::ColorSegByHSV(IplImage* img) 
    // 提取特定颜色
    {
    	//====================== 变量定义====================//
    	int x,y; //循环
    	
    	//====================== 输入彩色图像信息====================//
    	IplImage* pSrc = NULL;
    	pSrc = cvCreateImage(cvGetSize(img),img->depth,img->nChannels);
    	cvCopyImage(img,pSrc);
    
     	int width = pSrc->width;			//图像宽度
    	int height = pSrc->height;			//图像高度
    	int depth = pSrc->depth;			//图像位深(IPL_DEPTH_8U...)
    	int channels = pSrc->nChannels;		//图像通道数(1、2、3、4)
    	int imgSize = pSrc->imageSize;		//图像大小 imageSize = height*widthStep
    	int step = pSrc->widthStep/sizeof(uchar);    //相邻行的同列点之间的字节数: 注意widthStep != width*nChannels (有字节填零补充)
    	uchar* data    = (uchar *)pSrc->imageData;
    	int imageLen = width*height;		//
    
    	//=========================================//
    	double B=0.0,G=0.0,R=0.0,H=0.0,S=0.0,V=0.0;
    	IplImage* dstColorSegByColor = cvCreateImage(cvGetSize(pSrc),IPL_DEPTH_8U,3);
    	IplImage* dstColorSegByColorGray = cvCreateImage(cvGetSize(pSrc),IPL_DEPTH_8U,1);
    
    	//CvFont font = cvFont( 1, 1 );
    
    	for (y=0; y<height; y++)
    	{
    		for ( x=0; x<width; x++)
    		{
    			// 获取BGR值
    			B = ((uchar*)(pSrc->imageData + y*pSrc->widthStep))[x*pSrc->nChannels];
    			G = ((uchar*)(pSrc->imageData + y*pSrc->widthStep))[x*pSrc->nChannels+1];
    			R = ((uchar*)(pSrc->imageData + y*pSrc->widthStep))[x*pSrc->nChannels+2];
    			
    			//  RGB-HSV
    			pMyColorSpace.RGB2HSV(R,G,B,H,S,V);	
    			
    			H = (360*H)/(2*PI);	
    
    			//  黑白
    			//黑色
    			if(V<0.35)			
    			{
    				((uchar*)(dstColorSegByColorGray->imageData + y*dstColorSegByColorGray->widthStep))[x]
    					= 0;  //灰度
    				((uchar*)(dstColorSegByColor->imageData + y*dstColorSegByColor->widthStep))[x*dstColorSegByColor->nChannels] 
    					= 0;  //B
    				((uchar*)(dstColorSegByColor->imageData + y*dstColorSegByColor->widthStep))[x*dstColorSegByColor->nChannels+1] 
    					= 0;  //G
    				((uchar*)(dstColorSegByColor->imageData + y*dstColorSegByColor->widthStep))[x*dstColorSegByColor->nChannels+2] 
    					= 0;  //R
    			}			
    			//白色
    			if(S<0.15 && V>0.75)
    			{
    				((uchar*)(dstColorSegByColorGray->imageData + y*dstColorSegByColorGray->widthStep))[x]
    					= 255;  //灰度
    				((uchar*)(dstColorSegByColor->imageData + y*dstColorSegByColor->widthStep))[x*dstColorSegByColor->nChannels] 
    					= 255;  //B
    				((uchar*)(dstColorSegByColor->imageData + y*dstColorSegByColor->widthStep))[x*dstColorSegByColor->nChannels+1] 
    					= 255;  //G
    				((uchar*)(dstColorSegByColor->imageData + y*dstColorSegByColor->widthStep))[x*dstColorSegByColor->nChannels+2] 
    					= 255;  //R
    			}
    			
    			//灰色
    			if(S<0.15 && 0.35<V && V<0.75)
    			{
    				((uchar*)(dstColorSegByColorGray->imageData + y*dstColorSegByColorGray->widthStep))[x]
    					= 128;  //灰度
    				((uchar*)(dstColorSegByColor->imageData + y*dstColorSegByColor->widthStep))[x*dstColorSegByColor->nChannels] 
    					= 128;  //B
    				((uchar*)(dstColorSegByColor->imageData + y*dstColorSegByColor->widthStep))[x*dstColorSegByColor->nChannels+1] 
    					= 128;  //G
    				((uchar*)(dstColorSegByColor->imageData + y*dstColorSegByColor->widthStep))[x*dstColorSegByColor->nChannels+2] 
    					= 128;  //R
    			}
    
    			//  彩色
    			if(V>=0.35 && S>=0.15)
    			{
    				//红色相近
    				if((H>=0 && H<15) || (H>=340 && H<360))
    				{
    					((uchar*)(dstColorSegByColorGray->imageData + y*dstColorSegByColorGray->widthStep))[x]
    						= 40;  //灰度
    					((uchar*)(dstColorSegByColor->imageData + y*dstColorSegByColor->widthStep))[x*dstColorSegByColor->nChannels]
    						= 0;  //B
    					((uchar*)(dstColorSegByColor->imageData + y*dstColorSegByColor->widthStep))[x*dstColorSegByColor->nChannels+1] 
    						= 0;  //G
    					((uchar*)(dstColorSegByColor->imageData + y*dstColorSegByColor->widthStep))[x*dstColorSegByColor->nChannels+2] 
    						= 255;  //R					
    				}
    				//黄色相近
    				else if(H>=15 && H<75)
    				{
    					((uchar*)(dstColorSegByColorGray->imageData + y*dstColorSegByColorGray->widthStep))[x]
    						= 80;  //灰度
    					((uchar*)(dstColorSegByColor->imageData + y*dstColorSegByColor->widthStep))[x*dstColorSegByColor->nChannels]
    						= 0;  //B
    					((uchar*)(dstColorSegByColor->imageData + y*dstColorSegByColor->widthStep))[x*dstColorSegByColor->nChannels+1] 
    						= 255;  //G
    					((uchar*)(dstColorSegByColor->imageData + y*dstColorSegByColor->widthStep))[x*dstColorSegByColor->nChannels+2] 
    						= 255;  //R
    				}
    				//绿色相近
    				else if(H>=75 && H<150)
    				{
    					((uchar*)(dstColorSegByColorGray->imageData + y*dstColorSegByColorGray->widthStep))[x]
    						= 120;  //灰度
    					((uchar*)(dstColorSegByColor->imageData + y*dstColorSegByColor->widthStep))[x*dstColorSegByColor->nChannels]
    						= 0;  //B
    					((uchar*)(dstColorSegByColor->imageData + y*dstColorSegByColor->widthStep))[x*dstColorSegByColor->nChannels+1] 
    						= 255;  //G
    					((uchar*)(dstColorSegByColor->imageData + y*dstColorSegByColor->widthStep))[x*dstColorSegByColor->nChannels+2] 
    						= 0;  //R					
    				}
    				///*//青色相近
    				else if(H>=150 && H<185)
    				{
    					((uchar*)(dstColorSegByColorGray->imageData + y*dstColorSegByColorGray->widthStep))[x]
    						= 160;  //灰度
    					((uchar*)(dstColorSegByColor->imageData + y*dstColorSegByColor->widthStep))[x*dstColorSegByColor->nChannels]
    						= 255;  //B
    					((uchar*)(dstColorSegByColor->imageData + y*dstColorSegByColor->widthStep))[x*dstColorSegByColor->nChannels+1] 
    						= 255;  //G
    					((uchar*)(dstColorSegByColor->imageData + y*dstColorSegByColor->widthStep))[x*dstColorSegByColor->nChannels+2] 
    						= 0;  //R
    				}//*/
    			   //蓝色相近
    				else if(H>=185 && H<270)
    				{
    					((uchar*)(dstColorSegByColorGray->imageData + y*dstColorSegByColorGray->widthStep))[x]
    						= 200;  //灰度
    					((uchar*)(dstColorSegByColor->imageData + y*dstColorSegByColor->widthStep))[x*dstColorSegByColor->nChannels]
    						= 255;  //B
    					((uchar*)(dstColorSegByColor->imageData + y*dstColorSegByColor->widthStep))[x*dstColorSegByColor->nChannels+1] 
    						= 0;  //G
    					((uchar*)(dstColorSegByColor->imageData + y*dstColorSegByColor->widthStep))[x*dstColorSegByColor->nChannels+2] 
    						= 0;  //R					
    				}	
    		//	/*	//洋红:270-340
    				else if(H>=270 && H<340)
    				{
    					((uchar*)(dstColorSegByColorGray->imageData + y*dstColorSegByColorGray->widthStep))[x]
    						= 220;  //灰度
    					((uchar*)(dstColorSegByColor->imageData + y*dstColorSegByColor->widthStep))[x*dstColorSegByColor->nChannels]
    						= 255;  //B
    					((uchar*)(dstColorSegByColor->imageData + y*dstColorSegByColor->widthStep))[x*dstColorSegByColor->nChannels+1] 
    						= 0;  //G
    					((uchar*)(dstColorSegByColor->imageData + y*dstColorSegByColor->widthStep))[x*dstColorSegByColor->nChannels+2] 
    						= 255;  //R					
    				}//*/
    				else
    				{
    					((uchar*)(dstColorSegByColorGray->imageData + y*dstColorSegByColorGray->widthStep))[x]
    						= 180;  //灰度
    					((uchar*)(dstColorSegByColor->imageData + y*dstColorSegByColor->widthStep))[x*dstColorSegByColor->nChannels] 
    						= 128;  //B  //紫色Purple
    					((uchar*)(dstColorSegByColor->imageData + y*dstColorSegByColor->widthStep))[x*dstColorSegByColor->nChannels+1] 
    						= 0;  //G
    					((uchar*)(dstColorSegByColor->imageData + y*dstColorSegByColor->widthStep))[x*dstColorSegByColor->nChannels+2] 
    						= 128;  //R
    				}
    			}
    		}
    	}
    	//cvNamedWindow("src",1);
    	//cvShowImage("src",pSrc);
    	cvNamedWindow("dstColorSegByColor",1);
    	cvShowImage("dstColorSegByColor",dstColorSegByColor);
    	cvNamedWindow("dstColorSegByColorGray",1);
    	cvShowImage("dstColorSegByColorGray",dstColorSegByColorGray);
    	cvSaveImage(".\\dstColorSegByColor.jpg",dstColorSegByColor);
    	cvSaveImage(".\\dstColorSegByColorGray.jpg",dstColorSegByColorGray);
    
    	cvWaitKey(0);
    	cvDestroyAllWindows();
    	cvReleaseImage(&pSrc);
    	cvReleaseImage(&dstColorSegByColor);
    	cvReleaseImage(&dstColorSegByColorGray);
    
    }
    
     
     

    三 效果:

    (1)原图

    (2)颜色分割后彩色图

    (3)颜色分割后灰度图(利用不同灰度级显示)

      四 补充(RGB模式下,来源网络)

    1 源码

    void CFindRGBDlg::OnFind() 
    {
    	int color=m_colorList.GetCurSel();
    	
    	pic=cvCreateImage( cvSize(image->width,image->height), 8, 1 );
    	cvZero(pic);
    	for(int x=0;x<image->height;x++)
    	{
    		for(int y=0;y<image->width;y++) 
    		{
    			uchar* ptrImg = &CV_IMAGE_ELEM(image,uchar,x,y*3);
    		//	uchar* ptrPic = &((uchar*)(pic->imageData + pic->widthStep*y))[x];
    			//red
    			if(color==0)
    			{
    				if((ptrImg[0]-ptrImg[1])>200&&(ptrImg[0]-ptrImg[2])>200)
    					CV_IMAGE_ELEM(pic,uchar,x,y)=255;
    			}
    			//Green
    			else if(color==1)
    			{
    				if((ptrImg[1]-ptrImg[0])>200&&(ptrImg[1]-ptrImg[2])>200)
    					CV_IMAGE_ELEM(pic,uchar,x,y)=255;
    			}
    			//blue
    			else if(color==2)
    			{
    				if((ptrImg[2]-ptrImg[0])>200&&(ptrImg[2]-ptrImg[1])>200)
    					CV_IMAGE_ELEM(pic,uchar,x,y)=255;
    			}
    			
    		}
    	}
    
    	cvNamedWindow("temp",-1);
    	cvShowImage("temp",pic);
    	cvWaitKey();
    
    
    	storage = cvCreateMemStorage(0);
    	contour = 0;
    	mode = CV_RETR_EXTERNAL;
    	cvFindContours( pic, storage, &contour, sizeof(CvContour), 
    		  mode, CV_CHAIN_APPROX_SIMPLE);
    	cvDrawContours(image, contour, 
    		 CV_RGB(0,0,0), CV_RGB(0, 0, 0), 
    		 2, 2, 8);
    
    	CRect rect; 
    	GetDlgItem(IDC_PICTURE)->GetClientRect(&rect); 
    	InvalidateRect(rect,true);	
    }
    

    2 效果:

    More in  http://skyseraph.com/2011/08/27/CV/图像算法专题/ 

    Author:         SKySeraph

    Email/GTalk: zgzhaobo@gmail.com    QQ:452728574

    From:         http://www.cnblogs.com/skyseraph/

    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,请尊重作者的劳动成果

  • 相关阅读:
    每周工作进度及工作量统计
    debug阶段工作期站立会议2(进度推进)
    new NABCD
    事后诸葛亮会议 (尸体解剖)
    debug阶段工作期站立会议1
    用户使用报告
    Scrum会议10(Beta版本) 补交
    历年学生作品点评
    关于词频统计的效能测试
    敏捷开发之Scrum站立会议
  • 原文地址:https://www.cnblogs.com/skyseraph/p/2075599.html
Copyright © 2020-2023  润新知