-
-
Notifications
You must be signed in to change notification settings - Fork 287
Incoherent behaviour of "colour.SpectralDistribution.interpolate" and "colour.MultiSpectralDistributions.interpolate" methods. #566
Description
I noticed this a while ago and had that in my bottom-less stack of stuff to address:
colour.SpectralDistribution.interpolateandcolour.MultiSpectralDistributions.interpolatemethods should probably use underlying interpolator.
Context
The logic used by the colour.SpectralDistribution.interpolate and colour.MultiSpectralDistributions.interpolate methods to choose the interpolator was implemented as follows:
if interpolator is None:
if self.is_uniform():
interpolator = SpragueInterpolator
else:
interpolator = CubicSplineInterpolatorBasically, if the interpolator argument is not passed, the spectral distribution uniformity is tested and the Sprague (1880) method is used for interpolating if the wavelengths are uniform and the Cubic Spline method is used if they are not, according to CIE 167:2005 recommendation.
However, this is not applicable to most illuminants and light sources because their spectrum often possesses emission spikes:
Coincidentally, the CIE recommends using linear interpolation for the CIE Illuminant D Series, thus we use colour.LinearInterpolator as the default instantiation time interpolation class for all our illuminants and light sources. Note that we might in the future test for smoothness to choose the appropriate method.
Problem
The problem lies in the fact that when the colour.SpectralDistribution.align, colour.MultiSpectralDistributions.align, colour.SpectralDistribution.interpolate and colour.MultiSpectralDistributions.interpolate methods are invoked, they do not honour the instantiation time interpolation class and will forcibly use either the colour.SpragueInterpolator or colour.CubicSplineInterpolator classes unless an interpolator argument is passed.
This behaviour is not desirable and we are changing it so that if the instantiation time interpolation class is not one of colour.SpragueInterpolator or colour.CubicSplineInterpolator, then, it will be used instead and thus will take precedence over the CIE 167:2005 recommendation.
The new logic is as follows:
if interpolator is None:
if self.interpolator not in (SpragueInterpolator,
CubicSplineInterpolator):
interpolator = self.interpolator
elif self.is_uniform():
interpolator = SpragueInterpolator
else:
interpolator = CubicSplineInterpolatorThe immediate consequence is small numerical changes to various spectral computations, for example:
>>> illuminant = ILLUMINANTS_SDS['D65']
>>> sd_to_XYZ_tristimulus_weighting_factors_ASTME308(
... sd, cmfs, illuminant) # doctest: +ELLIPSIS
- array([ 10.8402899..., 9.6843539..., 6.2160858...])
+ array([ 10.8405832..., 9.6844909..., 6.2155622...])
>>> from colour import COLOURCHECKERS_SDS
>>> sd = COLOURCHECKERS_SDS['ColorChecker N Ohta']['dark skin']
>>> sd_to_aces_relative_exposure_values(sd) # doctest: +ELLIPSIS
- array([ 0.1171785..., 0.0866347..., 0.0589707...])
+ array([ 0.1171814..., 0.0866360..., 0.0589726...])
Colour quality metrics are affected a bit more severely:
```diff
>>> from colour import ILLUMINANTS_SDS
>>> sd = ILLUMINANTS_SDS['FL2']
>>> colour_rendering_index(sd) # doctest: +ELLIPSIS
- 64.1515202...
+ 64.2337241...
>>> from colour import ILLUMINANTS_SDS
>>> sd = ILLUMINANTS_SDS['FL2']
>>> colour_quality_scale(sd) # doctest: +ELLIPSIS
- 64.0172835...
+ 64.1117031...We will also need to update some chromaticity coordinates of various illuminants accordingly.

