这个 RGB 到 XYZ 色彩空间转换算法有什么问题?

发布于 2024-11-19 13:19:21 字数 2866 浏览 5 评论 0原文

我的目标是将 RGB 像素转换为 CIELab 颜色空间,以进行一些只能在 CIELab 中进行的特殊计算。为此,我必须首先将 RGB 转换为 XYZ,这是非常困难的部分。

我尝试在 Objective-C 中实现这个算法(虽然主要使用纯 C),但结果是错误的。

我的代码基于 easyrgb.com< 提供的伪实现/a>.他们有一个在线颜色转换器,效果很好。他们说他们的伪代码与转换器中使用的伪代码相同。

这是他们的伪代码:

var_R = ( R / 255 )        //R from 0 to 255
var_G = ( G / 255 )        //G from 0 to 255
var_B = ( B / 255 )        //B from 0 to 255

if ( var_R > 0.04045 ) var_R = ( ( var_R + 0.055 ) / 1.055 ) ^ 2.4
else                   var_R = var_R / 12.92
if ( var_G > 0.04045 ) var_G = ( ( var_G + 0.055 ) / 1.055 ) ^ 2.4
else                   var_G = var_G / 12.92
if ( var_B > 0.04045 ) var_B = ( ( var_B + 0.055 ) / 1.055 ) ^ 2.4
else                   var_B = var_B / 12.92

var_R = var_R * 100
var_G = var_G * 100
var_B = var_B * 100

//Observer. = 2°, Illuminant = D65
X = var_R * 0.4124 + var_G * 0.3576 + var_B * 0.1805
Y = var_R * 0.2126 + var_G * 0.7152 + var_B * 0.0722
Z = var_R * 0.0193 + var_G * 0.1192 + var_B * 0.9505

这是我在 Objective-C / C 中实现它的尝试:

void convertRGBtoXYZ(NSInteger * inR, NSInteger * inG, NSInteger * inB, CGFloat * outX, CGFloat * outY, CGFloat * outZ) {
    // http://www.easyrgb.com/index.php?X=MATH&H=02#text2

    CGFloat var_R = (*inR / 255); //R from 0 to 255
    CGFloat var_G = (*inG / 255); //G from 0 to 255
    CGFloat var_B = (*inB / 255); //B from 0 to 255

    if (var_R > 0.04045f) {
        var_R = powf(( (var_R + 0.055f) / 1.055f), 2.4f);
    } else {
        var_R = var_R / 12.92f;
    }

    if (var_G > 0.04045) {
        var_G = powf(( (var_G + 0.055f) / 1.055f), 2.4f);
    } else {
        var_G = var_G / 12.92f;
    }

    if (var_B > 0.04045f) {
        var_B = powf(( (var_B + 0.055f) / 1.055f), 2.4f);
    } else {
        var_B = var_B / 12.92f;
    }

    var_R = var_R * 100;
    var_G = var_G * 100;
    var_B = var_B * 100;

    //Observer. = 2°, Illuminant = D65
    *outX = var_R * 0.4124f + var_G * 0.3576f + var_B * 0.1805f;
    *outY = var_R * 0.2126f + var_G * 0.7152f + var_B * 0.0722f;
    *outZ = var_R * 0.0193f + var_G * 0.1192f + var_B * 0.9505f;
}

但是,我没有得到与他们的工具相同的结果(具有相同的观察者和光源设置)。

在我的测试中,我将这些值输入到他们的工具中,并得到了 XYZ 的结果,该结果与我的实现为该 RGB 值生成的结果相去甚远。请查看屏幕截图:


screenshot


生成的 Lab 颜色值非常接近 Photoshop 告诉我的值,因此转换器效果很好。

上面的 C 代码给了我这个结果:

X = 35.76... // should be 42.282
Y = 71.52... // should be 74.129
Z = 11.92... // should be 46.262

知道这个失败的原因是什么吗?我在实现中犯了错误,还是需要其他常量?

如果您知道一些经过测试的 RGB 到 XYZ、XYZ 到 CIELab 或 RGB 到 CIELab、XYZ 到 Lab 或 RGB 到 Lab 实现,请随时在此处发布它们。

基本上,我想做的就是计算两种颜色之间的偏差,也称为 Delta-E。这就是为什么我需要从 RGB 转换为 XYZ 到 Lab(或 CIELab)...

My goal is to convert an RGB pixel into CIELab color space for some special calculations only possible in CIELab. For this, I must convert RGB to XYZ first, which is the really hard part.

