從RGB 到 HSV 的轉換詳細介紹【轉】
從RGB 到 HSV 的轉換詳細介紹
1.RGB
RGB是從顏色發光的原理來設計定的,通俗點說它的顏色混合方式就好像有紅、綠、藍三盞燈,當它們的光相互疊合的時候,色彩相混,而亮度卻等於兩者亮度之總和,越混合亮度越高,即加法混合。
紅、綠、藍三個顏色通道每種色各分為256階亮度,在0時“燈”最弱——是關掉的,而在255時“燈”最亮。當三色灰度數值相同時,產生不同灰度值的灰色調,即三色灰度都為0時,是最暗的黑色調;三色灰度都為255時,是最亮的白色調。
在電腦中,RGB的所謂“多少”就是指亮度,並使用整數來表示。通常情況下,RGB各有256級亮度,用數字表示為從0、1、2...直到255。注意雖然數字最高是255,但0也是數值之一,因此共256級。
圖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%(白)。
圖2.1 HSV
2.1應用openCV中HSV取值範圍說明
我們需要注意的在不同應用場景中,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.RGB轉HSV
3.1公式
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.參考連結