Use macbethcal to calibrate textures

Dion Moult


Radiance is a rendering engine used to perform accurate lighting simulations. Sometimes, Radiance renders are only concerned with average luminance and illuminance values, which means that details like variations in the surface and even what colour an object is isn’t that important (as long as the average reflectance is correct!). The result is a scientifically accurate simulation, that unfortunately looks like a rather dull and unrealistic render. The good news is that with some properly calibrated image textures (or patterns, in Radiance speak), the render can look a lot more sexy!

The example below is the NRC office MGC example scene.

A scientifically accurate, but fake looking office scene
A scientifically accurate, but fake looking office scene

One of the most powerful tools a CG artist has to bring life to a render is to use different types of image textures. The most basic of these is known as a “diffuse map”, an image that holds the RGB values of the different diffuse ( i.e. non-specular) colours of the object. However, these images are rarely calibrated to make sure that their pixel values correlate with the actual spectral reflectance of red, green, and blue wavelengths of the visible spectrum. For instance, often these image maps will include absolute black (an RGB of 0, 0, 0) or absolute white (an RGB of 255, 255, 255). This is inccorrect, as most objects do not ever absolutely absorb all light, and absolutely reflect all light.

Taking a photo with the Macbeth colour checker

Before calibrating an existing image texture, you will need to find out the true colour of a real life sample. Get a sample of that material and take it outside on a bright and sunny day along with your Macbeth colour checker chart. I have purchased the X-Rite ColorChecker Classic. It’s best to do this with sunlight as it is a high quality light source that emits light across the full visible spectrum, unlike indoor artificial lights which are relatively spikey.

An example photo next to a brick to be measured
An example photo next to a brick to be measured

Take a RAW photo with the colour chart next to the object with the same even lighting across both the chart and the object. Make sure that you do not shadow the sample or the chart, and try to minimise self shadowing, or specular highlights for shinier materials. If you will take multiple photos, set your camera setting to manual to prevent any unwanted “autocorrection” by the camera.

You can then convert the raw file (in my case, a .CR2 file by Canon) to the .hdr format as so:

$ dcraw -4 *.CR2
$ ra_ppm -r -g 1 IMG_6054.ppm macbeth.hdr

The -4 argument to dcraw is shorthand for passing -6 -W -g 1 1 as an argument. -6 writes 16 bits per sample instead of eight, -W uses a fixed white balance, and -g 1 1 sets a straight gamma curve. This tip is provided by Greg Ward, as per his advice to avoid any non-linear quantization step.

Run Macbethcal

Macbethcal requires the pixel coordinates of the 4 corners of the colour checker chart. The chart has a crosshair on each corner, so open up the image with ximage, and then press p when your cursor is over a corner to print the coordinates. You can use Ctrl+LMB to pan around the image if the image is larger than your screen (don’t resize the image!).

Using ximage to show pixel coordinates by pressing ‘P’
Using ximage to show pixel coordinates by pressing ‘P’

Then run macbethcal with the following syntax, replacing things like TLX with the top left X coordinate and TLY with the top left Y coordinate, and so on. The order is top left, top right, bottom left, and bottom right.

Assuming that this succeeds (depending on lighting conditions and camera abilities), you can view the results in the debug.hdr file. This’ll show you how many colours it was able to match and you can visually see how close the colours are. This is useful to know how close the calibration was, and whether there are certain colours that are unreliable. Any colours with a diagonal hatching across it were not able to be calibrated.

Finally, use pcomb to calibrate the macbeth.hdr image based off the generated in the previous step. This will generate a new calibrated file called fixed.hdr. You can use this file directly in your image textures.

The full sequence of commands for this process is shown below:

$ ximage macbeth.hdr
$ macbethcal -d debug.hdr -p TLX TLY TRX TRY BLX BLY BRX BRY macbeth.hdr
$ ximage debug.hdr
$ pcomb -f macbeth.hdr > fixed.hdr

Calibrate other custom image textures

The easiest way to use a texture is to use the calibrated .hdr directly after running pcomb on it. In this case, we can apply the colorpict to a, say, plastic material with an RGB reflectance of 1 1 1. This RGB value is multiplied by the colorpict, so the fixed.hdr values remain unchanged and truly represent the object’s RGB. For instance:

void colorpict diffuse-map
7 red green blue fixed.hdr . frac(Lu) frac(Lv)

diffuse-map plastic material
5 1 1 1 0 0

However, it may be such that you have a custom painted texture, or an image texture downloaded from a third party. To deal with this, first take a photo with the colour checker and calibrate it as described above. Then, view it with ximage and sample the average colour RGB value at an area of the object that you can easily identify. For instance, if you have a calibrated .hdr of a wood panel with wood grain running through it, use the mouse to select a marquee of it in ximage, then press c to see the average RGB. Let’s say it’s .1 .2 .3.

Now open up your custom image texture of a wooden panel you have digitally painted with ximage. Again, sample the corresponding surface that is meant to have the same RGB as your physical sample using a marquee and by pressing c. Let’s say it’s .3 .1 .6.

This with these two sets of values, we will need to apply it to our example plastic material as follows. These multipliers are determined in order to convert .3 .1 .6 to .1 .2 .3.

diffuse-map plastic material
5 .33 2 .5 0 0

Issues with specular materials

An issue with this method is that it does not deal very well with specular materials. More specular materials will be measured to be darker than their true diffuse RGB reflectance. At the time of writing, I do not have a good general solution for this, and recommend heuristic measurements to test under known conditions.

However, I have rendered out various benchmark examples of specular and roughness values that you might find useful.


If you have any comments, please send them to