I tried to implement this algorithm in Objective-C (mostly using plain C though), but the results are wrong.

My code is based on the pseudo-implementation provided by easyrgb.com. They have an online-color-converter which works great. They say that their pseudo-code is the same one used in their converter.

This is their Pseudo-Code:

var_R = ( R / 255 )        //R from 0 to 255
var_G = ( G / 255 )        //G from 0 to 255
var_B = ( B / 255 )        //B from 0 to 255

if ( var_R > 0.04045 ) var_R = ( ( var_R + 0.055 ) / 1.055 ) ^ 2.4
else                   var_R = var_R / 12.92
if ( var_G > 0.04045 ) var_G = ( ( var_G + 0.055 ) / 1.055 ) ^ 2.4
else                   var_G = var_G / 12.92
if ( var_B > 0.04045 ) var_B = ( ( var_B + 0.055 ) / 1.055 ) ^ 2.4
else                   var_B = var_B / 12.92

var_R = var_R * 100
var_G = var_G * 100
var_B = var_B * 100

//Observer. = 2°, Illuminant = D65
X = var_R * 0.4124 + var_G * 0.3576 + var_B * 0.1805
Y = var_R * 0.2126 + var_G * 0.7152 + var_B * 0.0722
Z = var_R * 0.0193 + var_G * 0.1192 + var_B * 0.9505

This is my attempt to implement it in Objective-C / C:

void convertRGBtoXYZ(NSInteger * inR, NSInteger * inG, NSInteger * inB, CGFloat * outX, CGFloat * outY, CGFloat * outZ) {
    // http://www.easyrgb.com/index.php?X=MATH&H=02#text2

    CGFloat var_R = (*inR / 255); //R from 0 to 255
    CGFloat var_G = (*inG / 255); //G from 0 to 255
    CGFloat var_B = (*inB / 255); //B from 0 to 255

    if (var_R > 0.04045f) {
        var_R = powf(( (var_R + 0.055f) / 1.055f), 2.4f);
    } else {
        var_R = var_R / 12.92f;
    }

    if (var_G > 0.04045) {
        var_G = powf(( (var_G + 0.055f) / 1.055f), 2.4f);
    } else {
        var_G = var_G / 12.92f;
    }

    if (var_B > 0.04045f) {
        var_B = powf(( (var_B + 0.055f) / 1.055f), 2.4f);
    } else {
        var_B = var_B / 12.92f;
    }

    var_R = var_R * 100;
    var_G = var_G * 100;
    var_B = var_B * 100;

    //Observer. = 2°, Illuminant = D65
    *outX = var_R * 0.4124f + var_G * 0.3576f + var_B * 0.1805f;
    *outY = var_R * 0.2126f + var_G * 0.7152f + var_B * 0.0722f;
    *outZ = var_R * 0.0193f + var_G * 0.1192f + var_B * 0.9505f;
}

However, I don't get the same results as their tool (with same Observer and Illuminant setting).

In my test, I entered these values into their tool and got this result for XYZ which is far off from what my implementation produces for that RGB value. Please see screenshot:


screenshot


The resulting Lab color values are pretty close to what Photoshop tells me, so the converter works great.

The C-code above gives me this results though:

X = 35.76... // should be 42.282
Y = 71.52... // should be 74.129
Z = 11.92... // should be 46.262

Any idea what's the cause for this failure? Did I do a mistake in my implementation, or do I need other constants?

If you know some tested RGB to XYZ, XYZ to CIELab or RGB to CIELab, XYZ to Lab or RGB to Lab implementations, please don't hesitate to post them here.

Basically, all I want to do is calculate the deviation between two colors, also known as Delta-E. That's why I need to convert from RGB to XYZ to Lab (or CIELab)...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

人间不值得 2024-11-26 13:19:21

我相信这是您的问题,这是截断为整数:

CGFloat var_R = (*inR / 255); //R from 0 to 255
CGFloat var_G = (*inG / 255); //G from 0 to 255
CGFloat var_B = (*inB / 255); //B from 0 to 255

试试这个:

CGFloat var_R = (*inR / 255.0f); //R from 0 to 255
CGFloat var_G = (*inG / 255.0f); //G from 0 to 255
CGFloat var_B = (*inB / 255.0f); //B from 0 to 255

我还没有检查其余代码是否存在其他问题。

I believe here is your problem, this is truncating to an integer:

CGFloat var_R = (*inR / 255); //R from 0 to 255
CGFloat var_G = (*inG / 255); //G from 0 to 255
CGFloat var_B = (*inB / 255); //B from 0 to 255

