HSV通道是指图像处理中的一种颜色模型,它由色调(Hue)、饱和度(Saturation)和明度(Value)三个通道组成。色调表示颜色的种类,饱和度表示颜色的纯度或鲜艳程度,明度表示颜色的亮度。HSV通道常用于图像处理中的颜色分析、颜色过滤、颜色调整等任务,它相对于其他颜色模型具有更直观和易于调节的特点,因此被广泛应用于计算机视觉和图像处理的领域。
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的图像效果是:
这里需要注意的是,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')
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%代码--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');
同时,以上代码采用C++实现的话如下所示,这里为了保证精度,输出结果采用的是double类型,但是范围也是0到255之间,要显示的话,需要转化为unsigned char类型:
//将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));
}
}
}
同样的,采用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)); %%归一化到0到2*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');
同样的,采用C++实现:
//将HSV图像转化成RGB图像
/*
返回: NULL
作者: 祝春雨
时间: 2023.10.13
输入: 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];
}
}
}
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];
}
}