5
\$\begingroup\$

Say I've calibrated a monitor to the standard 6500k 2.2 gamma, and the color space is sRGB.

On this monitor, I would like to have a reasonably accurate representation of a monochromatic radiation (like a laser) of known wavelength.

The RGB pixel values should be deduced unambiguously from this data. How do I do it?

(I understand there is no way to truly show monochromatic stuff on a monitor - I'm just asking for the best approximation of the hue)

\$\endgroup\$
7
  • 1
    \$\begingroup\$ Maybe this is a question for Physics. \$\endgroup\$
    – xiota
    Nov 7, 2020 at 0:25
  • 1
    \$\begingroup\$ As Michael's answer points out, you can't get an exact sRGB value for any one wavelength. One tradeoff some find useful is to find the correct hue and highest saturation sRGB value for any given wavelength. Most wavelengths would be strongly desaturated therefore one of the 3 rgb values would be zero. Would that suffice? \$\endgroup\$
    – doug
    Nov 8, 2020 at 5:00
  • \$\begingroup\$ @doug That's exactly what I was thinking about, but I stopped there because I don't know the equations that would apply in my case. I've a degree in physics and electronics, I'm an amateur astronomer and photographer, and I understand the broad features of the CIE diagram (but not the things of detail). Case in point, the hydrogen alpha line at 656.3 nm - what's the most accurate way to show that on my calibrated monitor? Obviously G=0, maybe a bit of B, and surely a lot of R, but what are the exact values? But I would like to see a general solution as well for all wavelengths. \$\endgroup\$ Nov 8, 2020 at 22:24
  • 1
    \$\begingroup\$ Ah. This does come up from time to time. It's actually not that hard but looking around the net I haven't seen anyone address this. The math is not complicated but is tedious due to the various conversions and requirements to identify line intersections. I'll give it a shot. What I'll do is provide a list of visible wavelenths in increments of 1nm and the associated sRGB of maximally saturated values while maintaining hue. Stay tuned. I'll code it in Matlab. \$\endgroup\$
    – doug
    Nov 9, 2020 at 1:57
  • 1
    \$\begingroup\$ Well, I've got all the RGB values in 1nm increments for sRGB that gives the brightest, highest saturation, and matching hue. 656nm comes out to sRGB(255,0,87). Your estimate that there is a bit of blue in that is right. I'll put together an answer with a full listing for 400nm to 700nm tomorrow. The brightness is arbitrary so I maxed values out at 255. \$\endgroup\$
    – doug
    Nov 9, 2020 at 6:25

2 Answers 2

3
\$\begingroup\$

Maximally saturated monochromatic colors in sRGB

This is a list of sRGB values that preserve hue but are at the maximum color saturation achievable with sRGB in wavelength steps of 1nm from 390nm to 700nm.

These represent colors achievable by mixing D65 (White) with the XYZ colors along a monochromatic range such that the resulting color intersects with the sRGB gamut.

NM       ----------------------------------- RGB -----------------------------------
390      146   0 255     145   0 255     145   0 255     145   0 255     145   0 255
395      145   0 255     145   0 255     145   0 255     145   0 255     145   0 255
400      145   0 255     145   0 255     145   0 255     145   0 255     145   0 255
405      145   0 255     145   0 255     145   0 255     144   0 255     144   0 255
410      144   0 255     144   0 255     144   0 255     144   0 255     144   0 255
415      144   0 255     144   0 255     143   0 255     143   0 255     143   0 255
420      143   0 255     142   0 255     142   0 255     142   0 255     142   0 255
425      141   0 255     141   0 255     140   0 255     140   0 255     139   0 255
430      139   0 255     138   0 255     138   0 255     137   0 255     136   0 255
435      136   0 255     135   0 255     134   0 255     133   0 255     132   0 255
440      131   0 255     130   0 255     129   0 255     128   0 255     126   0 255
445      125   0 255     123   0 255     122   0 255     120   0 255     118   0 255
450      116   0 255     113   0 255     111   0 255     108   0 255     105   0 255
455      102   0 255      98   0 255      94   0 255      89   0 255      84   0 255
460       77   0 255      70   0 255      61   0 255      48   0 255      25   0 255
465        0  37 255       0  56 255       0  71 255       0  82 255       0  93 255
470        0 102 255       0 111 255       0 120 255       0 128 255       0 136 255
475        0 143 255       0 151 255       0 158 255       0 165 255       0 172 255
480        0 179 255       0 186 255       0 193 255       0 200 255       0 207 255
485        0 214 255       0 220 255       0 227 255       0 233 255       0 240 255
490        0 246 255       0 252 255       0 255 252       0 255 246       0 255 241
495        0 255 236       0 255 231       0 255 227       0 255 223       0 255 219
500        0 255 216       0 255 212       0 255 209       0 255 206       0 255 203
505        0 255 201       0 255 198       0 255 195       0 255 193       0 255 191
510        0 255 188       0 255 186       0 255 184       0 255 182       0 255 180
515        0 255 178       0 255 176       0 255 174       0 255 173       0 255 171
520        0 255 169       0 255 167       0 255 166       0 255 164       0 255 162
525        0 255 160       0 255 158       0 255 157       0 255 155       0 255 152
530        0 255 150       0 255 148       0 255 146       0 255 143       0 255 141
535        0 255 138       0 255 135       0 255 132       0 255 128       0 255 124
540        0 255 120       0 255 115       0 255 110       0 255 104       0 255  98
545        0 255  90       0 255  80       0 255  68       0 255  50       0 255  14
550       45 255   0      68 255   0      84 255   0      97 255   0     109 255   0
555      120 255   0     131 255   0     140 255   0     150 255   0     158 255   0
560      167 255   0     176 255   0     184 255   0     192 255   0     201 255   0
565      209 255   0     217 255   0     226 255   0     234 255   0     242 255   0
570      251 255   0     255 250   0     255 242   0     255 234   0     255 227   0
575      255 220   0     255 213   0     255 206   0     255 200   0     255 193   0
580      255 187   0     255 182   0     255 176   0     255 170   0     255 165   0
585      255 160   0     255 154   0     255 149   0     255 144   0     255 139   0
590      255 134   0     255 129   0     255 125   0     255 120   0     255 115   0
595      255 110   0     255 106   0     255 101   0     255  97   0     255  92   0
600      255  87   0     255  83   0     255  78   0     255  73   0     255  68   0
605      255  62   0     255  56   0     255  50   0     255  44   0     255  36   0
610      255  26   0     255  10   0     255   0  19     255   0  30     255   0  37
615      255   0  42     255   0  47     255   0  50     255   0  53     255   0  56
620      255   0  59     255   0  61     255   0  63     255   0  65     255   0  66
625      255   0  68     255   0  69     255   0  70     255   0  72     255   0  73
630      255   0  74     255   0  75     255   0  76     255   0  76     255   0  77
635      255   0  78     255   0  79     255   0  79     255   0  80     255   0  81
640      255   0  81     255   0  82     255   0  82     255   0  83     255   0  83
645      255   0  84     255   0  84     255   0  84     255   0  85     255   0  85
650      255   0  85     255   0  86     255   0  86     255   0  86     255   0  86
655      255   0  87     255   0  87     255   0  87     255   0  87     255   0  87
660      255   0  87     255   0  88     255   0  88     255   0  88     255   0  88
665      255   0  88     255   0  88     255   0  88     255   0  88     255   0  88
670      255   0  88     255   0  89     255   0  89     255   0  89     255   0  89
675      255   0  89     255   0  89     255   0  89     255   0  89     255   0  89
680      255   0  89     255   0  89     255   0  89     255   0  89     255   0  89
685      255   0  89     255   0  89     255   0  90     255   0  90     255   0  90
690      255   0  90     255   0  90     255   0  90     255   0  90     255   0  90
695      255   0  90     255   0  90     255   0  90     255   0  90     255   0  90
700      255   0  90

This is an image in sRGB over 390 to 700nm

sRGB of maximally bright gamut edge colors preserving hue

This is the Matlab code that produced the table and image.

% max_saturated_monochromatics in sRGB
r_xyY=[0.6400   0.3300  0.212656]; % sRGB Red
g_xyY=[0.3000   0.6000  0.715158]; % sRGB Green
b_xyY=[0.1500   0.0600  0.072186]; % sRGB Blue
w_xyY=[0.312727 0.329023 1.000000]; % D65 Whitepoint
% Whitepoint verify: xyYtoXYZ(r_xyY)+xyYtoXYZ(g_xyY)+xyYtoXYZ(b_xyY)
xy=[];
for i = 390:700
    xy(i-389,:)=get_intersection_points(i);
end
r=xyYtoXYZ([xy repmat(1,311,1)]);
r=xyz2rgb(r);
f=.9999;
for i = 1:length(r)       % reduce magnitude until legal max RGB
    while max(r(i,:)) > 1
        r(i,:)=f*r(i,:);
    end
end
r=round(255*r); % represent in 0-255 for 8 bit RGB
w_rgb=[(390:700)' r];
fprintf("NM       ----------------------------------- RGB -----------------------------------")
for i=390:700
    if mod(i,5)==0
        fprintf("\n%3d ", w_rgb(i-389, 1));
    end
    fprintf("    %4d%4d%4d", w_rgb(i-389, 2:4));
    if i==700
        fprintf("\n");
    end
end
imag=[];
index=1;
for i = 1:length(w_rgb)
    for ii = 1:2
        imag(index,:,:)=reshape(repmat(w_rgb(i,2:4),200,1),1,200,3);
        index=index+1;
    end
    if mod(i,10)==1
        imag(index,:,:)=reshape(repmat([0 0 0],200,1),1,200,3);
        index=index+1;
    end
    for ii = 1:2
        imag(index,:,:)=reshape(repmat(w_rgb(i,2:4),200,1),1,200,3);
        index=index+1;
    end
end
imwrite(imag/255, 'sRGB_WaveLength.tif', 'Resolution', 150)

function XYZ = xyYtoXYZ(xyY)
X = xyY(:,1).*xyY(:,3)./xyY(:,2);
Y = xyY(:,3);
Z = (1-xyY(:,1)-xyY(:,2)).*xyY(:,3)./xyY(:,2);
XYZ = [X Y Z];
end

% intersection of D65 whitepoint and gamut edge  with sRGB boundary chromaticities
function s_xy=get_intersection_points(wlen)
r_xy=[0.6400 0.3300];
g_xy=[0.3000 0.6000];
b_xy=[0.1500 0.0600];
w_xy=[0.312727 0.329023];
e_xy=getxy(wlen);
gb_xy=intersect(g_xy(1),g_xy(2), b_xy(1),b_xy(2), w_xy(1),w_xy(2), e_xy(1), e_xy(2));
rg_xy=intersect(r_xy(1),r_xy(2), g_xy(1),g_xy(2), w_xy(1),w_xy(2), e_xy(1), e_xy(2));
rb_xy=intersect(r_xy(1),r_xy(2), b_xy(1),b_xy(2), w_xy(1),w_xy(2), e_xy(1), e_xy(2));

% select intersection that cooresponds to 
if wlen < 465
    s_xy=rb_xy;
elseif wlen < 550
    s_xy=gb_xy;
elseif wlen < 612
    s_xy=rg_xy;
else
    s_xy=rb_xy;
end
end

%find intersection of two lines given endpoints
function s_xy=intersect(x1,y1, x2,y2, x3,y3, x4,y4)
s_xy(1)=((x1*y2-y1*x2)*(x3-x4) - (x1-x2)*(x3*y4-y3*x4)) / ...
    ((x1-x2)*(y3-y4) - (y1-y2)*(x3-x4));
s_xy(2)=((x1*y2-y1*x2)*(y3-y4) - (y1-y2)*(x3*y4-y3*x4)) / ...
    ((x1-x2)*(y3-y4) - (y1-y2)*(x3-x4));
end

function e_xy=getxy(wlength)
persistent cie
if isempty(cie)
    cie=load('ciexyz31_1.txt'); % CIE1931 2 degree wavelength and XYZ in 1nm from 360nm to 830nm
end
cie400=cie;% (41:end,:);
s=sum(cie400(wlength-359,2:4));     % convert to xy chromaticity coordinates
e_xy(1)=cie400(wlength-359,2)/s;
e_xy(2)=cie400(wlength-359,3)/s;
end
\$\endgroup\$
6
  • \$\begingroup\$ Holy cow, this is amazing. Thank you so much! I'll go play with the pixels now, I'm very curious to see how the images look like. \$\endgroup\$ Nov 9, 2020 at 20:49
  • 1
    \$\begingroup\$ Note that these values only work for sRGB color space. For other color spaces, such as AdobeRGB or Rec2020, they would need to be recalculated. How they display would also be dependent upon a given monitor's ability to accurately display 100% of the given color space. Many monitors do not have 100% coverage of sRGB, much less any larger color spaces. \$\endgroup\$
    – Michael C
    Nov 14, 2020 at 6:35
  • \$\begingroup\$ Also note that even with an accurate monitor with 100% coverage of sRGB, they would not produce the same response in a human retina that the pure spectral colors would. Rather, it would produce the nearest approximation that can be created using sRGB color space. \$\endgroup\$
    – Michael C
    Nov 14, 2020 at 6:38
  • \$\begingroup\$ @MichaelC Both of your last comments are quite correct. However, the OP asked about getting the closest, in a maximum saturation sense, pure spectral colors. In sRGB most of these are highly desaturated as sRGB is quite a small colorspace. As for monitors, most desktop monitors, when profiled, can do a reasonable job while laptop colorspaces are often quite a bit more narrow than sRGB to decrease battery drain. I considered adding Adobe RGB as it would have been easy, but that wasn't the OP's question. OTOH, it might be useful for other readers with a wider gamut monitor. \$\endgroup\$
    – doug
    Nov 14, 2020 at 14:55
  • \$\begingroup\$ @doug The OP asked about getting them in RGB, which encompasses all of the discussed color spaces involved including Rec2020, not about getting them in sRGB. Perhaps sRGB is what the OP meant, but it is not what the OP asked. \$\endgroup\$
    – Michael C
    Nov 15, 2020 at 23:20
5
\$\begingroup\$

You're not really trying to produce a reasonable representation of a single wavelength because, as you have noted, an RGB color reproduction system is not capable of doing that. (Unless that wavelength of light happens to coincide with one of the wavelengths used for either red, green or blue by the emissive RGB system and if the display used emits a very narrow band for each color it uses. Most displays do not emit narrow color bands for the three colors they use, and even fewer displays emit a pure spectral color as one of those three.)

What you're actually trying to do is produce a similar retinal response in humans that would occur if a human perceived a specific wavelength. You can reproduce many colors that humans can perceive by varying the intensity of the each of the three color channels used by RGB color reproduction systems.

Unfortunately, the short answer is that for many pure spectral colors, you can't reproduce the same retinal response using emissive RGB color reproduction systems. If why this is so were a "relationship status" (Single, Married, Taken, etc.), the explanation for this would be "It's Complicated." We'll try to break it down briefly below, but to do so we're going to have to leave pure spectral colors behind for a bit and talk about how our color reproduction systems can emulate many of the things we see in the world around us.

There are reams of material that discuss how this may be accomplished and most are far too involved to attempt to summarize here in one answer. One of my favorites that is reasonably brief and uses "layman's terms" is this basic course on color reproduction hosted on Memcode. I'll use a few illustrations from it below. Various aspects of color reproduction have been covered in a wide variety of existing questions here at Photography SE.

Here are a few of them:

Why are Red, Green, and Blue the primary colors of light?
What does an unprocessed RAW file look like?
RAW files store 3 colors per pixel, or only one?
Why don't mainstream sensors use CYM filters instead of RGB?
Why are camera sensors green?
Why do we use RGB instead of wavelengths to represent colours?

As they apply to this question, the basic answer is that human vision is trichromatic. The three types of cones in the human retina are most sensitive to light at approximately 420, 534, and 564 nanometers. But each type of cone is also sensitive to a much wider range of wavelengths on each side of those peaks. Please note that though the three types of cones may be identified as "red", "green", and "blue", their peak sensitivities do not correspond to the three wavelengths of light used by RGB color reproduction systems. This is particularly the case with L-cones that are most sensitive to 564nm yellow-green light, even though we have been calling them our "red" cones since long before we could accurately measure the actual peak sensitivities of each of the three types of retinal cones.

enter image description here

Our color cameras are usually covered by a Bayer Mask with filters that are what we call "red", "green", and "blue". Our Bayer Masked sensor use colors that mimic (though not exactly) the sensitivities of our retinal cones. They're usually most sensitive to around 460, 540, and 600 nanometers. 600nm is a yellowish-orange color. There are no true 'Red' filters in a Bayer mask, all of the cute little drawings on the internet notwithstanding.

enter image description here

On the other hand, RGB color reproduction systems usually emit light at about 460, 525, and 640 nanometers. The specific colors can vary widely from one display to the next. Some four-color emissive displays also have a yellow channel at about 580nm, which is actually closer to the the 564nm peak sensitivity of our "red" cones than the 590-600nm peak of the "red" filters on our Bayer Masks or the 640nm light emitted by the 'Red' channel of our RGB color reproduction systems.

Here's a graph that shows the sensitivity of a specific CMOS color sensor. I've drawn vertical lines that correspond to typical RGB and RYGB emissive displays.

enter image description here

It should be fairly obvious from the graph that one can't just take the raw illuminances measured by a Bayer masked sensor and take the monochrome luminance values from each "red", "green", and "blue" filtered photosite and feed them to an RGB emissive display and expect to produce anywhere near the same human retinal response that the original scene produced. The raw values from a digital camera's sensor must be processed to give an RGB value for each pixel in an image, as well as transform the linear response of a digital sensor to the logarithmic (with an S-curve at the upper and lower bounds) response of human vision to differences in brightness.

The following section draws upon material included in the color course hosted at Memcode linked above.

Most of the things we see in the world around us emit or reflect a distribution of various wavelengths of light. We call this the spectral distribution of an object.

enter image description here

Note that the HeNe laser has a single vertical line at about 633nm. The other things show a wide spectral distribution. Also notice that "LCD Blue" and "LED Red", two of the colors emitted by different types of RGB displays, have a moderately wide spectral distribution.

Now let's look at the spectral distribution of white light reflected off of a lemon versus the spectral distribution of a (color correct) picture of that lemon on an emissive RGB screen.

enter image description here

How do our eyes see the same color for these different spectral distributions?

enter image description here
enter image description here

Even though the shape of the area of the response is different for each of the cones, the total area of each response is the same! It's the total area that determines the strength of the signal from each cone that is sent to our brain for processing into our perception of what stimulates our retinal cones.

enter image description here

Now let's go back and look at all of the colors humans can perceive. This is often illustrated using a graph in CIE color space.

From Wikipedia:

The CIE 1931 color spaces are the first defined quantitative links between distributions of wavelengths in the electromagnetic visible spectrum, and physiologically perceived colors in human color vision.

enter image description here
The CIE 1931 color space chromaticity diagram. The outer curved boundary is the spectral (or monochromatic) locus, with wavelengths shown in nanometers. Note that the colors your screen displays in this image are specified using sRGB, so the colors outside the sRGB gamut are not displayed properly. Depending on the color space and calibration of your display device, the sRGB colors may not be displayed properly either.

Pure spectral colors fall along the dark black line on the outer edge of the curve.

Now let's superimpose the color gamut that shows what a three color emissive display can reproduce based on the three colors it emits (shown as the corners of a triangle):

enter image description here

Notice that the edge of the CIE color space where the pure spectral colors are located are outside of the triangle that can be reproduced by the three colors at the corners of the triangle!

Here's a slightly more sophisticated graph that shows a wide variety of commonly used color spaces for emissive color reproduction systems. It's from this page at Clarkvision.com, which is another excellent resource for learning about color reproduction.

enter image description here

As you can see, what is by far the most commonly used color space by emissive color displays worldwide, sRGB, does not include any pure spectral colors. Neither does the second most common one used by most more advanced emissive displays, AdobeRGB. Some fairly recent (and far less common) wide gamut devices use color spaces that are even wider than AdobeRGB. DCI-P3 and Rec2020 are two such very wide gamut color spaces that a few high end monitors can reproduce with a high degree of coverage. Rec2020 is spectrally defined with Red, Green, and Blue primaries at 467, 532, and 630 nanometers respectively. Because of the shape of the spectral locus, which is not triangular in shape when plotted on a CIE grid, the remaining pure spectral colors that humans can perceive cannot be created by any RGB emissive color system technologies.

To get to the left of the line between 467nm and 572nm in the Rec2020 color space and produce a retinal response equivalent to, say, a pure wavelength of 500nm, one would need to produce a negative value for Red at 630nm. That is, one would need for the retina's L-cones ("red" cones) most sensitive to about 564nm to somehow subtract from the signal going to the brain created by the display's Green channel emitting at 572nm while also allowing a significant response from the M-cones ("green" cones) most sensitive to about 534nm.

\$\endgroup\$
5
  • \$\begingroup\$ Amazing answer! \$\endgroup\$
    – Eric S
    Nov 7, 2020 at 12:58
  • \$\begingroup\$ I should have said I have a degree in physics and I understand what the CIE diagram stands for at a high level. But thanks for the answer! Can we not pick a dot on the perimeter of the sRGB triangle that most closely approximates the mono light? Maybe for the deepest reds that would involve adding a bit of blue. My post was prompted by this problem: I am about to take hydrogen-alpha images of the Sun at 656.3 nm, and I am wondering what are the RGB pixel values closest to that hue on my calibrated monitor. \$\endgroup\$ Nov 8, 2020 at 22:18
  • \$\begingroup\$ I realize "closest" might be subjective. \$\endgroup\$ Nov 8, 2020 at 22:32
  • \$\begingroup\$ @FlorinAndrei It would depend upon (a) What color space your graphics adapter is using, (b) what values your monitor uses for R, G, and, B, (c) how much of the color space used in a can actually be rendered by your monitor, and (d) how your monitor deals with out of gamut colors (perceptual, relative colorimetric, etc.). \$\endgroup\$
    – Michael C
    Nov 9, 2020 at 3:05
  • \$\begingroup\$ Hi @FlorinAndrei to answer your question of "Can we not pick a dot on the perimeter of the sRGB triangle that most closely approximates the mono light?" the answer is yes you can, it's known as the "dominant wavelength", (except of course if the color exists on the line of purples in which case it's the inverse dominant wavelength). Bruce Lindbloom has a JS calculator that tells you dominant wavelength here: http://brucelindbloom.com/?ColorCalculator.html TIP: set a white point to D65 \$\endgroup\$
    – Myndex
    Apr 28, 2023 at 12:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.