Matlab/C++ source code realizes the conversion of RGB channel and HSV channel (the effect is compared with Halcon)

The meaning of HSV channel

The HSV channel refers to a color model in image processing, which consists of three channels: hue (Hue), saturation (Saturation) and brightness (Value). Hue represents the type of color, saturation represents the purity or vividness of the color, and value represents the brightness of the color. The HSV channel is often used for tasks such as color analysis, color filtering, and color adjustment in image processing. Compared with other color models, it is more intuitive and easier to adjust, so it is widely used in the fields of computer vision and image processing.

Halcon operator routine

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)

Here, the three-channel RGB channel is first separated into separate channels, then the RGB and HSV channels are converted to each other, and finally the three-channel image is merged into an RGB image.
The image effect of Halcon is:

Source code implementation

Convert RGB to HSV

It should be noted here that halcon explains the value range of the three HSV channels. The value range of the H channel is 0 to 2*pi, the value range of the S channel is 0 to 1, and the value range of the V channel is 0 to 1. The commonly used images are BYTE byte type, and the numerical range is 0 to 255. The formula is modified here so that the image data range obtained by Matlab is 0 to 255, which can be displayed directly. You can see it from the workspace of matlab. calculation process.
The following is the effect of using Matlab to implement trans_from_rgb

trans_from_rgb (ImageR, ImageG, ImageB, ImageH, ImageS, ImageV, 'hsv')
Matlab source code
%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% code--RGB channel to HSV channel
%Time: 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);

%%%Convert to HSV channel
H_image = zeros(height,width);
S_image = zeros(height,width);
V_image = zeros(height,width);

 %%RGB to HSV
for i=1:1:height
     for j=1:1:width
         %%%Calculate the maximum and minimum values of the three channels
         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
              %%%Calculate saturation
              S_image(i,j) = (maxValue - minValue)*255/minValue;
              %%%Calculate H channel
              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 needs to be rounded
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');

The final effect is:

The final verified effect is consistent with the halcon effect;

At the same time, if the above code is implemented in C++, it is as follows. In order to ensure accuracy, the output result is of double type, but the range is also between 0 and 255. To display, it needs to be converted to unsigned char type:

C++ source code
//Convert RGB image to HSV image
/*
Input: rData: r channel image
gData: g channel image
bData: b channel image
Output: hDoubleData: h channel image, h channel adopts double type, retaining accuracy
sDoubleData: s channel image, s channel adopts double type, retaining accuracy
vDoubleData: v channel image, v channel adopts double type, retaining accuracy
*/
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;
//Allocate memory space outside the function
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 channel data, the maximum value of the three channels
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 channel
sDoubleData[i] = (maxValue - minValue)*255.0 / maxValue;
//H channel
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));
}
}
}
Convert HSV to RGB

The formula description given by halcon is:

Matlab source code

Similarly, using Matlab to implement:

%%%%%%%%%%%%%%%%%%%%%%%%
% code--HSV channel to RGB channel
%Time: 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);

%%%Convert to RGB channel
R_image = zeros(height,width);
G_image = zeros(height,width);
B_image = zeros(height,width);

%%%Convert HSV to 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)); %%normalized to 0 to 2*pi
            Hi = floor(image_H(i,j)*0.025);
            Hf = image_H(i,j)*0.025 - Hi;
            %%%%According to the value of H, map C, X, and m to the three components of RGB respectively.
            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 needs to be rounded
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');

The final effect is:

It can be seen that the effect is consistent with Halcon;

C++ source code

Similarly, implemented in C++:

//Convert HSV image to RGB image
/*
Input: hDoubleData: h channel image, h channel adopts double type, retaining accuracy
sDoubleData: s channel image, s channel adopts double type, retaining accuracy
vDoubleData: v channel image, v channel adopts double type, retaining accuracy
Output: rDoubleData: r channel image, r channel adopts double type, retaining accuracy
gDoubleData: g channel image, g channel adopts double type, retaining accuracy
bDoubleData: b channel image, b channel adopts double type, retaining accuracy
*/
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];
}
}
}

Channel splitting and merging C++ source code implementation

Three-channel split

In Halcon, the operator for splitting three channels is:

decompose3 (Image, ImageR, ImageG, ImageB)

The corresponding C++ function for splitting a three-channel image is:

//Split three-channel image
/*
Input: srcData: three-channel image, the memory arrangement is BGRBGRBGR...
Output: rData: r channel image
gData: g channel image
bData: b channel image
*/
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];
}
}

Three-channel merger

In Halcon, the operator for splitting three channels is:

compose3 (ImageR1, ImageG1, ImageB1, MultiChannelImage)

The corresponding C++ function for merging three-channel images is:

//Merge three-channel images
/*
Input: rData: r channel image
gData: g channel image
bData: b channel image
Output: bgrData: color images, merged into BGRBGR....arranged
*/
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];
}
}