美文网首页
揭秘色彩空间L*a*b L*u*v 【内包含R'G'B

揭秘色彩空间L*a*b L*u*v 【内包含R'G'B

作者: 罗引杰 | 来源:发表于2021-08-11 16:06 被阅读0次

XYZ 的衍生色彩空间 Lab* Luv*

由于XYZ色彩空间所描述的色彩并不是均匀的, 如蓝色的区域就会很密, x从0.2变到0.3, 颜色会有很大的不同, 绿色的y分量从0.7变到0.8 颜色只改变了一点点, 所以我们需要一个更加均匀的色彩空间CIE 1976 Lab 和 CIE 1976 Luv
Lab色彩空间中, ab 表示色度, Luv 色彩空间中, uv 表示色度。
其中, Lab 计算起来会比Luv复杂一些,更多的是非线性运算

image

XYZ转Lab*方法

image

XYZ转Luv*方法

image

Lab R'G'B'互转代码

在对颜色的处理中, 我们经常会用到Lab色彩空间, 这里把XYZ和Lab互转的源码贴出来,代码是自己亲手敲出来的,并且进行了严格的验证
这里使用的是sRGB色彩空间 方便大家理解
关于XYZ色彩空间的揭秘, 可以看我这篇博文:https://www.jianshu.com/p/1d45395c1ec8

#include <math.h>

typedef float (*FUNC_GAMMA)(float x);

static const float XYZn[3] = { 95.0489,100.0,108.8840 };

const float rgb2xyz_709[9] = {
        0.4124, 0.3576, 0.1805,
        0.2126, 0.7152, 0.0722,
        0.0193, 0.1192, 0.9505
};

const float xyz2rgb_709[9] = {
        3.2406   ,     -1.5372  ,      -0.4986,
        -0.9689  ,     1.8758   ,      0.0415,
        0.0557   ,     -0.2040  ,      1.0570
};

static void mul32f_3x3(const float* matrix, const float* in, float* out)
{
    out[0] = matrix[0] * in[0] + matrix[1] * in[1] + matrix[2] * in[2];
    out[1] = matrix[3] * in[0] + matrix[4] * in[1] + matrix[5] * in[2];
    out[2] = matrix[6] * in[0] + matrix[7] * in[1] + matrix[8] * in[2];
}

static float f(float t)
{
    float res = 0.0;
    const float sigma = 6.0 / 29.0;
    if (t > sigma* sigma* sigma) {
        res = pow(t, 1.0/3.0);
    }
    else {
        res = (t/(3*sigma*sigma)) + 4.0/29.0;
    }
    return res;
}

static float f_invert(float t) {
    float res = 0.0;
    float sigma = 6.0 / 29.0;
    if (t > sigma) {
        res = pow(t, 3.0);
    }
    else {
        res = 3.0 * sigma * sigma * (t - 4.0 / 29.0);
    }
    return res;
};

static void xyz2Lab(float* xyz, float* Lab)
{
    float X = xyz[0]/ XYZn[0];
    float Y = xyz[1]/ XYZn[1];
    float Z = xyz[2]/ XYZn[2];

    Lab[0] = 116.0 * f(Y) - 16.0;
    Lab[1] = 500.0 * (f(X) - f(Y));
    Lab[2] = 200.0 * (f(Y) - f(Z));
}

static  void Lab2xyz(float* Lab, float* xyz)
{
    float L = Lab[0];
    float a = Lab[1];
    float b = Lab[2];

    const float div_116 = 1.0 / 116.0;
    xyz[0] = XYZn[0] * f_invert(div_116 * (L + 16.0) + a / 500.0);
    xyz[1] = XYZn[1] * f_invert(div_116 * (L + 16.0));
    xyz[2] = XYZn[2] * f_invert(div_116 * (L + 16.0) - b / 200.0);
}


static  void rgb2xyz(float* rgb, float* xyz, const float *coeffs)
{
    mul32f_3x3(coeffs, rgb, xyz);
}

static  void xyz2rgb(float* xyz, float* rgb, const float* coeffs)
{
    mul32f_3x3(coeffs, xyz, rgb);
}

void rgbe2Lab(float* src, float* dst, FUNC_GAMMA func_gamma)
{
    float rgb[3];
    float xyz[3];
    for (int i = 0; i != 3; ++i) {
        rgb[i] = func_gamma(src[i]);
    }
    rgb[0] *= 100;
    rgb[1] *= 100;
    rgb[2] *= 100;
    rgb2xyz(rgb, xyz, rgb2xyz_709);
    xyz2Lab(xyz, dst);
}

void Lab2rgbe(float* src, float* dst, FUNC_GAMMA func_gamma)
{
    float rgb[3];
    float xyz[3];

    Lab2xyz(src, xyz);
    xyz2rgb(xyz, rgb, xyz2rgb_709);
    rgb[0] /= 100;
    rgb[1] /= 100;
    rgb[2] /= 100;

    for (int i = 0; i != 3; ++i) {
        dst[i] = func_gamma(rgb[i]);
    }
}

//For test

int main(int argc , char ** argv)
{
    float rgb[3] = { 1,0,0 };
    float lab[3] = {};
    float dstrgb[3] = {};
    rgbe2Lab(rgb, lab, rec_709_inverse_oetf);
    Lab2rgbe(lab, dstrgb, rec_709_oetf);
    getchar();
}

相关文章

网友评论

      本文标题:揭秘色彩空间L*a*b L*u*v 【内包含R'G'B

      本文链接:https://www.haomeiwen.com/subject/zyscbltx.html