LYGIA Shader Library

distance (lygia/color/distance)

Perceptual distance between two color according to CIE94 https://en.wikipedia.org/wiki/Color_difference#CIE94

Dependencies:

Use:

colorDistance(<vec3|vec4> rgbA, <vec3|vec4> rgbA)

Check it on Github



#ifndef COLORDISTANCE_FNC
#define COLORDISTANCE_FNC colorDistanceLABCIE94
#endif

#ifndef FNC_PERCEPTUALDISTANCE
#define FNC_PERCEPTUALDISTANCE
float colorDistanceLABCIE94(in vec3 rgb1, in vec3 rgb2) {
    vec3 lab1 = rgb2lab(rgb1);
    vec3 lab2 = rgb2lab(rgb2);

    vec3 delta = lab1 - lab2;
    float c1 = sqrt(lab1.y * lab1.y + lab1.z * lab1.z);
    float c2 = sqrt(lab2.y * lab2.y + lab2.z * lab2.z);
    float delta_c = c1 - c2;
    float delta_h = delta.x * delta.x + delta.z * delta.z - delta_c * delta_c;
    delta_h = mix( 0., sqrt(delta_h), step(0.,delta_h));

    float sc = 1. +.045 * c1;
    float sh = 1. + .015 * c1;

    float delta_ckcsc = delta_c / sc;
    float delta_hkhsh = delta_h / sh;

    float delta_e = delta.x * delta.x + delta_ckcsc * delta_ckcsc + delta_hkhsh * delta_hkhsh;
    return mix( 0., sqrt(delta_e), step(0.,delta_e));
}

float colorDistanceLAB(in vec3 rgb1, in vec3 rgb2)    { return distance(rgb2lab(rgb1), rgb2lab(rgb2)); }
float colorDistanceYCbCr(in vec3 rgb1, in vec3 rgb2)  { return distance(rgb2YCbCr(rgb1).yz, rgb2YCbCr(rgb2).yz); }
float colorDistanceYPbPr(in vec3 rgb1, in vec3 rgb2)  { return distance(rgb2YPbPr(rgb1).yz, rgb2YPbPr(rgb2).yz); }
float colorDistanceYUV(in vec3 rgb1, in vec3 rgb2)    { return distance(rgb2yuv(rgb1), rgb2yuv(rgb2)); }
float colorDistanceOKLAB(in vec3 rgb1, in vec3 rgb2)  { return distance(rgb2oklab(rgb1), rgb2oklab(rgb2)); }

float colorDistance(in vec3 rgb1, in vec3 rgb2)       { return COLORDISTANCE_FNC(rgb1, rgb2); }
float colorDistance(in vec4 rgb1, in vec4 rgb2)       { return COLORDISTANCE_FNC(rgb1.rgb, rgb2.rgb); }
#endif

Dependencies:

Use:

colorDistance(<float3|float4> rgbA, <float3|float4> rgbA)

Check it on Github



#ifndef COLORDISTANCE_FNC
#define COLORDISTANCE_FNC colorDistanceLABCIE94
#endif

#ifndef FNC_PERCEPTUALDISTANCE
#define FNC_PERCEPTUALDISTANCE
float colorDistanceLABCIE94(in float3 rgb1, in float3 rgb2) {
    float3 lab1 = rgb2lab(rgb1);
    float3 lab2 = rgb2lab(rgb2);

    float3 delta = lab1 - lab2;
    float c1 = sqrt(lab1.y * lab1.y + lab1.z * lab1.z);
    float c2 = sqrt(lab2.y * lab2.y + lab2.z * lab2.z);
    float delta_c = c1 - c2;
    float delta_h = delta.x * delta.x + delta.z * delta.z - delta_c * delta_c;
    delta_h = lerp( 0., sqrt(delta_h), step(0.,delta_h));

    float sc = 1. +.045 * c1;
    float sh = 1. + .015 * c1;

    float delta_ckcsc = delta_c / sc;
    float delta_hkhsh = delta_h / sh;

    float delta_e = delta.x * delta.x + delta_ckcsc * delta_ckcsc + delta_hkhsh * delta_hkhsh;
    return lerp( 0., sqrt(delta_e), step(0.,delta_e));
}

float colorDistanceLAB(in float3 rgb1, in float3 rgb2)    { return distance(rgb2lab(rgb1), rgb2lab(rgb2)); }
float colorDistanceYCbCr(in float3 rgb1, in float3 rgb2)  { return distance(rgb2YCbCr(rgb1).yz, rgb2YCbCr(rgb2).yz); }
float colorDistanceYPbPr(in float3 rgb1, in float3 rgb2)  { return distance(rgb2YPbPr(rgb1).yz, rgb2YPbPr(rgb2).yz); }
float colorDistanceYUV(in float3 rgb1, in float3 rgb2)    { return distance(rgb2yuv(rgb1), rgb2yuv(rgb2)); }
float colorDistanceOKLAB(in float3 rgb1, in float3 rgb2)  { return distance(rgb2oklab(rgb1), rgb2oklab(rgb2)); }

float colorDistance(in float3 rgb1, in float3 rgb2)       { return COLORDISTANCE_FNC(rgb1, rgb2); }
float colorDistance(in float4 rgb1, in float4 rgb2)       { return COLORDISTANCE_FNC(rgb1.rgb, rgb2.rgb); }
#endif

