关于HSV颜色空间,还有一些参考性的博客,如http://blog.sina.com.cn/s/blog_6a22365901012nxl.html
HSV的介绍请参见维基百科:http://en.wikipedia.org/wiki/HSL_and_HSV,与其类似的颜色空间还有HSL(或称HLS)和HSI。本文有两则代码,代码一,自实现了RGB颜色空间与HSV颜色空间之间的转换,并与OpenCV中的cvCvtColor进行了比较;代码二,实现了一个HSV颜色盘。
代码一:
- //====================================================================
- // 作者 : quarryman
- // 邮箱 : quarrying{at}qq.com
- // 主页 : http://blog.csdn.net/quarryman
- // 日期 : 2013年12月22日
- // 描述 : RGB颜色空间与HSV颜色空间之间的转换
- //====================================================================
- #include <cv.h>
- #include <highgui.h>
- #define max(a,b) (((a)>(b))?(a):(b))
- #define min(a,b) (((a)<(b))?(a):(b))
- IplImage* kcvRGB2HSV(IplImage* img)
- {
- int w=img->width;
- int h=img->height;
- IplImage* dst=cvCreateImage(cvSize(w,h),8,3);
- for(int j=0;j<w;++j)
- {
- for(int i=0;i<h;++i)
- {
- int b=CV_IMAGE_ELEM(img,uchar,i,j*3+0);
- int g=CV_IMAGE_ELEM(img,uchar,i,j*3+1);
- int r=CV_IMAGE_ELEM(img,uchar,i,j*3+2);
- int maxval=max(b,max(g,r));
- int minval=min(b,min(g,r));
- int v=maxval;
- double diff=maxval-minval;
- int s=diff*255/(v+DBL_EPSILON);
- double h=0;
- diff=60/(diff+DBL_EPSILON);
- if(v==r)
- {
- h=(g-b)*diff;
- }
- else if(v==g)
- {
- h=(b-r)*diff+120.f;
- }
- else
- {
- h=(r-g)*diff+240.f;
- }
- if( h<0)
- {
- h+=360.f;
- }
- CV_IMAGE_ELEM(dst,uchar,i,j*3+0)=h/2;
- CV_IMAGE_ELEM(dst,uchar,i,j*3+1)=s;
- CV_IMAGE_ELEM(dst,uchar,i,j*3+2)=v;
- }
- }
- return dst;
- }
- IplImage* kcvHSV2RGB(IplImage* img)
- {
- int w=img->width;
- int h=img->height;
- IplImage* dst=cvCreateImage(cvSize(w,h),8,3);
- for(int j=0;j<w;++j)
- {
- for(int i=0;i<h;++i)
- {
- int h=CV_IMAGE_ELEM(img,uchar,i,j*3+0);
- int s=CV_IMAGE_ELEM(img,uchar,i,j*3+1);
- int v=CV_IMAGE_ELEM(img,uchar,i,j*3+2);
- int c=(double)v*s/255;
- double hh=(double)h*2/60;
- double x=c*(1-abs(fmod(hh,2)-1));
- int r,g,b;
- if(0<=hh&&hh<1)
- {
- r=c;g=x;b=0;
- }
- else if(1<=hh&hh<2)
- {
- r=x;g=c;b=0;
- }
- else if(2<=hh&&hh<3)
- {
- r=0;g=c;b=x;
- }
- else if(3<=hh&&hh<4)
- {
- r=0;g=x;b=c;
- }
- else if(4<=hh&&hh<5)
- {
- r=x;g=0;b=c;
- }
- else
- {
- r=c;g=0;b=x;
- }
- int m=v-c;
- CV_IMAGE_ELEM(dst,uchar,i,j*3+0)=b+m;
- CV_IMAGE_ELEM(dst,uchar,i,j*3+1)=g+m;
- CV_IMAGE_ELEM(dst,uchar,i,j*3+2)=r+m;
- }
- }
- return dst;
- }
- int main( int argc, char** argv )
- {
- IplImage* img=cvLoadImage("lena.jpg",1);
- IplImage* hsv=kcvRGB2HSV(img);
- IplImage* hsv2=cvCreateImage(cvGetSize(img),8,3);
- cvCvtColor(img,hsv2,CV_BGR2HSV);
- // 注意不能是下面的语句
- // cvCvtColor(img,hsv2,CV_RGB2HSV);
- IplImage* dst=kcvHSV2RGB(hsv);
- IplImage* dst2=cvCreateImage(cvGetSize(img),8,3);
- cvCvtColor(hsv2,dst2,CV_HSV2BGR);
- // 注意不能是下面的语句
- // cvCvtColor(hsv2,dst2,CV_HSV2RGB);
- cvNamedWindow("img");
- cvNamedWindow("hsv");
- cvNamedWindow("hsv2");
- cvNamedWindow("dst");
- cvNamedWindow("dst2");
- cvShowImage("img",img);
- cvShowImage("hsv",hsv);
- cvShowImage("hsv2",hsv2);
- cvShowImage("dst",dst);
- cvShowImage("dst2",dst2);
- cvWaitKey(0);
- cvDestroyAllWindows();
- cvReleaseImage(&img);
- cvReleaseImage(&hsv);
- cvReleaseImage(&hsv2);
- cvReleaseImage(&dst);
- cvReleaseImage(&dst2);
- return 0;
- }
代码二:
- //====================================================================
- // 作者 : quarryman
- // 邮箱 : quarrying{at}qq.com
- // 主页 : http://blog.csdn.net/quarryman
- // 日期 : 2013年12月22日
- // 描述 : HSV颜色盘
- //====================================================================
- #include <cv.h>
- #include <highgui.h>
- #define max(a,b) (((a)>(b))?(a):(b))
- #define min(a,b) (((a)<(b))?(a):(b))
- double module(CvPoint pt)
- {
- return sqrt((double)pt.x*pt.x+pt.y*pt.y);
- }
- double distance(CvPoint pt1,CvPoint pt2)
- {
- int dx=pt1.x-pt2.x;
- int dy=pt1.y-pt2.y;
- return sqrt((double)dx*dx+dy*dy);
- }
- double cross(CvPoint pt1,CvPoint pt2)
- {
- return pt1.x*pt2.x+pt1.y*pt2.y;
- }
- double angle(CvPoint pt1,CvPoint pt2)
- {
- return acos(cross(pt1,pt2)/(module(pt1)*module(pt2)+DBL_EPSILON));
- }
- // p和c其中一个是圆心
- int inCircle(CvPoint p, CvPoint c, int r)
- {
- int dx=p.x-c.x;
- int dy=p.y-c.y;
- return dx*dx+dy*dy<=r*r?1:0;
- }
- IplImage* createPlate(int radius)
- {
- IplImage* img=cvCreateImage(cvSize(radius<<1,radius<<1),8,3);
- cvSet(img,cvScalar(0,0,255));
- int w=img->width;
- int h=img->height;
- int cx=w>>1;
- int cy=h>>1;
- CvPoint pt1=cvPoint(cx,0);
- for(int j=0;j<w;++j)
- {
- for(int i=0;i<h;++i)
- {
- CvPoint pt2=cvPoint(j-cx,i-cy);
- if(inCircle(cvPoint(0,0),pt2,radius))
- {
- int theta=angle(pt1,pt2)*180/3.1415926;
- if(i>cx)
- {
- theta=-theta+360;
- }
- CV_IMAGE_ELEM(img,uchar,i,j*3+0)=theta/2;
- CV_IMAGE_ELEM(img,uchar,i,j*3+1)=module(pt2)/cx*255;
- CV_IMAGE_ELEM(img,uchar,i,j*3+2)=255;
- }
- }
- }
- IplImage* dst=cvCreateImage(cvGetSize(img),8,3);
- cvCvtColor(img,dst,CV_HSV2BGR);
- cvReleaseImage(&img);
- return dst;
- }
- int main( int argc, char** argv )
- {
- IplImage* img=createPlate(300);
- cvNamedWindow("img");
- cvShowImage("img",img);
- cvWaitKey(0);
- cvDestroyAllWindows();
- cvReleaseImage(&img);
- return 0;
- }
效果图如下: