从 RGB 到 HSV 的转换详细介绍

RGB HSV 的转换详细介绍

1.RGB

       RGB是从颜色发光的原理来设计定的,通俗点说它的颜色混合方式就好像有红、绿、蓝三盏灯,当它们的光相互叠合的时候,色彩相混,而亮度却等于两者亮度之总和,越混合亮度越高,即加法混合。

        红、绿、蓝三个颜色通道每种色各分为256阶亮度,在0时“灯”最弱——是关掉的,而在255时“灯”最亮。当三色灰度数值相同时,产生不同灰度值的灰色调,即三色灰度都为0时,是最暗的黑色调;三色灰度都为255时,是最亮的白色调。

        在电脑中,RGB的所谓“多少”就是指亮度,并使用整数来表示。通常情况下,RGB各有256级亮度,用数字表示为从0、1、2...直到255。注意虽然数字最高是255,但0也是数值之一,因此共256级。

从 RGB 到 HSV 的转换详细介绍_第1张图片

图1.1 RGB

2.HSV

        HSV是一种比较直观的颜色模型,所以在许多图像编辑工具中应用比较广泛,这个模型中颜色的参数分别是:色调(H, Hue),饱和度(S,Saturation),明度(V, Value)。

色调H

        用角度度量,取值范围为0°~360°,从红色开始按逆时针方向计算,红色为0°,绿色为120°,蓝色为240°。它们的补色是:黄色为60°,青色为180°,品红为300°;

饱和度S

        饱和度S表示颜色接近光谱色的程度。一种颜色,可以看成是某种光谱色与白色混合的结果。其中光谱色所占的比例愈大,颜色接近光谱色的程度就愈高,颜色的饱和度也就愈高。饱和度高,颜色则深而艳。光谱色的白光成分为0,饱和度达到最高。通常取值范围为0%~100%,值越大,颜色越饱和。

明度V

        明度表示颜色明亮的程度,对于光源色,明度值与发光体的光亮度有关;对于物体色,此值和物体的透射比或反射比有关。通常取值范围为0%(黑)到100%(白)。

                    从 RGB 到 HSV 的转换详细介绍_第2张图片从 RGB 到 HSV 的转换详细介绍_第3张图片

图2.1 HSV

2.1应用openCVHSV取值范围说明

我们需要注意的在不同应用场景中,HSV取值范围是不尽相同的。

1.PS软件时,H取值范围是0-360,S取值范围是(0%-100%),V取值范围是(0%-100%)。

2.利用openCV中cvSplit函数的在选择图像IPL_DEPTH_32F类型时,H取值范围是0-360,S取值范围是0-1(0%-100%),V取值范围是0-1(0%-100%)。

3.利用openCV中cvSplit函数的在选择图像IPL_DEPTH_8UC类型时,H取值范围是0-180,S取值范围是0-255,V取值范围是0-255。

3.RGBHSV

3.1公式

从 RGB 到 HSV 的转换详细介绍_第4张图片

3.2代码

测试样例1
#include "cv.h"  
#include "highgui.h"  
#include "cxcore.h"  

/*--------------copyright-hanshanbuleng--------------------*/
// 将色调H的取值范围转换到0~180之间
int main()  
{  
	float H,S,V,H1,S1,V1;
	IplImage *src = cvLoadImage("F:\\vs2010program\\RGB_HSV\\study_test\\2.jpg", 1);  
	IplImage *hsv_img = cvCreateImage(cvGetSize(src), 8 , 3);  
	IplImage *h_img = cvCreateImage(cvGetSize(src), 8, 1);  
	IplImage *s_img = cvCreateImage(cvGetSize(src), 8, 1);  
	IplImage *v_img = cvCreateImage(cvGetSize(src), 8, 1);  

	cvCvtColor(src, hsv_img, CV_BGR2HSV);  
	cvSplit(hsv_img, h_img, s_img, v_img, NULL);  
	for(int y = 0; y < hsv_img->height; y++){  
		for(int x = 0; x < hsv_img->width; x++)  
		{  
			H1 = cvGetReal2D(h_img, y, x);
			S1 = cvGetReal2D(s_img, y, x);
			V1 = cvGetReal2D(v_img, y, x);

			//地址法
			H = (uchar)h_img->imageData[y*h_img->widthStep + x*h_img->nChannels];  
			S = (uchar)s_img->imageData[y*s_img->widthStep + x*s_img->nChannels];
			V = (uchar)v_img->imageData[y*v_img->widthStep + x*v_img->nChannels];

			printf("H:%f  S:%f  V:%f \n",H,S,V);
		}  

	}  
	cvNamedWindow("hsv_img", 0);                   //HSV图
	cvShowImage("hsv_img", hsv_img); 
	cvNamedWindow("h_img", 0);                     //H通道
	cvShowImage("h_img", h_img);  
	cvNamedWindow("s_img", 0);                     //S通道
	cvShowImage("s_img", s_img);              
	cvNamedWindow("v_img", 0);                     //V通道
	cvShowImage("v_img", v_img);  
	cvWaitKey(0);  
	cvReleaseImage(&hsv_img);  
	cvReleaseImage(&h_img);
	cvReleaseImage(&s_img);
	cvReleaseImage(&v_img);
	cvDestroyWindow("hsv_img"); 
	cvDestroyWindow("h_img");
	cvDestroyWindow("s_img");
	cvDestroyWindow("v_img");

	return 0;  
}
测试样例2
#include "cv.h"  
#include "highgui.h"  
#include "cxcore.h"  

