[comp.windows.x] Integer Pixel Intensities

awpaeth@watcgl.waterloo.edu (Alan Wm Paeth) (12/07/88)

>The particular problem I have in mind is that of a StaticGray display with N
>equally spaced intensities arranged in a ramp with black at 0 and white at
>N-1...Two different expressions for computing the appropriate pixel value...
>
>(a)	floor((.299r + .587g + .114b)(n - 1) + 0.5)		(a)
>
>(b)	floor((.299r + .587g + .114b)(n))			(b)
>
>..where maxColor is dependent upon which of (a) or (b) is chosen:
>	float maxColor = (float) (0xFFFF);		/* (a) */
>	float maxColor = (float) (0x10000);		/* (b) */


Your question is not so much on luminance _per se_ (else I would have asked
you questions about monitor calibration, gamma, etc.) but about integer
representation schemes for pixels.

I am adamant advocate of the interval [0.0..1.0] (a doubly-closed interval) to
represent [black..white]. This interval allows closure for both multiplication
(image blending) and complementation (1-x image reversal). This design topic is
covered at length in "The IM Raster Toolkit -- Design, Implementation and Use"
(U-of-W tech report CS-86-65), see also "PROCEEDINGS, Graphics Interface '86
(Vancouver), pg. 93.

I can think of no reason to justify the common practice of 0=black, 256=white
in which 256 (and hence, white) is not a symbol in the representation scheme.
(I'm dealing with the 8-bit integer intensity case as it is so familiar). This
approach treats the domain as the semi-open interval [0..1) which allows the
integer intensity to be viewed as a binary fraction (0.ffffffff). This in turn
means that mapping, say, a four-bit gray scale or 0.ffff onto an 8-bit scale
can be done with bit shifting. But this has obvious problems. A one-bit gray
scale yields the two symbols {0, 1} which as fractions are .0 and .1, so that
bit-shifting into higher precisions only gives a half-intensity value, that is,
the value .10000000 and not .11111111

By way of comparison, setting 0=black and 255=white means that white of the
form 2^m-1 (m the number of bits, eight in this case) is always present in the
representation scheme. Moreover, the upward mapping of a domain of lower
precision to a higher one remains simple -- it is merely an integer multiply
to go from n to m bits, if n divides m. For many machines the cost of the
integer multiply is on par with the multi-bit left shift (which is really just
a multiply by 2^(m-n)).

For instance, 4-bit gray [0..15] with 15 representing white (1.0) can be mapped
onto 12-bit gray [0..4095] by multiplying the 4-bit sample by 273. A "proof" to
show that an integer factor exists (as 4 divides 12) is illustrated below:

     4095 (12-bit white)   = 15 (4-bit white) *	   273 (integer scale factor)

  1 1 1 1  1 1 1 1  1 1 1 1    =   1 1 1 1    *    0 0 0 1  0 0 0 1  0 0 0 1

For other mappings an exact integer scale factor may not exist, but the
domains (typically 12 bits are less) are small enough that table look-up
is easily implemented, which in almost all cases is faster than either
bit-shift-style multiplies or the garden variety integer kind.

So in short, there are no advantages to using the [0..2^m) representation,
just liabilites -- so I choose your varient (a), which implies: [0..2^m-1].
    
    /Alan Paeth

PS - Copies of the IM Raster toolkit technical report are available from
the University of Waterloo, as is a magnetic tape distribution of over four
dozen machine-independent raster-based tools. For more information:

    IM Raster Toolkit
    c/o Computer Graphics Laboratory
    University of Waterloo
    Waterloo, Ont. N2L 3G1
    CANADA
    ph: 519-888-4534