Skip to content

Conversation

@lassefschmidt
Copy link
Contributor

Summary

A very small PR to enable selecting the Lab → DIN99 conversion variant when computing ΔE_DIN99.

Both colour.difference.delta_E and colour.models.Lab_to_DIN99 expose a method parameter, which makes it impossible to forward the conversion method via the existing **kwargs mechanism without a keyword collision.

To resolve this, a dedicated din99_method parameter is added to colour.difference.delta_E_DIN99. The parameter defaults to "DIN99", matching the normative DIN99 definition used by Lab_to_DIN99.

The provided value is validated against DIN99_METHODS, which remains the single source of truth for supported DIN99 variants.

Preflight

Code Style and Quality

  • [N/A] Unit tests have been implemented and passed.
  • Pyright static checking has been run and passed.
  • Pre-commit hooks have been run and passed.
  • [N/A] New transformations have been added to the Automatic Colour Conversion Graph.
  • [N/A] New transformations have been exported to the relevant namespaces, e.g. colour, colour.models.
TOTAL                                                                          44613   9996    78%
============================= slowest 5 durations =============================
78.73s call     colour/recovery/tests/test_gaussian.py::TestOptimiseGaussianBasisParameters::test_optimise_gaussian_basis_parameters
21.09s call     colour/recovery/tests/test_jakob2019.py::TestLUT3D_Jakob2019::test_size
16.30s call     colour/notation/tests/test_munsell.py::TestxyY_to_munsell_specification::test_xyY_to_munsell_specification
6.93s call     colour/io/luts/lut.py::colour.io.luts.lut.LUT3D.invert
6.55s call     colour/recovery/jakob2019.py::colour.recovery.jakob2019.LUT3D_Jakob2019.write
=========================== short test summary info ===========================
FAILED colour/io/image.py::colour.io.image.read_image_Imageio
FAILED colour/io/tests/test_image.py::TestWriteImageImageio::test_write_image_Imageio_exr
FAILED colour/io/tests/test_image.py::TestReadImageImageio::test_read_image_Imageio
==== 3 failed, 3697 passed, 17 skipped, 225 warnings in 112.27s (0:01:52) =====
===============================================================================
*                                                                             *
*   Checking codebase with "Pyright"...                                       *
*                                                                             *
===============================================================================
0 errors, 0 warnings, 0 informations

Documentation

  • New features are documented along with examples if relevant.
  • The documentation is Sphinx and numpydoc compliant.

@KelSolaar
Copy link
Member

Thanks @lassefschmidt, it is the first time we introduce this pattern, makes me wonder if we should not adopt the machinery that the convert definition uses, e.g., to target the args of sd_to_XYZ specifically:

convert(
    sd,
    "Spectral Distribution",
    "sRGB",
    sd_to_XYZ={"illuminant": SDS_ILLUMINANTS["FL2"]},
)

@KelSolaar
Copy link
Member

KelSolaar commented Jan 30, 2026

So yeah something that we might be able to do:

# Layer 1: filter direct kwargs by target function signature
filtered_kwargs = filter_kwargs(conversion_function, **kwargs)

# Layer 2: merge in function-name-keyed dict (overrides)
filtered_kwargs.update(kwargs.get(conversion_function_name, {}))
delta_E(a, b, method="DIN99", delta_E_DIN99={"method": "DIN99b"})

And delta_E_DIN99 could simply have a method parameter (consistent with the other 100+ functions in the codebase):

def delta_E_DIN99(Lab_1, Lab_2, textiles=False, method="DIN99"):
    ...

@lassefschmidt
Copy link
Contributor Author

Thanks @lassefschmidt, it is the first time we introduce this pattern, makes me wonder if we should not adopt the machinery that the convert definition uses, e.g., to target the args of sd_to_XYZ specifically:

convert(
    sd,
    "Spectral Distribution",
    "sRGB",
    sd_to_XYZ={"illuminant": SDS_ILLUMINANTS["FL2"]},
)

I had the same thought when writing this PR, but didn’t want to introduce too big of a change. This way, we would also get rid of all the « extra » parameters depending on the function (e.g. the textiles boolean or the l:c values)

We could even allow users to provide ANY color space array for a and b (and a and b must not even have the same color space), the keyword dict for the conversion function to the desired target space and use the conversion graph. Which would create a super convenient delta E wrapper. But possibly overkill !

@KelSolaar KelSolaar changed the title Enable DIN99 method selection in ΔE_DIN99 PR: Enable *DIN99* method selection in colour.difference.delta_E_DIN99 definition. Jan 30, 2026
@KelSolaar
Copy link
Member

I tend to prefer API consistency over special cases (I know that we already have plenty!) so if you are happy with suggested changes, please roll!

@lassefschmidt
Copy link
Contributor Author

Happy to propose a new implementation then. Give me a few days max and I should push an update to this PR (probably rebased on most recent develop branch).

One clarification : if we extend to arbitrary color space inputs a and b and pass the conversion args for the .convert function, do we also want to « improve » how we treat the different additional arguments of the delta E methods (such as textiles boolean or l:c) ? Can we introduce breaking changes here (e.g. via the keyword dict using the delta E method name as you proposed) or we keep supporting a direct pass of textiles and l:c in the delta E wrapper ?

@KelSolaar
Copy link
Member

how we treat the different additional arguments of the delta E methods (such as textiles boolean or l:c) ?

Can you clarify? textiles for example should be filtered and only passed if relevant to a function right?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants