I finished working on spectral upsampling methods about two weeks ago. Since then I've been working on a different part of the library, the
quality submodule. As described in the original project idea, the goals are:
- Adding support for CIE 224:2017 Colour Fidelity Index.
- Adding support for ANSI/IES TM-30-18, a standard defining the same index and a couple more.
- Adding support for creating TM-30-18 Color Rendition Reports. This part I proposed myself after seeing an open issue for it.
The first two are already complete, see the pull request. The last goal is being worked on in a separate repository, since I'm not yet sure how exactly I want to implement the reports (just Matplotlib, HTML, something else?).
I took the dataset published alongside Otsu et. al (2018) and colorcheckers included in Colour, about 1300 reflectance spectra in total, reconstructed them using various methods and compared them with the original data. I used CIE Standard Illuminant D65 and two metrics:
- CIE 1976 ΔE1), quantizing the perceived difference between two colors. Values around 2.4 are taken as the just-noticeable difference, so deltas smaller than this should be insignificant.
- Mean squared error (MSE), the mean squared difference between the original and reconstructed spectra. For any reflectance, there infinitely many metamers, other reflectances that look exactly the same (ΔE=0) under a given illuminant. Good spectral upsampling should result in realistic spectra, i.e. those that look similar to those of common and natural materials. This helps spectral rendering to achieve natural results as well. See Peters et al. (2019) for an interesting and more in-depth discussion of the topic.
Below are chromaticity diagrams with error heatmaps drawn over them. The color of each square bin represents the mean error of samples lying inside the square. The numbers above the diagrams are, in order, the minimum, maximum, mean and standard deviation of the errors.
In the previous part I mentioned that reflectances reconstructed using this method can exceed the [0, 1] range and violate conservation of energy. Indeed, I could simply ask it for an imaginary color and get a weird, unphysical spectrum.
What's interesting is that this doesn't happen in practice, when upsampling real data. Out of almost 1300 reflectances I tested, I found only one bad reconstruction. Using the original clustering, the result for
BabelColor Average colorchecker reflects 100,6% of light at 730 nm. Clipping this value to 100% creates a tiny color difference, orders of magnitude smaller than the just-noticeable difference.
Many methods have this property of being able to create perfect metamers, so looking at ΔE's isn't very interesting. In a future post I'll take a look at MSE (mean square error), which quantizes differences between spectra themselves, and compare a few methods.