/*---------------copyright-hanshanbuleng-------------

问题描述:
用cvShowImage显示32bits float(IPL_DEPTH_32F)型单通道灰度图像时就出了问题,
图像只有黑白两种颜色,没有灰色的,出现了严重失真,这就是没有正确显示;
问题原因:
如果图像是32位float型,cvShowImage会把像素值乘以255然后再与[0,255]的colormap结合起来显示图像,
也就是说,原来32位folat型图像中值为0的像素被显示成黑色,值大于或等于1的像素被显示成白色。

---------------------------------------------------*/
//此时H的范围只能在0~360之间
int main()  
{  
	float H,S,V,H1,S1,V1;
	IplImage *src = cvLoadImage("F:\\vs2010program\\RGB_HSV\\study_test\\2.jpg", 1);   
	IplImage *hsv_img = cvCreateImage(cvGetSize(src), IPL_DEPTH_32F , 3);  
	cvConvertScale(src, hsv_img, 1.0, 0.0);

	IplImage *hsv_img1 = cvCreateImage(cvGetSize(src), IPL_DEPTH_32F , 3);

	IplImage *h_img = cvCreateImage(cvGetSize(src), IPL_DEPTH_32F, 1);  
	IplImage *s_img = cvCreateImage(cvGetSize(src), IPL_DEPTH_32F, 1);  
	IplImage *v_img = cvCreateImage(cvGetSize(src), IPL_DEPTH_32F, 1);  

	IplImage *h_img1 = cvCreateImage(cvGetSize(src), 8, 1);  
	IplImage *s_img1 = cvCreateImage(cvGetSize(src), 8, 1);  
	IplImage *v_img1 = cvCreateImage(cvGetSize(src), 8, 1);   

	cvCvtColor(hsv_img, hsv_img1, CV_BGR2HSV);  
	cvSplit(hsv_img1, h_img, s_img, v_img, NULL);  
	for(int y = 0; y < hsv_img->height; y++){  
		for(int x = 0; x < hsv_img->width; x++)  
		{  
			H1 = cvGetReal2D(h_img, y, x);   //0-360  
			S1 = cvGetReal2D(s_img, y, x);   //0-1
			V1 = cvGetReal2D(v_img, y, x);   //0-255

			////地址法  还是有问题  待研究
			//H = (double)h_img->imageData[y*h_img->widthStep + x*h_img->nChannels];  
			//S = s_img->imageData[y*s_img->widthStep + x*s_img->nChannels];
			//V = v_img->imageData[y*v_img->widthStep + x*v_img->nChannels];

			printf("H:%f  S:%f  V:%f \n",H1,S1,V1);
		}  
		
	}  

	cvCvtScale(v_img,h_img1,255.0/360.0);

	cvNamedWindow("hsv_img");                   //HSV图
	cvShowImage("hsv_img", hsv_img); 
	cvNamedWindow("h_img");                     //H通道    0-360 显示不正常
	cvShowImage("h_img", h_img);  
	cvNamedWindow("s_img");                     //S通道    0-1 
	cvShowImage("s_img", s_img);              
	cvNamedWindow("h_img1");                    //V通道   0-255
	cvShowImage("h_img1", h_img1);  

	cvNamedWindow("v_img");               
	cvShowImage("v_img", v_img);  

	cvWaitKey(0);  
	cvReleaseImage(&hsv_img);  
	cvReleaseImage(&h_img);
	cvReleaseImage(&s_img);
	cvReleaseImage(&v_img);
	cvDestroyWindow("hsv_img"); 
	cvDestroyWindow("h_img");
	cvDestroyWindow("s_img");
	cvDestroyWindow("v_img");

	return 0;  
}  
测试样例3
#include "cv.h"  
#include "highgui.h"  
#include "cxcore.h"  

