'How to convert RGB to Wavelength in python
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 ?
Solution 1:[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.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Kel Solaar |

