четверг, 17 января 2013 г.

LCH Color Model. Photoshop blend modes: Hue, Saturation, Color

Wikipedia:

  • The Hue blend mode preserves the luma and chroma of the bottom layer, while adopting the hue of the top layer.
  • The Saturation blend mode preserves the luma and hue of the bottom layer, while adopting the chroma of the top layer.
  • The Color blend mode preserves the luma of the bottom layer, while adopting the hue and chroma of the top layer.


Good. But what is "Luma", "chroma", "hue"? This is CIE LCH color model.

Converting from RGB:
RGB --> XYZ --> LAB --> LCH and back.


#define min(a,b) (((a) < (b)) ? (a) : (b))
#define max(a,b) (((a) > (b)) ? (a) : (b))

typedef int uint8_t;

typedef struct { //Android RGBA format #AARRGGBB
    uint8_t red;
    uint8_t green;
    uint8_t blue;
    uint8_t alpha;
} argb;

#define WHITEPOINT_X 0.950456
#define WHITEPOINT_Y 1.0
#define WHITEPOINT_Z 1.088754
#define MIN3(A,B,C) (((A) <= (B)) ? min(A,C) : min(B,C))

#define INVGAMMACORRECTION(t) (((t) <= 0.0404482362771076)? ((t)/12.92) : pow(((t) + 0.055)/1.055, 2.4))
#define GAMMACORRECTION(t) (((t) <= 0.0031306684425005883) ? (12.92*(t)) : (1.055*pow((t), 0.416666666666666667) - 0.055))
#define LABF(t) ((t >= 8.85645167903563082e-3) ? pow(t,0.333333333333333) : (841.0/108.0)*(t) + (4.0/29.0))
#define LABINVF(t) ((t >= 0.206896551724137931) ? ((t)*(t)*(t)) : (108.0/841.0)*((t) - (4.0/29.0)))

#define MIN3(A,B,C) (((A) <= (B)) ? min(A,C) : min(B,C))
#define MAX3(A,B,C) (((A) >= (B)) ? max(A,C) : max(B,C))

static void Rgb2Xyz(double *X, double *Y, double *Z, double R, double G, double B)
{
R = INVGAMMACORRECTION(R);
G = INVGAMMACORRECTION(G);
B = INVGAMMACORRECTION(B);
*X = (double)(0.4123955889674142161*R + 0.3575834307637148171*G + 0.1804926473817015735*B);
*Y = (double)(0.2125862307855955516*R + 0.7151703037034108499*G + 0.07220049864333622685*B);
*Z = (double)(0.01929721549174694484*R + 0.1191838645808485318*G + 0.9504971251315797660*B);
}

static void Xyz2Lab(double *L, double *a, double *b, double X, double Y, double Z)
{
X /= WHITEPOINT_X;
Y /= WHITEPOINT_Y;
Z /= WHITEPOINT_Z;
X = LABF(X);
Y = LABF(Y);
Z = LABF(Z);
*L = 116*Y - 16;
*a = 500*(X - Y);
*b = 200*(Y - Z);
}

static void Xyz2Lch(double *L, double *C, double *H, double X, double Y, double Z)
{
double a, b;
Xyz2Lab(L, &a, &b, X, Y, Z);
*C = sqrt(a*a + b*b);
*H = atan2(b, a)*180.0/M_PI;
if(*H < 0)
*H += 360;
}

static void Rgb2Lch(double *L, double *C, double *H, double R, double G, double B)
{
double X, Y, Z;
Rgb2Xyz(&X, &Y, &Z, R, G, B);
Xyz2Lch(L, C, H, X, Y, Z);
}

void Lab2Xyz(double *X, double *Y, double *Z, double L, double a, double b)
{
L = (L + 16)/116;
a = L + a/500;
b = L - b/200;
*X = WHITEPOINT_X*LABINVF(a);
*Y = WHITEPOINT_Y*LABINVF(L);
*Z = WHITEPOINT_Z*LABINVF(b);
}


static void Lch2Xyz(double *X, double *Y, double *Z, double L, double C, double H)
{
double a = C * cos(H*(M_PI/180.0));
double b = C * sin(H*(M_PI/180.0));
Lab2Xyz(X, Y, Z, L, a, b);
}

static void Xyz2Rgb(double *R, double *G, double *B, double X, double Y, double Z)
{
double R_1, B_1, G_1, Min;
R_1 = (double)( 3.2406*X - 1.5372*Y - 0.4986*Z);
G_1 = (double)(-0.9689*X + 1.8758*Y + 0.0415*Z);
B_1 = (double)( 0.0557*X - 0.2040*Y + 1.0570*Z);
Min = MIN3(R_1, G_1, B_1);
    
if(Min < 0) {
R_1 -= Min;
G_1 -= Min;
B_1 -= Min;
}
    
*R = GAMMACORRECTION(R_1);
*G = GAMMACORRECTION(G_1);
*B = GAMMACORRECTION(B_1);
    
    *R = max(*R, 0);
    *R = min(*R, 1);
    *G = max(*G, 0);
    *G = min(*G, 1);
    *B = max(*B, 0);
    *B = min(*B, 1);
}


static void Lch2Rgb(double *R, double *G, double *B, double L, double C, double H)
{
double X, Y, Z;
Lch2Xyz(&X, &Y, &Z, L, C, H);
Xyz2Rgb(R, G, B, X, Y, Z);
}

note!

You can use HSV/HSL transformation instead the RGBtoLCH. But!

LCH color model (Photoshop)


HSV/HSL color model (GIMP)



Комментариев нет:

Отправить комментарий