1. 程式人生 > >從RGB 到 HSV 的轉換詳細介紹【轉】

從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應用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公式


3.2程式碼

測試樣例1
  1. #include "cv.h"
  2. #include "highgui.h"
  3. #include "cxcore.h"
  4. /*--------------copyright-hanshanbuleng--------------------*/
  5. // 將色調H的取值範圍轉換到0~180之間
  6. int main()
  7. {
  8. float H,S,V,H1,S1,V1;
  9. IplImage *src = cvLoadImage("F:\\vs2010program\\RGB_HSV\\study_test\\2.jpg", 1);
  10. IplImage *hsv_img = cvCreateImage(cvGetSize(src), 8 , 3);
  11. IplImage *h_img = cvCreateImage(cvGetSize(src), 8, 1);
  12. IplImage *s_img = cvCreateImage(cvGetSize(src), 8, 1);
  13. IplImage *v_img = cvCreateImage(cvGetSize(src), 8, 1);
  14. cvCvtColor(src, hsv_img, CV_BGR2HSV);
  15. cvSplit(hsv_img, h_img, s_img, v_img, NULL);
  16. for(int y = 0; y < hsv_img->height; y++){
  17. for(int x = 0; x < hsv_img->width; x++)
  18. {
  19. H1 = cvGetReal2D(h_img, y, x);
  20. S1 = cvGetReal2D(s_img, y, x);
  21. V1 = cvGetReal2D(v_img, y, x);
  22. //地址法
  23. H = (uchar)h_img->imageData[y*h_img->widthStep + x*h_img->nChannels];
  24. S = (uchar)s_img->imageData[y*s_img->widthStep + x*s_img->nChannels];
  25. V = (uchar)v_img->imageData[y*v_img->widthStep + x*v_img->nChannels];
  26. printf("H:%f S:%f V:%f \n",H,S,V);
  27. }
  28. }
  29. cvNamedWindow("hsv_img", 0); //HSV圖
  30. cvShowImage("hsv_img", hsv_img);
  31. cvNamedWindow("h_img", 0); //H通道
  32. cvShowImage("h_img", h_img);
  33. cvNamedWindow("s_img", 0); //S通道
  34. cvShowImage("s_img", s_img);
  35. cvNamedWindow("v_img", 0); //V通道
  36. cvShowImage("v_img", v_img);
  37. cvWaitKey(0);
  38. cvReleaseImage(&hsv_img);
  39. cvReleaseImage(&h_img);
  40. cvReleaseImage(&s_img);
  41. cvReleaseImage(&v_img);
  42. cvDestroyWindow("hsv_img");
  43. cvDestroyWindow("h_img");
  44. cvDestroyWindow("s_img");
  45. cvDestroyWindow("v_img");
  46. return 0;
  47. }
測試樣例2
  1. #include "cv.h"
  2. #include "highgui.h"
  3. #include "cxcore.h"
  4. /*---------------copyright-hanshanbuleng-------------
  5. 問題描述:
  6. 用cvShowImage顯示32bits float(IPL_DEPTH_32F)型單通道灰度影象時就出了問題,
  7. 影象只有黑白兩種顏色,沒有灰色的,出現了嚴重失真,這就是沒有正確顯示;
  8. 問題原因:
  9. 如果影象是32位float型,cvShowImage會把畫素值乘以255然後再與[0,255]的colormap結合起來顯示影象,
  10. 也就是說,原來32位folat型影象中值為0的畫素被顯示成黑色,值大於或等於1的畫素被顯示成白色。
  11. ---------------------------------------------------*/
  12. //此時H的範圍只能在0~360之間
  13. int main()
  14. {
  15. float H,S,V,H1,S1,V1;
  16. IplImage *src = cvLoadImage("F:\\vs2010program\\RGB_HSV\\study_test\\2.jpg", 1);
  17. IplImage *hsv_img = cvCreateImage(cvGetSize(src), IPL_DEPTH_32F , 3);
  18. cvConvertScale(src, hsv_img, 1.0, 0.0);
  19. IplImage *hsv_img1 = cvCreateImage(cvGetSize(src), IPL_DEPTH_32F , 3);
  20. IplImage *h_img = cvCreateImage(cvGetSize(src), IPL_DEPTH_32F, 1);
  21. IplImage *s_img = cvCreateImage(cvGetSize(src), IPL_DEPTH_32F, 1);
  22. IplImage *v_img = cvCreateImage(cvGetSize(src), IPL_DEPTH_32F, 1);
  23. IplImage *h_img1 = cvCreateImage(cvGetSize(src), 8, 1);
  24. IplImage *s_img1 = cvCreateImage(cvGetSize(src), 8, 1);
  25. IplImage *v_img1 = cvCreateImage(cvGetSize(src), 8, 1);
  26. cvCvtColor(hsv_img, hsv_img1, CV_BGR2HSV);
  27. cvSplit(hsv_img1, h_img, s_img, v_img, NULL);
  28. for(int y = 0; y < hsv_img->height; y++){
  29. for(int x = 0; x < hsv_img->width; x++)
  30. {
  31. H1 = cvGetReal2D(h_img, y, x); //0-360
  32. S1 = cvGetReal2D(s_img, y, x); //0-1
  33. V1 = cvGetReal2D(v_img, y, x); //0-255
  34. ////地址法 還是有問題 待研究
  35. //H = (double)h_img->imageData[y*h_img->widthStep + x*h_img->nChannels];
  36. //S = s_img->imageData[y*s_img->widthStep + x*s_img->nChannels];
  37. //V = v_img->imageData[y*v_img->widthStep + x*v_img->nChannels];
  38. printf("H:%f S:%f V:%f \n",H1,S1,V1);
  39. }
  40. }
  41. cvCvtScale(v_img,h_img1,255.0/360.0);
  42. cvNamedWindow("hsv_img"); //HSV圖
  43. cvShowImage("hsv_img", hsv_img);
  44. cvNamedWindow("h_img"); //H通道 0-360 顯示不正常
  45. cvShowImage("h_img", h_img);
  46. cvNamedWindow("s_img"); //S通道 0-1
  47. cvShowImage("s_img", s_img);
  48. cvNamedWindow("h_img1"); //V通道 0-255
  49. cvShowImage("h_img1", h_img1);
  50. cvNamedWindow("v_img");
  51. cvShowImage("v_img", v_img);
  52. cvWaitKey(0);
  53. cvReleaseImage(&hsv_img);
  54. cvReleaseImage(&h_img);
  55. cvReleaseImage(&s_img);
  56. cvReleaseImage(&v_img);
  57. cvDestroyWindow("hsv_img");
  58. cvDestroyWindow("h_img");
  59. cvDestroyWindow("s_img");
  60. cvDestroyWindow("v_img");
  61. return 0;
  62. }