Try this:

CGFloat var_R = (*inR / 255.0f); //R from 0 to 255
CGFloat var_G = (*inG / 255.0f); //G from 0 to 255
CGFloat var_B = (*inB / 255.0f); //B from 0 to 255

I haven't checked the rest of the code for other problems.

你在看孤独的风景 2024-11-26 13:19:21

*inR/255 是整数除法。 1/255 为零。改为写入 *inR/255.0。

*inR/255 is an integer division. 1/255 is zero. Write *inR/255.0 instead.

怎言笑 2024-11-26 13:19:21
#include <stdio.h>
#include <math.h>

float ref_X = 95.047;
float ref_Y = 100.0;
float ref_Z = 108.883;


void convertRGBtoXYZ(int inR, int inG, int inB, float * outX, float * outY, float * outZ) {


    float var_R = (inR / 255.0f); //R from 0 to 255
    float var_G = (inG / 255.0f); //G from 0 to 255
    float var_B = (inB / 255.0f); //B from 0 to 255

    if (var_R > 0.04045f)
        var_R = powf(( (var_R + 0.055f) / 1.055f), 2.4f);
    else 
        var_R = var_R / 12.92f;

    if (var_G > 0.04045)
        var_G = powf(( (var_G + 0.055f) / 1.055f), 2.4f);
    else
        var_G = var_G / 12.92f;

    if (var_B > 0.04045f)
        var_B = powf(( (var_B + 0.055f) / 1.055f), 2.4f);
    else
        var_B = var_B / 12.92f;

    var_R = var_R * 100;
    var_G = var_G * 100;
    var_B = var_B * 100;

    //Observer. = 2°, Illuminant = D65
    *outX = var_R * 0.4124f + var_G * 0.3576f + var_B * 0.1805f;
    *outY = var_R * 0.2126f + var_G * 0.7152f + var_B * 0.0722f;
    *outZ = var_R * 0.0193f + var_G * 0.1192f + var_B * 0.9505f;
}

void convertXYZtoLab(float inX, float inY, float inZ, float * outL, float * outa, float * outb) {

    float var_X = (inX / ref_X); //ref_X = 95.047
    float var_Y = (inY / ref_Y); //ref_Y = 100.0
    float var_Z = (inZ / ref_Z); //ref_Z = 108.883

    if ( var_X > 0.008856 ) 
        var_X = powf(var_X , ( 1.0f/3 )); 
    else 
        var_X = ( 7.787 * var_X ) + ( 16.0f/116 );

    if ( var_Y > 0.008856 )
        var_Y = powf(var_Y , ( 1.0f/3 )); 
    else
        var_Y = ( 7.787 * var_Y ) + ( 16.0f/116 );

    if ( var_Z > 0.008856 )
        var_Z = powf(var_Z , ( 1.0f/3 )); 
    else 
        var_Z = ( 7.787 * var_Z ) + ( 16.0f/116 );

    *outL = ( 116 * var_Y ) - 16;
    *outa = 500 * ( var_X - var_Y );
    *outb = 200 * ( var_Y - var_Z );
}

void convertLabtoXYZ( float inL, float ina, float  inb, float * outX, float * outY, float * outZ) {

    float var_Y = ( inL + 16 ) / 116;
    float var_X = (ina/500) + var_Y;
    float var_Z = var_Y - (inb/200);

    if ( powf(var_Y,3.f) > 0.008856 ) 
        var_Y = powf(var_Y,3.f);
    else
        var_Y = ( var_Y - (16/116) ) / 7.787;

    if ( powf(var_X,3.f) > 0.008856 ) 
        var_X = powf(var_X,3.f);
    else 
        var_X = ( var_X - (16/116) ) / 7.787;

    if ( powf(var_Z,3.f) > 0.008856 )
        var_Z = powf(var_Z,3.f);
    else
        var_Z = ( var_Z - (16/116) ) / 7.787;

    *outX = ref_X * var_X;     //ref_X =  95.047     Observer= 2°, Illuminant= D65
    *outY = ref_Y * var_Y;     //ref_Y = 100.000
    *outZ = ref_Z * var_Z;     //ref_Z = 108.883
}