/*--------------copyright-hanshanbuleng--------------------*/
//此时H,S,V的范围均在0~255之间
int main()  
{  
	float H,S,V,H1,S1,V1;
	IplImage *src = cvLoadImage("F:\\vs2010program\\RGB_HSV\\study_test\\2.jpg", 1);  
	IplImage *hsv_img = cvCreateImage(cvGetSize(src), IPL_DEPTH_32F , 3);  
	cvConvertScale(src, hsv_img, 1.0, 0.0); 

	IplImage *hsv_img1 = cvCreateImage(cvGetSize(src), IPL_DEPTH_32F , 3);

	IplImage *h_img = cvCreateImage(cvGetSize(src), IPL_DEPTH_32F, 1);  
	IplImage *s_img = cvCreateImage(cvGetSize(src), IPL_DEPTH_32F, 1);  
	IplImage *v_img = cvCreateImage(cvGetSize(src), IPL_DEPTH_32F, 1);  

	IplImage *h = cvCreateImage(cvGetSize(src), 8, 1);  
	IplImage *s = cvCreateImage(cvGetSize(src), 8, 1);  
	IplImage *v = cvCreateImage(cvGetSize(src), 8, 1);  

	cvCvtColor(hsv_img, hsv_img1, CV_BGR2HSV);  
	cvSplit(hsv_img1, h_img, s_img, v_img, NULL);  

	//转换表示范围
	cvConvertScale(h_img, h, (1.0/360)*255, 0.0); 
	cvConvertScale(s_img, s, 255.0, 0.0);  
	cvConvertScale(v_img, v, 1.0, 0.0);

	for(int y = 0; y < hsv_img->height; y++){  
		for(int x = 0; x < hsv_img->width; x++)  
		{  
			//转换后的h_img,s_img,v_img 取值查看
			/*----------------------------------*/
			//转换后的h,s,v 取值查看
// 			H1 = cvGetReal2D(h_img, y, x);
// 			S1 = cvGetReal2D(s_img, y, x);
// 			V1 = cvGetReal2D(v_img, y, x);
// 
// 			//地址法 对比
// 			H = (double)h_img->imageData[y*h_img->widthStep + x*h_img->nChannels];  
// 			S = (double)s_img->imageData[y*s_img->widthStep + x*s_img->nChannels];
// 			V = v_img->imageData[y*v_img->widthStep + x*v_img->nChannels];
			/*----------------------------------*/

			//转换后的h,s,v 取值查看
			/*----------------------------------*/
 			H1 = cvGetReal2D(h, y, x);
 			S1 = cvGetReal2D(s, y, x);
 			V1 = cvGetReal2D(v, y, x);
 
 			//地址法 对比
 			H = (uchar)h->imageData[y*h->widthStep + x*h->nChannels];  
 			S = (uchar)s->imageData[y*s->widthStep + x*s->nChannels];
 			V = (uchar)v->imageData[y*s->widthStep + x*s->nChannels];
 			/*----------------------------------*/

			printf("H:%f  S:%f  V:%f \n",H,S,V);
		}  

	}  
	cvNamedWindow("hsv_img", 0);                   //HSV图
	cvShowImage("hsv_img", hsv_img); 
	cvNamedWindow("h_img", 0);                     //H通道
	cvShowImage("h_img", h_img);  
	cvNamedWindow("s_img", 0);                     //S通道
	cvShowImage("s_img", s_img);              
	cvNamedWindow("v_img", 0);                     //V通道
	cvShowImage("v_img", v_img);  
	cvWaitKey(0);  
	cvReleaseImage(&hsv_img);  
	cvReleaseImage(&h_img);
	cvReleaseImage(&s_img);
	cvReleaseImage(&v_img);
	cvDestroyWindow("hsv_img"); 
	cvDestroyWindow("h_img");
	cvDestroyWindow("s_img");
	cvDestroyWindow("v_img");

	return 0;  
}  
 

4.引申本实例使用opencv函数简介

函数介绍百度一下就可以,在此我只是简单说明一下

cvLoadImage() //加载图片

cvCreateImage()//创建图片大小

cvCvtColor()  //空间转换

cvSplit()     //分离不同通道

cvCvtScale()  //调整比例

cvNamedWindow()//创建图像显示窗口

cvReleaseImage()//释放创建的图片

cvWaitKey()    //等待

cvDestroyWindow()//销毁窗口


5.参考链接

https://blog.csdn.net/yangdashi888/article/details/53782481

https://blog.csdn.net/zhupananhui/article/details/21157541

https://baike.baidu.com/item/HSV/547122

 



你可能感兴趣的:(opencv学习,图像处理)