Comprehensive Python library providing algorithms and datasets for colour science computations, including chromatic adaptation, colour appearance models, colorimetry, and spectral analysis.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Comprehensive colour difference calculation functions implementing various industry-standard metrics for quantifying perceptual differences between colours. These functions support CIE standard formulas, CAM-based uniform colour spaces, and advanced perceptual models.
The primary entry point for colour difference calculations with automatic method selection and validation.
def delta_E(a: ArrayLike, b: ArrayLike, method: str = "CIE 2000", **kwargs) -> NDArray:
"""
Calculate colour difference ΔE between two colour arrays using specified method.
Parameters:
- a: first colour array in appropriate colour space (L*a*b*, J'a'b', or ICtCp)
- b: second colour array in appropriate colour space
- method: calculation method, supports:
* "CIE 1976": CIE76 ΔE*ab (Euclidean distance in L*a*b*)
* "CIE 1994": CIE94 ΔE*94 with perceptual weighting
* "CIE 2000": CIEDE2000 ΔE*00 (default, most accurate)
* "CMC": CMC l:c colour difference
* "ITP": ITU-R BT.2124 ΔE_ITP for HDR/WCG
* "CAM02-LCD", "CAM02-SCD", "CAM02-UCS": CIECAM02-based
* "CAM16-LCD", "CAM16-SCD", "CAM16-UCS": CAM16-based
* "DIN99": DIN99 colour difference formula
- **kwargs: method-specific parameters (textiles, l, c, etc.)
Returns:
Colour difference values as NDArray
Notes:
- Input colour spaces depend on method:
* CIE methods: L*a*b* colour space
* CAM methods: J'a'b' colour space from respective appearance models
* ITP method: ICtCp colour encoding
- Values typically range 0-100+, with ~1-3 being just noticeable
- CIEDE2000 is recommended for most applications
"""
# Available calculation methods
DELTA_E_METHODS = {
"CIE 1976": delta_E_CIE1976,
"CIE 1994": delta_E_CIE1994,
"CIE 2000": delta_E_CIE2000,
"CMC": delta_E_CMC,
"ITP": delta_E_ITP,
"CAM02-LCD": delta_E_CAM02LCD,
"CAM02-SCD": delta_E_CAM02SCD,
"CAM02-UCS": delta_E_CAM02UCS,
"CAM16-LCD": delta_E_CAM16LCD,
"CAM16-SCD": delta_E_CAM16SCD,
"CAM16-UCS": delta_E_CAM16UCS,
"DIN99": delta_E_DIN99
}
# Just Noticeable Difference threshold
JND_CIE1976 = 2.3 # Standard JND threshold for CIE 1976Industry-standard colour difference formulas based on CIE recommendations.
def delta_E_CIE1976(Lab_1: ArrayLike, Lab_2: ArrayLike) -> NDArray:
"""
Calculate CIE 1976 colour difference ΔE*ab (Euclidean distance in L*a*b*).
Parameters:
- Lab_1: first L*a*b* colour array, shape (..., 3)
- Lab_2: second L*a*b* colour array, shape (..., 3)
Returns:
CIE76 ΔE*ab values
Notes:
- Simple Euclidean distance: √[(ΔL*)² + (Δa*)² + (Δb*)²]
- Fast computation but less perceptually uniform
- L*: [0, 100], a*,b*: [-100, 100] in reference scale
- JND threshold: ~2.3 (see JND_CIE1976)
"""
def delta_E_CIE1994(Lab_1: ArrayLike, Lab_2: ArrayLike, textiles: bool = False) -> NDArray:
"""
Calculate CIE 1994 colour difference ΔE*94 with perceptual weighting factors.
Parameters:
- Lab_1: reference L*a*b* colour array, shape (..., 3)
- Lab_2: sample L*a*b* colour array, shape (..., 3)
- textiles: use textile industry parameters if True
Returns:
CIE94 ΔE*94 values
Notes:
- Improved perceptual uniformity over CIE76
- Non-symmetric: delta_E_CIE1994(a,b) ≠ delta_E_CIE1994(b,a)
- Textile parameters: kL=2, kC=kH=1, k1=0.048, k2=0.014
- Graphic arts parameters: kL=kC=kH=1, k1=0.045, k2=0.015 (default)
"""
def delta_E_CIE2000(Lab_1: ArrayLike, Lab_2: ArrayLike, textiles: bool = False) -> NDArray:
"""
Calculate CIEDE2000 colour difference ΔE*00, the most accurate CIE standard.
Parameters:
- Lab_1: first L*a*b* colour array, shape (..., 3)
- Lab_2: second L*a*b* colour array, shape (..., 3)
- textiles: use textile industry weighting (kL=2) if True
Returns:
CIEDE2000 ΔE*00 values
Notes:
- Most perceptually uniform CIE formula (recommended default)
- Accounts for perceptual non-uniformities in L*a*b* space
- Reference conditions: D65, 1000 lx, uniform gray background L*=50
- Includes rotation term for interaction between chroma and hue
- Sample size >4°, direct edge contact, ΔE < 5.0
"""
def delta_E_CMC(Lab_1: ArrayLike, Lab_2: ArrayLike, l: float = 2, c: float = 1) -> NDArray:
"""
Calculate CMC l:c colour difference with configurable lightness/chroma weighting.
Parameters:
- Lab_1: reference L*a*b* colour array, shape (..., 3)
- Lab_2: sample L*a*b* colour array, shape (..., 3)
- l: lightness weighting factor (2 for acceptability, 1 for perceptibility)
- c: chroma weighting factor (typically 1)
Returns:
CMC ΔE values
Notes:
- Common ratios: 2:1 (acceptability), 1:1 (threshold of imperceptibility)
- Developed by Colour Measurement Committee
- Good correlation with visual assessments
- Non-symmetric like CIE94
"""Modern colour difference metrics for HDR, wide gamut, and specialized applications.
def delta_E_ITP(ICtCp_1: ArrayLike, ICtCp_2: ArrayLike) -> NDArray:
"""
Calculate ITU-R BT.2124 ΔE_ITP for HDR and wide colour gamut applications.
Parameters:
- ICtCp_1: first ICtCp colour encoding array, shape (..., 3)
- ICtCp_2: second ICtCp colour encoding array, shape (..., 3)
Returns:
ΔE_ITP values (1.0 ≈ just noticeable difference)
Notes:
- Designed for HDR/WCG content (Rec.2020, HDR10, Dolby Vision)
- Value of 1.0 equals just noticeable difference in critical adaptation
- Uses ICtCp encoding: I (intensity), Ct (chroma-red), Cp (chroma-yellow)
- Optimized for high dynamic range and wide color gamut displays
"""
def delta_E_DIN99(Lab_1: ArrayLike, Lab_2: ArrayLike, textiles: bool = False) -> NDArray:
"""
Calculate DIN99 colour difference using DIN99 colour space transformation.
Parameters:
- Lab_1: first L*a*b* colour array, shape (..., 3)
- Lab_2: second L*a*b* colour array, shape (..., 3)
- textiles: use textile parameters (kE=2, kCH=0.5) if True
Returns:
DIN99 ΔE values
Notes:
- Based on DIN99 colour space with improved perceptual uniformity
- Standard parameters: kE=1, kCH=1
- Textile parameters: kE=2, kCH=0.5
- Often shows better correlation than CIELAB-based formulas
"""Colour difference calculations in uniform colour spaces derived from CIECAM02 appearance model.
def delta_E_CAM02LCD(Jpapbp_1: ArrayLike, Jpapbp_2: ArrayLike) -> NDArray:
"""
Calculate colour difference in CAM02-LCD uniform colour space.
Parameters:
- Jpapbp_1: first J'a'b' array from CAM02-LCD space, shape (..., 3)
- Jpapbp_2: second J'a'b' array from CAM02-LCD space, shape (..., 3)
Returns:
CAM02-LCD ΔE' values
Notes:
- LCD: Large Colour Differences - optimized for large colour differences
- Input must be CAM02-LCD J'a'b', not CIE L*a*b*
- Based on CIECAM02 appearance model for better perceptual uniformity
- Lightness scaling factor KL accounts for perceptual non-linearities
"""
def delta_E_CAM02SCD(Jpapbp_1: ArrayLike, Jpapbp_2: ArrayLike) -> NDArray:
"""
Calculate colour difference in CAM02-SCD uniform colour space.
Parameters:
- Jpapbp_1: first J'a'b' array from CAM02-SCD space, shape (..., 3)
- Jpapbp_2: second J'a'b' array from CAM02-SCD space, shape (..., 3)
Returns:
CAM02-SCD ΔE' values
Notes:
- SCD: Small Colour Differences - optimized for small colour differences
- Input must be CAM02-SCD J'a'b', not CIE L*a*b*
- Different coefficients than CAM02-LCD for improved small difference detection
- Useful for quality control and fine colour matching
"""
def delta_E_CAM02UCS(Jpapbp_1: ArrayLike, Jpapbp_2: ArrayLike) -> NDArray:
"""
Calculate colour difference in CAM02-UCS uniform colour space.
Parameters:
- Jpapbp_1: first J'a'b' array from CAM02-UCS space, shape (..., 3)
- Jpapbp_2: second J'a'b' array from CAM02-UCS space, shape (..., 3)
Returns:
CAM02-UCS ΔE' values
Notes:
- UCS: Uniform Colour Space - balanced for various difference magnitudes
- Input must be CAM02-UCS J'a'b', not CIE L*a*b*
- Compromise between LCD and SCD optimization
- General purpose CAM02-based colour difference metric
"""Next-generation colour difference calculations based on the improved CAM16 appearance model.
def delta_E_CAM16LCD(Jpapbp_1: ArrayLike, Jpapbp_2: ArrayLike) -> NDArray:
"""
Calculate colour difference in CAM16-LCD uniform colour space.
Parameters:
- Jpapbp_1: first J'a'b' array from CAM16-LCD space, shape (..., 3)
- Jpapbp_2: second J'a'b' array from CAM16-LCD space, shape (..., 3)
Returns:
CAM16-LCD ΔE' values
Notes:
- Based on improved CAM16 appearance model
- LCD: Large Colour Differences optimization
- Input must be CAM16-LCD J'a'b', not CIE L*a*b*
- Successor to CAM02-LCD with improved predictions
"""
def delta_E_CAM16SCD(Jpapbp_1: ArrayLike, Jpapbp_2: ArrayLike) -> NDArray:
"""
Calculate colour difference in CAM16-SCD uniform colour space.
Parameters:
- Jpapbp_1: first J'a'b' array from CAM16-SCD space, shape (..., 3)
- Jpapbp_2: second J'a'b' array from CAM16-SCD space, shape (..., 3)
Returns:
CAM16-SCD ΔE' values
Notes:
- Based on improved CAM16 appearance model
- SCD: Small Colour Differences optimization
- Input must be CAM16-SCD J'a'b', not CIE L*a*b*
- Better small difference detection than CAM02-SCD
"""
def delta_E_CAM16UCS(Jpapbp_1: ArrayLike, Jpapbp_2: ArrayLike) -> NDArray:
"""
Calculate colour difference in CAM16-UCS uniform colour space.
Parameters:
- Jpapbp_1: first J'a'b' array from CAM16-UCS space, shape (..., 3)
- Jpapbp_2: second J'a'b' array from CAM16-UCS space, shape (..., 3)
Returns:
CAM16-UCS ΔE' values
Notes:
- Based on improved CAM16 appearance model
- UCS: Uniform Colour Space - general purpose optimization
- Input must be CAM16-UCS J'a'b', not CIE L*a*b*
- State-of-the-art appearance-based colour difference metric
"""Advanced functions for improving colour difference formula performance and correlation with visual assessment.
def power_function_Huang2015(d_E: ArrayLike, coefficients: str = "CIE 2000") -> NDArray:
"""
Apply Huang et al. (2015) power function to improve ΔE formula performance.
Parameters:
- d_E: computed colour difference array
- coefficients: power function coefficients for specific method:
* "CIE 1976": [1.26, 0.55]
* "CIE 1994": [1.41, 0.70]
* "CIE 2000": [1.43, 0.70] (default)
* "CMC": [1.34, 0.66]
* "CAM02-LCD": [1.00, 0.85]
* "CAM02-SCD": [1.45, 0.75]
* "CAM02-UCS": [1.30, 0.75]
* "CAM16-UCS": [1.41, 0.63]
* "DIN99d": [1.28, 0.74]
* "OSA": [3.32, 0.62]
* "OSA-GP-Euclidean": [1.52, 0.76]
* "ULAB": [1.17, 0.69]
Returns:
Improved ΔE values with better correlation to visual assessment
Notes:
- Formula: ΔE' = a × ΔE^b where [a,b] are method-specific coefficients
- Significantly improves correlation with visual datasets
- Apply after computing base ΔE with standard formulas
- Coefficients derived from extensive psychophysical experiments
"""
# Available power function coefficients
COEFFICIENTS_HUANG2015 = {
"CIE 1976": [1.26, 0.55],
"CIE 1994": [1.41, 0.70],
"CIE 2000": [1.43, 0.70],
"CMC": [1.34, 0.66],
"CAM02-LCD": [1.00, 0.85],
"CAM02-SCD": [1.45, 0.75],
"CAM02-UCS": [1.30, 0.75],
"CAM16-UCS": [1.41, 0.63],
"DIN99d": [1.28, 0.74],
"OSA": [3.32, 0.62],
"OSA-GP-Euclidean": [1.52, 0.76],
"ULAB": [1.17, 0.69]
}Statistical measures for evaluating colour difference formula performance against visual datasets.
def index_stress(d_E: ArrayLike, d_V: ArrayLike, method: str = "Garcia 2007") -> NDArray:
"""
Calculate Kruskal's Standardized Residual Sum of Squares (STRESS) index.
Parameters:
- d_E: computed colour difference array ΔE
- d_V: visual colour difference array ΔV from psychophysical experiments
- method: computation method ("Garcia 2007")
Returns:
STRESS index values (lower = better correlation)
Notes:
- Measures goodness-of-fit between computed and visual differences
- Values closer to 0 indicate better correlation with human vision
- Used to evaluate and compare colour difference formulas
- Essential for psychophysical validation of new metrics
"""
def index_stress_Garcia2007(d_E: ArrayLike, d_V: ArrayLike) -> NDArray:
"""
Calculate STRESS index using Garcia et al. (2007) method.
Parameters:
- d_E: computed colour difference array ΔE
- d_V: visual colour difference array ΔV
Returns:
STRESS index value
Notes:
- Standard implementation for colour difference evaluation
- Used in research for validating new colour difference formulas
- Lower values indicate better correlation with visual assessment
"""
# Available stress index methods
INDEX_STRESS_METHODS = {
"Garcia 2007": index_stress_Garcia2007
}import numpy as np
from colour import delta_E
# CIE L*a*b* colour arrays
lab1 = np.array([50.0, 20.0, -30.0]) # Reference colour
lab2 = np.array([55.0, 18.0, -25.0]) # Sample colour
# Calculate CIEDE2000 (recommended)
de2000 = delta_E(lab1, lab2, method="CIE 2000")
print(f"CIEDE2000 ΔE: {de2000:.2f}")
# Compare different methods
de76 = delta_E(lab1, lab2, method="CIE 1976")
de94 = delta_E(lab1, lab2, method="CIE 1994")
decmc = delta_E(lab1, lab2, method="CMC")
print(f"CIE76 ΔE: {de76:.2f}")
print(f"CIE94 ΔE: {de94:.2f}")
print(f"CMC ΔE: {decmc:.2f}")# Textile-specific parameters for closer tolerances
de2000_textiles = delta_E(lab1, lab2, method="CIE 2000", textiles=True)
de94_textiles = delta_E(lab1, lab2, method="CIE 1994", textiles=True)
din99_textiles = delta_E(lab1, lab2, method="DIN99", textiles=True)
print(f"CIEDE2000 (textiles): {de2000_textiles:.2f}")
print(f"CIE94 (textiles): {de94_textiles:.2f}")
print(f"DIN99 (textiles): {din99_textiles:.2f}")# ICtCp colour encoding for HDR content
ictcp1 = np.array([0.4885, -0.0474, 0.0748]) # HDR colour 1
ictcp2 = np.array([0.4899, -0.0457, 0.0736]) # HDR colour 2
# Calculate ΔE_ITP for HDR applications
de_itp = delta_E(ictcp1, ictcp2, method="ITP")
print(f"ΔE_ITP: {de_itp:.3f}") # ~1.0 = just noticeablefrom colour import XYZ_to_CAM16UCS
# Convert XYZ to CAM16-UCS J'a'b' space first
xyz1 = np.array([0.20654008, 0.12197225, 0.05136952])
xyz2 = np.array([0.14222010, 0.06157513, 0.06157513])
# Convert to CAM16-UCS space
jpapbp1 = XYZ_to_CAM16UCS(xyz1)
jpapbp2 = XYZ_to_CAM16UCS(xyz2)
# Calculate CAM16-based differences
de_cam16_ucs = delta_E(jpapbp1, jpapbp2, method="CAM16-UCS")
de_cam16_lcd = delta_E(jpapbp1, jpapbp2, method="CAM16-LCD")
de_cam16_scd = delta_E(jpapbp1, jpapbp2, method="CAM16-SCD")
print(f"CAM16-UCS ΔE': {de_cam16_ucs:.3f}")
print(f"CAM16-LCD ΔE': {de_cam16_lcd:.3f}")
print(f"CAM16-SCD ΔE': {de_cam16_scd:.3f}")from colour import power_function_Huang2015
# Calculate base ΔE and apply Huang2015 enhancement
base_de = delta_E(lab1, lab2, method="CIE 2000")
enhanced_de = power_function_Huang2015(base_de, coefficients="CIE 2000")
print(f"Base CIEDE2000: {base_de:.3f}")
print(f"Enhanced: {enhanced_de:.3f}")
# Enhancement for other methods
de_cmc_base = delta_E(lab1, lab2, method="CMC")
de_cmc_enhanced = power_function_Huang2015(de_cmc_base, coefficients="CMC")
print(f"Base CMC: {de_cmc_base:.3f}")
print(f"Enhanced CMC: {de_cmc_enhanced:.3f}")from colour import index_stress
# Simulated data for evaluation
computed_de = np.array([2.04, 2.86, 3.44, 1.75, 4.12]) # Calculated ΔE
visual_de = np.array([1.26, 1.26, 1.87, 1.15, 2.34]) # Visual assessment
# Calculate STRESS index
stress = index_stress(computed_de, visual_de)
print(f"STRESS index: {stress:.4f}") # Lower = better correlation# Multiple colour pairs
lab_refs = np.array([[50, 20, -30], [60, -15, 25], [40, 10, -20]])
lab_samples = np.array([[52, 18, -28], [58, -12, 28], [42, 12, -18]])
# Calculate all differences at once
de_batch = delta_E(lab_refs, lab_samples, method="CIE 2000")
print("Batch CIEDE2000 results:", de_batch)
# Apply enhancement to batch
enhanced_batch = power_function_Huang2015(de_batch, coefficients="CIE 2000")
print("Enhanced results:", enhanced_batch)General Purpose (Recommended)
power_function_Huang2015 for improved correlationIndustry-Specific
textiles=TruePerformance vs. Accuracy Trade-offs
ΔE Value Interpretation (approximate guidelines)
Important Notes
# Just Noticeable Difference threshold
JND_CIE1976 = 2.3 # Standard JND for CIE 1976 ΔE*ab
# Available calculation methods
DELTA_E_METHODS = {
"CIE 1976", "CIE 1994", "CIE 2000", "CMC", "ITP",
"CAM02-LCD", "CAM02-SCD", "CAM02-UCS",
"CAM16-LCD", "CAM16-SCD", "CAM16-UCS", "DIN99"
}
# Power function enhancement coefficients
COEFFICIENTS_HUANG2015 = {
"CIE 1976": [1.26, 0.55], "CIE 1994": [1.41, 0.70],
"CIE 2000": [1.43, 0.70], "CMC": [1.34, 0.66],
"CAM02-LCD": [1.00, 0.85], "CAM02-SCD": [1.45, 0.75],
"CAM02-UCS": [1.30, 0.75], "CAM16-UCS": [1.41, 0.63],
"DIN99d": [1.28, 0.74], "OSA": [3.32, 0.62],
"OSA-GP-Euclidean": [1.52, 0.76], "ULAB": [1.17, 0.69]
}
# Stress index evaluation methods
INDEX_STRESS_METHODS = {"Garcia 2007": index_stress_Garcia2007}The colour difference module provides comprehensive tools for quantifying perceptual colour differences across various applications, from quality control to psychophysical research, with state-of-the-art formulas and performance enhancements.
Install with Tessl CLI
npx tessl i tessl/pypi-colour-science