2
$\begingroup$

I need to draw a simple square filled with a flat uniform color, from a given spectral function. The color should simulate as close as possible what an human eye/brain would see, if the light intensity was defined as an integral of a simple function : $$\tag{1} f(\omega, \alpha, \kappa) = \kappa \, \omega^{\alpha}, $$ where $\alpha \ge 0$ is a parameter and $0 \le \omega \le \omega_{\text{max}}$. Here, $\omega \equiv 2 \pi c /\lambda$ is the angular frequency of light and the minimal wavelength $\lambda_{\text{min}} \le 700 \, \text{nm}$ is another parameter that should be at least in the visible spectrum. $\kappa$ is a parameter that defines the whole intensity level of light, so $\kappa = 0$ should give black and $\kappa = \kappa_{\text{max}}$ should give a saturated color. The light intensity is defined as this : $$\tag{2} I(\alpha, \kappa, \lambda_{\text{min}}) = \int_0^{2\pi c/\lambda_{\text{min}}} f(\omega, \alpha, \kappa) \, d\omega. $$ I'm not a specialist on the eye/cones and color perception, but I guess that I need to call three "color" functions $r(\omega)$, $g(\omega)$ and $b(\omega)$ (the cones sensibility in the eye ?) to define the RGB values of my color, something like this (I'm not even sure this is necessary, with Mathematica, since it may be built-in somehow) : \begin{aligned} R(\alpha, \kappa, \omega_{\text{max}}) &= \frac{\int_0^{\omega_{\text{max}}} r(\omega) \, f(\omega, \alpha, \kappa) \, d\omega}{\int_0^{\omega_{\text{max}}} r(\omega) \, d\omega}, \\[12pt] G(\alpha, \kappa, \omega_{\text{max}}) &= \frac{\int_0^{\omega_{\text{max}}} g(\omega) \, f(\omega, \alpha, \kappa) \, d\omega}{\int_0^{\omega_{\text{max}}} g(\omega) \, d\omega}, \\[12pt] B(\alpha, \kappa, \omega_{\text{max}}) &= \frac{\int_0^{\omega_{\text{max}}} b(\omega) \, f(\omega, \alpha, \kappa) \, d\omega}{\int_0^{\omega_{\text{max}}} b(\omega) \, d\omega}. \end{aligned} Then Mathematica would use the values of $R(\alpha, \kappa, \omega_{\text{max}})$, $G(\alpha, \kappa, \omega_{\text{max}})$, $B(\alpha, \kappa, \omega_{\text{max}})$ to draw the color filled square.

Any idea about how to achieve this ?

I'm posting a working "Manipulate" code to show a very partial solution. Currently, it is highly approximate and it needs to be fixed in some way.

Clear["Global`*"]  (* removes all definitions *)

c = 299792458;  (* velocity of light *)
nm = 10^(-9);  (* nanometer *)

(* normalized distribution of frequencies : *)

f[ω_, d_, κ_, λ_] := κ If[ω <=  2Pi c/(λ nm), ω^(d/2), 0]/Integrate[u^(d/2), {u, 0, 2Pi c/(λ nm)}]

(* very approximate Red, Green, Blue channels : *)

Rcolor[d_, κ_, λ_] := f[2Pi c/(700 nm), d, κ, λ]2Pi c/(λ nm)
Gcolor[d_, κ_, λ_] := f[2Pi c/(550 nm), d, κ, λ]2Pi c/(λ nm)
Bcolor[d_, κ_, λ_] := f[2Pi c/(450 nm), d, κ, λ]2Pi c/(λ nm)

(* the full color : *)

color[d_, κ_, λ_] := RGBColor[
    If[Rcolor[d, κ, λ] < 1, Rcolor[d, κ, λ], 1],
    If[Gcolor[d, κ, λ] < 1, Gcolor[d, κ, λ], 1],
    If[Bcolor[d, κ, λ] < 1, Bcolor[d, κ, λ], 1]
]

(* the manipulate code to show a color square with adjustable parameters : *)

Manipulate[
    If[d < 0 || d > 6 || Not[NumericQ[d]], d = 4];
    If[κ < 0 || κ > 1 || Not[NumericQ[κ]], κ = 0.5];
    If[λ < 100 || λ > 700 || Not[NumericQ[λ]], λ = 400];
    Show[
        Graphics[{color[d, κ, λ], Rectangle[]}],
    ImageSize -> 400
],
{{d, 4, Style["d", 10]}, 0, 6, 0.01,
    ImageSize -> Medium,
    Appearance -> {"Labeled", "Closed"}
},
{{κ, 0.5, Style["Intensity", 10]}, 0, 1, 0.01,
    ImageSize -> Medium,
    Appearance -> {"Labeled", "Closed"}
},
{{λ, 400, Style["λ (nm)", 10]}, 100, 700, 0.01,
    ImageSize -> Medium,
    Appearance -> {"Labeled", "Closed"}
},
ControlPlacement -> Bottom,
FrameMargins -> None,
FrameLabel ->  {None, None, 
    Style["Deep space color", Bold, 14, FontFamily -> "Helvetica"]}
]

In this code, the color "cones" are peaked at some arbitrary values : Red = 700 nm, Green = 550 nm and Blue = 450 nm (all arbitrary values).

How can I improve that code to get a more realistic color output ?


EDIT : I just found a similar question here, which can be usefull : Convert spectral distribution to RGB color. However, my question is specific with the spectral function and its parameters, and I'm unable to understand and adapt the answers from that question. The answers don't work at all on my system (Mathematica 7.0 on OS X).

$\endgroup$
  • 3
    $\begingroup$ Ouch, version 7 is pretty outdated. A lot of new a useful functionality had been added since, it may be tricky for someone used to modern Wolfram Language methods to immediately offer something to help. $\endgroup$ – user6014 Oct 28 '16 at 3:22
  • $\begingroup$ Well then, there is surely a trick to get the approximate color of the distribution. It may be enough for me, I don't need something exact. $\endgroup$ – Cham Oct 28 '16 at 13:12
  • $\begingroup$ "The answers don't work at all on my system" - even the functions here and here don't work for you? $\endgroup$ – J. M. will be back soon Dec 28 '16 at 11:59
  • $\begingroup$ The correct procedure for this problem is as follows: Choose an illuminant for the spectral power distribution values. D50 is what is used in my industry and what I use for illuminant. Then convert spectral power to CIEXYZ, then from there to RGB based on your chosen RGB color space. More than likely its your monitor. $\endgroup$ – R Hall Jan 30 '17 at 20:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.