色彩转换系列之RGB格式与HSI格式互转原理及实现

写在前面 

HSI色彩空间是从人的视觉系统出发,直接用颜色三要素:色调(Hue)、饱和度(Saturation或Chroma)和亮度 (Intensity或Brightness)来描述色彩。

  • H——表示颜色的相位角,是彩色最重要的属性,决定颜色的本质。红、绿、蓝分别相隔120度;互补色分别相差180度,即颜色的类别。
  • S——表示颜色的深浅程度,饱和度越高,颜色越深。与白色的比例有关,白色比例越多,饱和度越低。
  • I——表示色彩的明亮程度,人眼对亮度很敏感。

HSI彩色空间可以用一个圆锥空间模型来描述:

                                                           å¨è¿éæå¥å¾çæè¿°

可以看到HSI色彩空间和RGB色彩空间只是同一物理量的不同表示法,因而它们之间存在着转换关系:HSI颜色模式中的色调使用颜色类别表示,饱和度与颜色的白光光亮亮度刚好成反比,代表灰色与色调的比例,亮度是颜色的相对明暗程度。 

由于人的视觉对亮度的敏感程度远强于对颜色浓淡的敏感程度,为了便于颜色处理和识别,人的市局系统经常采用HSI彩色空间,它比RGB空间更符合人的视觉特性。此外,由于HSI空间中亮度和色度具有可分离性,使得图像处理和机器视觉中大量灰度处理算法都可在HSI空间方便进行。笔者此前做过一个矫正人脸图像偏光的小项目,用到的某算法的关键一步即是在HSI空间中进行亮度矫正

应用:可以用于偏光矫正、去除阴影、图像分割等。 

RGB与HSI相互转换