void convertXYZtoRGB(float inX, float inY, float inZ, int * outR, int * outG, int * outB) {


    float var_X = inX/100;
    float var_Y = inY/100;
    float var_Z = inZ/100;

    float var_R = var_X *  3.2406 + (var_Y * -1.5372) + var_Z * (-0.4986);
    float var_G = var_X * (-0.9689) + var_Y *  1.8758 + var_Z *  0.0415;
    float var_B = var_X *  0.0557 + var_Y * (-0.2040) + var_Z *  1.0570;

    if ( var_R > 0.0031308 )
        var_R = 1.055 * powf(var_R, ( 1.0f / 2.4 ) )  - 0.055;
    else 
        var_R = 12.92 * var_R;

    if ( var_G > 0.0031308 ) 
        var_G = 1.055 * powf(var_G, ( 1.0f / 2.4 ) ) - 0.055;
    else 
        var_G = 12.92 * var_G;

    if ( var_B > 0.0031308 )
        var_B = 1.055 * powf(var_B, ( 1.0f / 2.4 ) ) - 0.055;
    else
        var_B = 12.92 * var_B;

    *outR = (int)(var_R * 255);
    *outG = (int)(var_G * 255);
    *outB = (int)(var_B * 255);


}

float Lab_color_difference( float inL1, float ina1, float  inb1, float inL2, float ina2, float  inb2){
    return( sqrt( powf(inL1 - inL2, 2.f) + powf(ina1 - ina2, 2.f) + powf(inb1 - inb2, 2.f) ) );
}

float RGB_color_Lab_difference( int R1, int G1, int B1, int R2, int G2, int B2){
    float x1=0,y1=0,z1=0;
    float x2=0,y2=0,z2=0;
    float l1=0,a1=0,b1=0;
    float l2=0,a2=0,b2=0;

    convertRGBtoXYZ(R1, G1, B1, &x1, &x1, &z1);
    convertRGBtoXYZ(R2, G2, B2, &x2, &x2, &z2);

    convertXYZtoLab(x1, y1, z1, &l1, &a1, &b1);
    convertXYZtoLab(x2, y2, z2, &l2, &a2, &b2); 

    return( Lab_color_difference(l1 ,a1 ,b1 ,l2 ,a2 ,b2) );
}


void main(int argc, char const *argv[])
{
    int R1,G1,B1,R2,G2,B2;
    float x=0.f,y=0.f,z=0.f;
    float l=0.f,a=0.f,b=0.f;

    R1 = 200;
    G1 = 2;
    B1 = 50; 

    R2 = 200;
    G2 = 2;
    B2 = 70; 

    printf("LAB DISTANCE = %lf \n", RGB_color_Lab_difference(R1,G1,B1,R2,G2,B2) );

    /*convertRGBtoXYZ(R, G, B, &x, &y, &z);
    printf("R =%d,G =%d,B =%d,x =%lf,y =%lf,z =%lf\n",R,G,B,x,y,z );
    convertXYZtoLab(x, y, z, &l, &a, &b);
    printf("x =%lf,y =%lf,z =%lf, l =%lf,a =%lf,b =%lf\n",x,y,z, l,a,b );
    convertLabtoXYZ( l, a, b ,&x, &y, &z);
    printf("x =%lf,y =%lf,z =%lf, l =%lf,a =%lf,b =%lf\n",x,y,z, l,a,b );
    convertXYZtoRGB( x, y, z,&R, &G, &B);
    printf("R =%d,G =%d,B =%d,x =%lf,y =%lf,z =%lf\n",R,G,B,x,y,z );*/

}

C 语言中的颜色转换和差异 https://github.com/gi0rikas/Color-conversions Lab 距离~= 2.3 对应于 JND(只是明显的差异)

#include <stdio.h>
#include <math.h>

float ref_X = 95.047;
float ref_Y = 100.0;
float ref_Z = 108.883;


void convertRGBtoXYZ(int inR, int inG, int inB, float * outX, float * outY, float * outZ) {


    float var_R = (inR / 255.0f); //R from 0 to 255
    float var_G = (inG / 255.0f); //G from 0 to 255
    float var_B = (inB / 255.0f); //B from 0 to 255

    if (var_R > 0.04045f)
        var_R = powf(( (var_R + 0.055f) / 1.055f), 2.4f);
    else 
        var_R = var_R / 12.92f;

    if (var_G > 0.04045)
        var_G = powf(( (var_G + 0.055f) / 1.055f), 2.4f);
    else
        var_G = var_G / 12.92f;

    if (var_B > 0.04045f)
        var_B = powf(( (var_B + 0.055f) / 1.055f), 2.4f);
    else
        var_B = var_B / 12.92f;

    var_R = var_R * 100;
    var_G = var_G * 100;
    var_B = var_B * 100;

    //Observer. = 2°, Illuminant = D65
    *outX = var_R * 0.4124f + var_G * 0.3576f + var_B * 0.1805f;
    *outY = var_R * 0.2126f + var_G * 0.7152f + var_B * 0.0722f;
    *outZ = var_R * 0.0193f + var_G * 0.1192f + var_B * 0.9505f;
}

