2

I am trying to extract the wavelength of a pixel by mapping its R,G,B values ​​(0 to 255) with the individual bandwidths of their visible wavelengths

Here is my current python program

#variable

r, g, b = 245, 122, 155 #let's take RGB value of a pixel



def my_map(x, in_min, in_max, out_min, out_max):  #Prominent map function
            return int((x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min)


# Map 8 bits value of R,G,B (0 to 255) to their bandwidth of wavelength
        
R = my_map(r, 0, 255, 499, 700)# rgb 0 = 499 nm, rgb 255 = 700   
G = my_map(g, 0, 255, 440 , 580) # rgb 0 = 440 nm, rgb 255 = 580
B = my_map(b, 0, 255, 380, 490)   # rgb 0 = 440 nm, rgb 255 = 490

print('\nWavelength of R', r , 'is', R, '\nWavelength of G', g , 'is', G, '\nWavelength of B', b , 'is', B,)



#mean of constituent wavelengths

Wavelength = R+G+B
Wavelength /= 3
print('\nWavelength : ', Wavelength )

The map function is working fine, the individual wavelength value of r or g or b is accurate, but the wavelength is a point value in the entire visible spectrum, etc.

In above code I take average of RGB, but it is not accurate. I know this is not the way.

What should I do for accurate wavelength measurement ?

Abhijeet
  • 140
  • 4
  • 14

1 Answers1

1

Nothing guarantees that the RGB values you picked are on the spectral locus, thus you need to find the dominant wavelength.

You need to know which RGB colourspace your RGB values are encoded with, convert to CIE XYZ tristimulus values then CIE xy chromaticity coordinates and finally, you can compute the dominant wavelength. In your case, and because your RGB values are integers, you need to also normalise them to floating point representation whilst not forgetting to apply the inverse encoding colour component transfer function.

Using Colour, which I maintain, and assuming that the values are encoded with sRGB here is how you could do it:

import colour
import numpy as np

RGB_f = np.array([245.0, 122.0, 155.0]) / 255

# Using the individual definitions:
RGB_l = colour.models.eotf_sRGB(RGB_f)
XYZ = colour.RGB_to_XYZ(
    RGB_l,
    colour.models.RGB_COLOURSPACE_sRGB.whitepoint,
    colour.models.RGB_COLOURSPACE_sRGB.whitepoint,
    colour.models.RGB_COLOURSPACE_sRGB.matrix_RGB_to_XYZ,
)
xy = colour.XYZ_to_xy(XYZ)
wl, xy_1, xy_2 = colour.dominant_wavelength(
    xy, colour.models.RGB_COLOURSPACE_sRGB.whitepoint
)

# Using the automatic colour conversion graph:
wl, xy_1, xy_2 = colour.convert(RGB_f, "Output-Referred RGB", "Dominant Wavelength")

print(wl, xy_1, xy_2)

colour.plotting.colour_style()
figure, axes = colour.plotting.plot_chromaticity_diagram_CIE1931(
    diagram_opacity=0.15, standalone=False
)

xy_i = np.vstack([xy_1, xy, colour.models.RGB_COLOURSPACE_sRGB.whitepoint, xy_2])
axes.plot(xy_i[..., 0], xy_i[..., 1], "-o")
colour.plotting.render()

-496.0 [ 0.63564364 0.21924977] [ 0.0211551 0.42807958]

So here, you will notice that the dominant wavelength is negative because the closest intersection is on the line of purples, thus the complementary wavelength is returned instead.

Dominant Wavelength

Kel Solaar
  • 3,660
  • 1
  • 23
  • 29