# Converting spectral data to RGB and normalizing appropriately

I have spectral data which tells me how strong of a response in RGB values for some color-space I get for a particular wavelength of light.

Typically, if I want "plain" white light, I'd have to sum up all the values in equal amounts and it should result in RGB #FFFFFF white. However, my data isn't normalized like that. I overshoot pure white by quite a bit. And what's worse, this overshoot doesn't happen equally for my three channels, ending up in something that evidently is not pure white.

Now I wonder: Would it be accurate to just normalize by a factor per color channel so it "simply works"? Or do I have to consider correlations between color channels and the spectral data set more carefully? If so, how exactly would I go about that?

If my actual dataset helps, it's simply what WolframAlpha puts out when you put in wavelengths in the visible spectrum. For instance, 500nm results in RGB: {0., 0.671, 0.492} - it's accurate to 1nm and goes from 380nm to 750nm.

Now, I'm not sure if this is the right place to ask this question. I could think of several SE sites that may touch on this to varying extends. However, I believe that this can probably be applied to more generic problems that would arise in statistics and the fit is closest to it, so I'll ask here. If you think, this rather is unrelated, please comment me either how to make the question more relevant or where I should ask it. Similarly, I'm not sure if I am using the best tags.

-
Your question touches on a number of essential aspects of color science. For a suitable answer, it would be good to know what you are ultimately trying to achieve with your analysis. –  caracal Feb 26 '13 at 17:05
@caracal Ultimately, I'd like to get a 3D renderer that doesn't directly support it to allow for chromatic aberation as physically correct as possible. Essentially, I want to assign a transparent material that has a different index of refraction for each wavelength. For this to work, I'd need the RGB-response per wavelength to totally add up to pure white. That's where my normalization question comes into play. –  kram1032 Feb 26 '13 at 19:57
@caracal a basic version where I just split into three wavelengths that roughly correspond to R, G and B respectively, would already give nice results, however, especially in the purple, high-energy region that has a response from both R and B, the render in the software wouldn't take those into account, since a single blue-sample wouldn't add in red. I probably wouldn't need the full data-set, but in any case, I'd like to normalize apropriately. For instance, I could easily just take ever 10nm or so. –  kram1032 Feb 26 '13 at 20:04
@carcal if the values were to add up to anything else than 1, I would either loose light and things would be darker than they should be, or I'd generate more energy and light than there is. Technically getting the data to normalize to that isn't hard. However, if I normalize inappropriately, I'll skew colors in the process, making, say, red darker than it should be while blue becomes brighter, turning everything blueish or cyan. –  kram1032 Feb 26 '13 at 20:08

tl;dr: $RGB$ is the wrong space to do the normalizing in since it is device dependent. You should work with device independent color coordinates like $xyL$. Only in the final step transform to $RGB$. Any per-scene intensity reduction has to be made by scaling the $L$ coordinate from $xyL$ space with a common factor.

For a transparency model based on physics see this paper, especially section 2.2. Follow-up paper 1, follow up paper 2.

Long answer: I think it's necessary to avoid some conceptual confusion regarding the subject matter. Most importantly, color is not a physical property.

• Light (=physical quantity) is characterized by its energy distribution over the spectrum. The human visual system responsible for daylight vision has three cone types with different sensitivity over the spectrum (peak sensitivity for Long, Medium, and Short wavelengths). This means that a light beam will elicit a specific triple in cone excitations (but different lights may well lead to the same cone excitation triple).
• Color (=psychological property) is linked to the cone excitation triple. Therefore, one way to uniquely represent one color impression is to take the corresponding cone excitation triple (strictly speaking, this is only true for isolated light beams). Nicely enough, the space generated by these triples behaves like a linear 3D-vector space. Versions of this space are the $XYZ$ and the $LMS$ color space. A common transformation is $xyL$ space where chromaticity ($xy$) and luminance $L$ are separated.
• Using the cone sensitivity functions thought to be universal for all humans, you can calculate the corresponding cone excitation triple or $xyL$ coordinates for all light beams with a specified energy distribution of the spectrum.
• $RGB$ is a different kind of space: It tells a monitor the intensities for each of its three "light guns" (as it was called for CRTs). This is device dependent, meaning that one $RGB$-triple is uniquely associated with one specific light and hence one color impression only for a particular monitor. This problem is what monitor calibration is all about. In addition, since the output of a monitor is restricted in energy, it cannot create arbitrary lights and hence arbitrary color impressions.

Coming to the question of normalizing: With your goal of physically correct rendering, you need to do all your computations per wavelength. With the final result, you then need to apply the cone sensitivity functions to get to $xyL$ space. Then, you need to apply the monitor specs to know which $RGB$ values will produce these $xyL$ triples. For this step, you need to have the specs for a typical LCD (this is what Wolfram alpha must be doing - otherwise the answer would be nonsensical since there is no unique relationship between a device dependent format like $RGB$ and a device independent light).

If some $xyL$ triples cannot be elicited due to monitor restrictions, you need to reduce the intensity of the rendered scene until all $xyL$ triples are inside the monitor gamut. This can be done with a single scalar factor that applies to all $L$ coordinates. This will make the whole scene uniformly darker. Since the 3D-shape of the monitor gamut is weird, this is not a simple normalizing step.

-
that's an excellent answer. The only problem is that in the software as it currently is, I can merely approximate spectral data in the first place. I'll have to dig a bit deeper to see the necessary conversions. Thank you for all the extra information. That will be very useful. –  kram1032 Feb 27 '13 at 13:11