測試樣例3
  1. #include "cv.h"
  2. #include "highgui.h"
  3. #include "cxcore.h"
  4. /*--------------copyright-hanshanbuleng--------------------*/
  5. //此時H,S,V的範圍均在0~255之間
  6. int main()
  7. {
  8. float H,S,V,H1,S1,V1;
  9. IplImage *src = cvLoadImage("F:\\vs2010program\\RGB_HSV\\study_test\\2.jpg", 1);
  10. IplImage *hsv_img = cvCreateImage(cvGetSize(src), IPL_DEPTH_32F , 3);
  11. cvConvertScale(src, hsv_img, 1.0, 0.0);
  12. IplImage *hsv_img1 = cvCreateImage(cvGetSize(src), IPL_DEPTH_32F , 3);
  13. IplImage *h_img = cvCreateImage(cvGetSize(src), IPL_DEPTH_32F, 1);
  14. IplImage *s_img = cvCreateImage(cvGetSize(src), IPL_DEPTH_32F, 1);
  15. IplImage *v_img = cvCreateImage(cvGetSize(src), IPL_DEPTH_32F, 1);
  16. IplImage *h = cvCreateImage(cvGetSize(src), 8, 1);
  17. IplImage *s = cvCreateImage(cvGetSize(src), 8, 1);
  18. IplImage *v = cvCreateImage(cvGetSize(src), 8, 1);
  19. cvCvtColor(hsv_img, hsv_img1, CV_BGR2HSV);
  20. cvSplit(hsv_img1, h_img, s_img, v_img, NULL);
  21. //轉換表示範圍
  22. cvConvertScale(h_img, h, (1.0/360)*255, 0.0);
  23. cvConvertScale(s_img, s, 255.0, 0.0);
  24. cvConvertScale(v_img, v, 1.0, 0.0);
  25. for(int y = 0; y < hsv_img->height; y++){
  26. for(int x = 0; x < hsv_img->width; x++)
  27. {
  28. //轉換後的h_img,s_img,v_img 取值檢視
  29. /*----------------------------------*/
  30. //轉換後的h,s,v 取值檢視
  31. // H1 = cvGetReal2D(h_img, y, x);
  32. // S1 = cvGetReal2D(s_img, y, x);
  33. // V1 = cvGetReal2D(v_img, y, x);
  34. //
  35. // //地址法 對比
  36. // H = (double)h_img->imageData[y*h_img->widthStep + x*h_img->nChannels];
  37. // S = (double)s_img->imageData[y*s_img->widthStep + x*s_img->nChannels];
  38. // V = v_img->imageData[y*v_img->widthStep + x*v_img->nChannels];
  39. /*----------------------------------*/
  40. //轉換後的h,s,v 取值檢視
  41. /*----------------------------------*/
  42. H1 = cvGetReal2D(h, y, x);
  43. S1 = cvGetReal2D(s, y, x);
  44. V1 = cvGetReal2D(v, y, x);
  45. //地址法 對比
  46. H = (uchar)h->imageData[y*h->widthStep + x*h->nChannels];
  47. S = (uchar)s->imageData[y*s->widthStep + x*s->nChannels];
  48. V = (uchar)v->imageData[y*s->widthStep + x*s->nChannels];
  49. /*----------------------------------*/
  50. printf("H:%f S:%f V:%f \n",H,S,V);
  51. }
  52. }
  53. cvNamedWindow("hsv_img", 0); //HSV圖
  54. cvShowImage("hsv_img", hsv_img);
  55. cvNamedWindow("h_img", 0); //H通道
  56. cvShowImage("h_img", h_img);
  57. cvNamedWindow("s_img", 0); //S通道
  58. cvShowImage("s_img", s_img);
  59. cvNamedWindow("v_img", 0); //V通道
  60. cvShowImage("v_img", v_img);
  61. cvWaitKey(0);
  62. cvReleaseImage(&hsv_img);
  63. cvReleaseImage(&h_img);
  64. cvReleaseImage(&s_img);
  65. cvReleaseImage(&v_img);
  66. cvDestroyWindow("hsv_img");
  67. cvDestroyWindow("h_img");
  68. cvDestroyWindow("s_img");
  69. cvDestroyWindow("v_img");
  70. return 0;
  71. }

4.引申本例項使用opencv函式簡介

函式介紹百度一下就可以,在此我只是簡單說明一下

cvLoadImage() //載入圖片

cvCreateImage()//建立圖片大小

cvCvtColor()  //空間轉換

cvSplit()     //分離不同通道

cvCvtScale()  //調整比例

cvNamedWindow()//建立影象顯示視窗

cvReleaseImage()//釋放建立的圖片

cvWaitKey()    //等待

cvDestroyWindow()//銷燬視窗

5.參考連結