8000 GitHub - faern/colorimetry-harbik
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

faern/colorimetry-harbik

 
 

Repository files navigation

Build Status

A Rust library for color modeling in illumination and engineering projects, with early JavaScript/WebAssembly support. Algorithms follow standards from the CIE, ICC, and IES. It intends to provide a comprehensive framework for spectral colorimetry:

  • Standard Spectrum representation

    • All spectra—illuminants, filters, surface reflectance, or stimuli—are defined on a fixed internal grid of 401 samples spanning 380 nm to 780 nm in 1 nm increments, using the Spectrum object.
    • Leverages the nalgebra linear-algebra library for efficient vector and matrix operations on spectral data, providing high-performance processing and access to advanced mathematical routines.
    • Imports measurements from arbitrary or irregular wavelength grids by resampling onto the internal grid using configurable interpolation methods (linear or Sprague–Karup), with optional smoothing for oversampled datasets.
  • Built-in spectral datasets

    • Munsell color book (Munsell feature)
    • CRI TCS (Test Color Samples, with cri feature)
  • Generate spectral distributions from analytical models

    • Planck’s law for blackbody radiators
    • Gaussian functions for custom filter shapes
    • RGB channel mixtures to approximate display pixel spectra
  • CIE standard Colorimetric Observers each represented in the Observer instance. Calculate associated tristimulus values XYZ for spectral entities.

    • CIE 1931 2º,
    • CIE 1964 10º,
    • CIE 2015 2º,
    • CIE 2015 10º,
  • Spectrally based RGB Color Spaces with transformation matrices between Rgb and XYZ values for all color spaces and observers

    • sRGB
    • Adobe RGB
    • DisplayP3
  • Advanced color models

Installation

To use this library in a Rust application, run the command:

   cargo add colorimetry

or add this line to the dependencies in your Cargo.toml file:

    colorimetry = "0.0.6"

The easiest way to use the objects and functions in this library is through its prelude.

    use colorimetry::prelude::*;
    use colorimetry::illuminant::D65;

    // D65 Tristimulus values, using the CIE1931 standard observer by default
    let [x, y, z] = D65.xyz(None).set_illuminance(100.0).values();

    approx::assert_ulps_eq!(x, 95.04, epsilon = 5E-3);
    approx::assert_ulps_eq!(y, 100.0, epsilon = 5E-3);
    approx::assert_ulps_eq!(z, 108.86, epsilon = 5E-3);

Features

This library includes a range of spectral data collections, with only a minimal set enabled by default.
Additional functionality can be activated using Cargo feature flags.

Default Features These features are enabled by default. To disable, use:
cargo add colorimetry --no-default-features
  • cie-illuminants
    Adds a large collection of standard illuminants (e.g., Fluorescent and LED series) beyond the D50 and D65, which are always included.

  • supplemental-observers
    Adds the following CIE standard colorimetric observers beyond the CIE 1931 2º Standard Observer:

    • CIE 1964 10° Standard Observer
    • CIE 2015 Cone Fundamental based Standard Observers (2° & 10°)
Optional Features
  • munsell
    Include reflection spectra for Munsell colors.

  • cct
    Included automatically if the cri feature is enabled. Calculates correlated color temperatures (CCT) for illuminants. Generates a 4096-entry lookup table (each entry containing three f64 values). Memory is reserved at compile time but computed on demand.

  • cri
    Enables Color Rendering Index (CRI) calculations, providing Ra and R1–R14 values for illuminants.
    Loads an additional 14 test color sample spectra.

Enable Features

To enable a feature, such as cri and munsell, use

cargo add colorimetry -F cri,munsell

or

cargo add colorimetry --features cri,munsell

Alternatively, configure features manually in your Cargo.toml:

colorimetry = { version = "0.0.6", features = ["cri", "munsell"] }

