CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-colour-science

Comprehensive Python library providing algorithms and datasets for colour science computations, including chromatic adaptation, colour appearance models, colorimetry, and spectral analysis.

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

colour-difference.mddocs/

Colour Difference Calculations

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.

Capabilities

Main Delta E Function

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 1976

CIE Standard Delta E Functions

Industry-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
    """

Advanced Colour Difference Functions

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
    """

CAM02-Based Colour Difference Functions

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
    """

CAM16-Based Colour Difference Functions

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
    """

Performance Enhancement Functions

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]
}

Stress Index Functions

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
}

Usage Examples

Basic Colour Difference Calculation

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 Industry Application

# 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}")

HDR/WCG Content

# 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 noticeable

CAM-Based Advanced Metrics

from 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}")

Performance Enhancement

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}")

Quality Assessment

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

Batch Processing

# 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)

Method Selection Guidelines

Recommended Methods by Application

General Purpose (Recommended)

  • CIEDE2000: Best overall perceptual uniformity, CIE standard
  • Enhanced CIEDE2000: Apply power_function_Huang2015 for improved correlation

Industry-Specific

  • Textiles: CIE 1994, CIEDE2000, or DIN99 with textiles=True
  • Printing/Graphics: CIEDE2000, CMC 2:1, enhanced with Huang2015
  • HDR/Broadcasting: ΔE_ITP for HDR content, CIEDE2000 for SDR
  • Research: CAM16-UCS for appearance-based studies

Performance vs. Accuracy Trade-offs

  • Fastest: CIE 1976 (simple Euclidean distance)
  • Balanced: CIE 1994, CMC
  • Most Accurate: CIEDE2000, CAM16-UCS
  • HDR/WCG: ΔE_ITP

Perceptual Significance

ΔE Value Interpretation (approximate guidelines)

  • 0-1: Imperceptible difference
  • 1-2: Perceptible by expert observers
  • 2-3.5: Perceptible by untrained observers
  • 3.5-5: Clear difference
  • 5+: Very different colours

Important Notes

  • Thresholds vary by viewing conditions, colour region, and application
  • Textile/printing industries often use tighter tolerances
  • HDR content may have different perceptual thresholds
  • Always validate with visual assessment for critical applications

Constants and Datasets

# 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

docs

advanced-features.md

chromatic-adaptation.md

colorimetry.md

colour-appearance.md

colour-difference.md

colour-models.md

constants.md

geometry.md

index.md

input-output.md

math-utilities.md

notation.md

plotting.md

quality-assessment.md

temperature.md

tile.json