Color Distance and Delta E
The difference or distance between two colors allows for a quantified analysis of how far apart two colors are from one another. This metric is of particular interest in the field of color science, but it has practical applications in color libraries working with colors.
Usually, color distance is applied to near perceptual uniform color spaces in order to obtain a metric regarding a color's visual, perceptual distance from another color. This can be useful in gamut mapping or even determining that colors are close enough or far enough away from each other.
Color Distance
ColorAide provides a simple euclidean color distance function. By default, it evaluates the distance in the CIELab color space, but it can be configured to evaluate in any color space, such as Oklab, etc. It may be less useful in some color spaces compared to others. Cylindrical spaces with polar coordinates will be converted to rectangular coordinates if specified. Some spaces might not be as very perceptually uniform.
>>> Color("red").distance("blue", space="srgb")
1.4142135623730951
>>> Color("red").distance("blue", space="lab")
184.0190486209969
New 3.3
Handling spaces with polar coordinates is new in 3.3.
Delta E
The delta_e
function gives access to various ∆E implementations, which are just different algorithms to calculate distance. Some are simply Euclidean distance withing a certain color space, some are far more complex.
If no method
is specified, the default implementation is ∆E*ab (CIE76) which uses a simple Euclidean distancing algorithm on the CIELab color space. It is fast, but not as accurate as later iterations of the algorithm as CIELab is not actually as perceptually uniform as it was thought when CIELab was originally developed.
>>> Color("red").delta_e("blue")
176.3084955965824
When method
is set, the specified ∆E algorithm will be used instead. For instance, below we use ∆E*00 which is a more complex algorithm that accounts for the CIELab's weakness in perceptually uniformity. It does come at the cost of being a little slower.
>>> Color("red").delta_e("blue", method="2000")
52.87819528592645
Distancing and Symmetry
It should be noted that not all distancing algorithms are symmetrical. Some are order dependent.
Delta E CIE76
The ∆Eab distancing algorithm is registered in Color
by default
Delta E | Symmetrical | Name | Parameters |
---|---|---|---|
∆E*ab (CIE76) | 76 | space='lab-d65' |
One of the first approaches to color distancing and is actually just Euclidean distancing in the CIELab color space.
Note
By default, Lab D65 is used for color distancing. In the print industry, it is common for Lab D50 to be used. If Lab D50 is desired, simply specify it as the space
color space. space
must be a CIE Lab color space.
>>> Color("red").delta_e("blue", method="76")
176.3084955965824
>>> Color("red").delta_e("blue", method="76", space='lab')
184.0190486209969
Delta E CMC (1984)
The ∆Ecmc distancing algorithm is registered in Color
by default
Delta E | Symmetrical | Name | Parameters |
---|---|---|---|
∆E*cmc (CMC l:c (1984)) | cmc | l=2, c=1, space='lab-d65' |
Delta E CMC is based on the CIELCh color space. The CMC calculation mathematically defines an ellipsoid around the standard color with semi-axis corresponding to hue, chroma and lightness.
Parameter | Acceptability | Perceptibility |
---|---|---|
l | 2 | 1 |
c | 1 | 1 |
Note
By default, Lab D65 is used for color distancing. In the print industry, it is common for Lab D50 to be used. If Lab D50 is desired, simply specify it as the space
color space. space
must be a CIE Lab color space.
>>> Color("red").delta_e("blue", method="cmc")
108.56925233888809
>>> Color("red").delta_e("blue", method="cmc", space='lab')
114.2301281201658
Delta E CIE94
The ∆E*94 distancing algorithm is registered in Color
by default
Delta E | Symmetrical | Name | Parameters |
---|---|---|---|
∆E*94 (CIE94) | 94 | kl=1, k1=0.045, k2=0.015, space='lab-d65' |
The 1976 definition was extended to address perceptual non-uniformities, while retaining the CIELab color space, by the introduction of application-specific weights derived from an automotive paint test's tolerance data.
Parameter | Graphic Arts | Textiles |
---|---|---|
kl | 1 | 2 |
k1 | 0.045 | 0.048 |
k2 | 0.015 | 0.014 |
Note
By default, Lab D65 is used for color distancing. In the print industry, it is common for Lab D50 to be used. If Lab D50 is desired, simply specify it as the space
color space. space
must be a CIE Lab color space.
>>> Color("red").delta_e("blue", method="94")
70.57699903580162
>>> Color("red").delta_e("blue", method="94", space='lab')
73.82677591958294
Delta E CIEDE2000
The ∆E*00 distancing algorithm is registered in Color
by default
Delta E | Symmetrical | Name | Parameters |
---|---|---|---|
∆E*00 (CIEDE2000) | 2000 | kl=1, kc=1, kh=1, space='lab-d65' |
Since the 1994 definition did not adequately resolve the perceptual uniformity issue, the CIE refined their definition, adding five corrections:
- A hue rotation term (RT), to deal with the problematic blue region (hue angles in the neighborhood of 275°)
- Compensation for neutral colors (the primed values in the LCh differences)
- Compensation for lightness (SL)
- Compensation for chroma (SC)
- Compensation for hue (SH)
Note
By default, Lab D65 is used for color distancing. In the print industry, it is common for Lab D50 to be used. If Lab D50 is desired, simply specify it as the space
color space. space
must be a CIE Lab color space.
>>> Color("red").delta_e("blue", method="2000")
52.87819528592645
>>> Color("red").delta_e("blue", method="2000", space='lab')
55.79977339019779
Delta E HyAB
The ∆EHyAB distancing algorithm is registered in Color
by default
Delta E | Symmetrical | Name | Parameters |
---|---|---|---|
∆EHyAB (HyAB) | hyab | space="lab-d65" |
A combination of a Euclidean metric in hue and chroma with a city‐block metric to incorporate lightness differences. It can be used on any Lab like color space, the default being CIELab D65.
Delta E OK
The ∆Eok distancing algorithm is registered in Color
by default
Delta E | Symmetrical | Name | Parameters |
---|---|---|---|
∆Eok | ok | scalar=1 |
A color distancing algorithm that performs Euclidean distancing in the Oklab color space. This is used in the OkLCh Chroma gamut mapping algorithm. The scalar
parameter allows you to scale the result up if desired.
Delta E ITP
The ∆Eitp distancing algorithm is registered in Color
by default
Delta E | Symmetrical | Name | Parameters |
---|---|---|---|
∆Eitp (ICtCp) | itp | scalar=720 |
Various algorithms are designed for and perform decently in the SDR range, but ∆Eitp aims to provide good distancing in the HDR range using the ICtCp color space (must be registered in order to use ∆Eitp). It was determined that a scalar
of 240 was more comparable to the average ∆E*00 result from the JND data set and 720 equates them to a JND.
Delta E Z
The ∆Ez distancing algorithm is registered in Color
by default
Delta E | Symmetrical | Name | Parameters |
---|---|---|---|
∆Ez (Jzazbz) | jz |
Performs Euclidean distancing in the Jzazbz color space, useful for the HDR range.
Delta E 99o
The ∆E99o distancing algorithm is not registered in Color
by default
Delta E | Symmetrical | Name | Parameters |
---|---|---|---|
∆E99o (DIN99o) | 99o |
∆E99o performs Euclidean distancing in the DIN99o color space.
Both the DIN99o color space and the ∆E algorithm must be registered to use.
from coloraide import Color as Base
from coloraide.distance.delta_e_99o import DE99o
from coloraide.spaces.din99o import DIN99o
class Color(Base): ...
Color.register([DIN99o(), DE99o()])
Delta E CAM16
The ∆Ecam16 distancing algorithm is not registered in Color
by default
Delta E | Symmetrical | Name | Parameters |
---|---|---|---|
∆Ecam16 | cam16 | space='cam16-ucs' |
The CAM16 UCS uniform color space applies an additional nonlinear transformation to lightness and colorfulness so that a color difference metric ΔE can be based more closely on Euclidean distance. This algorithm performs distancing using the CAM16 UCS color space. If desired model
can be changed to use the SCD or LCD model for "small" and "large" distancing respectively
Parameter | Default | Description |
---|---|---|
space | cam16-ucs | The CAM16 color space derived from the CAM16UCS space. cam16-ucs , cam16-scd , and cam16-lcd are provided in ColorAide (unregistered by default). Variants using different lighting environments can be created and registered and provided as the UCS space to operate in. |
Deprecated model
parameter
In 3.3 the model
parameter was deprecated and will be removed at some future time. space
is more flexible and should be used instead.
The CAM16 JMh color space, one or more of the CAM16 (UCS/SCD/LCD) color spaces, and the ∆E algorithm must be registered to use this ∆E method.
from coloraide import Color as Base
from coloraide.distance.delta_e_cam16 import DECAM16
from coloraide.spaces.cam16_ucs import CAM16UCS, CAM16SCD, CAM16LCD
from coloraide.spaces.cam16_jmh import CAM16JMh
class Color(Base): ...
Color.register([CAM16JMh(), CAM16UCS(), CAM16SCD(), CAM16LCD(), DECAM16()])
Delta E HCT
The ∆Ehct distancing algorithm is not registered in Color
by default
Warning
This approach was specifically added to help produce tonal palettes, but with the recent addition of the ray trace approach to chroma reduction in any perceptual space, users can defer to the ray tracing approach which does not require a special ∆E method and it performs much faster.
On occasions, MINDE approach can be slightly more accurate very close to white due to the way ray trace handles HCT's atypical achromatic response, but differences should be imperceptible to the eye at such lightness levels making the improved performance of the ray trace approach much more desirable.
>>> c = Color('hct', [325, 24, 50])
>>> tones = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 95, 100]
>>> Steps([c.clone().set('tone', tone).convert('srgb').to_string(hex=True, fit={'method': 'raytrace', 'pspace': 'hct'}) for tone in tones])
['#000000', '#29132e', '#3f2844', '#573e5b', '#705574', '#8a6d8d', '#a587a8', '#c1a1c3', '#debcdf', '#fbd7fc', '#ffebfd', '#ffffff']
Delta E | Symmetrical | Name | Parameters |
---|---|---|---|
∆EHCT | hct |
This takes the HCT color space C and H components (CAM16's M and h) and converts them to CAM16 UCS M and h, and applies Euclidean distancing on them along with the T component (CIELab's L*). This is necessary for the HCT Chroma gamut mapping approach.
from coloraide import Color as Base
from coloraide.distance.delta_e_hct import DEHCT
from coloraide.spaces.HCT import HCT
class Color(Base): ...
Color.register([HCT(), DEHCT()])
Finding Closest Color
ColorAide implements a simple way to find the closest color, given a list of colors, to another color. The method is called closest
and takes a list of colors that are to be compared to the calling color object. The first color with the smallest distance between the calling color object and itself will be considered the nearest/closest color.
Consider the following example. Here we provide a list of colors to compare against red
. After comparing all the colors, the closest ends up being maroon
.
>>> Color('red').closest(['pink', 'yellow', 'green', 'blue', 'purple', 'maroon'])
color(srgb 0.50196 0 0 / 1)
The default distancing method is used if one is not supplied, but others can be used:
>>> Color('red').closest(['pink', 'yellow', 'green', 'blue', 'purple', 'maroon'], method='2000')
color(srgb 0.50196 0 0 / 1)
Configuring Delta E Defaults
A number of distancing algorithms have configurable features that can be set on demand. If you'd like to have these options set by default, you create a custom class and register the plugins with the defaults of your choice.
In this example, we will configure ∆E*00 to use CIE Lab D50 instead of D65 by default.
>>> from coloraide import Color as Base
>>> from coloraide.distance.delta_e_2000 import DE2000
>>> class Color(Base):
... ...
...
>>> Color.register(DE2000(space='lab'), overwrite=True)
>>> Color('red').delta_e('blue', method='2000')
55.79977339019779
>>> Color('red').delta_e('blue', method='2000', space='lab-d65')
52.87819528592645