Académique Documents
Professionnel Documents
Culture Documents
introductory notes
by
Richard Beare
1
# function imloadtiff to the variable ‘‘b’’.
# ‘‘b’’ is now an image class object.
# More discussion of this later.
# Note that the ‘‘#’’ symbol is a comment
• “if” statements. Formally described by “if (cond) expr else expr”. Use “help(”if”)” to get
the online help.
if (i > 1) {
# do stuff here
b <- imloadtiff(‘‘image.tiff’’)
} else {
# do something else
}
for (i in 1:10) {
j <- j + i
}
2
The “data” command loads mona as an R array (not an image!) from the package installation.
The second command converts the array to an image in the appropriate form.
All arithmetic operators should operate on images in the expected fashion. For example
imC <- imA op imB op imX op numericvalue
should work with any combination of images and R numeric variables or literals where “op”
is any arithmetic or logical operator. The restrictions and promotion rules will be discussed in
Section 3.5.
Now lets try a simple example of top hat filtering, followed by thresholding, labelling and
attribute based selection.
tophat <- imfclosepoly(imA, 31, 0, 0) - imA
thrsh <- tophat > 10
labelled <- imstats(thrsh)
tbl <- imobjstats(labelled)
The first command is a simple top hat filter - the difference between a closing and the orignal
image. The second command is a thresholding that returns a binary image. The third is more
interesting. It returns a labelled image - each connected binary component is assigned a unique
integer value. A table of component statistics is also generated by the imstats command. It is
extracted by the imobjstats command and assigned to the variable “tbl” (type “tbl” to print the
contents). “tbl” is an R array object with named columns. We shall see how this can be useful
later on.
The intermediate results can be viewed using imview
imview(tophat)
or
print(tophat)
or
tophat
Entering the name of an object in R causes the print method for the object class to be called.
For image objects this means sending the image to imview. The difference between the two
methods is that the first will result in an image named “tophat” being present in imview’s list of
images. The second option causes one with the name “noname” to be entered in the list. Thus,
displaying another image this way will overwrite the first.
Now lets try manipulating the image using the results of the labelling operation. R provides
very powerful array selection and manipulation commands. The connected component statistics
are returned in an array and can therefore be manipulated easily.
Suppose we want to keep all connected components with an area greater than 50. The following
commands do it
onum <- tbl[,"area"] > 50
keep <- tbl[onum, "number"]
result <- imkeepobj(labelled, keep)
imview(imA)
imview.overlay(result)
The first command produces a vector of boolean values. The values in the vector are “true”
when the value in the column named “area” is greater than 50. The second command uses this
vector to produce a vector of object numbers. Only entries in the “number” column with “true”
values in the boolean vector are returned. Similar operations can be combined in a huge variety of
ways to produce very powerful selection mechanisms. It is all based on the array/matrix subsetting
rules, so check the Splus/R books for more details.
3
3.3 Image and pixel types
Images in Voir can vary in complexity. The simplest is a single component image. For example
“summary(imA)” (from above) will produce the following:
Image type is IM.SINGLE
Comp:1, type = IM.UINT1, nx = 432 [0:431], ny = 440 [0:439], nz = 1 [0:0]
The “IM.SINGLE” description indicates that this is a single component image.
The single component may be 1, 2, 3 or 4 dimensional. 2 dimensions are most common, and
all image related functions can be expected to work on a 2 dimensional image. 1 dimensional
images can be useful when it is desirable to apply image analysis functions to more conventional
signals (like speech), or when a 2 dimensional image has been projected to form a 1 dimensional
one. Not all functions will work on 1 dimensional images, but most do. 3 dimensional images may
come from modalities such as MRI or confocal microscopy - they have an intensity value for every
voxel. 3 dimensional images are not designed to store the output from stereo reconstruction or
range imaging modalities. A variety of 3D operations have been implemented, and most have “3d”
in the name. Arithmetic and logical operators work on 3D without any problem. 4 dimensional
images are supported by the underlying data types and the associated contruction routines, but
no functions use the facility at this stage. The obvious use of the fourth dimension is time, but
this has not yet been considered useful. A component may also have an offset, which just means
that the coordinates of the top left corner will not be (1,1,1,1), but will be set to some other value.
Note that the pixels are stored in raster order, with the origin at the top left and the underlying
data stored so that the x axis changes most rapidly. This is the transpose of the way in which R
represents matrices.
The pixels within the component may also be represented in different ways. Broadly speaking,
the different pixel types have different storage requirements and different precision. The exam-
ple above uses “IM.UINT1”, which is a common, 8 bit, unsigned pixel format. Alternatives are
IM.BINARY – also 8 bit in our implementation, but only 2 values, IM.INT1 and IM.CHAR – signed 8
bit quantities that are not used. These are all 1 byte representations and are very commonly used.
The 2 byte types are IM.SHORT, IM.INT2 and IM.UINT2. The first two are identical, signed 16 bit
representations while the last is an unsigned version. 2 byte image representations are becoming
more common, but not many functions operate on them, which often makes it necessary to cast
to a 4 byte representation (see Section 3.6 on casting methods). The 4 byte types are IM.INT,
IM.INT4, IM.UINT4 – the first two are signed and are the most commonly used. There are also 8
byte integer representations – IM.INT8 and IM.UINT8 that are never used. Finally there are real
valued types – IM.FLOAT and IM.DOUBLE, with IM.DOUBLE being most widely used.
Now that the nature of the simplest image type has been explored, the more complex versions
will be introduced. The level of complexity above IM.SINGLE is multi-spectral – IM.SPECTRUM.
An image of this type may have many components, however all components must be the same
dimensions and have the same pixel types and same offset. Special cases of multi-spectral images
are IM.RGB and IM.HLS, each of which has three components. IM.RGB is the standard representation
for colour images, with the first component being red, the second green and the third blue. IM.HLS
is an alternative colour space representation (hue-lightness-saturation). IM.LUT is a special type
intended for use as lookup tables - not used anymore??
The most general image type is a multi-component image – IM.MULTI. A multi-component
image may have many components, each of which can have different dimensions, pixel types and
offsets. Such images are not widely used, but are important when returning complex results, such
as the results of labelling and statistical functions. In general such image types are more important
for library level programmers than Voir users.
Finally there is an IM.DEFAULT image type that is used as a flag in arithmetic operations. It
should not be necessary to use this at the Voir level.
Different image types are created using the imconstruct family of functions. These include
imconstructsingle, imconstructrgb, etc. These functions have an argument that specifies the
pixel type. It is rare to need to use these functions within Voir, because it is often easier to copy
4
an existing image, or load a previously stored one.
5
The resulting image will have pixels of either integer or double, depending on the storage mode
of the array. The image can be cast as described in Section 3.6.
• IM.ALL can be used to specify that a function should operate on all image components.
Not all functions accept a component argument, but those that do will typically be able to
accept IM.ALL.
• IM.BINARY, IM.CHAR, IM.INT1, IM.UINT1, IM.SHORT, IM.INT2, IM.UINT2,
IM.INT, IM.INT4, IM.UINT4, IM.INT8, IM.UINT8, IM.FLOAT, IM.DOUBLE,
IM.DEFAULT refer to pixel representations. These are used by the imconstruct family
of routines and imsetpixtype.
• IM.BADIMAGE, IM.MULTI, IM.SPECTRUM, IM.SINGLE, IM.RGB, IM.HLS,
IM.LUT refer to image types used by the imsetimgtype function.
6
where a and b are images will work, however a pointer copy has occurred, rather than a data
copy, so both variables refer to the same image. This relates to the underlying image representa-
tion. If an inplace image operation, like drawing, is used then the changes will be visible in both
a and b because they reference the same object.
An image copy can be made using the imcopy function, or a shortcut using array subsetting
notation.
a <- imcopy(b, IM.ALL)
a <- b[] # equivalent
7
• imthreeD2mult - goes back the other way.
• imresize - not a zoom function - it extracts a subset or increases the size of an image by
padding with a user defined value. The array subsetting operations can achieve equivalent
functionality, but imresize may be more efficient in some situations.
• Segmentation faults. Errors in image analysis functions can cause fatal errors to occur. Un-
der unix the first time an error of this kind occurs you will be prompted to press control-c to
return to R. Subsequent similar errors will appear to result in a freeze of R becuase the signal
handler is not reset. It is recommended that you don’t do too much after the first segmenta-
tion fault. Such errors are most likely to result from incorrect function arguments (because
not everything is checked as thoroughly as it should be) or in relatively new functions.
8
• Optional image arguments. In some functions the documentation may claim that an image
argument is optional. This does not mean that it can be left out (as in R), but that the
underlying C code is expecting a NULL argument. In such cases the appropriate parameter
to use is POINTER(), which returns a NULL image value.
• Checking results of image operations. It is sometimes necessary to check whether an im-
age operation has been successful. An example may be when loading an image. Use
is.nullImage to check whether an empty image pointer has been returned.
• Saving. R allows users to save a workspace on exit. Any images saved using this mechanism
will be reloaded as NULL pointers, and therefore not be very useful. It is possible to automate
the loading and saving of images using the following code in your .Rprofile file(although it
isn’t necessarily a good idea)
library(Voir)
imloadall(envir=.GlobalEnv, where=".RImages")
.Last<- function()
{
unlink(".RImages/*")
imsaveall(envir=.GlobalEnv, where="./.RImages/")
cat("Finished saving images\n")
}
9
• im.imview Image display and animation functions.
• im.io Image file IO.
• im.linear Linear filters - blurring etc.
• im.melanoma Functions related to the melanoma project.
• im.neigh Neighbourhood operations.
• im.other Things that have been written just for Voir and don’t have a direct libray
equivalent.
• im.pde Partial differential equation based morphology routines.
• im.skeleton Skeletonisation realisation.
• im.stats Image statistics - max, min, means, histograms etc.
• im.thresh Thresholding functions.
• im.transf Transforms - fitchar, stretch, lintrans, hough.
• im.utils Line and ellipse drawing.
• mona A dataset than can be converted to an image using as.image
10