Dependencies:

Use:

colorDistance(<float3|float4> rgbA, <float3|float4> rgbA)

Check it on Github



#ifndef COLORDISTANCE_FNC
#define COLORDISTANCE_FNC colorDistanceLABCIE94
#endif

#ifndef FNC_PERCEPTUALDISTANCE
#define FNC_PERCEPTUALDISTANCE
float colorDistanceLABCIE94(float3 rgb1, float3 rgb2) {
    float3 lab1 = rgb2lab(rgb1);
    float3 lab2 = rgb2lab(rgb2);

    float3 delta = lab1 - lab2;
    float c1 = sqrt(lab1.y * lab1.y + lab1.z * lab1.z);
    float c2 = sqrt(lab2.y * lab2.y + lab2.z * lab2.z);
    float delta_c = c1 - c2;
    float delta_h = delta.x * delta.x + delta.z * delta.z - delta_c * delta_c;
    delta_h = mix( 0., sqrt(delta_h), step(0.,delta_h));

    float sc = 1. +.045 * c1;
    float sh = 1. + .015 * c1;

    float delta_ckcsc = delta_c / sc;
    float delta_hkhsh = delta_h / sh;

    float delta_e = delta.x * delta.x + delta_ckcsc * delta_ckcsc + delta_hkhsh * delta_hkhsh;
    return mix( 0., sqrt(delta_e), step(0.,delta_e));
}

float colorDistanceLAB(float3 rgb1, float3 rgb2)    { return distance(rgb2lab(rgb1), rgb2lab(rgb2)); }
float colorDistanceYCbCr(float3 rgb1, float3 rgb2)  { return distance(rgb2YCbCr(rgb1).yz, rgb2YCbCr(rgb2).yz); }
float colorDistanceYPbPr(float3 rgb1, float3 rgb2)  { return distance(rgb2YPbPr(rgb1).yz, rgb2YPbPr(rgb2).yz); }
float colorDistanceYUV(float3 rgb1, float3 rgb2)    { return distance(rgb2yuv(rgb1), rgb2yuv(rgb2)); }
float colorDistanceOKLAB(float3 rgb1, float3 rgb2)  { return distance(rgb2oklab(rgb1), rgb2oklab(rgb2)); }

float colorDistance(float3 rgb1, float3 rgb2)       { return COLORDISTANCE_FNC(rgb1, rgb2); }
float colorDistance(float4 rgb1, float4 rgb2)       { return COLORDISTANCE_FNC(rgb1.rgb, rgb2.rgb); }
#endif

Dependencies:

Use:

colorDistance(<vec3|vec4> rgbA, <vec3|vec4> rgbA)

Check it on Github



fn colorDistanceLABCIE94(rgb1 : vec3<f32>, rgb2 : vec3<f32>) -> f32 {
    let lab1 = rgb2lab(rgb1);
    let lab2 = rgb2lab(rgb2);

    let delta = lab1 - lab2;
    let c1 = sqrt(lab1.y * lab1.y + lab1.z * lab1.z);
    let c2 = sqrt(lab2.y * lab2.y + lab2.z * lab2.z);
    let delta_c = c1 - c2;
    var delta_h = delta.x * delta.x + delta.z * delta.z - delta_c * delta_c;
    delta_h = mix(0., sqrt(delta_h), step(0., delta_h));

    let sc = 1. + .045 * c1;
    let sh = 1. + .015 * c1;

    let delta_ckcsc = delta_c / sc;
    let delta_hkhsh = delta_h / sh;

    let delta_e = delta.x * delta.x + delta_ckcsc * delta_ckcsc + delta_hkhsh * delta_hkhsh;
    return mix(0., sqrt(delta_e), step(0., delta_e));
}

fn colorDistanceLAB(rgb1 : vec3<f32>, rgb2 : vec3<f32>) -> f32 {
    return distance(rgb2lab(rgb1), rgb2lab(rgb2));
}
fn colorDistanceYCbCr(rgb1 : vec3<f32>, rgb2 : vec3<f32>) -> f32 {
    return distance(rgb2YCbCr(rgb1).yz, rgb2YCbCr(rgb2).yz);
}
fn colorDistanceYPbPr(rgb1 : vec3<f32>, rgb2 : vec3<f32>) -> f32 {
    return distance(rgb2YPbPr(rgb1).yz, rgb2YPbPr(rgb2).yz);
}
fn colorDistanceYUV(rgb1 : vec3<f32>, rgb2 : vec3<f32>) -> f32 {
    return distance(rgb2yuv(rgb1), rgb2yuv(rgb2));
}
fn colorDistanceOKLAB(rgb1 : vec3<f32>, rgb2 : vec3<f32>) -> f32 {
    return distance(rgb2oklab(rgb1), rgb2oklab(rgb2));
}

Licenses

LYGIA is dual-licensed under the Prosperity License and the Patron License for sponsors and contributors.

Sponsors and contributors are automatically added to the Patron License and they can ignore the any non-commercial rule of the Prosperity Licensed software (please take a look to the exception).

It's also possible to get a permanent comercial license hook to a single and specific version of LYGIA.

Get the latest news and releases

Sign up for the news letter bellow, joing the LYGIA's channel on Discord or follow the Github repository