Visualising 2D Data
In the lectures we have learned that the visualisation techniques
employed depend
on the category of data we are dealing with and that we need to know
the properties of that data set to employ the best visualisation
methods.
In this laboratory exercise you will have a large volumetric data
set
of scalar values, comprising of (x, y, z, f(x,y,z)).
You can find this data set in the /cslinx/examples/CITS4241/FullHead directory.
The best way to access to files in this directory is to logon
to the School's Linux server using your Linux user account.
The storage of this data set is as follows,
- The data for each value of z are stored in a separate file.
Thus, each file, HEADSQ.n,
where n
varies from 1 to 94, comprises of a set of (x, y, f(x,y)) values.
- The data in each file are square, i.e. they are equally
sampled in the x and
the y directions.
- The (x, y) position data are not stored, as they can be
determined from the file structure. Clearly,
the data set is from a regular sampling; in particular, the
distance between
samples is fixed and equal in the x- and y-directions.
- The scalar attribute value, f(x,y), for each (x,y)
position is stored in two
(2) bytes
with the least significant byte first.
This value will therefore be defined over the 16 bits, but
the high order bit (bit 15) is always set, and does not
contribute to the scalar value. The high order bit is used to
indicate the connectivity between slices of data and MUST be ignored
for our
purposes. Thus, when processing the high resolution data this bit will
need to
be masked out.
For instance, if the first (least
significant) byte was 00001001 and the second (most significant) byte
was 10000001 for a given (x,y) position, then the binary representation
of f(x,y) is

In your program, f(x,y) should then be computed as
f(x,y) =
|
byte1
+
|
(byte1 is the least significant byte, containing 00001001)
|
|
(byte2 & 0x7f) << 8
|
(byte2 is the most significant byte, containing 10000001)
|
where 0x7f is the hexadecimal representation of 01111111.
Thus, f(x,y) = 2^0 + 2^3 + 2^8 = 265 (in base 10)
- The ordering of the scalar attribute values, f(x,y), in the file
is row major.
- The size of each file in the data set is 131072 bytes, so there are 256 x 256 different f(x,y) values
stored in each file.
The data in each file belong to the ES2 category,
so there are a number of techniques we can apply. You can guess from
each file name
that the data are best visualised as an image where the (x, y)
values define the pixel positions
and the function values f(x, y, z=constant) represent intensity --- colour won't mean
much until we define a suitable colour mapping.
The exercise for this laboratory session is to write a program that
can read each of these data files and generate an image for each of
them. You can then visualise each image by using a
simple image analysis package such as xv on the Linux platform.
Further hints:
- xv can read a wide variety of image formats so you will
have
to convert each slice of data to one of these image formats.
We will use the PGM image format - in raw bits. The earlier versions of xv accept only 8-bit (unsigned char) raw data for PGM
image files; however, the current version
of xv accepts both 8-bit and
16-bit (unsigned short) raw data for PGM image files. PGM files
begin with some header information (which is
interpreted as ASCII) followed by the raw binary pixel data. That
is,
P5
x_size y_size
maximum_pixel_value
raw_data...
Note that the first line is capital P5. The items in the
header are
whitespace delimited. Use a newline character to terminate each line.
Example
1: If the data are 64 x 64 and the pixel values range from 0 to
255 then the header might look something like the following:
P5
64 64
255
raw_data...
In this case,
xv expects each pixel value to be
8 bits in length, as the maximum value 255 just fits into one single
byte (being an unsigned char).
Example 2: If the
data are 512 x 512 and the pixel values range from 0 to 599 then the
header might look something like the following:
P5
512 512
599
raw_data...
In this case,
xv expects each
pixel value to be 16 bits in length, as the maximum value 599 requires
two bytes to store.
Note: There are no whitespace included in the raw
data block. To write the raw data block, use the C function fwrite (or an equivalent Java
method). See also the man page for PGM, by typing man pgm
under Linux.
- For visualisation purpose, it is often desirable to scale the
intensity values so that they are within the interval [0,255], with 0
representing black, 255 representing white, and intermediate values
representing various shades of gray (i.e. we follow the 8-bit data
format as given in example 1). You will therefore need to go through
all the pixel positions and compute the maximum intensity value (stored
in variable m, say) and then
rescale all the intensity values using an assignment statement such as
f(x,y) = f(x,y) * 255.0 / (double)m
- Two sample PGM image
files, HEADSQ.1.pgm
and HEADSQ.2.pgm,
have been generated for you. You should inspect the first three
lines of these files and view the images via
xv
HEADSQ.1.pgm
xv HEADSQ.2.pgm
- After generating all the PGM
image files, try
xv
*.pgm
Click the right button when the mouse is positioned inside the window
to bring up a dialog box, then click the "Next" button shown in the
dialog box to view the next PGM image and so on.