Skip to content
HN On Hacker News ↗

What every coder should know about gamma

▲ 127 points 46 comments by sph 2w ago HN discussion ↗

Pangram verdict · v3.3

We believe that this document is fully human-written

0 %

AI likelihood · overall

Human
100% human-written 0% AI-generated
SEGMENTS · HUMAN 5 of 5
SEGMENTS · AI 0 of 5
WORD COUNT 1,829
PEAK AI % 0% · §1
Analyzed
Jun 15
backend: pangram/v3.3
Segments scanned
5 windows
avg 366 words each
Distribution
100 / 0%
human / AI fraction
Verdict
Human
Pangram v3.3

Article text · 1,829 words · 5 segments analyzed

Human AI-generated
§1 Human · 0%

2016 Sep 21graphicsgammalinear workflowTable of contentsA short quizThe arcane art of gamma-correctnessWhat is gamma and why do we need it?Light emission vs perceptual brightnessPhysical vs perceptual linearityEfficient image encodingThe gamma transfer functionGamma vs sRGBGamma calibrationProcessing gamma-encoded imagesEffects of gamma-incorrectnessGradientsColour blendingAlpha blending / compositingImage resizingAntialiasingPhysically-based renderingConclusionReferences & further readingGeneral gamma/sRGB infoLinear lighting & workflow (LWF)Bonus stuffA short quizIf you have ever written, or are planning to write, any kind of code that deals with image processing, you should complete the below quiz. If you have answered one or more questions with a yes, there’s a high chance that your code is doing the wrong thing and will produce incorrect results. This might not be immediately obvious to you because these issues can be subtle and they’re easier to spot in some problem domains than in others.So here’s the quiz:I don’t know what gamma correction is (duh!)Gamma is a relic from the CRT display era; now that almost everyone uses LCDs, it’s safe to ignore it.Gamma is only relevant for graphics professionals working in the print industry where accurate colour reproduction is of great importance—for general image processing, it’s safe to ignore it.I’m a game developer, I don’t need to know about gamma.The graphics libraries of my operating system handle gamma correctly.1The popular graphics library <insert name here> I’m using handles gamma correctly.Pixels with RGB values of (128, 128, 128) emit about half as much light as pixels with RGB values of (255, 255, 255).It is okay to just load pixel data from a popular image format (JPEG, PNG, GIF etc.) into a buffer using some random library and run image processing algorithms on the raw data directly.Don’t feel bad if you have answered most with a yes! I would have given a yes to most of these questions a week ago myself too. Somehow, the topic of gamma is just under most computer users' radar (including programmers writing commercial graphics software!), to the extent that most graphics libraries, image viewers, photo editors and drawing software of today still don’t get gamma right and produce incorrect results.

§2 Human · 0%

So keep on reading, and by the end of this article you’ll be more knowledgeable about gamma than the vast majority of programmers!The arcane art of gamma-correctnessGiven that vision is arguably the most important sensory input channel for human-computer interaction, it is quite surprising that gamma correction is one of the least talked about subjects among programmers and it’s mentioned in technical literature rather infrequently, including computer graphics texts. The fact that most computer graphics textbooks don’t explicitly mention the importance of correct gamma handling, or discuss it in practical terms, does not help matters at all (my CG textbook from uni falls squarely into this category, I’ve just checked). Some books mention gamma correction in passing in somewhat vague and abstract terms, but then provide neither concrete real-world examples on how to do it properly, nor explain what the implications of not doing it properly are, nor show image examples of incorrect gamma handling.I came across the need for correct gamma handling during writing my ray tracer and I had to admit that my understanding of the topic was rather superficial and incomplete. So I had spent a few days reading up on it online, but it turned out that many articles about gamma are not much help either, as many of them are too abstract and confusing, some contain too many interesting but otherwise irrelevant details, and then some others lack image examples or are just simply incorrect or hard to understand. Gamma is not a terribly difficult concept to begin with, but for some mysterious reason it’s not that trivial to find articles on it that are correct, complete and explain the topic in a clear language.What is gamma and why do we need it?Alright, so this is my attempt to offer a comprehensive explanation of gamma, focusing just on the most important aspects and assuming no prior knowledge of it.The image examples in this article assume that you are viewing this web page in a modern browser on a computer monitor (CRT or LCD, doesn’t matter). Tablets and phones are generally quite inaccurate compared to monitors, so try to avoid those. You should be viewing the images in a dimly lit room, so no direct lights or flare on your screen please.Light emission vs perceptual brightnessBelieve it or not, the difference of light energy emission between any two neighbouring vertical bars in the below image is a constant. In other words, the amount of light energy emitted by your screen increases by a constant amount from bar to bar, left to right.

§3 Human · 0%

