Digital image processing – mutual conversion between Lab, YCbCr, HSV, RGB

Lab

The “Lab” image format usually refers to the CIELAB color space, also known as the Lab color space. It is a device-independent color space used to describe the color of human visual perception, which is different from the common RGB and CMYK color spaces. CIELAB was defined by the International Commission on Illumination (CIE) in 1976 to more accurately represent the human eye’s perception of color.
CIELAB includes three channels: L (luminance), a (color components from green to red), and b (color components from blue to yellow). The main advantage of this color space is that it tries to simulate the way the human eye perceives colors such that colors that are closer together in Lab space are also more visually similar. This makes the Lab color space useful in many color-related applications, such as image processing, color correction, and color matching.
However, it’s important to note that the Lab image format itself is not a common image file format like JPEG, PNG, or GIF. In contrast, the Lab color space is often used as an intermediate color space in image processing to aid in color correction, color adjustment, and other color-related operations. To represent the Lab color space on a computer, floating point values are usually used to represent the L, a, and b channel values.

YCbCr

YCbCr is a color space used for digital image and video encoding, which is different from RGB color space. YCbCr is often used in image and video compression, transmission, and digital media processing because it has the property of separating color and brightness information that is perceived differently by the human eye, which can reduce the amount of data transmission while maintaining visual quality.
YCbCr consists of three components:
Y (brightness): Indicates the brightness component of the image. This component corresponds to the brightness perception of the image by the human eye.
Cb and Cr (Color Difference): These two components represent the chrominance or color difference components in the color information. Cb represents the difference between blue and brightness, while Cr represents the difference between red and brightness. This separation allows color information to be separated from luminance information, allowing compression without significantly affecting visual perception.
YCbCr is widely used in digital media technologies such as JPEG image compression, video encoding such as MPEG and H.264, and digital television broadcasting. Many image and video formats use the YCbCr color space to store data because it reduces the amount of data stored and transmitted while preserving image quality. In these formats, the color information of the image is mapped into the Cb and Cr channels, while the luminance information is kept in the Y channel.

HSV

It is based on how the human visual system perceives color and is different from RGB and CMYK color spaces. HSV stands for Hue, Saturation, and Value, and it provides an intuitive way to describe different aspects of color.
The following are the three components of the HSV color space:

  1. Hue: Hue represents the basic properties of a color, that is, the name of the color we often say, such as red, green, blue, etc. Hue typically ranges from 0 to 360
    degree, divides the entire color circle into different colors.
  2. Saturation: Saturation indicates the purity or vividness of a color. A less saturated color will be darker or washed out, while a more saturated color will be more vibrant. Saturation typically ranges in value from 0% (gray) to 100% (fully saturated).
  3. Brightness (Value): Brightness indicates how light or dark a color is. Higher brightness values indicate brighter colors, while lower values indicate darker colors. Brightness typically ranges in value from 0% (black) to 100% (white).
    The HSV color space is often used in image processing and computer graphics because it provides a more intuitive way to control the appearance of colors. Compared with the RGB color space, HSV is more suitable for adjusting the saturation and lightness of colors without considering the complex interaction between colors.

Code

First, define the data structure of these color spaces. In order to facilitate reading and writing of images, here we use OpenCV to read in images, and convert BGR to RGB after reading.

#pragma once
#include <iostream>
#include <algorithm>
#include <opencv2/opencv.hpp>
structLab
{<!-- -->
float L;
float a;
float b;
};

struct YCbCr
{<!-- -->
    float Y;
    float Cb;
    float Cr;
};

struct HSV
{<!-- -->
int h;
double s;
double v;
};

struct BGR
{<!-- -->
float b;
float g;
float r;
};

Implement code

void BGR_YCbCr(BGR & amp; bgr, YCbCr & amp; y)
{<!-- -->
    y.Y = 0.257 * bgr.r + 0.564 * bgr.g + 0.098 * bgr.b + 16;
    y.Cb = -0.148 * bgr.r - 0.291 * bgr.g + 0.439 * bgr.b + 128;
    y.Cr = 0.439 * bgr.r - 0.368 * bgr.g - 0.071 * bgr.b + 128;
}

