Color Gradient Algorithm in Lab Color Space

Let's say I have two colors in Lab color space -

Color 1: L = 81, a = -8, b = 74
Color 2: L = 64, a = -14, b = 3

I want to create n colors in between. For example, n = 100 or as many colors in between as possible.

I know RGB and HSV color gradient algorithm. But I want to create a gradient in LAB color spaces. I don't want to convert colors to HSV or RGB as different color models generate different gradients.

This is a link I found that generates a gradient in Lab and other color models: http://davidjohnstone.net/pages/lch-lab-colour-gradient-picker

I'm trying to do something like this in Java, but the language doesn't matter, I just need to understand the logic and algorithm behind it.

I do this mainly to match the scanned color value with a chart of 5 colors that I have. So, I must first create all the colors between these 5 colors (using a gradient) and compare another color to find the one that is closest to it. (For comparison, I am using the CIEDE2000 Delta-e method). But this is secondary, I think.


Adding to the last part of my question

I am guessing that I will need to create a gradient because I want to find the exact location of a color from my swatch in a diagram sequence I have.

For example, I have 6 shades of green (light to dark) in my chart, each corresponding to a specific numerical data from 0 to 450 mg as shown below (with LAB values)

Color 1: 78, -10, -71 [0 mg]
Color 2: 73,-14,44 [30 mg]
Color 3: 71, -19, 53 [80 mg]
Color 4: 67, -18, 31 [160 mg]
Color 5: 69, -2, 29  [300 mg]
Color 6: 61, -14, 3 [450 mg]

      

Now I want to generate all the colors in between and find the location of my scanned color and return the mg value. Say my color is exactly between color 1 and color 2 then it will return 15 mg, otherwise if it is closer to color 2 it will return 28.5 mg, etc.

Hopefully this clears up what I am trying to achieve.

+3


source to share


1 answer


To create a gradient between two color values, you can simply linearly interpolate between them. This will work in any color space, although if the conversion between the two color spaces is not linear, the gradient obtained linearly interpolating in one space will not be linear in the other. Thus, generating gradients in the Lab color space is exactly the same as generating them, for example, in RGB space.

(For color spaces like HSV or HSL that have a hue coordinate that "goes around" it may need some extra help to get the right direction for interpolation, luckily you don't ask about those color spaces here, so I don't need to go into such details.)


As a demonstration, how you will create an n-sample gradient between colors c1 and c2 (each defined as an object LabColor

with properties L

, a

and b

):

public static LabColor[] makeGradient(LabColor c1, LabColor c2, int n) {
    LabColor gradient = new LabColor[n];
    for (int i = 0; i < n; i++) {
        float alpha = (float)i / (n-1);  // 0.0 <= alpha <= 1.0 
        float L = (1-alpha) * c1.L + alpha * c2.L;
        float a = (1-alpha) * c1.a + alpha * c2.a;
        float b = (1-alpha) * c1.b + alpha * c2.b;
        gradient[i] = new LabColor(L, a, b);
    }
    return gradient;
}

      



This returns a gradient with n color swatches, where the first color is c1, the last color is c2, and the rest are interpolated between them.


However, based on the note at the end of your question, I suspect you really don't need to create any gradients. Rather, to find the color in the chart that most closely matches the one in your example, you just need to compute the perceptual distance of each color in the chart from the sample (which in the Lab color space can be well approximated simply by their Euclidean distance) and pick the closest one:

public static LabColor findNearest(LabColor sample, LabColor[] chart) {
    LabColor nearest = null;
    float minDistanceSquared = Float.POSITIVE_INFINITY;
    for (int i = 0; i < chart.length; i++) {
        float dL = sample.L - chart[i].L;
        float da = sample.a - chart[i].a;
        float db = sample.b - chart[i].b;
        float distanceSquared = dL*dL + da*da + db*db;
        if (distanceSquared < minDistanceSquared) {
            nearest = chart[i];
            minDistanceSquared = distanceSquared;
        }
    }
    return nearest;
}

      

+2


source







All Articles