Concepts and Examples

  • While the core data structure of the library is Spectrum, all colorimetric models operate on higher-level abstractions such as Illuminant, Colorant, and Stimulus, each encapsulating spectral data in a way that aligns with standard colorimetric principles.
  • Depending on the spectral type, the library provides specialized methods—for example:
    • Correlated color temperature CCT and color rendering index CRI calculations for Illuminants.
    • CIELAB and CIECAM color appearance model computations for Colorants.
    • RGB conversions and colorimetric projections for Stimulus data.
  • As a first step in almost any colorimetric model, Colorimetric Observers are used to compute the tristimulus values (X, Y, Z), which indirectly represent the responses of the eye's cone receptors to external optical stimuli. The library includes multiple CIE standard observers as Observer instances.
  • Advanced color models such as CIELAB and CIECAM build on these tristimulus values to describe our color perceptions—how we see color—taking into account the state of visual adaptation and viewing conditions.
  • These models also enable the estimation of perceived color differences between stimuli, making it possible to compare how colors appear across displays, printed materials, and real-world objects.

Spectral Distributions

The Spectrum struct underpins all spectral calculations in this library. It stores spectral data in a nalgebra::SVector<f64, NS> vector, with length NS = 401, over a wavelength domain ranging from 380 nm to 780 nm in 1 nm steps.

To perform colorimetric calculations, use either Illuminant for light source spectra, or Colorant for modeling surface colors, such as paints and printed inks. A Stimulus is used to model pixels in displays, where a combination of red, green, and blue sub-pixels are controlled to create sensations of color, directly viewed by looking at them.

Intialize from Array
    use colorimetry::prelude::*;
    use colorimetry::spectrum::NS;

    // a black hole stimulus spectrum, using NS = 401 zero values
    let black_hole_spectrum = Spectrum::new([0.0; NS]);
    
    // the stimulus, reaching our eyes, when looking at a black hole:
    let black_hole_stimulus = Stimulus::new(black_hole_spectrum);
Using data with other wavelength domains

If you have spectral data defined over a wavelength domain different from the 380-780-1 nanometers as used in this library, you can use two interpolation methods converting your data into a Spectrum:

  • Linear interpolation
    The Spectrum::linear_interpolate constructor takes a slice of wavelengths and a corresponding slice of spectral values. It returns a Spectrum if both slices are of equal length and the wavelengths are ordered.

  • Sprague interpolation
    For smoother interpolation, Spectrum::sprague_interpolate implements the Sprague-Karup interpolation method, commonly used in color science. This method requires that the input wavelengths be evenly spaced. It takes the domain bounds and a slice of spectral values as input and produces a high-resolution Spectrum aligned with the internal wavelength grid.

References This spectral domain aligns with standards such as:

This 380–780 nm range is also the default domain used by the IES TM-30 Spectral Calculator.

Illuminants

An Illuminant is a spectral representation of a light which hits an object, which, upon scattering on its way to our eyes, creates the sensations of color we experience. The spectral composition of an illuminant influences the colors we see.

Illuminants can be created using spectral data, in form of a Spectrum instance, or can be generated from various spectral models. Alternatively, the library includes the CIE standard illuminants.

Initialize from Spectrum To get an `Illuminant` from your spectral data, first create a `Spectrum`, for example by using one of the interpolation methods, or directly using an array.
    use colorimetry::prelude::*;

    // create equal energy spectrum from an array, with values of 1.0.
    let spectrum = Spectrum::new([1.0; 401]);
    let illuminant = Illuminant::new(spectrum);
    
    // calculate chromaticity coordinates as used in the CIE 1931 chromaticity diagram
    // use `None` as argument to used the default CIE 1931 2º standard observer
    let chromaticity = illuminant.xyz(None).chromaticity();
    
    // check the values
    approx::assert_abs_diff_eq!(chromaticity.x(), 0.3333, epsilon=1E-4);
    approx::assert_abs_diff_eq!(chromaticity.y(), 0.3333, epsilon=1E-4);
Factory Functions
  • Planckian illuminant, a pure thermal emission based spectrum. Uses Plank's law, and takes an absolute temperature, in Kelvin, as argument.

        use crate::colorimetry::prelude::*;
    
        // Plankian illuminant with a temperature of 3000 Kelvin
        let p3000 = Illuminant::planckian(3000.0);
        let chromaticity = CIE1931.xyz(&p3000, None).chromaticity();
    
        approx::assert_abs_diff_eq!( chromaticity.x(), 0.436_935, epsilon = 1E-6);
        approx::assert_abs_diff_eq!( chromaticity.y(), 0.404_083, epsilon = 1E-6);
  • Generic Daylight CIE D-illuminant, generating a daylight spectrum with a characteristic correlated color temperature in the range from 4000 to 25_000 Kelvin.

  • LED illuminant, with a spectral distribution described by an analytical function, as proposed by Yoshi Ohno, as published in Optical Engineering 44(11), 2005.

  • Equal Energy Illuminant, with a uniform spectral distribution with an irradiance of 1 watt per square meter.

