Here is a physical analogy to clarify why nonlinear coding is important.
I can easily perceive the difference in weight between a 1.6 kg boulder and a 2.4 kg boulder. But when I put each of them on a digital bathroom scale that properly rounds to the nearest kilogram, they both read the identical value, 2 kg.
My brother Allen is a lot heavier than either of these boulders, but last time I saw him, I could pick him up. He weighed about 56 kg. But I couldn't perceive whether he was lighter or heavier than my other brother, Dave, who weighed 57 kg.
Now suppose I have two digits worth of data channel capacity in which to telegraph to you the weight of an object. I telegraph the scale readings for the boulders (2 kg and 2 kg), on a scale 00 to 99 kg. To the best of the information available to you at the receiving end, you will conclude the objects have have the same weight. When I telegraph the scale readings for my brothers, you conclude they have different weights. This system works physically, but it fails for the purpose of perception. You can perceive the difference between the weights of the boulders, but linear coding in two digits reports the same value. You cannot perceive the difference in weight between Allen and David, but linear coding reports them as different. In this application, linear coding results that do not accord with perception.
Perhaps you are selling boulders by the kilogram. You might want to use two digits to telegraph an indication of the physical weights of objects. In that case, use linear coding. But if you want to use two digits to telegraph an indication of how you would perceive the weights of objects, you'll need nonlinear coding. Start with a precision much greater than one kilo, 0.1 kg, for example. Take the weight, divide that number by 100 ("full scale"), take the square root, round it to two digits (0.0 to 9.9), and send those two digits. The boulders report square roots of 1.3 and 1.5, representing the fact that I can perceive that difference. For my brothers, 56 and 57 round to the same value (7.5), parallelling my perceptual inability to tell the difference.
Perhaps your task at the receiving end of the two-digit link is to put flour into a sack, so that the sack will be perceived as having the same weight as the original object. In that application, you can reconstruct an approximation to the weight of the original object by squaring the value that was telegraphed.
My ability to detect a difference in two weights is proportional to the ratio of the weights. I can tell that there's a difference in the weight of two things when the ratio of their weights is more than a certain fraction. With nonlinear coding, the reconstructed value is accurate, plus or minus a rounding error that mimics perception. The coding preserves the values to some extent, but more importantly, preserves the ratios.
Consider the weigh scale:
To properly represent perceptible weights (technically, mass), you must start with a weigh scale that senses mass. If you quantize to 100 codes (increments of 1 kg over the range 0 to 99 kilograms full scale), coding the mass of an object (in kilograms) linearly into that range will erase easily-perceptible differences among lightweight objects, while preserving imperceptible differences among heavy objects. If you have only 2 digits to express the perception of weight, you must start with mass values having precision better than 1 kg, and you must assign code values from 0 to 99 nonlinearly: The step sizes must be nonuniform.
Translate the principle to image data:
To properly represent perceptible intensities of light (technically, luminance), you must start with a camera or scanner that senses luminance. If you quantize to 256 codes (increments of one LSB in 8 bits, 0 to 255 full scale), coding the luminance of a scene element (in normalized candelas per meter squared) linearly into that range will erase easily-perceptible differences among the dark shades, while preserving imperceptible differences among the light shades. If you have only 8 bits to express the perception of luminance, you must start with luminance values having precision better than 8 bits, and you must assign code values from 0 to 255 nonlinearly: The step sizes must be nonuniform.
See also: Gamma FAQ - Linear and nonlinear coding
Charles Poynton
Copyright © 1998-03-12