Search code examples
pythoncolors

Multispectral image to RGB in Python


I would like to convert a multispectral image to RGB. After parsing said image, its an ndarray of shape (w, h, c). where c is the hundred-or-so wavelengths which were measured. Null measurements are -999, not 0.

For a single pixel, it is easy to use the colour library to use the "intensities" of each wavelength to recover the colour in sRGB:

import colour

pixel_intensities = {380: 0.048, 385: 0.051, 390: 0.055}

sd = colour.SpectralDistribution(pixel_intensities )
cmfs = colour.MSDS_CMFS["CIE 1931 2 Degree Standard Observer"]
illuminant = colour.SDS_ILLUMINANTS["D65"]

XYZ = colour.sd_to_XYZ(sd, cmfs, illuminant)
red, green, blue = colour.XYZ_to_sRGB(XYZ)

A naive solution for applying this to the entire image would be to go through each pixel and run it through the function one at a time. I found that it was very slow.

Another naive solution would be to cherry pick only three wavelengths: one for the red channel, one for the green channel, and one for the blue channel. This yielded decent results and executed almost instantly in comparison. However, I found that the colours were not very accurate.

Is there an alternative solution that also requires little code?


Solution

  • It is possible to integrate an Array directly but you need to pass the shape along side the array. We also recommend using colour.msds_to_XYZ definition even though it uses colour.sd_to_XYZ definition under the hood. This clarifies the intent! Finally, it is much faster to use the Integration method:

    import numpy as np
    
    import colour.plotting
    from colour import (
        MSDS_CMFS,
        SDS_ILLUMINANTS,
        MultiSpectralDistributions,
        SpectralShape,
        msds_to_XYZ,
    )
    
    cmfs = MSDS_CMFS["CIE 1931 2 Degree Standard Observer"]
    illuminant = SDS_ILLUMINANTS["D65"]
    shape = SpectralShape(400, 700, 60)
    data = np.array(
        [
            [
                0.0137,
                0.0159,
                0.0096,
                0.0111,
                0.0179,
                0.1057,
                0.0433,
                0.0258,
                0.0248,
                0.0186,
                0.0310,
                0.0473,
            ],
            [
                0.0913,
                0.3145,
                0.2582,
                0.0709,
                0.2971,
                0.4620,
                0.2683,
                0.0831,
                0.1203,
                0.1292,
                0.1682,
                0.3221,
            ],
            [
                0.0152,
                0.0842,
                0.4139,
                0.0220,
                0.5630,
                0.1918,
                0.2373,
                0.0430,
                0.0054,
                0.0079,
                0.3719,
                0.2268,
            ],
            [
                0.0281,
                0.0907,
                0.2228,
                0.1249,
                0.2375,
                0.5625,
                0.0518,
                0.3230,
                0.0065,
                0.4006,
                0.0861,
                0.3161,
            ],
            [
                0.1918,
                0.7103,
                0.0041,
                0.1817,
                0.0024,
                0.4209,
                0.0118,
                0.2302,
                0.1860,
                0.9404,
                0.0041,
                0.1124,
            ],
            [
                0.0430,
                0.0437,
                0.3744,
                0.0020,
                0.5819,
                0.0027,
                0.0823,
                0.0081,
                0.3625,
                0.3213,
                0.7849,
                0.0024,
            ],
        ]
    )
    msds = MultiSpectralDistributions(data, shape)
    XYZ = msds_to_XYZ(msds, cmfs, illuminant, method="Integration") / 100
    colour.plotting.plot_image(np.clip(colour.XYZ_to_sRGB(XYZ.reshape(3, 4, 3)), 0, 1))
    
    [[ 0.0750297   0.03948784  0.08403467]
     [ 0.26925968  0.15072461  0.28705781]
     [ 0.16703219  0.28217235  0.25645598]
     [ 0.11576701  0.08640099  0.06576841]
     [ 0.18731479  0.35075036  0.30145727]
     [ 0.45165676  0.39613692  0.4367835 ]
     [ 0.0817557   0.13093418  0.25942094]
     [ 0.22467629  0.19309908  0.07963755]
     [ 0.06578124  0.02525535  0.11093077]
     [ 0.43914736  0.27980392  0.11729266]
     [ 0.08536592  0.19703017  0.17705093]
     [ 0.23908825  0.26212953  0.30676315]]
    

    enter image description here