0

I'm working with HSV image pixels. I need to get wavelengths of those pixels. By [this][1] particular question I understood, how to get in touch with standard colors. I know the fact that some colors (e.g. magenta) cant be directly converted because they are a mix of wavelengths. I need to prepare in order to work with them still. I want to get the distribution like this: the X axis is wavelength, and the Y axis is the part, that the particular wavelength is taking in the final color. Obviously, the sum of all Y's should be 1 (the full color). How to implement this thing with python? I'm investigating this for quite some time, still didn't get it. Thank you!

UPD #1: As posted in the comments, there are infinite ways to do this. It would be convenient if for each color it would be the least possible number of wavelengths (for example, for blue, just one needed, for magenta, e.g. two, for white e.g. 3). [1]: Hue to wavelength mapping

Aromik AR
  • 3
  • 2
  • As stated in your link, you can't recover the full spectrum. Many different spectrums will map to the same hue. You need to first decide which of those you will want. Do you want one that contains only 3 wavelengths, with all others zero (same 3 wavelengths for all hues)? Do you want one that contains only one wavelength, with all others zero (different wavelength for different hue)? If not one of those options, your requirements are ambiguous and need to be refined. – Dan Getz Aug 15 '22 at 19:20
  • For any given color, there are an infinite number of wavelengths that can combine to create it, just because of the way our eyes work. – Mark Ransom Aug 15 '22 at 19:30
  • @DanGetz I didn't know about the fact of different distributions. I know, that, probably, not all colors work with just one wavelength (e.g. white), so imma state the question like this: how to do this is minimum possible number of wavelengths (for example, for blue, just one needed, for magenta, e.g. two, for white e.g. 3)? – Aromik AR Aug 15 '22 at 19:42
  • @MarkRansom It would be convenient to get that color in the least possible number of different wavelengths – Aromik AR Aug 15 '22 at 19:42
  • For any hue, like blue, magenta, yellow, green, etc, only one is needed. More are needed to include saturation and value components, to make things like white, black, etc. A common way to encode colors with a small number of wavelengths is RGB. But I think you need to take a step back and ask yourself the question of *why* you're looking for wavelength information from HSV values, *what* would you do with that? There's a good chance whatever you thought you'd do with it won't work the way you originally expected. – Dan Getz Aug 15 '22 at 19:48
  • @DanGetz I need to get particularly the wavelengths, and the only way I found to work with them is converting the color scheme into HSV. I don't particularly know how to do this in RGB. If it's possible, would be great. About least numbers, how to express with just one wavelength, e.g., the color pink? Its a mix of red and purple, not obvious – Aromik AR Aug 15 '22 at 19:52
  • The whole point is that "the wavelengths" is ambiguous. There is no single answer to the question. For example, if you take a digital photo, you can never, ever find out the wavelength spectrum that caused a given pixel value in that photo. It sounds like you have an X-Y problem. You should mention the next step in your process, so people can help point you in the right direction. – Dan Getz Aug 15 '22 at 19:57
  • Ok, @DanGetz Its astronomical things, I will calculate the "average" wavelength based on that distribution, and then imma change it according to some rule, and then I'll need to build up a new color for the pixel, based on that new "average" wavelength Obviously, most of the colors can be represented with just one wavelength, and that distribution isn't even needed, but I may get in touch with non-standard colors, like pink, who (I think) cant be represented with just one wavelength. – Aromik AR Aug 15 '22 at 20:00
  • No, it's **not** obvious that most colors can be represented with just one wavelength, particularly the colors of stars - the color of our own star for example, the Sun, is by definition white. And white consists of an even distribution of *all* wavelengths. – Mark Ransom Aug 16 '22 at 03:15
  • @MarkRansom can you please suggest a way of calculating that WL? – Aromik AR Aug 16 '22 at 08:50
  • What part of *impossible* do you not understand? – Mark Ransom Aug 16 '22 at 13:41
  • @MarkRansom you said that every color can be represented with just one wavelength. Then why is it impossible? You said its possible with just one WL for each color, and now you say its impossible? – Aromik AR Aug 16 '22 at 14:00
  • At no point did I state or imply that a color is a single wavelength, in fact I've been stressing the opposite. That's why RGB works so well. The only way to get a single wavelength is with a prism or a laser. – Mark Ransom Aug 16 '22 at 16:26
  • From a colour science standpoint, you can describe any colour by its dominant wavelength, e.g. 450nm and excitation purity, e.g. 0.6. Once you have the wavelength in nm, you can compute the actual colour on the spectral locus. Would you be interested in an example? A more naive way is to convert to HSV, keep the Hue and set the saturation to maximum. – Kel Solaar Aug 16 '22 at 19:12
  • @KelSolaar yes, please. That would be the possible answer. – Aromik AR Aug 16 '22 at 19:14

