Spectral reflectance data to Radiance RGB conversion

Dear community,

i used a portable spectrophotometer (cm-600d) to take reflectance measurements at 10 nm bands of the visible spectrum, and i will need to convert those spectral data to Radiance RGB data to use as input with the “plastic” primitive.
I am having difficulty following the correct procedure suggested in the book (pages 305-307), maybe because of my novice scripting abilities. It seems that a spct2xyz.csh is required to convert a list of spectral data to a single (CIE) XYZ triplet. Subsequently, a xyz2rgb.csh is required to convert from XYZ to Radiance RGB.

  1. Is this procedure still used or is there a newer method?
  2. Can anyone provide the aforementioned c shell scripts or other necessary files and describe shortly how to use them to derive the Radiance RGB values?
  3. In what form should the spectral data be provided (type of file) for spct2xyz.csh to read them?
  4. How would i derive the value for specularity for input in the plastic primitive (a single value)? (SCI and SCE measurements are available for each 10 nm band)

It seems that this topic has been brought up in the past but necessary links are not available today. More recently the same question was asked but the answers were only enough for experienced Radiance users.
Any help would be appreciated.

The easiest way to convert spectral measurements to Radiance primitives is using mgf2rad, which takes MGF input. In your case, that input will look something like this:
m grass_greenish =
cspec 400 700 3.72 4.12 4.43 4.68 4.86 5.05 5.18 \
5.27 5.36 5.53 6.02 7.15 9.24 11.27 12.51 \
13.07 12.85 11.86 10.79 10.22 9.94 9.53 9.11 \
8.88 8.39 7.68 7.12 6.75 7.13 10.11 16.52
rd 0.1040

The above defines a material “grass_greenish” from spectral measurements between 400 and 700 nm, and a measured diffuse reflectance value of 0.1040. You will then need to use this material on a surface for mgf2rad to output it:
m grass_greenish
v v1 =
p 0 0 0
n 0 0 1
ring v1 0 1
If you run these two bits of text together into mgf2rad, it will produce your desired plastic and a surface using it.
Regarding the desired specularity, it is easiest to guesstimate this in the case of a known plastic, using the SCE measurement in the above specification, but adding a specular component of the desired amount, e.g.:
rs 0.03 .05

The “c” entity establishes a neutral color, and the “rs” entity specifies the specular amount and RMS surface roughness, respectively. The above added to the greenish_grass example would yield the following plastic description using mgf2rad:

void plastic grass_greenish
5 0.100713 0.116060 0.042367 0.030000 0.050000

Hope this helps!

1 Like

Thank you Greg, yes it helps, to start thinking (!)
I read the documentation of MGF and went through some example files available to understand better.

I think i need some clarifications:

  1. Where do the rd and rs values you mentioned (0.1040 and 0.03 respectively) come from? I was expecting that they would be deducted from the spectral measurements, is that not so?

  2. Can you tell me exactly how to run mgf2rad? In C:\Radiance, i typed mgf2rad and hit return, then I pasted the lines you provided, hit return, but nothing was calculated. I am missing something i guess…

  3. Maybe it is a different method but i want to ask: The spectrophotometer also provides two XYZ coordinates (one for SCI and one for SCE, for a 2° observer and a D65 light source). Is there maybe a way to deduct “red”, “green”, “blue” and “specularity” from those coordinates? That way i can compare the two methods (mgf2rad vs xyz2rgb). And why is using mgf2rad different?

Thank you for your time and detailed explanations.

Repeating your questions with my responses below:

  1. Where do the rd and rs values you mentioned (0.1040 and 0.03
    respectively) come from? I was expecting that they would be deducted
    from the spectral measurements, is that not so?

The reflectance can be derived from integrating your spectral measurements with V(lambda), the photopic sensitivity curve. It’s much easier just to take the Y value that the reflectometer gives you for each measurement, however. The roughness value is not measured by the reflectometer, so you more or less have to take an educated guess based on how glossy the surface is. If it has no specular component, then it doesn’t matter. If it is like a perfectly smooth mirror, then the roughness would be zero.

Can you tell me exactly how to run mgf2rad? In C:\Radiance, i typed
mgf2rad and hit return, then I pasted the lines you provided, hit
return, but nothing was calculated. I am missing something i guess…

Put the lines in a file and give the file name to mgf2rad. That would be easiest.

You can use the XYZ coordinates together with Radiance “xyz_rgb.cal” file and calc or rcalc to convert. The main difference is that mgf2rad makes the same assumptions about the standard equal-energy white illuminant that Radiance does. Your spectrophotometer will use D65 or something else. You can still get close to the right answer with some additional math, but mgf2rad just takes care of all that for you.

1 Like

Got it!

So the illuminant is the only difference,
and from what i read here, you have already given the math you refer to (white point D65 -> Equal Energy).

Your help was more than enough!

Oh, cool – I’m glad someone knows how to use the search function on this site! I had even forgotten sending that earlier response…

Hi Greg,

With the measurement of spectrophotometer, I am still wondering if there is a way to get the “specularity” from the SCI and SCE data. For the MGF input, it seems just to use the SCE data for different bands.

Hi @threegreen,

There isn’t a direct way get the specularity from a spectrophotometer measurement without also knowing the roughness. This is because the spectrophotometer measures the specular component at one specific angle, while the specularity value in Radiance includes the energy of specular reflections that are disbursed in multiple directions by the roughness of the surface.

Now, if we assume there the surface is perfectly smooth, we can make some approximations. On a per-wavelength basis, the specular component is SCI - SCE, and you can find the tristimulus Y value (the brightness) of the specular reflection just as you would find the tristimulus values of SCE.

Once you have done this, you will need to modify the diffuse component using the specular because Radiance does not assume that specular + diffuse ≤ 1. The modification is as follows:

(modified diffuse component) = (diffuse component based on SCE) / (1 - specular component)

Hi @Nathaniel_Jones

Thanks a lot! I hope to ensure that I understand correctly through a set of data.

I‘ve measured a floor through a portable spectrophotometer. The SCI measurements are X 49.17, Y 50.98, Z 42.41, and the SCE measurements are X 48.16, Y 49.93, Z 41.34.

According to your reply, “specularity” in rad file should be Y(SCI-SCE)=0.0105.

modified X(SCE) = 48.16 / (1 - 0.0105) = 48.67
modified Y(SCE) = 49.93 / (1 - 0.0105) = 50.46
modified Z(SCE) = 41.34 / (1 - 0.0105) = 41.78

I don’t know if this is correct.

By the way, in another topic, @Greg_Ward Greg mentioned that RGB can equal the SCI RGB value when using the Y value for specularity. Does this mean that I can also use XYZ(SCI) to generate RGB channel in rad file without using the modification.

Hi @threegreen,

I have never done it the way you propose, so I’m not sure if your method is mathematically equivalent. I calculate SCI-SCE on the original wavelength bands, and the modification is done on the Radiance RGB values.

I also recommend the per-wavelength subtraction Nathaniel describes, which will give you a more accurate result.

In other news, I just checked in a new version of mgf2rad that actually preserves spectra, which are understood by the latest HEAD pre-release. So, conversion may be done during rendering if you use the latest HEAD. You just specify the SCE color as a “spectrum” or “specfile” primitive as described in the “ray/doc/ray.html” manual included in the package and modify a “plastic” primitive with specularity computed using the DIFFUSE/(1-SPECULAR) factor.