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复杂一些,更多的是非线性运算
XYZ转Lab*方法
imageXYZ转Luv*方法
imageLab 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();
}
网友评论