1 Answers1

0

Using colour and the dominant_wavelength definition, it is relatively straightforward to achieve in 3 or 4 lines:

# 6 Random RGB values, assuming that they are "sRGB" encoded.
RGB = np.random.random([6, 3])

# Converted to "CIE xy" chromaticity coordinates.
xy = colour.XYZ_to_xy(colour.sRGB_to_XYZ(RGB, apply_cctf_decoding=False))
whitepoint = colour.models.RGB_COLOURSPACE_sRGB.whitepoint

# The dominant wavelength computation call, "wl" represents the
# wavelengths, "f_i" and "s_i" the first and second intersection
# on the spectral locus.
# A negative dominant wavelength means that the line of purple is
# where the intersection occurred
wl, f_i, s_i = colour.dominant_wavelength(xy, whitepoint)

# ****************************************************************************

# Plotting the data in the "CIE 1931 Chromaticity Diagram".
figure, axes = colour.plotting.plot_chromaticity_diagram_CIE1931(
    diagram_opacity=0.15, standalone=False
)

cycle = colour.plotting.colour_cycle()
for i in range(len(f_i)):
    point_colour = next(cycle)
    axes.plot(xy[i, 0], xy[i, 1], "o", color=point_colour)
    axes.plot(
        [whitepoint[0], f_i[i][0]],
        [whitepoint[1], f_i[i][1]],
        color=point_colour,
    )

# Plotting the data as colour swatches.
# !!! Note that your display most likely cannot represent
# them properly, they are out-of-gamut !!!
RGB_wl = colour.XYZ_to_sRGB(colour.xy_to_XYZ(f_i), apply_cctf_encoding=False)

colour_swatches = [
    colour.plotting.ColourSwatch(a, wl[i])
    for i, a in enumerate(colour.cctf_encoding(RGB))
] + [
    colour.plotting.ColourSwatch(a, wl[i])
    for i, a in enumerate(colour.cctf_encoding(RGB_wl))
]
colour_swatches = [
    swatch
    for pairs in zip(
        colour_swatches[0 : len(colour_swatches) // 2],
        colour_swatches[len(colour_swatches) // 2 :],
    )
    for swatch in pairs
]
colour.plotting.plot_multi_colour_swatches(
    colour_swatches,
    columns=len(RGB),
    compare_swatches="Diagonal",
)

Google Colab notebook if you want to test live: https://colab.research.google.com/drive/1cxhLBh2JtzVh8XUfe0-oJ4YDCyrW7mD5?usp=sharing

CIE 1931 Chromaticity Diagram Colour Swatches

Kel Solaar
  • 3,660
  • 1
  • 23
  • 29
  • 1
    Ok, this works perfectly But is there a way of converting wavelength back into RGB? – Aromik AR Jan 06 '23 at 09:50
  • The `colour.wavelength_to_XYZ` definition allows you to convert back to CIE XYZ tristimulus values, then you can use the `colour.XYZ_to_RGB` definition. It can be done in one call with the `colour.convert(wavelengths, "Wavelength", "RGB")` definition. – Kel Solaar Jan 06 '23 at 23:28