void convertXYZtoLab(float inX, float inY, float inZ, float * outL, float * outa, float * outb) {

    float var_X = (inX / ref_X); //ref_X = 95.047
    float var_Y = (inY / ref_Y); //ref_Y = 100.0
    float var_Z = (inZ / ref_Z); //ref_Z = 108.883

    if ( var_X > 0.008856 ) 
        var_X = powf(var_X , ( 1.0f/3 )); 
    else 
        var_X = ( 7.787 * var_X ) + ( 16.0f/116 );

    if ( var_Y > 0.008856 )
        var_Y = powf(var_Y , ( 1.0f/3 )); 
    else
        var_Y = ( 7.787 * var_Y ) + ( 16.0f/116 );

    if ( var_Z > 0.008856 )
        var_Z = powf(var_Z , ( 1.0f/3 )); 
    else 
        var_Z = ( 7.787 * var_Z ) + ( 16.0f/116 );

    *outL = ( 116 * var_Y ) - 16;
    *outa = 500 * ( var_X - var_Y );
    *outb = 200 * ( var_Y - var_Z );
}

void convertLabtoXYZ( float inL, float ina, float  inb, float * outX, float * outY, float * outZ) {

    float var_Y = ( inL + 16 ) / 116;
    float var_X = (ina/500) + var_Y;
    float var_Z = var_Y - (inb/200);

    if ( powf(var_Y,3.f) > 0.008856 ) 
        var_Y = powf(var_Y,3.f);
    else
        var_Y = ( var_Y - (16/116) ) / 7.787;

    if ( powf(var_X,3.f) > 0.008856 ) 
        var_X = powf(var_X,3.f);
    else 
        var_X = ( var_X - (16/116) ) / 7.787;

    if ( powf(var_Z,3.f) > 0.008856 )
        var_Z = powf(var_Z,3.f);
    else
        var_Z = ( var_Z - (16/116) ) / 7.787;

    *outX = ref_X * var_X;     //ref_X =  95.047     Observer= 2°, Illuminant= D65
    *outY = ref_Y * var_Y;     //ref_Y = 100.000
    *outZ = ref_Z * var_Z;     //ref_Z = 108.883
}

void convertXYZtoRGB(float inX, float inY, float inZ, int * outR, int * outG, int * outB) {


    float var_X = inX/100;
    float var_Y = inY/100;
    float var_Z = inZ/100;

    float var_R = var_X *  3.2406 + (var_Y * -1.5372) + var_Z * (-0.4986);
    float var_G = var_X * (-0.9689) + var_Y *  1.8758 + var_Z *  0.0415;
    float var_B = var_X *  0.0557 + var_Y * (-0.2040) + var_Z *  1.0570;

    if ( var_R > 0.0031308 )
        var_R = 1.055 * powf(var_R, ( 1.0f / 2.4 ) )  - 0.055;
    else 
        var_R = 12.92 * var_R;

    if ( var_G > 0.0031308 ) 
        var_G = 1.055 * powf(var_G, ( 1.0f / 2.4 ) ) - 0.055;
    else 
        var_G = 12.92 * var_G;

    if ( var_B > 0.0031308 )
        var_B = 1.055 * powf(var_B, ( 1.0f / 2.4 ) ) - 0.055;
    else
        var_B = 12.92 * var_B;

    *outR = (int)(var_R * 255);
    *outG = (int)(var_G * 255);
    *outB = (int)(var_B * 255);


}

float Lab_color_difference( float inL1, float ina1, float  inb1, float inL2, float ina2, float  inb2){
    return( sqrt( powf(inL1 - inL2, 2.f) + powf(ina1 - ina2, 2.f) + powf(inb1 - inb2, 2.f) ) );
}

float RGB_color_Lab_difference( int R1, int G1, int B1, int R2, int G2, int B2){
    float x1=0,y1=0,z1=0;
    float x2=0,y2=0,z2=0;
    float l1=0,a1=0,b1=0;
    float l2=0,a2=0,b2=0;

    convertRGBtoXYZ(R1, G1, B1, &x1, &x1, &z1);
    convertRGBtoXYZ(R2, G2, B2, &x2, &x2, &z2);

    convertXYZtoLab(x1, y1, z1, &l1, &a1, &b1);
    convertXYZtoLab(x2, y2, z2, &l2, &a2, &b2); 

    return( Lab_color_difference(l1 ,a1 ,b1 ,l2 ,a2 ,b2) );
}


