【图像算法】彩色图像分割专题五:提取彩色图像上特定色彩
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
2 国内很多关于车牌识别的论文中,当利用到颜色信息时,一般都是在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/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,请尊重作者的劳动成果
作者:skyseraph
出处:http://www.cnblogs.com/skyseraph/
更多精彩请直接访问SkySeraph个人站点:http://skyseraph.com//
Email/GTalk: zgzhaobo@gmail.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。