天天看點

七、使用OpenCV徒手實作:RGB轉HSI,并提取紅色

點選連結→【數字圖像處理】簡單實踐彙總

文章目錄

      • 1. RBG轉HSI理論
      • 2. RBG轉HSI代碼
      • 3. HSI轉RBG,提取紅色
      • 4. 效果

1. RBG轉HSI理論

  • H:色調(Hue);
  • S:飽和度(Saturation);
  • I:亮度(Intensity);
  • 公式:

    亮 度 : I = 1 3 ( R + G + B ) 飽 和 度 : S = I − 3 ( R + G + B ) [ min ⁡ ( R , G , B ) ] 色 調 : H = arccos ⁡ { [ ( R − G ) + ( R − B ) ] / 2 [ ( R − G ) 2 + ( R − B ) ( G − B ) ] 1 / 2 } 亮度:I = \frac { 1 } { 3 } ( R + G + B ) \\ 飽和度:S = I - \frac { 3 } { ( R + G + B ) } [ \min ( R , G , B ) ] \\ 色調:H = \arccos \left\{\frac { [ ( R - G ) + ( R - B ) ] / 2 } { \left[ ( R - G ) ^ { 2 } + ( R - B ) ( G - B ) \right] ^ { 1 / 2 } } \right\} 亮度:I=31​(R+G+B)飽和度:S=I−(R+G+B)3​[min(R,G,B)]色調:H=arccos{[(R−G)2+(R−B)(G−B)]1/2[(R−G)+(R−B)]/2​}

七、使用OpenCV徒手實作:RGB轉HSI,并提取紅色

2. RBG轉HSI代碼

#define H_RANGE_1					25
#define H_RANGE_2					300

Mat srcImage = imread(SRC_IMAGE, 1);
imshow(WIMDOW_NAME, srcImage);
Mat img_HSI;
img_HSI.create(srcImage.rows, srcImage.cols, CV_8UC3);
Mat img_Out;
img_Out.create(srcImage.rows, srcImage.cols, CV_8UC3);

//srcImage to img_HSI
for (int i = 0; i < srcImage.rows; i++) {
	for (int j = 0; j < srcImage.cols; j++) {
		double b = (double)srcImage.at<Vec3b>(i, j)[0] / 255;
		double g = (double)srcImage.at<Vec3b>(i, j)[1] / 255;
		double r = (double)srcImage.at<Vec3b>(i, j)[2] / 255;
		double H, S, I;
		double num = 0.5 * ((r - g) + (r - b));
		double den = sqrt((r - g) * (r - g) + (r - b) * (g - b));
		if (den == 0)
		{
			H = 0;
		}
		else
		{
			double theta = acos(num / den);
			H = 360 * theta / (PI * 2);
			if (b > g)
			{
				H = 360 - H;
			}
		}
		double minRGB = min(min(r, g), b);
		den = r + g + b;
		if (den == 0)
		{
			S = 0;
		}
		else
		{
			S = 1 - 3.0 * minRGB / den;
		}
		I = den / 3.0;
		img_HSI.at<Vec3b>(i, j)[0] = H / 360 * 255;
		img_HSI.at<Vec3b>(i, j)[1] = S * 255;
		img_HSI.at<Vec3b>(i, j)[2] = I * 255;
	}
}
imshow("HSI", img_HSI);
           

3. HSI轉RBG,提取紅色

注意: 因為白色的色調也在紅色範圍,是以需要用飽和度來排除白色

//img_HSI to img_Out
for (int i = 0; i < srcImage.rows; i++) {
	for (int j = 0; j < srcImage.cols; j++) {
		double H = (double)img_HSI.at<Vec3b>(i, j)[0] / 255 * 360;
		double S = (double)img_HSI.at<Vec3b>(i, j)[1] / 255;
		double I = (double)img_HSI.at<Vec3b>(i, j)[2] / 255;
		double R = 0, G = 0, B = 0;
		if (H >= H_RANGE_1 && H < H_RANGE_2)
		{
			H = 0;
			S = 0;
			I = 0;
		}
		if (S < 0.2) //用飽和度排除白色
		{
			H = 0;
			S = 0;
			I = 0;
		}
		if (H > 0 && H < 120)
		{
			B = I * (1 - S);
			R = I * (1 + (S * cos(H * PI / 180)) / (cos((60 - H) * PI / 180)));
			G = 3 * I - (R + B);
		}
		else if (H >= 120 && H < 240)
		{
			H = H - 120;
			R = I * (1 - S);
			G = I * (1 + (S * cos(H * PI / 180)) / (cos((60 - H) * PI / 180)));
			B = 3 * I - (R + G);
		}
		else if (H >= 240 && H < 360)
		{
			H = H - 240;
			G = I * (1 - S);
			B = I * (1 + (S * cos(H * PI / 180)) / (cos((60 - H) * PI / 180)));
			R = 3 * I - (G + B);
		}
		img_Out.at<Vec3b>(i, j)[0] = B * 255;
		img_Out.at<Vec3b>(i, j)[1] = G * 255;
		img_Out.at<Vec3b>(i, j)[2] = R * 255;
	}
}
imshow("Out", img_Out);
           

4. 效果

七、使用OpenCV徒手實作:RGB轉HSI,并提取紅色