void main(int argc, char const *argv[])
{
    int R1,G1,B1,R2,G2,B2;
    float x=0.f,y=0.f,z=0.f;
    float l=0.f,a=0.f,b=0.f;

    R1 = 200;
    G1 = 2;
    B1 = 50; 

    R2 = 200;
    G2 = 2;
    B2 = 70; 

    printf("LAB DISTANCE = %lf \n", RGB_color_Lab_difference(R1,G1,B1,R2,G2,B2) );

    /*convertRGBtoXYZ(R, G, B, &x, &y, &z);
    printf("R =%d,G =%d,B =%d,x =%lf,y =%lf,z =%lf\n",R,G,B,x,y,z );
    convertXYZtoLab(x, y, z, &l, &a, &b);
    printf("x =%lf,y =%lf,z =%lf, l =%lf,a =%lf,b =%lf\n",x,y,z, l,a,b );
    convertLabtoXYZ( l, a, b ,&x, &y, &z);
    printf("x =%lf,y =%lf,z =%lf, l =%lf,a =%lf,b =%lf\n",x,y,z, l,a,b );
    convertXYZtoRGB( x, y, z,&R, &G, &B);
    printf("R =%d,G =%d,B =%d,x =%lf,y =%lf,z =%lf\n",R,G,B,x,y,z );*/

}

Color conversions and differences in C https://github.com/gi0rikas/Color-conversions Lab distance ~= 2.3 corresponds to JND(Just noticeable difference)

川水往事 2024-11-26 13:19:21

该矩阵的右值略有不同,准确的值来自 http://www.brucelindbloom 中的“RGB/XYZ Matrices” .com

sX = sRed * 0.4124564 + sGreen * 0.3575761 + sBlue * 0.1804375
sY = sRed * 0.2126729 + sGreen * 0.7151522 + sBlue * 0.072175
sZ = sRed * 0.0193339 + sGreen * 0.119192 + sBlue * 0.9503041

The right values of this matrix is different slightly,the accurate one from "RGB/XYZ Matrices" in http://www.brucelindbloom.com

sX = sRed * 0.4124564 + sGreen * 0.3575761 + sBlue * 0.1804375
sY = sRed * 0.2126729 + sGreen * 0.7151522 + sBlue * 0.072175
sZ = sRed * 0.0193339 + sGreen * 0.119192 + sBlue * 0.9503041
强辩 2024-11-26 13:19:21

我只是使用您的代码从 RGB(到 XYZ)转换为 La*b*,并且我刚刚发现 XYZ 值应该在 0 到 1 之间,然后再尝试将它们转换为 La*b*

var_R = var_R * 100;
var_G = var_G * 100;
var_B = var_B * 100;

所以前面的代码必须是擦除以获得正确的 La*b* 值。

I just use your code to convert from RGB (to XYZ) to La*b*, and I just found that the XYZ values should go between 0 a 1 before you try to convert them to La*b*

var_R = var_R * 100;
var_G = var_G * 100;
var_B = var_B * 100;

So the previous code must be erased in order to get correct La*b* values.

情泪▽动烟 2024-11-26 13:19:21

正如他们所说:

var_R = ( R / 255 )  ->  var_R = ( R / 255.0 ) or var_R = ( R * 0.003922 ) 
var_G = ( G / 255 )  ->  var_G = ( G / 255.0 ) or var_G = ( G * 0.003922 )
var_B = ( B / 255 )  ->  var_B = ( B / 255.0 ) or var_B = ( B * 0.003922 )

这是因为隐式转换。尽管 var_R、var_G 和 var_B 变量是浮点类型,但 / 运算符看到两个整数 R、G、B 和 255。它必须进行除法并返回一个整数。

为了获得 float 类型值,您可以执行 CAST 或将至少一个变量转换为添加小数点的 float 类型,如下所示:

var_B = (B/255.0f)

RGB2LAB 和 LAB2RGB 转换的另一个示例(请记住,这是 CIE Lab D65):

