The man page for the pgm file format specifies that the standard transfer curve of ITU Rec. 709 should be used to convert data values into relative brightnesses. (The ITU, like the CIE and several other international standards bodies, charges excessively for their standards documents; but the essential information is available in many places, such as Charles Poynton's very useful website, and the Mathworks website.)
NOTE: the man page for pgm says “CIE” where it really means “ITU”. Probably the confusion arose because the CIE is the standards body for color science, and the ITU is related to the CCIR — which has just enough letters in common with CIE to facilitate the error.
Fortunately, if we are dealing with grayscale images, we need only deal with the issue of gamma or contrast, and can forget about the 3×3 color-transformation matrices, color spaces, etc.
The basic reason why image data aren't proportional to brightnesses is that computers started out using CRT displays, which themselves aren't linear. The engineers wanted data values that would be proportional to the driving voltages, and the brightness produced by a CRT is approximately proportional to the square of the voltage. So the data values are nearly proportional to the square roots of the image brightnesses.
Even though CRT displays have largely been replaced with various flat-panel technologies, we now have the properties of an average color CRT frozen into the image-format standards. (Another familiar example of fossil technology is the 80-column text display on screens, copied from the 80-column punched cards that disappeared in the 1980s. Those cards themselves fossilized the size and shape of the old “bedsheet”-style U.S. dollar bill that was current in the 1890s, when punched cards were introduced.)
To complicate this mess further, the actual relation between CRT voltage and brightness is a little steeper than a square law; it's closer to the 2.5 power, on the average. And, more confusingly, Rec. 709 actually uses a linear section at near-black levels, plus a 2.4-power law at greater brightnesses, which together approximate a 2.2-power law — a little less correction than you'd expect. (The reason for the undercorrection is to make the displayed image appear more contrasty, which looks better in a dimly-lit room; this standard arose in connection with television, remember, not computers.)
The exponent in this power law is called gamma, a term that goes back to photography. That is, the brightness B is proportional to the data value V, raised to a power gamma:
To avoid the complications of Rec. 709 — which must be taken into account in careful work, but tend to obscure the principles involved — I'll describe everything in crudely terms of squares and square roots. So although the “gamma” (the slope of the logarithm of the brightness as a function of the voltage) is really closer to 2.5, we'll treat the exponent as if it were just 2 even — at least, for rough estimates.
So, as the maximum data value is 255 for a standard pgm file, we should expect the brightness corresponding to about half this value, or 127, to be about (1/2)2 or 1/4 of the maximum brightness. Conversely, to find the data value required to produce half the maximum brightness, we need a data value of about 255/sqrt(2) or 180. Here's what that color looks like, compared to black and white:
(This image was produced from a pgm file that contains just 3 data values: 0 for black, 255 for white, and 180 for the gray.) The middle square appears a light gray here. CAUTION: Don't expect this half-of-white-brightness gray to look midway in lightness between white and black. Because of the nonlinearity of the visual system, what looks like a medium gray actually reflects about 20% as much as a “white” surface. To get that brightness, we need a data value near 255 × sqrt(0.2), or 114. Here's what that color looks like, compared to black and white:
That's actually too dark, because we used a square root (the 0.5 power) instead of the more accurate 0.4 power. If we ask for the 0.4 power of 0.2, and multiply that by 255, we get 134; here's a gray spot using 134 for the data:
Sure enough, that's a pretty good approximation to medium gray. This confirms that the exponents are about right, and that data values in pgm files are indeed CRT signals rather than brightnesses.
As it happens, the nonlinearity of the visual system has just about compensated for the nonlinearity of the CRT display here: 134 isn't far from half of 255. But when we need to deal with brightnesses rather than signals that are almost proportional to the visual sensation of brightness, we have to take these nonlinearities into account.
If a data value of 134 — more than half of the maximum value of 255 — corresponds to a brightness only 20% of white, you can see that the CRT brightnesses are always much darker than the data values would suggest at first glance. As the maximum data value is always 255, regardless of the gamma used, converting a normal pgm file to relative brightness values will make all the values between 0 and 255 smaller. So the effect of linearizing the transfer function, so that the data values represent relative brightnesses, will make the image much darker.
It's very confusing that changing the gamma of an image also changes the average brightness. You'd expect that gamma should affect the contrast instead. The brightness change is a side effect, due to the 255 maximum white value: if we could increase the contrast and still keep the average brightness the same, the brightest areas would have to grow brighter; but this isn't possible if white is 255 in the output as well as the input. So with white fixed at 255, everything else has to get darker.
It may be useful to think of the maximum value as 1.0 instead of 255. Then you can see that squaring the values (to convert them to relative brightnesses) has to make them all smaller, as everything is some fraction of the white value.
The pnmgamma command changes the gamma of a pgm file. To convert a normal pgm file to relative brightness values, do
pnmgamma –ungamma –cieramp < file.pgm > linear.pgm
This only works if the input is redirected; it fails unless pnmgamma reads from stdin. The man page for pnmgamma is not very clear about this.
Similarly, to convert a brightness-valued image back to a normal pgm file that will display correctly on your monitor, do
pnmgamma –cieramp < linear.pgm > display.pgm
— again being careful to redirect the input.
Here are some good websites that explain the gamma problem in more detail:
CGSD Gamma Correction Home Page has links to several excellent explanations of gamma.
The Gamma Adjustment Page tells how to determine and adjust the gamma of your monitor.
Copyright © 2006 – 2008, 2012 Andrew T. Young
GF home page
or the website overview page