七、使用OpenCV徒手实现:RGB转HSI,并提取红色

点击链接→【数字图像处理】简单实践汇总

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\}

在这里插入图片描述

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. 效果

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_34451909/article/details/107612157