Показаны сообщения с ярлыком cpp. Показать все сообщения
Показаны сообщения с ярлыком cpp. Показать все сообщения

четверг, 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)



среда, 31 октября 2012 г.

Blend Modes: How to convert HSV <--> RGB and apply Hue/Saturation filters?


Step 1: RGB to HSV;
Step 2: Blending;
Step 3: HSV to RGB.

Blends:

  • 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.
  • The Luminosity blend mode preserves the hue and chroma of the bottom layer, while adopting the luma of the top layer.


#define ROUND(x) ((int) ((x) + 0.5))
void rgb_to_hsv (    int *red,
                     int *green,
                     int *blue)
{
    double  r, g, b;
    double  h, s, v;
    int     min;
    double  delta;
    
    r = *red;
    g = *green;
    b = *blue;
    
    if (r > g)
    {
        v = max(r, b);
        min = min(g, b);
    }
    else
    {
        v = max (g, b);
        min = min (r, b);
    }
    
    delta = v - min;
    
    if (v == 0.0)
        s = 0.0;
    else
        s = delta / v;
    
    if (s == 0.0)
    {
        h = 0.0;
    }
    else
    {
        if (r == v)
            h = 60.0 * (g - b) / delta;
        else if (g == v)
            h = 120 + 60.0 * (b - r) / delta;
        else
            h = 240 + 60.0 * (r - g) / delta;
        
        if (h < 0.0)
            h += 360.0;
        
        if (h > 360.0)
            h -= 360.0;
    }
    
    *red   = ROUND (h);
    *green = ROUND (s * 255.0);
    *blue  = ROUND (v);
    
    if (*red == 360)
        *red = 0;
}

void hsv_to_rgb (    int *hue,
                     int *saturation,
                     int *value)
{
    double h, s, v, h_temp;
    double f, p, q, t;
    int i;
    
    if (*saturation == 0)
    {
        *hue        = *value;
        *saturation = *value;
        *value      = *value;
    }
    else
    {
        h = *hue;
        s = *saturation / 255.0;
        v = *value      / 255.0;
        
        if (h == 360)
            h_temp = 0;
        else
            h_temp = h;
        
        h_temp = h_temp / 60.0;
        i = floor (h_temp);
        f = h_temp - i;
        p = v * (1.0 - s);
        q = v * (1.0 - (s * f));
        t = v * (1.0 - (s * (1.0 - f)));
        
        switch (i)
        {
            case 0:
                *hue        = ROUND (v * 255.0);
                *saturation = ROUND (t * 255.0);
                *value      = ROUND (p * 255.0);
                break;
                
            case 1:
                *hue        = ROUND (q * 255.0);
                *saturation = ROUND (v * 255.0);
                *value      = ROUND (p * 255.0);
                break;
                
            case 2:
                *hue        = ROUND (p * 255.0);
                *saturation = ROUND (v * 255.0);
                *value      = ROUND (t * 255.0);
                break;
                
            case 3:
                *hue        = ROUND (p * 255.0);
                *saturation = ROUND (q * 255.0);
                *value      = ROUND (v * 255.0);
                break;
                
            case 4:
                *hue        = ROUND (t * 255.0);
                *saturation = ROUND (p * 255.0);
                *value      = ROUND (v * 255.0);
                break;
                
            case 5:
                *hue        = ROUND (v * 255.0);
                *saturation = ROUND (p * 255.0);
                *value      = ROUND (q * 255.0);
                break;
        }
    }
}

void hueLayers (int *rs, int  *gs, int *bs, int  *rd, int  *gd, int *bd)
{
    rgb_to_hsv(rs, gs, bs);
    rgb_to_hsv(rd, gd, bd);
    
    hsv_to_rgb(rs, gd, bd);
    *gs = *gd;
    *bs = *bd;
}


void satLayers (int *rs, int  *gs, int *bs, int  *rd, int  *gd, int *bd)
{
    rgb_to_hsv(rs, gs, bs);
    rgb_to_hsv(rd, gd, bd);
    
    hsv_to_rgb(rd, gs, bd);
    *rs = *rd;
    *bs = *bd;
}

//Tests
void saturationTest(){

    int sr = (int)(0x55);
    int sg = (int)(0x66);
    int sb = (int)(0x77);

    int dr = (int)0xAA;
    int dg = (int)0xFF;
    int db = (int)0x99;
    
    int bgr = dr;
    int bgg = dg;
    int bgb = db;
    
    float a = 0.5f;

    satLayers(&sr, &sg, &sb, &dr, &dg, &db);
    printf("   SaturationBlend = #%02X %02X %02X \n", sr, sg, sb);
}

void hueTest(){
    
    int sr = (int)(0x55);
    int sg = (int)(0x66);
    int sb = (int)(0x77);
    
    int dr = (int)0xAA;
    int dg = (int)0xFF;
    int db = (int)0x99;
    
    int bgr = dr;
    int bgg = dg;
    int bgb = db;
    
    float a = 0.25f;
    
    hueLayers(&sr, &sg, &sb, &dr, &dg, &db);
    printf("   HUE Blend = #%02X %02X %02X \n", sr, sg, sb);
}