RICE local "28 March 1996"

NAME

rice, unrice -- compress/uncompress a 16-bit integer FITS 2-D image file

SYNOPSIS

rice file [optimize] [noise=N] [unsigned]
unrice compressed_file [unsigned]

DESCRIPTION

This pair of programs compresses or uncompresses a simple 2-D 16-bit integer FITS file. The FITS header is left in ASCII form, so that one can use more or one's favorite pager to examine the header. The original FITS image (compressed image) is not deleted after the program finishes creating a compressed (uncompressed) version. rice gives its output file the same name as the input file, but with an extension of ".ftz" Thus, rice m67.fit yields output file m67.ftz, and rice bigimage yields output file bigimage.ftz. unrice replaces the extension of its input file with .fts. Thus, unrice m67.ftz produces an output file m67.fts.

The noise=N option allows the user to set the number of "noise bits" used in the compression. See the section on ALGORITHM below for an explanation of the "noise bits". If the user does not supply a value, a default of 5 is used.

If the user specifies optimize, the program loops through values of 1,2,..,8 for "noise bits", calculating the degree of compression in each case. It prints a line to stdout for each value. If all values cause the output file to exceed the input file in size, the program prints a message to that effect and quits. Otherwise, it chooses the value which yields the smallest output file and initiates compression.

When rice is run, it inserts a line into the FITS header with keyword COMPRESS and value 'riceXX', where XX is a 2-digit, zero-padded integer which is the number of "noise bits" used in the compression. When one uncompresses the file, this keyword is kept in the header, but its value is set to 'none'.

EXAMPLES

          rice m67 

Compress file "m67", producing new compressed file m67.ftz,

         rice high_23.fit unsigned

Treats file "high_23.fit" as a pseudo-FITS image with unsigned 16-bit integers and SIMPLE=F in its header. Compresses the image, producing a compressed file high_23.ftz.

         unrice high_23.ftz unsigned

Uncompresses the file "high_23.ftz", producing a pseudo-FITS image with SIMPLE=F in the header.

         rice m51 noise=3

Compress the image "m51", treating the 3 lowest-order bits in each pixel as "noise". Produce an output file called m51.ftz.

         rice bigimage.fts optimize

Step through all the possible values of "noise bits", from 1 to 8, and choose the best one. Then compress the image "bigimage.fts" with that value, producing an output file bigimage.ftz. If all values for "noise bits" yield files bigger than the original, produce no output file.

ALGORITHM

A variant of "Rice-compression" is used by these programs. The basic idea is to separate each pixel value into two pieces: the low-order bits, which vary strongly from pixel-to-pixel (and hence are called "noise bits"), and the high-order bits, which don't change much at all, at least in a typical astronomical image which is filled with blank sky. The "noise bits" can't be compressed much, so one writes them out verbatim; but the high-order bits DO compress, and so one can encode them into a small number of bits before writing them out.

There are a couple of extra ideas tacked on to this framework. First, one can measure the difference between each pixel and its neighbor (delta-encoding) and use that, rather than the raw pixel value. In (most) images which are not very undersampled, the differences between adjacent pixel values are smaller than their absolute values, and so can be encoded in fewer bits. Second, when one pixel really is VERY different from its neighbors (due to a cosmic ray, for example), the Rice-encoding algorithm doesn't work well -- it produces a very long string of zeroes. These programs therefore set a maximum value of the difference between adjacent pixels, and if any delta exceeds this difference, the offending pixel value is written out in its original, 16-bit integer form.

Now, a detailed look at the algorithm.

  1. Calculate the maximum number of zeroes allowed in an encoded value. This is
              max_zeroes = MAXDELT / (2^(noise_bits - 1)).
    
  2. Calculate
              delta = current pixel - previous pixel.
    
  3. If abs(delta) >= MAXDELT, write out
              max_zeroes 0-bits
              one more 0-bit
              one 1-bit
              the pixel value, in a 16-bit integer form
    
  4. If abs(delta) < MAXDELT, then encode the delta into an unsigned 16-bit integer "val", as follows:
              if (delta >= 0), let val = 2*delta
              if (delta < 0), let val = 2*(0 - delta) - 1.
    
    Now, consider the top 16-noise_bits bits in "val". If one shifts them rightwards by "noise_bits" bits, they form what is (usually) a small integer.
              Write this many 0-bits to the output.  
    
    If this integer is 0, then write no 0-bits to the output.
              Write a single 1-bit to the output.
              Write the "noise_bits" lowest-order bits in "val" 
                   to the output, just as they are.
    
  5. Move to next pixel and go to Step 1.

To read a compressed file, unrice looks at the number of 0-bits present at the start of each number; the number of 0-bits tells it what sort of encoding has been done to the pixel value, and it then reads the encoded value and de-codes it appropriately. Note that the single 1-bit must always be inserted, since it is possible to write no 0-bits for an encoded pixel value.

BUGS

Can probably be speeded up quite a bit by carefully examining the code in bit-I/O routines, especially "bwrite_number" and "bread_number".