void RGB2LAB(uint8_t R, uint8_t G, uint8_t B, float *l, float *a, float *b) {
    float RGB[3], XYZ[3];

    RGB[0] = R * 0.003922;
    RGB[1] = G * 0.003922;
    RGB[2] = B * 0.003922;

    RGB[0] = (RGB[0] > 0.04045) ? pow(((RGB[0] + 0.055)/1.055), 2.4) : RGB[0] / 12.92;
    RGB[1] = (RGB[1] > 0.04045) ? pow(((RGB[1] + 0.055)/1.055), 2.4) : RGB[1] / 12.92;
    RGB[2] = (RGB[2] > 0.04045) ? pow(((RGB[2] + 0.055)/1.055), 2.4) : RGB[2] / 12.92;

    XYZ[0] = 0.412424  * RGB[0] + 0.357579 * RGB[1] + 0.180464  * RGB[2];
    XYZ[1] = 0.212656  * RGB[0] + 0.715158 * RGB[1] + 0.0721856 * RGB[2];
    XYZ[2] = 0.0193324 * RGB[0] + 0.119193 * RGB[1] + 0.950444  * RGB[2];

    *l = 116 * ( ( XYZ[1] / 1.000000) > 0.008856 ? pow(XYZ[1] / 1.000000, 0.333333) : 7.787 * XYZ[1] / 1.000000 + 0.137931) - 16;
    *a = 500 * ( ((XYZ[0] / 0.950467) > 0.008856 ? pow(XYZ[0] / 0.950467, 0.333333) : 7.787 * XYZ[0] / 0.950467 + 0.137931) - ((XYZ[1] / 1.000000) > 0.008856 ? pow(XYZ[1] / 1.000000, 0.333333) : 7.787 * XYZ[1] / 1.000000 + 0.137931) );
    *b = 200 * ( ((XYZ[1] / 1.000000) > 0.008856 ? pow(XYZ[1] / 1.000000, 0.333333) : 7.787 * XYZ[1] / 1.000000 + 0.137931) - ((XYZ[2] / 1.088969) > 0.008856 ? pow(XYZ[2] / 1.088969, 0.333333) : 7.787 * XYZ[2] / 1.088969 + 0.137931) );
}

void LAB2RGB(float L, float A, float B, uint8_t *r, uint8_t *g, uint8_t *b) {
    float XYZ[3], RGB[3];

    XYZ[1] = (L + 16 ) / 116;
    XYZ[0] = A / 500 + XYZ[1];
    XYZ[2] = XYZ[1] - B / 200;

    XYZ[1] = (XYZ[1]*XYZ[1]*XYZ[1] > 0.008856) ? XYZ[1]*XYZ[1]*XYZ[1] : (XYZ[1] - (16 / 116)) / 7.787;
    XYZ[0] = (XYZ[0]*XYZ[0]*XYZ[0] > 0.008856) ? XYZ[0]*XYZ[0]*XYZ[0] : (XYZ[0] - (16 / 116)) / 7.787;
    XYZ[2] = (XYZ[2]*XYZ[2]*XYZ[2] > 0.008856) ? XYZ[2]*XYZ[2]*XYZ[2] : (XYZ[2] - (16 / 116)) / 7.787;

    RGB[0] = 0.950467 * XYZ[0] *  3.2406 + 1.000000 * XYZ[1] * -1.5372 + 1.088969 * XYZ[2] * -0.4986;
    RGB[1] = 0.950467 * XYZ[0] * -0.9689 + 1.000000 * XYZ[1] *  1.8758 + 1.088969 * XYZ[2] *  0.0415;
    RGB[2] = 0.950467 * XYZ[0] *  0.0557 + 1.000000 * XYZ[1] * -0.2040 + 1.088969 * XYZ[2] *  1.0570;

    *r = (255 * ( (RGB[0] > 0.0031308) ? 1.055 * (pow(RGB[0], (1/2.4)) - 0.055) : RGB[0] * 12.92 ));
    *g = (255 * ( (RGB[1] > 0.0031308) ? 1.055 * (pow(RGB[1], (1/2.4)) - 0.055) : RGB[1] * 12.92 ));
    *b = (255 * ( (RGB[2] > 0.0031308) ? 1.055 * (pow(RGB[2], (1/2.4)) - 0.055) : RGB[2] * 12.92 ));
}

As they said:

var_R = ( R / 255 )  ->  var_R = ( R / 255.0 ) or var_R = ( R * 0.003922 ) 
var_G = ( G / 255 )  ->  var_G = ( G / 255.0 ) or var_G = ( G * 0.003922 )
var_B = ( B / 255 )  ->  var_B = ( B / 255.0 ) or var_B = ( B * 0.003922 )

This is because of implicit conversion. Despite the fact that var_R, var_G and var_B variables are float type, the / operator sees two integers R, G, B and 255. it has to divide and returns an integer.