CIE Standard Illuminants

The following standard illuminants are available in the library using the cie-illuminants feature, which is enabled by default.

Correlated Color Temperature (CCT)

Illuminants are typically characterized by their correlated color temperature (CCT), expressed in Kelvin (K), and by their tint, which describes the chromaticity deviation from the Planckian (blackbody) locus.

The CCT is defined as the temperature of the Planckian (ideal blackbody) radiator whose perceived color most closely matches that of the test light source, when viewed under identical conditions. Because many real-world light sources (e.g., fluorescent or LED lamps) do not emit light that exactly matches any blackbody radiator, their color temperature is termed correlated rather than exact.

CCT is not derived directly from spectral data, but is calculated using the chromaticity coordinates by finding the closest point on the Planckian locus—usually by minimizing the Euclidean or perceptual distance in color space1.

In this library, an advanced, high accuracy, iterative Robertson's method is used to calculate both values.

Here we us Plank's law, to create an illuminant spectrum, and check its temperature and tint.

    # #[cfg(feature = "cct")]{
    // this example requires `cct` feature enabled
    use crate::colorimetry::prelude::*;

    // Plankian illuminant with a temperature of 3000 Kelvin
    let p3000 = Illuminant::planckian(3000.0);

    // calculate CCT and Duv for this illuminant
    // unwrap OK as we know values should be approximately 3000.0, and 0.0
    let [cct, duv] = p3000.cct().unwrap().values();

    approx::assert_abs_diff_eq!( cct, 3000.0, epsilon = 1E-4);
    approx::assert_abs_diff_eq!( duv, 0.0, epsilon = 1E-6);
  # }
Correlated Color Rendering Index (CRI)

The CIE Color Rendering Index (CRI), including the general color rendering index (Rₐ) and the individual special color rendering indices (R₁ through R₁₅), can be calculated using the cri method, which follows the procedure specified by the CIE2.

  # #[cfg(all(feature = "cri", feature = "cie-illuminants"))]{
  // this example requires `cri` and `cie-illuminants` features enabled

  use crate::colorimetry::prelude::*;

  let f3_11 = CieIlluminant::F3_11.illuminant();
  let cri = f3_11.cri().unwrap();

  let expected_ra = 78.0;
  approx::assert_abs_diff_eq!(cri.ra(), expected_ra, epsilon = 1.0);

  let expected_values = [
      90.0, 86.0, 49.0, 82.0, 81.0, 70.0, 85.0, 79.0, 24.0, 34.0, 64.0, 50.0, 90.0, 67.0,
  ];

  approx::assert_abs_diff_eq!(
      cri.values().as_ref(),
      expected_values.as_ref(),
      epsilon = 1.0
  );

  # }

Colorants

A Colorant represents a color filter or surface (such as a color patch), defined by dimensionless spectral values ranging from 0.0 to 1.0.

Each value corresponds to the proportion of light at a given wavelength that is not absorbed:

  • 0.0 → Full absorption (no transmission or reflection)
  • 1.0 → Full transmission or reflection (no absorption)

This model is commonly used in color science to describe the spectral behavior of materials and follows conventions used in CIE colorimetry.

In color models, a Colorant spectrum in not used directly, but is always associated with an illuminant; without an illuminant, objects appear black.

Initialize from Spectrum

A Colorant is a wrapper around Spectrum and can be created using its new method, which accepts a Spectrum and ensures that all values lie within the range 0.0 to 1.0. If any value falls outside this range, the constructor returns an error.

Factory Functions

The library defines different model based factory functions. Here are a couple of examples.

use crate::colorimetry::prelude::*;

// Create a perfect white `Colorant` or color patch, with no absorption.
let white = Colorant::white(); 

// Create a gray neutral colorant with 30% reflectance at all wavelengths
let gray = Colorant::gray(0.3); 

// A perfect absorber absorbing all light.
let black = Colorant::black();

// A `top_hat` colorant or rectangular bandfilter, defined by a center wavelength,
// and a width, both expressed in units of nanometer or meters.
let green_mono = Colorant::top_hat(550.0, 1.0);

