OpenCV实现RGB颜色空间和HSI颜色空间的相互转换
2017-01-25 20:07
1096 查看
核心的转换公式:
RGB-->HSI
截图来自中科院刘定生老师的《数字图像处理与分析》课件。
HSI-->RGB
具体的数学公式参照冈萨雷斯版《数字图像处理(第三版)》432-434页,中译版的260-261页。
下面贴代码:
下面要说的RGB到HSI空间的转换。我是用OPENCV来实现图像处理的,OPENCV读入图像是存储在IplImage结构中。对于彩色图像可以分开成三个通道存储 cvLoadImage(imageName, 1);三个通道依次是blue, green, red. 在OPENCV中并没有实现转化成HSI空间,这个我们得针对每个像素点自己手动写,公式在上面那个链接里。 上代码
RGB-->HSI
截图来自中科院刘定生老师的《数字图像处理与分析》课件。
HSI-->RGB
具体的数学公式参照冈萨雷斯版《数字图像处理(第三版)》432-434页,中译版的260-261页。
下面贴代码:
1 #include "opencv_libs.h" 2 #include <highgui.h> 3 #include <cv.h> 4 #include <math.h> 5 6 /* 7 * 描述:实现RGB颜色模型到HSI颜色模型之间的相互转换 8 * 作者:qdsclove(qdsclove@gmail.com) 9 * 时间:16:01 4/17 星期三 2013 10 */ 11 12 // 将HSI颜色空间的三个分量组合起来,便于显示 13 IplImage* catHSImage(CvMat* HSI_H, CvMat* HSI_S, CvMat* HSI_I) 14 { 15 IplImage* HSI_Image = cvCreateImage( cvGetSize( HSI_H ), IPL_DEPTH_8U, 3 ); 16 17 for(int i = 0; i < HSI_Image->height; i++) 18 { 19 for(int j = 0; j < HSI_Image->width; j++) 20 { 21 double d = cvmGet( HSI_H, i, j ); 22 int b = (int)(d * 255/360); 23 d = cvmGet( HSI_S, i, j ); 24 int g = (int)( d * 255 ); 25 d = cvmGet( HSI_I, i, j ); 26 int r = (int)( d * 255 ); 27 28 cvSet2D( HSI_Image, i, j, cvScalar( b, g, r ) ); 29 } 30 } 31 32 return HSI_Image; 33 } 34 35 // 将HSI颜色模型的数据转换为RGB颜色模型的图像 36 IplImage* HSI2RGBImage(CvMat* HSI_H, CvMat* HSI_S, CvMat* HSI_I) 37 { 38 IplImage * RGB_Image = cvCreateImage(cvGetSize(HSI_H), IPL_DEPTH_8U, 3 ); 39 40 int iB, iG, iR; 41 for(int i = 0; i < RGB_Image->height; i++) 42 { 43 for(int j = 0; j < RGB_Image->width; j++) 44 { 45 // 该点的色度H 46 double dH = cvmGet( HSI_H, i, j ); 47 // 该点的色饱和度S 48 double dS = cvmGet( HSI_S, i, j ); 49 // 该点的亮度 50 double dI = cvmGet( HSI_I, i, j ); 51 52 double dTempB, dTempG, dTempR; 53 // RG扇区 54 if(dH < 120 && dH >= 0) 55 { 56 // 将H转为弧度表示 57 dH = dH * 3.1415926 / 180; 58 dTempB = dI * (1 - dS); 59 dTempR = dI * ( 1 + (dS * cos(dH))/cos(3.1415926/3 - dH) ); 60 dTempG = (3 * dI - (dTempR + dTempB)); 61 } 62 // GB扇区 63 else if(dH < 240 && dH >= 120) 64 { 65 dH -= 120; 66 67 // 将H转为弧度表示 68 dH = dH * 3.1415926 / 180; 69 70 dTempR = dI * (1 - dS); 71 dTempG = dI * (1 + dS * cos(dH)/cos(3.1415926/3 - dH)); 72 dTempB = (3 * dI - (dTempR + dTempG)); 73 } 74 // BR扇区 75 else 76 { 77 dH -= 240; 78 79 // 将H转为弧度表示 80 dH = dH * 3.1415926 / 180; 81 82 dTempG = dI * (1 - dS); 83 dTempB = dI * (1 + (dS * cos(dH))/cos(3.1415926/3 - dH)); 84 dTempR = (3* dI - (dTempG + dTempB)); 85 } 86 87 iB = dTempB * 255; 88 iG = dTempG * 255; 89 iR = dTempR * 255; 90 91 cvSet2D( RGB_Image, i, j, cvScalar( iB, iG, iR ) ); 92 } 93 } 94 95 return RGB_Image; 96 } 97 98 99 int main() 100 { 101 IplImage* img = cvLoadImage("lena.bmp"); 102 103 // 三个HSI空间数据矩阵 104 CvMat* HSI_H = cvCreateMat( img->height, img->width, CV_32FC1 ); 105 CvMat* HSI_S = cvCreateMat( img->height, img->width, CV_32FC1 ); 106 CvMat* HSI_I = cvCreateMat( img->height, img->width, CV_32FC1 ); 107 108 // 原始图像数据指针, HSI矩阵数据指针 109 uchar* data; 110 111 // rgb分量 112 byte img_r, img_g, img_b; 113 byte min_rgb; // rgb分量中的最小值 114 // HSI分量 115 float fHue, fSaturation, fIntensity; 116 117 for(int i = 0; i < img->height; i++) 118 { 119 for(int j = 0; j < img->width; j++) 120 { 121 data = cvPtr2D(img, i, j, 0); 122 img_b = *data; 123 data++; 124 img_g = *data; 125 data++; 126 img_r = *data; 127 128 // Intensity分量[0, 1] 129 fIntensity = (float)((img_b + img_g + img_r)/3)/255; 130 131 // 得到RGB分量中的最小值 132 float fTemp = img_r < img_g ? img_r : img_g; 133 min_rgb = fTemp < img_b ? fTemp : img_b; 134 // Saturation分量[0, 1] 135 fSaturation = 1 - (float)(3 * min_rgb)/(img_r + img_g + img_b); 136 137 // 计算theta角 138 float numerator = (img_r - img_g + img_r - img_b ) / 2; 139 float denominator = sqrt( 140 pow( (img_r - img_g), 2 ) + (img_r - img_b)*(img_g - img_b) ); 141 142 // 计算Hue分量 143 if(denominator != 0) 144 { 145 float theta = acos( numerator/denominator) * 180/3.14; 146 147 if(img_b <= img_g) 148 { 149 fHue = theta ; 150 } 151 else 152 { 153 fHue = 360 - theta; 154 } 155 } 156 else 157 { 158 fHue = 0; 159 } 160 161 // 赋值 162 cvmSet( HSI_H, i, j, fHue ); 163 cvmSet( HSI_S, i, j, fSaturation); 164 cvmSet( HSI_I, i, j, fIntensity ); 165 } 166 } 167 168 IplImage* HSI_Image = catHSImage( HSI_H, HSI_S, HSI_I ); 169 IplImage* RGB_Image = HSI2RGBImage( HSI_H, HSI_S, HSI_I ); 170 171 cvShowImage("img", img); 172 cvShowImage("HSI Color Model", HSI_Image); 173 cvShowImage("RGB Color Model", RGB_Image); 174 175 cvWaitKey(0); 176 177 cvReleaseImage( &img ); 178 cvReleaseImage( &HSI_Image ); 179 cvReleaseImage( &RGB_Image ); 180 cvReleaseMat( &HSI_H); 181 cvReleaseMat( &HSI_S); 182 cvReleaseMat( &HSI_I); 183 184 cvDestroyAllWindows(); 185 186 return 0; 187 } 另一种方法: 对彩色图像处理的时候,一般都是基于颜色空间来做的,比如要检测一片连续的蓝色,就可以基于颜色空间来实现分割。大家首先想到的是RGB,但是这里有个问题。RGB关联太大,每个通道都编入了亮度信息,容易受周围环境的处理,比如说光照不足。而HSI空间就不会。HSI空间是从人的视觉系统出发用色调(Hue), 色饱和度(Situration)和亮度(Intensity)来描述颜色,一旦用HSI空间就可以从色调通道中分离出蓝色色调,蓝色色调差不多在220左右。
下面要说的RGB到HSI空间的转换。我是用OPENCV来实现图像处理的,OPENCV读入图像是存储在IplImage结构中。对于彩色图像可以分开成三个通道存储 cvLoadImage(imageName, 1);三个通道依次是blue, green, red. 在OPENCV中并没有实现转化成HSI空间,这个我们得针对每个像素点自己手动写,公式在上面那个链接里。 上代码
// HSI.cpp : RGB TO HSI并显示出来 // #include <stdio.h> #include <math.h> #include <cv.h> #include <highgui.h> #include <cxcore.h> #include <cvaux.h> int min(int a, int b, int c); int main(int argc, char ** argv) { IplImage * Img = cvLoadImage(argv[1], 1); IplImage * HImg = cvCreateImage(cvGetSize(Img), IPL_DEPTH_8U, 1); IplImage * SImg = cvCreateImage(cvGetSize(Img), IPL_DEPTH_8U, 1); IplImage * IImg = cvCreateImage(cvGetSize(Img), IPL_DEPTH_8U, 1); if( Rgb2Hsi(Img, HImg, SImg, IImg) == 0) { printf("Convert Error!\n"); exit(-1); } //高斯滤波先,以平滑图像 cvSmooth(SImg, SImg, CV_GAUSSIAN, 3, 0, 0, 0); // cvThreshold(SImg, SImg, 100, 255, CV_THRESH_BINARY); IplImage *pImgCanny = cvCreateImage(cvGetSize(SImg), IPL_DEPTH_8U, 1); cvCanny(SImg, pImgCanny, 50, 150, 3); cvNamedWindow("Img", 1); cvNamedWindow("HImg", 1); cvNamedWindow("SImg", 1); cvNamedWindow("IImg", 1); cvShowImage("Img", Img); cvShowImage("HImg", HImg); cvShowImage("SImg", SImg); cvShowImage("IImg", IImg); cvWaitKey(0); return 0; } int Rgb2Hsi(const IplImage* src, IplImage* dataH, IplImage* dataS, IplImage* dataI) { //返回0:成功,1:失败 //输入为彩色图像src, 输出dataH,dataS,dataI,分别为HSI模型的H、S、I分量 int y,x,offsetSrc,offsetHsi; int step,channels,step1; int r,g,b,minRgb; double cosThita,num,den,S,H; uchar *dataImg; uchar *dataS1; uchar *dataI1; uchar *dataH1; channels = src->nChannels; dataImg = (uchar *)src->imageData; dataI1 = (uchar *)dataI->imageData; dataH1=(uchar *)dataH->imageData; dataS1=(uchar *)dataS->imageData; if (channels!=3) { printf("The input image is not 3-channels!\n"); return 0; } step=src->widthStep; step1=dataI->widthStep; for (y=0; y<src->height; y++) for (x=0; x<src->width; x++) { offsetSrc = y*step + x*channels; offsetHsi=y*step1+x; b = dataImg[offsetSrc]; g=dataImg[offsetSrc+1]; r=dataImg[offsetSrc+2]; dataI1[offsetHsi] = (int)((r+g+b)/3+0.5); num=(2*r-g-b)/2; den=sqrt((r-g)*(r-g)+(r-b)*(g-b)); if (den==0) den=0.01; cosThita=acos(num/den); minRgb = min(r, g, b); den=r+g+b; if (den==0) den=0.01; S=1-3*minRgb/den; dataS1[offsetHsi]=(int) (S*255+0.5);//将S分量和H分量都扩充到[0,255]区间以便于显示 //一般H分量在[0,2pi]之间,S在[0,1]之间 if (b<=g) H=cosThita/(2*3.14); else H=(2*3.14-cosThita)/(2*3.14); dataH1[offsetHsi] = (int)(H*255+0.5); if (S==0) dataH1[offsetHsi]=0; } return 1; } int min(int a, int b, int c) { int m = a; if(m > b) m = b; if( m > c) m = c; return m; }
相关文章推荐
- OpenCV实现RGB颜色空间和HSI颜色空间的相互转换
- OpenCV实现RGB颜色空间和HSI颜色空间的相互转换
- OpenCV实现RGB颜色空间和HSI颜色空间的相互转换
- OpenCV实现RGB颜色空间和HSI颜色空间的相互转换
- 使用OpenCV实现RGB、HSI、CMYK颜色空间的转换
- 数字图像处理 颜色空间RGB、HSI、CMYK、YUV的相互转换
- opencv实现将RGB图像转换到HSI空间
- 数字图像处理 颜色空间RGB、HSI、CMYK、YUV的相互转换
- HSI颜色空间和RGB颜色空间之间的相互转换
- Java 利用 ICC 色彩空间 color space profile 实现 RGB 和 CMYK 颜色的相互转换
- RGB空间与HSV空间的相互转换(C++实现,修正网上大多数的代码错误)
- VC编程实现色彩空间RGB与HSB(HSV)相互转换
- flex实现16进制颜色和RGB颜色值的相互转换
- 【OpenCV】颜色空间RGB与HSV(HSL)的转换
- VC编程实现色彩空间RGB与XYZ相互转换
- RGB空间与HSV空间的相互转换(C++实现,修正网上大多数的代码错误)
- OPENCV中 RGB 转换到 HSI空间
- HSV颜色空间 与 RGB 颜色空间的相互转换
- VC编程实现色彩空间RGB与XYZ相互转换
- RGB与HSI空间相互转换