# Integrating over colors

I'm trying to compute the following integral:

$$\int_{380 \, \mathrm{nm}}^{700 \, \mathrm{nm}}\mathbf{RGB}(\mathrm{Hue}(\lambda))\frac{\mathrm{d}\lambda}{\lambda^4}$$

where $$\mathbf{RBG}$$ takes in a Hue and outputs a vector like {0., 1., 1.}.

This is how I've tried to implement this:

lambdaToHue[wavelength_] := Hue[-.8/(700 - 380) wavelength + 1.75]


which takes wavelengths into Hues, (evaluating it on 380 gives purple, on 700 gives red). Then

hueToRBG[hue_] := Table[ColorConvert[hue, "RGB"][[i]], {i, 1, 3}]


takes Hues into vectors, so e.g. evaluating it on lambdaToHue[380] gives {0.8, 0., 1.}. So I can put in values for wavelength and get numbers from hueToRBG[wavelengthToHue[wavelengths]]. So I should be able to compute an integral, like

NIntegrate[hueToRBG[lambdaToHue[l]]/l^4,{l,380,700}]


but in reality Mathematica complains:

"The integrand Hue[1.75 -0.0025\ l] has evaluated to \
non-numerical values for all sampling points in the region with \
boundaries {{380,700}}"


How can I get mathematica to actually just compute the integral of this function which takes numbers into lists of numbers? It works fine, e.g., for

NIntegrate[{x,Sin[x],Sqrt[x]}/x^4,{x,2,4}].


Much thanks!

• Better use ColorData["VisibleSpectrum"] instead of Hue. Should be more related to the actual physical colors... – Henrik Schumacher Dec 3 '18 at 20:19
• @HenrikSchumacher thanks I'll be sure to use that! But I still have the same issue with Mathematica complaining that I'm trying to integrate over colors without noticing that I'm actually summing vectors – Diffycue Dec 3 '18 at 20:36
• I have found an extremely hacky way of doing this; waiting for a better solution: integrate numerically using Total /@ Transpose[(Table[ ColorData["VisibleSpectrum"][\[Lambda]] /. RGBColor[a___] -> {a}, {\[Lambda], 380, 750, 0.1}]* Table[0.1/\[Lambda]^2.5, {\[Lambda], 380, 750, 0.1}])] – Diffycue Dec 3 '18 at 20:57
• Sum [.1 1/\[Lambda]^4 Apply[List, ColorData["VisibleSpectrum"][\[Lambda]]], {\[Lambda], 380, 750, 0.1}] evaluates to {1.56038*10^-9, 1.46384*10^-9, 2.74953*10^-9} black – Ulrich Neumann Dec 3 '18 at 21:16
• Perhaps: f[\[Lambda]_?NumericQ, k_] := (ColorData["VisibleSpectrum"][\[Lambda]])[[k]];NIntegrate[f[\[Lambda], #]/\[Lambda]^4, {\[Lambda], 380, 700}] & /@ Range[3]? – chuy Dec 3 '18 at 21:29

As noted in this thread, the CIE sensitivity functions are built-in, yet undocumented:

ChromaticityPlot; (* force autoload *)
xyz = Interpolation[Transpose[{ImageColorOperationsDump$wavelengths, #}]] & /@ Transpose[ImageColorOperationsDumptris];  However, MinMax[ImageColorOperationsDump$wavelengths]
{{385, 745}}


its coverage is a little off from the desired integral in the OP, so I'll just demonstrate the integral from $$385$$ to $$700\,\mathrm{nm}$$. (If wanted, you can download a finer tabulation with more coverage.)

From here, we can use the sRGB conversion functions from this answer, and then use NIntegrate[] with the setting Method -> "InterpolationPointsSubdivision":

(* gamma correction *)
sRGBGamma = Function[x, With[{z = Abs[x]},
Sign[x] Piecewise[{{12.92 z, z <= 0.0031308}},
1.055 z^(1/2.4) - 0.055]],
Listable];

NIntegrate[Clip[#, {0, 1}]/λ^4, {λ, 385, 700},
Method -> "InterpolationPointsSubdivision"] & /@
sRGBGamma[{{3.2404542, -1.5371385, -0.49853141},
{-0.96926603, 1.8760108, 0.041556017},
{0.055643431, -0.20402591, 1.0572252}}.Through[xyz[λ]]]
{1.48544*10^-9, 1.36666*10^-9, 2.28451*10^-9}