void BGR_Lab(BGR & amp; bgr, Lab & amp; lab)
{<!-- -->
    double X, Y, Z;
    double Fx = 0, Fy = 0, Fz = 0;
    double b = bgr.b / 255.00;
    double g = bgr.g / 255.00;
    double r = bgr.r / 255.00;


    // gamma 2.2
    if (r > 0.04045)
        r = pow((r + 0.055) / 1.055, 2.4);
    else
        r = r / 12.92;
    if (g > 0.04045)
        g = pow((g + 0.055) / 1.055, 2.4);
    else
        g = g / 12.92;
    if (b > 0.04045)
        b = pow((b + 0.055) / 1.055, 2.4);
    else
        b = b / 12.92;
    // sRGB
    X = r * 0.436052025 + g * 0.385081593 + b * 0.143087414;
    Y = r * 0.222491598 + g * 0.716886060 + b * 0.060621486;
    Z = r * 0.013929122 + g * 0.097097002 + b * 0.714185470;
    //XYZ range: 0~100
    X = X * 100.000;
    Y = Y * 100.000;
    Z = Z * 100.000;
    // Reference White Point
    //2 degree field of view D50 light source tristimulus value
    double ref_X = 96.4221;
    double ref_Y = 100.000;
    double ref_Z = 82.5211;


    X = X / ref_X;
    Y = Y / ref_Y;
    Z = Z / ref_Z;


    //Lab
    if (X > 0.008856)
        Fx = pow(X, 1 / 3.000);
    else
        Fx = (7.787 * X) + (16 / 116.000);
    if (Z > 0.008856)
        Fz = pow(Z, 1 / 3.000);
    else
        Fz = (7.787 * Z) + (16 / 116.000);
    if (Y > 0.008856)
    {<!-- -->
        Fy = pow(Y, 1 / 3.000);
        lab.L = (116.000 * Fy) - 16.0 + 0.5;
    }
    else
    {<!-- -->
        Fy = (7.787 * Y) + (16 / 116.000);
        lab.L = 903.3 * Y;
    }

    lab.a = 500.000 * (Fx - Fy) + 0.5;
    lab.b = 200.000 * (Fy - Fz) + 0.5;
}

bool IsEquals(double val1, double val2)
{<!-- -->
return fabs(val1 - val2) < 0.001;
}

void BGR_HSV(BGR & bgr, HSV & hsv)
{<!-- -->
double b, g, r;
double h, s, v;
double min, max;
double delta;

b = bgr.b / 255.0;
g = bgr.g / 255.0;
r = bgr.r/255.0;

if (r > g)
{<!-- -->
max = std::max(r, b);
min = std::min(g, b);
}
else
{<!-- -->
max = std::max(g, b);
min = std::min(r, b);
}

v = max;
delta = max - min;

if (IsEquals(max, 0))
s = 0.0;
else
s = delta / max;

if (max == min)
h = 0.0;
else
{<!-- -->
if (IsEquals(r, max) & amp; & amp; g >= b)
{<!-- -->
h = 60 * (g - b) / delta + 0;
}
else if (IsEquals(r, max) & amp; & amp; g < b)
{<!-- -->
h = 60 * (g - b) / delta + 360;
}
else if (IsEquals(g, max))
{<!-- -->
h = 60 * (b - r) / delta + 120;
}
else if (IsEquals(b, max))
{<!-- -->
h = 60 * (r - g) / delta + 240;
}
}

hsv.h = (int)(h + 0.5);
hsv.h = (hsv.h > 359) ? (hsv.h - 360) : hsv.h;
hsv.h = (hsv.h < 0) ? (hsv.h + 360) : hsv.h;
hsv.s = s;
hsv.v = v;
}

BGR BGR_value(cv::Mat & cv_src)
{<!-- -->
    cv::Scalars = cv::mean(cv_src);
    BGR bgr;
    bgr.b = s[0];
    bgr.g = s[1];
    bgr.r = s[2];

    return bgr;
}