您的位置:首页 > 运维架构

OpenCV实现RGB颜色空间和HSI颜色空间的相互转换

2013-04-17 16:22 861 查看
关于HSI颜色空间参照维基百科:http://zh.wikipedia.org/wiki/HSI%E8%89%B2%E5%BD%A9%E5%B1%AC%E6%80%A7%E6%A8%A1%E5%BC%8F

核心的转换公式:

RGB-->HSI



截图来自中科院刘定生老师的《数字图像处理与分析》课件。

HSI-->RGB

具体的数学公式参照冈萨雷斯版《数字图像处理(第三版)》432-434页,中译版的260-261页。

下面贴代码:

#include "opencv_libs.h"
#include <highgui.h>
#include <cv.h>
#include <math.h>

/*
* 描述:实现RGB颜色模型到HSI颜色模型之间的相互转换
* 作者:qdsclove(qdsclove@gmail.com)
* 时间:16:01 4/17 星期三 2013
*/

// 将HSI颜色空间的三个分量组合起来,便于显示
IplImage* catHSImage(CvMat* HSI_H, CvMat* HSI_S, CvMat* HSI_I)
{
IplImage* HSI_Image = cvCreateImage( cvGetSize( HSI_H ), IPL_DEPTH_8U, 3 );

for(int i = 0; i < HSI_Image->height; i++)
{
for(int j = 0; j < HSI_Image->width; j++)
{
double d = cvmGet( HSI_H, i, j );
int b = (int)(d * 255/360);
d = cvmGet( HSI_S, i, j );
int g = (int)( d * 255 );
d = cvmGet( HSI_I, i, j );
int r = (int)( d * 255 );

cvSet2D( HSI_Image, i, j, cvScalar( b, g, r ) );
}
}

return HSI_Image;
}

// 将HSI颜色模型的数据转换为RGB颜色模型的图像
IplImage* HSI2RGBImage(CvMat* HSI_H, CvMat* HSI_S, CvMat* HSI_I)
{
IplImage * RGB_Image = cvCreateImage(cvGetSize(HSI_H), IPL_DEPTH_8U, 3 );

int iB, iG, iR;
for(int i = 0; i < RGB_Image->height; i++)
{
for(int j = 0; j < RGB_Image->width; j++)
{
// 该点的色度H
double dH = cvmGet( HSI_H, i, j );
// 该点的色饱和度S
double dS = cvmGet( HSI_S, i, j );
// 该点的亮度
double dI = cvmGet( HSI_I, i, j );

double dTempB, dTempG, dTempR;
// RG扇区
if(dH < 120 && dH >= 0)
{
// 将H转为弧度表示
dH = dH * 3.1415926 / 180;
dTempB = dI * (1 - dS);
dTempR = dI * ( 1 + (dS * cos(dH))/cos(3.1415926/3 - dH) );
dTempG = (3 * dI - (dTempR + dTempB));
}
// GB扇区
else if(dH < 240 && dH >= 120)
{
dH -= 120;

// 将H转为弧度表示
dH = dH * 3.1415926 / 180;

dTempR = dI * (1 - dS);
dTempG = dI * (1 + dS * cos(dH)/cos(3.1415926/3 - dH));
dTempB = (3 * dI - (dTempR + dTempG));
}
// BR扇区
else
{
dH -= 240;

// 将H转为弧度表示
dH = dH * 3.1415926 / 180;

dTempG = dI * (1 - dS);
dTempB = dI * (1 + (dS * cos(dH))/cos(3.1415926/3 - dH));
dTempR = (3* dI - (dTempG + dTempB));
}

iB = dTempB * 255;
iG = dTempG * 255;
iR = dTempR * 255;

cvSet2D( RGB_Image, i, j, cvScalar( iB, iG, iR ) );
}
}

return RGB_Image;
}

int main()
{
IplImage* img = cvLoadImage("lena.bmp");

// 三个HSI空间数据矩阵
CvMat* HSI_H = cvCreateMat( img->height, img->width, CV_32FC1 );
CvMat* HSI_S = cvCreateMat( img->height, img->width, CV_32FC1 );
CvMat* HSI_I = cvCreateMat( img->height, img->width, CV_32FC1 );

// 原始图像数据指针, HSI矩阵数据指针
uchar* data;

// rgb分量
byte img_r, img_g, img_b;
byte min_rgb;  // rgb分量中的最小值
// HSI分量
float fHue, fSaturation, fIntensity;

for(int i = 0; i < img->height; i++)
{
for(int j = 0; j < img->width; j++)
{
data = cvPtr2D(img, i, j, 0);
img_b = *data;
data++;
img_g = *data;
data++;
img_r = *data;

// Intensity分量[0, 1]
fIntensity = (float)((img_b + img_g + img_r)/3)/255;

// 得到RGB分量中的最小值
float fTemp = img_r < img_g ? img_r : img_g;
min_rgb = fTemp < img_b ? fTemp : img_b;
// Saturation分量[0, 1]
fSaturation = 1 - (float)(3 * min_rgb)/(img_r + img_g + img_b);

// 计算theta角
float numerator = (img_r - img_g + img_r - img_b ) / 2;
float denominator = sqrt(
pow( (img_r - img_g), 2 ) + (img_r - img_b)*(img_g - img_b) );

// 计算Hue分量
if(denominator != 0)
{
float theta = acos( numerator/denominator) * 180/3.14;

if(img_b <= img_g)
{
fHue = theta ;
}
else
{
fHue = 360 - theta;
}
}
else
{
fHue = 0;
}

// 赋值
cvmSet( HSI_H, i, j, fHue );
cvmSet( HSI_S, i, j, fSaturation);
cvmSet( HSI_I, i, j, fIntensity );
}
}

IplImage* HSI_Image = catHSImage( HSI_H, HSI_S, HSI_I );
IplImage* RGB_Image = HSI2RGBImage( HSI_H, HSI_S, HSI_I );

cvShowImage("img", img);
cvShowImage("HSI Color Model", HSI_Image);
cvShowImage("RGB Color Model", RGB_Image);

cvWaitKey(0);

cvReleaseImage( &img );
cvReleaseImage( &HSI_Image );
cvReleaseImage( &RGB_Image );
cvReleaseMat( &HSI_H);
cvReleaseMat( &HSI_S);
cvReleaseMat( &HSI_I);

cvDestroyAllWindows();

return 0;
}


写的比较仓促,代码结构稍微有点混乱。

测试图像为彩色Lena图,运行结果如下:



左图为显示出来的HSI颜色模型图,右图为RGB颜色模型图。

HSI颜色模型为了显示,做了点处理,具体见代码。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: