Matlab/C++源码实现RGB通道与HSV通道的转换(效果对比Halcon)

HSV通道的含义

HSV通道是指图像处理中的一种颜色模型,它由色调(Hue)、饱和度(Saturation)和明度(Value)三个通道组成。色调表示颜色的种类,饱和度表示颜色的纯度或鲜艳程度,明度表示颜色的亮度。HSV通道常用于图像处理中的颜色分析、颜色过滤、颜色调整等任务,它相对于其他颜色模型具有更直观和易于调节的特点,因此被广泛应用于计算机视觉和图像处理的领域。

Halcon算子例程

read_image (Image, 'D:/lena.jpg')
decompose3 (Image, ImageR, ImageG, ImageB)
trans_from_rgb (ImageR, ImageG, ImageB, ImageH, ImageS, ImageV, 'hsv')
trans_to_rgb (ImageH, ImageS, ImageV, ImageR1, ImageG1, ImageB1, 'hsv')
compose3 (ImageR1, ImageG1, ImageB1, MultiChannelImage)

这里先将三通道RGB三通道拆开成单独的通道,再将RGB与HSV通道互相转换,最后将三通道图像合并成RGB图像。
Halcon的图像效果是:
在这里插入图片描述

源代码实现

RGB转成HSV

在这里插入图片描述

这里需要注意的是,halcon这里将HSV三通道的取值范围作了说明,H通道的数值范围是0到2*pi,S通道的数值范围是0到1,V通道的数值范围是0到1。而常用的图像为BYTE字节型,数值范围是0到255,这里对公式做了修改,使Matlab得出的图像数据范围是0到255,可以直接显示,这里可以从matlab的workspace中看到计算过程。
以下便是使用Matlab实现trans_from_rgb的效果

trans_from_rgb (ImageR, ImageG, ImageB, ImageH, ImageS, ImageV, 'hsv')
Matlab源码
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%代码--RGB通道转HSV通道
%时间:2023.9
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
clc;
image=imread('D:\lena.jpg');
[height,width,channels]=size(image);
figure;
imshow(image);
title('rgb-image');
image_R=image(:,:,1);
image_R=double(image_R);
image_G=image(:,:,2);
image_G=double(image_G);
image_B=image(:,:,3);
image_B=double(image_B);

%%%转化成HSV通道
H_image = zeros(height,width);
S_image = zeros(height,width);
V_image = zeros(height,width);

 %%RGB转成HSV
for i=1:1:height
     for j=1:1:width
         %%%计算三通道的最大最小值计算
         image_matrix = [image_R(i,j), image_G(i,j), image_B(i,j)];
         maxValue = max(image_matrix);
         minValue = min(image_matrix);
         V_image(i,j) = maxValue;
         if(maxValue == minValue)
             S_image(i,j) = 0;
             H_image(i,j) = 0;
         else
              %%%计算饱和度
              S_image(i,j) = (maxValue - minValue)*255/minValue;
              %%%计算H通道
              if(maxValue == image_R(i,j))
                  H_image(i,j) = 42.5.*(image_G(i,j) - image_B(i,j))./(maxValue - minValue);
              elseif(maxValue == image_G(i,j))
                  H_image(i,j) = 42.5 * (2 + (image_B(i,j) - image_R(i,j)) / (maxValue - minValue));
              elseif(maxValue == image_B(i,j)) 
                  H_image(i,j) = 42.5 * (4 + (image_R(i,j) - image_G(i,j)) / (maxValue - minValue));
              end
         end
     end
end

 %%%RGB要取整
H_image = uint8(H_image);
S_image = uint8(S_image);
V_image = uint8(V_image);

figure;
imshow(H_image);
title('H_image');

figure;
imshow(S_image);
title('S_image');

figure;
imshow(V_image);
title('V_image');

最终实现的效果是:
在这里插入图片描述
最终验证的效果与halcon效果一致;

同时,以上代码采用C++实现的话如下所示,这里为了保证精度,输出结果采用的是double类型,但是范围也是0到255之间,要显示的话,需要转化为unsigned char类型:

C++源码
//将RGB图像转化成HSV图像
/*
输入:  rData : r通道图像
		gData : g通道图像
		bData : b通道图像
输出:  hDoubleData : h通道图像, h通道采用double类型,保留精度
		sDoubleData : s通道图像,s通道采用double类型,保留精度
		vDoubleData : v通道图像,v通道采用double类型,保留精度
*/
void trans_from_rgb(unsigned char *rData, unsigned char *gData, unsigned char *bData, double *hDoubleData, double *sDoubleData, double *vDoubleData, int height, int width)
{
	if ((height <= 0) || (width <= 0))
		return;
	//在函数外部分配好内存空间
	if (rData == NULL || gData == NULL || bData == NULL || hDoubleData == NULL || sDoubleData == NULL || vDoubleData == NULL)
		return;
	int i;
	unsigned char minValue,maxValue;
	for (i = 0; i < width * height; i++){
		//V通道数据,三通道的最大值
		maxValue = std::max(std::max(rData[i], gData[i]), bData[i]);
		minValue = std::min(std::min(rData[i], gData[i]), bData[i]);
		vDoubleData[i] = maxValue;
		if (maxValue == minValue){
			sDoubleData[i] = 0;
			hDoubleData[i] = 0;
		}
		else{
			//S通道
			sDoubleData[i] = (maxValue - minValue)*255.0 / maxValue;
			//H通道
			if (maxValue == rData[i])
				hDoubleData[i] = 42.5 * (gData[i] - bData[i]) / (maxValue - minValue);    
			else if (maxValue == gData[i])
				hDoubleData[i] = 42.5 * (2 + (bData[i] - rData[i]) / (maxValue - minValue));
			else if (maxValue == bData[i])
				hDoubleData[i] = 42.5 * (4 + (rData[i] - gData[i]) / (maxValue - minValue));
		}
	}
}
HSV转成RGB

halcon给出的公式说明为:
在这里插入图片描述

Matlab源码

同样的,采用Matlab实现:

%%%%%%%%%%%%%%%%%%%%%%%%%%%
%代码--HSV通道转RGB通道
%时间:2023.9
%%%%%%%%%%%%%%%%%%%%%%%%%%%%
clc;
image1=imread('D:\lena.jpg');
[height,width,channels]=size(image1);
image_H=double(image1);
image2=imread('E:\S_image.bmp');
image_S=double(image2);
image3=imread('E:\V_image.bmp');
image_V=double(image3);

%%%转化成RGB通道
R_image = zeros(height,width);
G_image = zeros(height,width);
B_image = zeros(height,width);

%%%HSV转成RGB
for i=1:1:height
     for j=1:1:width
        if(image_S(i,j) == 0)
            R_image(i,j) = image_V(i,j);
            G_image(i,j) = image_V(i,j);
            B_image(i,j) = image_V(i,j);
        else
            %%Hi = floor(image_H(i,j)*2*pi/255/deg2rad(60));    %%归一化到02*pi
            Hi = floor(image_H(i,j)*0.025);
            Hf = image_H(i,j)*0.025 - Hi;
            %%%%根据H的值,将C,X,m分别对应到RGB三个分量上
            if(Hi == 0)
                R_image(i,j) = image_V(i,j);
                G_image(i,j) = image_V(i,j) * (1 - image_S(i,j)/255*(1-Hf));
                B_image(i,j) = image_V(i,j) * (1 - image_S(i,j)/255);
            elseif(Hi == 1)
                R_image(i,j) = image_V(i,j) * (1 - image_S(i,j)/255*Hf);
                G_image(i,j) = image_V(i,j);
                B_image(i,j) = image_V(i,j) * (1 - image_S(i,j)/255);
            elseif(Hi == 2)
                R_image(i,j) = image_V(i,j) * (1 - image_S(i,j)/255);
                G_image(i,j) = image_V(i,j);
                B_image(i,j) = image_V(i,j) * (1 - image_S(i,j)/255*(1-Hf));
            elseif(Hi == 3)
                R_image(i,j) = image_V(i,j) * (1 - image_S(i,j)/255);
                G_image(i,j) = image_V(i,j) * (1 - image_S(i,j)/255*Hf);
                B_image(i,j) = image_V(i,j);
            elseif(Hi == 4)
                R_image(i,j) = image_V(i,j) * (1 - image_S(i,j)/255*(1-Hf));
                G_image(i,j) = image_V(i,j) * (1 - image_S(i,j)/255);
                B_image(i,j) = image_V(i,j);
            elseif(Hi == 5)
                R_image(i,j) = image_V(i,j);
                G_image(i,j) = image_V(i,j) * (1 - image_S(i,j)/255);
                B_image(i,j) = image_V(i,j) * (1 - image_S(i,j)/255*Hf);
            end
        end
     end
end

%%%RGB要取整
R_image = uint8(R_image);
G_image = uint8(G_image);
B_image = uint8(B_image);

figure;
imshow(R_image);
title('R_image');

figure;
imshow(G_image);
title('G_image');

figure;
imshow(B_image);
title('B_image');

最终实现的效果是:
在这里插入图片描述
可以看出,与Halcon效果一致;

C++源码

同样的,采用C++实现:

//将HSV图像转化成RGB图像
/*
输入:  hDoubleData : h通道图像 ,h通道采用double类型,保留精度
		sDoubleData : s通道图像 ,s通道采用double类型,保留精度
		vDoubleData : v通道图像 ,v通道采用double类型,保留精度
输出:  rDoubleData : r通道图像 ,r通道采用double类型,保留精度
		gDoubleData : g通道图像 ,g通道采用double类型,保留精度
		bDoubleData : b通道图像 ,b通道采用double类型,保留精度
*/
void trans_to_rgb(double *hDoubleData, double *sDoubleData, double *vDoubleData, double *rDoubleData, double *gDoubleData, double *bDoubleData, int height, int width)
{
	if ((height <= 0) || (width <= 0))
		return;
	if (rDoubleData == NULL || gDoubleData == NULL || bDoubleData == NULL || hDoubleData == NULL || sDoubleData == NULL || vDoubleData == NULL)
		return;
	int i;
	double Hi, Hf;
	for (i = 0; i < width * height; i++){
		if (sDoubleData[i] > 0){
			Hi = floor(hDoubleData[i] * 0.025);
			Hf = hDoubleData[i] * 0.025 - Hi;
			if (Hi == 0){
				rDoubleData[i] = vDoubleData[i];
				gDoubleData[i] = vDoubleData[i] * (1 - sDoubleData[i] / 255.0*(1 - Hf));
				bDoubleData[i] = vDoubleData[i] * (1 - sDoubleData[i] / 255.0);
			}
			else if (Hi == 1){
				rDoubleData[i] = vDoubleData[i] * (1 - sDoubleData[i] / 255.0 * Hf);
				gDoubleData[i] = vDoubleData[i];
				bDoubleData[i] = vDoubleData[i] * (1 - sDoubleData[i] / 255.0);
			}
			else if (Hi == 2){
				rDoubleData[i] = vDoubleData[i] * (1 - sDoubleData[i] / 255.0);
				gDoubleData[i] = vDoubleData[i];
				bDoubleData[i] = vDoubleData[i] * (1 - sDoubleData[i] / 255.0*(1 - Hf));
			}
			else if (Hi == 3){
				rDoubleData[i] = vDoubleData[i] * (1 - sDoubleData[i] / 255.0);
				gDoubleData[i] = vDoubleData[i] * (1 - sDoubleData[i] / 255.0 * Hf);
				bDoubleData[i] = vDoubleData[i];
			}
			else if (Hi == 4){
				rDoubleData[i] = vDoubleData[i] * (1 - sDoubleData[i] / 255.0*(1 - Hf));
				gDoubleData[i] = vDoubleData[i] * (1 - sDoubleData[i] / 255.0);
				bDoubleData[i] = vDoubleData[i];
			}
			else if (Hi == 5){
				rDoubleData[i] = vDoubleData[i];
				gDoubleData[i] = vDoubleData[i] * (1 - sDoubleData[i] / 255.0);
				bDoubleData[i] = vDoubleData[i] * (1 - sDoubleData[i] / 255.0 * Hf);
			}
		}
		else{
			rDoubleData[i] = gDoubleData[i] = bDoubleData[i] = vDoubleData[i];
		}
	}
}

通道拆分与合并C++源代码实现

三通道拆分

Halcon中,拆分三通道的算子为:

decompose3 (Image, ImageR, ImageG, ImageB)

对应的拆分三通道图像的C++函数为:

//拆分三通道图像
/*
输入:  srcData : 三通道图像,内存排列方式是BGRBGRBGR......
输出:  rData : r通道图像
		gData : g通道图像
		bData : b通道图像
*/
void decompose3(unsigned char *srcData, unsigned char *rData, unsigned char *gData, unsigned char *bData, int height, int width)
{
	if ((height <= 0) || (width <= 0))
		return;
	if (srcData == NULL || rData == NULL || gData == NULL || bData == NULL)
		return;
	int i;
#pragma omp parallel for num_threads(3)
	for (i = 0; i < width * height; i++)
	{
		bData[i] = srcData[3 * i];
		gData[i] = srcData[3 * i + 1];
		rData[i] = srcData[3 * i + 2];
	}
}

三通道合并

Halcon中,拆分三通道的算子为:

compose3 (ImageR1, ImageG1, ImageB1, MultiChannelImage)

对应的合并三通道图像的C++函数为:

//合并三通道图像
/*
输入:  rData : r通道图像
		gData : g通道图像
		bData : b通道图像
输出:  bgrData:彩色图像,合并成BGRBGR.....排列
*/
void compose3(unsigned char *rData, unsigned char *gData, unsigned char *bData, unsigned char *bgrData, int height, int width)
{
	if ((height <= 0) || (width <= 0))
		return;
	if (bgrData == NULL || rData == NULL || gData == NULL || bData == NULL)
		return;
	int i;
#pragma omp parallel for num_threads(3)
	for (i = 0; i < width * height; i++)
	{
		bgrData[3 * i] = bData[i];
		bgrData[3 * i + 1] = gData[i];
		bgrData[3 * i + 2] = rData[i];
	}
}
  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

手写不期而遇

感谢你的打赏,也欢迎一起学习

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值