Figure 1 — Evenly-spaced greyscale bars in terms of emitted light intensity (Nim source code)Now consider the following image:Figure 2 — Evenly-spaced greyscale bars in terms of perceptual light intensity (Nim source code)On which image does the gradation appear more even? It’s the second one! But why is that so? We have just established that in the first image the bars are evenly (linearly) spaced in terms of emitted light intensity between the darkest black and brightest white your monitor is capable of reproducing. But why don’t we see that as a nice even gradation from black to white then? And what is being displayed on the second image that we perceive as a linear gradation?The answer lies in the response of the human eye to light intensity, which is non-linear. One the first image, the difference between the nominal light intensity of any two neighbouring bars is constant:$$\Δ_{\linear} = I_n-I_{n-1}$$On the second image, however, this difference is not constant but changes from bar to bar; it follows a power law relationship, to be exact. All human sensory perception follows a similar power law relationship in terms of the magnitude of stimulus and its perceived intensity.Because of this, we say that there is a power law relationship between nominal physical light intensity and perceptual brightness.Physical vs perceptual linearityLet’s say we wanted to store a representation of the following real-world object as an image file on the computer (let’s pretend for a moment that perfect greyscale gradients exist in the real world, okay?) Here’s how the “real world object” looks like:Figure 3 — Ideal smooth greyscale ramp (Nim source code)Now, let’s pretend that we can only store 5-bit greyscale images on this particular computer system, which gives us 32 distinct shades of grey ranging from absolute black to absolute white. Also, on this computer, greyscale values are proportional with their corresponding physical light intensities, which will result in a 32-element greyscale as shown on Figure 1. We can say that this greyscale is linear in terms of light emission between successive values.

§4 Human · 0%

If we encoded our smooth gradient using only these 32 grey values, we would get something like this (let’s just ignore dither for now to keep things simple):Figure 4 — Ideal smooth greyscale ramp represented with 32 physically-linear greyscale values (Nim source code)Well, the transitions are rather abrupt, especially on the left side, because we only had 32 grey values to work with. If we squint a little, it’s easy to convince ourselves that this is a more or less “accurate” representation of the smooth gradient, as far as our limited bit-depth allows it. But note how the steps are much larger on the left side than on the right—this is because we are using a greyscale that is linear in terms of emitted light intensity, but as we have mentioned before, our eyes don’t perceive light intensity in a linear way!This observation has some interesting implications. The error between the original and the 5-bit encoded version is uneven across the image; it’s much larger for dark values than for light ones. In other words, we are losing representational precision for dark values and are using relatively too much precision for lighter shades. Clearly, we’d be better off choosing a different set of 32 greys for our limited palette of shades that would make this error evenly distributed across the whole range, so both dark and light shades would be represented with the same precision. If we encoded our original image with such a greyscale that is perceptually linear, but consequently non-linear in terms of emitted light intensity, and that non-linearity would match that of the human vision, we’d get the exact same greyscale image we have already seen in Figure 2:Figure 5 — Ideal smooth greyscale represented with 32 perceptually-linear greyscale values (Nim source code)The non-linearity we’re talking about here is the power law relationship we mentioned before, and the non-linear transformation we need to apply to our physically linear greyscale values to transform them into perceptually linear values is called gamma correction.Efficient image encodingWhy is the all the above important? Colour data in so-called “true colour” or “24-bit” bitmap images is stored as three 8-bit integers per pixel.

§5 Human · 0%

With 8 bits, 256 distinct intensity levels can be represented, and if the spacing of these levels were physically linear, we would be losing a lot of precision on dark shades while being unnecessarily precise on light shades (relatively speaking), as shown above.Clearly, this is not ideal. One solution would be to simply keep using the physically linear scale and increase the bit depth per channel to 16 (or more). This would double the storage requirements (or worse), which was not an option when most common image formats were invented. Therefore, a different approach was taken. The idea was to let the 256 distinct levels represent intensity values on a perceptually linear scale instead, in which case the vast majority of images could be adequately represented on just 8 bits per colour channel.The transformation used to represent the physically linear intensity data either generated synthetically via an algorithm or captured by a linear device (such as a CMOS of a digital camera or a scanner) with the discrete values of the perceptually linear scale is called gamma encoding.The 24-bit RGB colour model (RGB24) used on virtually all consumer level electronic devices uses 8-bit gamma encoded values per channel to represent light intensities. If you recall what we discussed earlier, this means that pixels with RGB(128, 128, 128) will not emit approximately 50% the light energy of pixels with RGB(255, 255, 255), but only about 22%! That makes perfect sense! Because of the non-linear nature of human vision, a light source needs to be attenuated to about 22% of its original light intensity to appear half as bright to humans. RGB(128, 128, 128) appears to be half as bright as RGB(255, 255, 255) to us! If you find this confusing, reflect a bit on it because it’s crucial to have a solid understanding of what has been discussed so far (trust me, it will only get more confusing).Of course, gamma encoding is always done with the assumption that the image is ultimately meant to be viewed by humans on computer screens. In some way, you can think of it as a lossy MP3 like compression but for images.