In order to get a float type value you can do a CAST or convert at least one of the variables into float type adding of a decimal point as follows:

var_B = ( B / 255.0f)

Another example of RGB2LAB and LAB2RGB conversion (bear in mind that is CIE Lab D65):

void RGB2LAB(uint8_t R, uint8_t G, uint8_t B, float *l, float *a, float *b) {
    float RGB[3], XYZ[3];

    RGB[0] = R * 0.003922;
    RGB[1] = G * 0.003922;
    RGB[2] = B * 0.003922;

    RGB[0] = (RGB[0] > 0.04045) ? pow(((RGB[0] + 0.055)/1.055), 2.4) : RGB[0] / 12.92;
    RGB[1] = (RGB[1] > 0.04045) ? pow(((RGB[1] + 0.055)/1.055), 2.4) : RGB[1] / 12.92;
    RGB[2] = (RGB[2] > 0.04045) ? pow(((RGB[2] + 0.055)/1.055), 2.4) : RGB[2] / 12.92;

    XYZ[0] = 0.412424  * RGB[0] + 0.357579 * RGB[1] + 0.180464  * RGB[2];
    XYZ[1] = 0.212656  * RGB[0] + 0.715158 * RGB[1] + 0.0721856 * RGB[2];
    XYZ[2] = 0.0193324 * RGB[0] + 0.119193 * RGB[1] + 0.950444  * RGB[2];

    *l = 116 * ( ( XYZ[1] / 1.000000) > 0.008856 ? pow(XYZ[1] / 1.000000, 0.333333) : 7.787 * XYZ[1] / 1.000000 + 0.137931) - 16;
    *a = 500 * ( ((XYZ[0] / 0.950467) > 0.008856 ? pow(XYZ[0] / 0.950467, 0.333333) : 7.787 * XYZ[0] / 0.950467 + 0.137931) - ((XYZ[1] / 1.000000) > 0.008856 ? pow(XYZ[1] / 1.000000, 0.333333) : 7.787 * XYZ[1] / 1.000000 + 0.137931) );
    *b = 200 * ( ((XYZ[1] / 1.000000) > 0.008856 ? pow(XYZ[1] / 1.000000, 0.333333) : 7.787 * XYZ[1] / 1.000000 + 0.137931) - ((XYZ[2] / 1.088969) > 0.008856 ? pow(XYZ[2] / 1.088969, 0.333333) : 7.787 * XYZ[2] / 1.088969 + 0.137931) );
}

void LAB2RGB(float L, float A, float B, uint8_t *r, uint8_t *g, uint8_t *b) {
    float XYZ[3], RGB[3];

    XYZ[1] = (L + 16 ) / 116;
    XYZ[0] = A / 500 + XYZ[1];
    XYZ[2] = XYZ[1] - B / 200;

    XYZ[1] = (XYZ[1]*XYZ[1]*XYZ[1] > 0.008856) ? XYZ[1]*XYZ[1]*XYZ[1] : (XYZ[1] - (16 / 116)) / 7.787;
    XYZ[0] = (XYZ[0]*XYZ[0]*XYZ[0] > 0.008856) ? XYZ[0]*XYZ[0]*XYZ[0] : (XYZ[0] - (16 / 116)) / 7.787;
    XYZ[2] = (XYZ[2]*XYZ[2]*XYZ[2] > 0.008856) ? XYZ[2]*XYZ[2]*XYZ[2] : (XYZ[2] - (16 / 116)) / 7.787;

    RGB[0] = 0.950467 * XYZ[0] *  3.2406 + 1.000000 * XYZ[1] * -1.5372 + 1.088969 * XYZ[2] * -0.4986;
    RGB[1] = 0.950467 * XYZ[0] * -0.9689 + 1.000000 * XYZ[1] *  1.8758 + 1.088969 * XYZ[2] *  0.0415;
    RGB[2] = 0.950467 * XYZ[0] *  0.0557 + 1.000000 * XYZ[1] * -0.2040 + 1.088969 * XYZ[2] *  1.0570;

    *r = (255 * ( (RGB[0] > 0.0031308) ? 1.055 * (pow(RGB[0], (1/2.4)) - 0.055) : RGB[0] * 12.92 ));
    *g = (255 * ( (RGB[1] > 0.0031308) ? 1.055 * (pow(RGB[1], (1/2.4)) - 0.055) : RGB[1] * 12.92 ));
    *b = (255 * ( (RGB[2] > 0.0031308) ? 1.055 * (pow(RGB[2], (1/2.4)) - 0.055) : RGB[2] * 12.92 ));
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文