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.
- Calculate the maximum number of zeroes allowed in an encoded
value. This is
max_zeroes = MAXDELT / (2^(noise_bits - 1)).
-
Calculate
delta = current pixel - previous pixel.
-
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
-
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.
-
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".