1、RGB2HSI 

                           H=\left\{\begin{array}{ll}{\theta,} & {G \geq B} \\ { 360-\theta,} & {G<B}\end{array}\right.             where:\theta=\cos ^{-1}\left(\frac{(R-G)+(R-B)}{2 \sqrt{(R-G)^{2}+(R-B)(G-B)}}\right)

                          S=1-\frac{3 \min (R . G, B)}{R+G+B}

                          I=\frac{R+G+B}{3}

假定RGB值归一化为[0,1]范围内,色调H可以用得到的值除以360归一化,其他两个分量已经在[0,1]范围之内了。

2、HSI2RGB

                     0=< H < 120:

                                              B=I(1-S)

                                             R=I\left[1+\frac{S \cos H}{\cos \left(60^{\circ}-H\right)}\right]

                                             G=3 I-(R+B)

                      120=< H < 240:  首先H=H-120°

                                          \begin{array}{c}{R=I(1-S)} \\ {G=I\left[1+\frac{S \cos H}{\cos \left(60^{\circ}-H\right)}\right]} \\ {B=3 I-(R+G)}\end{array}

                       240=< H < 360:  首先H=H-240°

                                          \begin{array}{c}{G=I(1-S)} \\ {B=I\left[1+\frac{S \cos H}{\cos \left(60^{\circ}-H\right)}\right]} \\ {R=3 I-(G+B)}\end{array}

                                             

实现

#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
using namespace cv;


Mat RGB2HSI(Mat src){
	int row = src.rows;
	int col = src.cols;
	Mat dsthsi(row, col, CV_64FC3);
	Mat H = Mat(row, col, CV_64FC1);
	Mat S = Mat(row, col, CV_64FC1);
	Mat I = Mat(row, col, CV_64FC1);
	for (int i = 0; i < row; i++){
		for (int j = 0; j < col; j++){
			double h, s, newi, th;
			double B = (double)src.at<Vec3b>(i, j)[0] / 255.0;
			double G = (double)src.at<Vec3b>(i, j)[1] / 255.0;
			double R = (double)src.at<Vec3b>(i, j)[2] / 255.0;
			double mi, mx;
			if (R > G && R > B){
				mx = R;
				mi = min(G, B);
			}
			else{
				if (G > B){
					mx = G;
					mi = min(R, B);
				}
				else{
					mx = B;
					mi = min(R, G);
				}
			}
			newi = (R + G + B) / 3.0;
			if (newi < 0)  newi = 0;
			else if (newi > 1) newi = 1.0;
			if (newi == 0 || mx == mi){
				s = 0;
				h = 0;
			}
			else{
				s = 1 - mi / newi;
				th = (R - G) * (R - G) + (R - B) * (G - B);
				th = sqrt(th) + 1e-5;
				th = acos(((R - G + R - B)*0.5) / th);
				if (G >= B) h = th;
				else h = 2 * CV_PI - th;
			}
			h = h / (2 * CV_PI);
			H.at<double>(i, j) = h;
			S.at<double>(i, j) = s;
			I.at<double>(i, j) = newi;

			dsthsi.at<Vec3d>(i, j)[0] = h  ;
			dsthsi.at<Vec3d>(i, j)[1] = s;
			dsthsi.at<Vec3d>(i, j)[2] = newi;

		}
	}
	return dsthsi;
}

Mat HSI2RGB(Mat src){
	int row = src.rows;
	int col = src.cols;
	Mat dst(row, col, CV_64FC3);

	for (int i = 0; i < row; i++){
		for (int j = 0; j < col; j++){
			double preh = src.at<Vec3d>(i, j)[0] * 2 * CV_PI;//H
			double pres = src.at<Vec3d>(i, j)[1];  //S
			double prei = src.at<Vec3d>(i, j)[2];  //I
			double r = 0, g = 0, b = 0;
			double t1, t2, t3;
			t1 = (1.0 - pres) / 3.0;
			if (preh >= 0 && preh < (CV_PI * 2 / 3)){
				b = t1;
				t2 = pres * cos(preh);
				t3 = cos(CV_PI / 3 - preh);
				r = (1 + t2 / t3) / 3;
				r = 3 * prei * r;
				b = 3 * prei * b;
				g = 3 * prei - (r + b);
			}
			else if (preh >= (CV_PI * 2 / 3) && preh < (CV_PI * 4 / 3)){
				r = t1;
				t2 = pres * cos(preh - 2 * CV_PI / 3);
				t3 = cos(CV_PI - preh);
				g = (1 + t2 / t3) / 3;
				r = 3 * prei * r;
				g = 3 * g * prei;
				b = 3 * prei - (r + g);
			}
			else if (preh >= (CV_PI * 4 / 3) && preh <= (CV_PI * 2)){
				g = t1;
				t2 = pres * cos(preh - 4 * CV_PI / 3);
				t3 = cos(CV_PI * 5 / 3 - preh);
				b = (1 + t2 / t3) / 3;
				g = 3 * g * prei;
				b = 3 * prei * b;
				r = 3 * prei - (g + b);
			}
			dst.at<Vec3d>(i, j)[0] = b;
			dst.at<Vec3d>(i, j)[1] = g;
			dst.at<Vec3d>(i, j)[2] = r;
		}
	}
	return dst;
}


int main(){
	cv::Mat src = cv::imread("I:/Learning-and-Practice/2019Change/Image process algorithm/Img/002.jpg");

	if (src.empty()){
		return -1;
	}
	cv::Mat dst, dst2;

	//RGB2HSI//
	double t1 = (double)cv::getTickCount(); //测时间

	dst = RGB2HSI(src); //RGB2HSI
	dst2 = HSI2RGB(dst); //HSI2BGR
	//std::cout << dst << std::endl;

	t1 = (double)cv::getTickCount() - t1;
	double time1 = (t1 *1000.) / ((double)cv::getTickFrequency());
	std::cout << "My_RGB2HSI=" << time1 << " ms. " << std::endl << std::endl;


	cv::namedWindow("src", CV_WINDOW_NORMAL);
	imshow("src", src);
	cv::namedWindow("My_RGB2HSI", CV_WINDOW_NORMAL);
	imshow("My_RGB2HSI", dst);
	cv::namedWindow("My_HSI2RGB", CV_WINDOW_NORMAL);
	imshow("My_HSI2RGB", dst2);
	cv::waitKey(0);
	return 0;

}

 

效果

找了张有阴影的图:

 

参考:

 https://blog.csdn.net/just_sort/article/details/87102898

《精通Matlab数字图像处理与识别》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值