PDA

View Full Version : تبدیل RGB به CIELab و برعکس...



IamOverlord
جمعه 03 مرداد 1393, 13:31 عصر
سلام دوستان!
یه کدی رو به ‌++C نوشتم (در اصل تبدیل کردم...) که برای تبدیل ‌‌RGB به CIELab هست و برعکس... اما خطا داره! مثلا RGB 220,60,100 رو تبدیل می کنه به CIELab 53.8048 66.4264 15.4166 و بعد این رو تبدیل می کنه به RGB 232 63 105...
می خواستم بدونم کسی یه نسخه ی بهترش رو داره؟!

void RGB2Lab (unsigned char R, unsigned char G, unsigned char B, double* L, double* a, double* b){
double var_R = ( (double)R / 255 ); //R from 0 to 255
double var_G = ( (double)G / 255 ); //G from 0 to 255
double var_B = ( (double)B / 255 ); //B from 0 to 255


if ( var_R > 0.04045 ) var_R = pow ( var_R + 0.055 / 1.055 , 2.4);
else var_R = var_R / 12.92;
if ( var_G > 0.04045 ) var_G = pow ( var_G + 0.055 / 1.055 , 2.4);
else var_G = var_G / 12.92;
if ( var_B > 0.04045 ) var_B = pow ( 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
double X = var_R * 0.4124 + var_G * 0.3576 + var_B * 0.1805;
double Y = var_R * 0.2126 + var_G * 0.7152 + var_B * 0.0722;
double Z = var_R * 0.0193 + var_G * 0.1192 + var_B * 0.9505;



double ref_X = 95.047;
double ref_Y = 100;
double ref_Z = 108.833;

double var_X = X / ref_X; //ref_X = 95.047 Observer= 2°, Illuminant= D65
double var_Y = Y / ref_Y; //ref_Y = 100.000
double var_Z = Z / ref_Z; //ref_Z = 108.883


if ( var_X > 0.008856 ) var_X = pow(var_X , 1.0/3.0 );
else var_X = ( 7.787 * var_X ) + ( 16.0 / 116.0 );
if ( var_Y > 0.008856 ) var_Y = pow(var_Y , 1.0/3.0 );
else var_Y = ( 7.787 * var_Y ) + ( 16.0 / 116.0 );
if ( var_Z > 0.008856 ) var_Z = pow(var_Z , 1.0/3.0 );
else var_Z = ( 7.787 * var_Z ) + ( 16.0 / 116.0 );


*L = ( 116 * var_Y ) - 16;
*a = 500 * ( var_X - var_Y );
*b = 200 * ( var_Y - var_Z );

}










void Lab2RGB (double L, double a, double b, unsigned char* R, unsigned char* G, unsigned char* B)
{
double var_Y = ( L + 16 ) / 116;
double var_X = a / 500 + var_Y;
double var_Z = var_Y - b / 200;


if ( pow(var_Y, 3) > 0.008856 ) var_Y = pow(var_Y, 3);
else var_Y = ( var_Y - 16 / 116 ) / 7.787;
if ( pow(var_X, 3) > 0.008856 ) var_X = pow(var_X, 3);
else var_X = ( var_X - 16 / 116 ) / 7.787;
if ( pow(var_Z, 3) > 0.008856 ) var_Z = pow(var_Z, 3);
else var_Z = ( var_Z - 16 / 116 ) / 7.787;


double ref_X = 95.047;
double ref_Y = 100;
double ref_Z = 108.833;


double X = ref_X * var_X; //ref_X = 95.047 Observer= 2°, Illuminant= D65
double Y = ref_Y * var_Y; //ref_Y = 100.000
double Z = ref_Z * var_Z; //ref_Z = 108.883





var_X = X / 100; //X from 0 to 95.047 (Observer = 2°, Illuminant = D65)
var_Y = Y / 100; //Y from 0 to 100.000
var_Z = Z / 100; //Z from 0 to 108.883


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





if ( var_R > 0.0031308 ) var_R = 1.055 * pow( var_R , 1 / 2.4 ) - 0.055;
else var_R = 12.92 * var_R;
if ( var_G > 0.0031308 ) var_G = 1.055 * pow( var_G , 1 / 2.4 ) - 0.055;
else var_G = 12.92 * var_G;
if ( var_B > 0.0031308 ) var_B = 1.055 * pow( var_B , 1 / 2.4 ) - 0.055;
else var_B = 12.92 * var_B;


*R =(unsigned char) (var_R * 255);
*G =(unsigned char) (var_G * 255);
*B =(unsigned char) (var_B * 255);
}

IamOverlord
جمعه 03 مرداد 1393, 16:25 عصر
سلام دوستان!
فکر کنم درستش کردم!:
(Xn و Yn و Zn رو ببینید... ضمنا صحت کد رو اگه بشه چک کنید ممنون می شم!)
double ft(double t) { if (t>0.008856) return pow(t, 1.0/3.0);
else return 7.787 * t + 16.0/116.0;
}


void RGB2Lab (unsigned char R, unsigned char G, unsigned char B, double* L, double* a, double* b)
{
// Here Xn, Yn and Zn are the tristimulus values of the reference white.
double Xn = 95.047/100;
double Yn = 1;
double Zn = 108.883/100;

// RGB to XYZ
double X = (double)R/255.0 * 0.412453 + (double)G/255.0 * 0.357580 + (double)B/255.0 * 0.180423;
double Y = (double)R/255.0 * 0.212671 + (double)G/255.0 * 0.715160 + (double)B/255.0 * 0.072169;
double Z = (double)R/255.0 * 0.019334 + (double)G/255.0 * 0.119193 + (double)B/255.0 * 0.950227;

// XYZ to CIELAB
if (Y/Yn > 0.008856)
*L = 116 * pow(Y/Yn, 1.0/3.0) - 16;
else
*L = 903.3 * Y/Yn;
*a = 500 * (ft(X/Xn) - ft(Y/Yn));
*b = 200 * (ft(Y/Yn) - ft(Z/Zn));
}


void Lab2RGB (double L, double a, double b, unsigned char* R, unsigned char* G, unsigned char* B)
{
double Xn = 95.047/100;
double Yn = 1;
double Zn = 108.883/100;

// CIELAB to XYZ
double X = Xn * pow((L+16)/116.0+a/500.0, 3);
double Y = Yn * pow((L+16)/116.0, 3);
double Z = Zn * pow((L+16)/116.0-b/200.0, 3);


// XYZ to RGB
*R = (X * 3.240479 + Y * -1.537150 + Z * -0.498535) * 255;
*G = (X * -0.969256 + Y * 1.875992 + Z * 0.041556) * 255;
*B = (X * 0.055648 + Y * -0.204043 + Z * 1.057311) * 255;
}