// A `gaussian` shaped colorant, defined by a center values, and a standard deviation 
// `sigma` value, with a peak value of 1.0. 
let red = Colorant::gaussian(610.0, 5.0);
Mixing and Adding

Colorants support several operations useful for simulating physical interactions with light:

  • Multiplication models subtractive mixing, such as placing multiple filters in sequence or layering ink and pigment. For example, multiplying two Colorants simulates how their combined spectral transmissions reduce the overall light passing through.

  • Addition is helpful in constructing synthetic spectral functions—such as building up a custom filter shape by combining multiple Gaussians. Any resulting values above 1.0 are clipped to 1.0.

  • Scalar multiplication adjusts the transmission intensity of a Colorant. This can be used to simulate partial transparency or adjust the concentration of a dye. Resulting values are clamped to the valid [0.0, 1.0] range: values above 1.0 become 1.0, and those below 0.0 become 0.0.

CIELAB The [`Colorant::cielab`] method calculates a colorant's CIELAB values. Here is an example calculating the CIELAB coordinates for a perfect white colorant:
  use crate::colorimetry::prelude::*;

  let colorant = Colorant::white();

  // use default (None) D65 illuminant  and default CIE 1931 standard observer (second None)
  let [l, a, b] = colorant.cielab(None, None).values();

  approx::assert_abs_diff_eq!(l, 100.0, epsilon = 1E-4); // L* should be 100 for white
  approx::assert_abs_diff_eq!(a, 0.0, epsilon = 1E-4); // a* should be 0 for white
  approx::assert_abs_diff_eq!(b, 0.0, epsilon = 1E-4); // b* should be 0 for white

Stimuli

A Stimulus wraps a Spectrum representing the spectral power distribution of light as it arrives at an observer or sensor. This could be a pixel in a camera sensor, or a set of photoreceptors in the human eye. The spectral data is expressed in physical radiometric terms, with units corresponding to luminance: candelas per square meter (cd/m²), integrated over the visible range.

A Stimulus may describe:

  • Emitted light from a self-luminous source, such as a display pixel
  • Reflected light from an object surface element illuminated by a known source
  • Transmitted light after passing through a wavelength-selective medium, such as a colored filter element

In all cases, the stimulus encapsulates the final spectral signal available for visual or digital perception, after any combination of emission, reflection, or transmission events.

Initialize from Spectrum

A Stimulus is a wrapper around Spectrum and can be created using its new method, which accepts a Spectrum and ensures that all values lie within the range 0.0 to 1.0. If any value falls outside this range, the constructor returns an error.

Factory functions
  • Stimulus::from_srgb, and Stimulus::from_rgb, create a Stimulus of a set of RGB pixel values. The first takes three u8 arguments, while the second uses a Rgb object as argument. This function allows calculating the perceived color difference between different observers, from the perspective of a single observer.

    use colorimetry::prelude::*;
    let red = Stimulus::from_srgb(255, 0, 0);
    let red_chromaticity = CIE1931.xyz(&red, None).chromaticity();
    approx::assert_abs_diff_eq!(
        red_chromaticity.to_array().as_ref(),
        &[0.64, 0.33].as_ref(),
        epsilon = 1E-5
    );

Standard Observers

In colorimetry, color perception is modeled as the response of the human visual system to spectral stimuli. Human vision is trichromatic, based on the relative excitations of three cone types (L, M, and S) in the retina. These physiological responses are abstracted in the CIE XYZ color space as X, Y, and Z tristimulus values.

Tristimulus values are computed by integrating a spectral power distribution with a set of three color matching functions (CMFs), which represent the average spectral sensitivity of the human eye. A set of CMFs defines a standard observer.

The primary observer used in most applications is the CIE 1931 2º Standard Observer, derived from color matching experiments with foveal (central) vision. This observer is represented in this library by a static Observer instance: CIE1931.

With the supplemental-observers feature enabled, the library also includes:

License

All content ©2025 Harbers Bik LLC, and licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Footnotes

  1. Commission Internationale de l'Éclairage. (2004). CIE 015:2004: Colorimetry (3rd ed.). Vienna: CIE.

  2. CIE 13.3-1995: Method of Measuring and Specifying Colour Rendering Properties of Light Sources* (Commission Internationale de l'Éclairage, 1995).

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Rust 97.7%
  • JavaScript 2.3%
0