Introduction
Over the years, many people have felt the need to create their own
image processing programs. They have ranged from the few hardy types who
invented the data formats we know and love (NDF, FITS, IRAF, Figaro,
etc.), to the more modest majority who have to wrestle with these formats
and the various ways of accessing them. Some people, perhaps, still have
private image formats of their own.
"Wouldn't it be nice...", we've been told, "... if there were just one
way of accessing an image -- no matter where it came from?".
Well now there is. It takes the form of a subroutine library, called
IMG, designed for easy use by the majority of astronomers. IMG offers
enormous flexibility by giving straightforward, no-nonsense access to most
of the mainstream astronomical data formats. As a bonus, it can also be
used from both the Fortran and C programming languages.
Simple Image Access
For example, accessing an input image "in" uses just one call:
CALL IMG_IN( 'IN', NX, NY, IP, STATUS ) (Fortran)
imgIn( "in", nx, ny, ip, status ); (C)
and getting a new image "out" (initialised with a copy
of "in") is one more call:
CALL IMG_OUT( 'IN', 'OUT', IP, STATUS )
imgOut( "in", "out", ip, status );
You are not restricted to 2-dimensional "images" either. Spectra and
data cubes can be accessed in the same way just by adding the number of
dimensions to the routine name (two dimensions being the default):
CALL IMG_IN1( 'SPECTRUM', NPIX, IP, STATUS )
CALL IMG_IN3( 'CUBE', NX, NY, NZ, IP, STATUS )
imgIn1( "spectrum", npix, ip, status );
imgIn3( "cube", nx, ny, nz, ip, status );
You can also use whatever data type you choose simply by adding a
further character to the routine name:
CALL IMG_IN1D( 'SPECTRUM', NPIX, IP, STATUS )
CALL IMG_INI( 'IN', NX, NY, IP, STATUS )
CALL IMG_IN3W( 'CUBE', NX, NY, NZ, IP, STATUS )
imgIn1d( "spectrum", npix, ip, status );
imgIni( "in", nx, ny, ip, status );
imgIn3s( "cube", nx, ny, nz, ip, status );
In this example, we access a DOUBLE PRECISION (double in C) spectrum,
an INTEGER (int) image and an INTEGER*2 (short) cube. The default is REAL
(float in C).
A Fortran Program
As a simple example of a complete IMG program, consider the
following. It gets an image, works out its mean value, and writes the
value out:
SUBROUTINE MEAN( ISTAT )
C Get the input image.
CALL IMG_IN( 'IN', NX, NY, IP, ISTAT )
C Derive the mean and write it out.
CALL DOSTAT( %VAL( IP ), NX, NY )
C Free the image.
CALL IMG_FREE( 'IN', ISTAT )
END
C This routine does all the work.
SUBROUTINE DOSTAT( IMAGE, NX, NY )
REAL IMAGE( NX, NY )
SUM = 0.0
DO 1 J = 1, NY
DO 2 I = 1, NX
SUM = SUM + IMAGE( I, J )
2 CONTINUE
1 CONTINUE
WRITE( *, * ) 'Mean = ', SUM / REAL( NX * NY )
END
Note that the "program" is actually a subroutine with an INTEGER
argument so that it can work with the Starlink Software Environment. To
work with images of any size, it also uses the "%VAL" cheat to make the
image look like an adjustable dimension array.
A C Program
Here is exactly the same program written in C:
void mean_( int *istat ) {
float *ip, sum = 0.0f;
int nx, ny, i;
/* Get the input image. */
imgIn( "in", &nx, &ny, &ip, istat );
/* Derive the mean and write it out. */
for ( i = 0; i < nx * ny; i++ ) sum += ip[ i ];
printf( "Mean value = %f\n", sum / ( nx * ny ) );
/* Free the image. */
imgFree( "in", istat );
}
In C, using a pointer to access the image is more natural, but on the
other hand arrays cannot have adjustable dimensions as they can in
Fortran.
Accessing Different Data Formats
You may have noticed that we haven't yet talked about data formats, and
that's because to a large extent they aren't important.
When your program asks for an image, IMG goes to great lengths to
deliver exactly what you asked for. If the data aren't quite right, it
converts them into the form you want. This may involve running a "driver"
- a program which grants access to a particular data format, but you
shouldn't need to worry about this because a selection of standard drivers
is available simply by typing:
% convert
This command enables your IMG programs to access Figaro (.dst), IRAF
and FITS files, plus a few others, in addition to the default Starlink NDF
format.
You could then run the "mean" program (above) and give it the name of a
data file in any of these formats:
% mean
IN - Input image > myimage
Mean = 108.3154
%
Whichever format you have, the result is the same. Only if you had the
same file in two formats (say "myimage.sdf" and "myimage.imh") would you
need to distinguish them by adding ".imh" to the name.
In fact, this facility is not unique to the IMG library and is becoming
available to many Starlink applications, most recently Figaro. For the
more experienced programmer, who perhaps has data in a private format,
this opens the possibility of writing a "driver" to allow existing
Starlink software to operate on those data.
Header Items
Of course, most astronomical data have additional values associated
with them in the form of "header items", and no description of data access
would be complete without mentioning these. Characteristically, IMG makes
it all very straightforward.
For example, to read a header item you might use:
CALL HDR_INR( 'IN', ' ', 'AIRMASS', 1, AIRMAS, STATUS )
hdrInf( "in", " ", "airmass", 1, airmass, status );
Which would return the value of the AIRMASS header item (if one exists)
for image "in".
Writing header items is also simple:
CALL HDR_OUT( 'OUT', ' ', 'OBSERVER', 'Our Hero', 'Captain Starlink', STATUS )
hdrOut( "out", " ", "OBSERVER", "Our Hero", "Captain Starlink", 0, status );
Further Reading
A full description of the IMG library can be found in Starlink User
Note 160 (SUN/160) This contains further details and instructions on how
to link your programs which you should read before getting started.
The more adventurous can discover how to provide access to new data
formats by reading Starlink System Note 20 (SSN/20).
|