Gamma function comparison (corrected) Much has been written about gamma correction;

Gamma function comparison (corrected)
Much has been written about gamma correction; here I took a look at various correction functions for speed and accuracy. For newer folk: gamma correction is a way to make the numeric values for a given color render so that they look right on different devices (e.g. an LCD screen vs an LED strip). Recently I was doing some experiments, the results of which I will (eventually! really!) share converting colors from on-screen colors to LED strip colors, and it turns out that you need to apply a gamma correction to get the colors to match even remotely. But what gamma function to use?

The mathematically correct formula is to convert brightness to a fractional value, raise it to an exponent, and then convert it back. This involves floating point math, which on Arduino can be slow and bulky … and slow.

I’ve been using FastLED’s dim8_video(…) function as a proxy for floating point gamma correction, but now I wanted to see how close it was to the traditional exponential floating point gamma corrections. Typical popular exponent values (“pow(…)”) for gamma correction are 2.2 and 2.5. Here’s how applying dim8_video compares to pow(2.2) and pow(2.5).

As you can see, dim8_video( input ) is relatively close to pow( input, 2.2) – and it’s much much faster to execute (also smaller code). It works out that dim8_video is basically the same as an exponential gamma of 2.0, not 2.2, but often this is a good, fast, approximation.

Accordingly, applying dim8_video( dim8_video( input )) is very similar to pow( input, 4.0).

I had often wondered ‘how good’ an approximation dim8_video is to an exponential floating point gamma correction of 2.2, and now we know: it’s a reasonably good approximation (gamma=2.0) given the big speed advantage. Applying dim8_video twice gives a gamma of 4.0.

One even faster technique and more accurate technique you can use is to define a 256-byte lookup table in PROGMEM (flash) that has precomputed gamma values in it. If you do that, you can precalculate any gamma correction you like, e.g. 2.45, and it’ll all run just as fast – at the cost of 256 bytes of program space. We don’t provide a gamma table like that in FastLED, but the ever-awesome Adafruit folks have one you can cut-and-paste, here https://learn.adafruit.com/led-tricks-gamma-correction/the-issue

Here’s a great in-depth discussion of gamma correction and the role it plays in on-screen color rendering, including common misconceptions and what the underlying facts are.

Of course, rendering color on RGB emissive LEDs is a different kettle of fish…

A good fast fixed point approximation for floating point pow(input,2.5) may be
uint8_t d8 = dim8_video( input);
uint8_t d8d8 = dim8_video(d8);
uint8_t output = (d8 + d8 + d8 + d8d8) / 4;
But at this point maybe a gamma lookup table is a better deal, depending on whether you’re more pressed for CPU cycles or flash storage.

Thanks Mark! Great to know.

The link to the massive 20k LED video wall had a shot of the “gamma correction setup” involving each panel being inspected with a DSLR (still or video I’m not sure). Am I to infer from this they were gamma-correcting each single pixel individually? Are the variances between individual LED pixels/strings/batches such that this would be necessary for this scale of installation?

Nah probably just measuring the overall curve. But maybe!