Vous êtes sur la page 1sur 11

The Voir Image Analysis Environment -

introductory notes

CSIRO internal use only

by
Richard Beare

CSIRO Mathematical and Information Sciences


Macquarie University Campus
Locked Bag 17, North Ryde NSW 2113

July 29, 2002


1 Introduction
Voir - Vision, objects and images in R, is an image analysis package for the R data analysis envi-
ronment. The R/Voir combination produces a powerful and flexible language based environment
for the development of image analysis procedures.
The image analysis functions in Voir are implemented in a C library developed by the CMIS
Image Analysis group. The package includes the support necessary to make images appear to be
native R objects. R/Voir can therefore be used to develop prototype applications that will later
be implemented in standalone code based on the underlying image analysis library, or it may be
appropriate to implement the application in the R environment.
This document is intended for completely new users of Voir who have no background in using
image analysis environments developed by the CMIS Image Analysis group. (This includes Zimage,
S-Zimage as well as programming in the LIAR and C2LIAR libraries).

2 Installing the components


A working Voir installation requires 3 parts - R, imview and Voir. R, the data analysis environment,
is described on its web page (“http://www.r-project.org”) as a language which is not entirely unlike
the S language developed at AT&T Bell Laboratories by Rick Becker, John Chambers and Allan
Wilks. It is available from that site as well as many mirrors. Imview, an image analysis oriented
viewing application is available from “http://www.cmis.csiro.au/Hugues.Talbot/imview/”. Voir
is available within CSIRO from “to be decided”.
After installing R and imview (see the relevant instructions on their home pages), Voir may be
installed using the usual approach for an R package. Under unix a command such as
R INSTALL -l pathtolibrary Voir Linux.tgz
would be appropriate. Under Windows you can start R and select the “package→install from
local zip file” menu item.
Another option that should work on all platforms is to execute
install.packages("pathtopackage/Voir NT.zip", CRAN=NULL)
from within R. The success of all these options will depend on the permissions associated with
the installation directory.

3 Getting started – a quick tutorial


3.1 R basics
R is a sophisticated interpreted language that provides all of the standard programming structures,
including loops, conditional statements, functions as well as object oriented features. (The OO
features are not generally used directly by interactive users, but are exploited by the Voir package).
R also provides a number of fundamental data types, including numeric, character and boolean
objects, arrays and matrices, character strings, lists and data frames. Functions support default
arguments and variable numbers of arguments. List components and array rows and columns can
be named.
The important language control structures are outlined below.
• <-
is the assignment symbol.

a <- 1 #assigns the numeric value 1 to the variable ‘‘a’’

b <- imloadtiff("image.tiff") # assigns the output of the

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” loops. Formally described by “for(var in seq) expr”.

for (i in 1:10) {
j <- j + i
}

• “while” loops. “while(cond) expr”

while (i < 10) {


j <- j + i
}

3.2 Voir basics


Once R is running, Voir can be loaded using
library(Voir)
This command can be placed in a special file called .Rprofile, along with any other commands
that you want executed when R begins.
The Voir online help is integrated with the standard R help. The help browser may be started
using
help.start()
The Voir specific help can then be located inside the “packages” section.
The help is broken into sections organised by function type. The section names begin with
“im.” and should be located at the beginning of the help contents. There should be some help for
each function, but some of them are pretty unclear. Hopefully this will improve over time.
Now lets try some simple image analysis commands.
If you have an image, in TIF or Zimage format (ideally grey scale), then you may load it using
a command like this
imA <- imloadtiff("myimage.tif")
or
imA <- imloadzimage("myimage z")
If you don’t have an image handy, then we can use the one packaged with Voir.
data(mona)
imA <- imchar(as.image(mona))

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.

3.4 Images as R objects


Images in Voir are not arrays or matrices, but many of the operations that work on R arrays will
work on images. These include subsetting and component selection. It is also possible to import
an image into an array and vice versa.
General image information (dimensions, type, pixel representation etc) may be viewed using
summary(imA)
Images can be placed in lists in the same way as other complex R objects.
The aperm functions also work on images and can be especially useful when looking at 3D
images.
cbind and rbind can be used to glue 2 dimensional images together (they just call imweld).

3.4.1 Subsetting images


Images can be treated like matrices for subsetting purposes.
imSmall <- imA[100:200, 100:200]
imsubsamp <- imA[seq(100,200,by=2), seq(100,200,by=2)]
With a bit of imagination this notation can be used for flipping and mirroring images too.
Images can be 3D, and the subsetting operations extend to 3D.
If the result is a single pixel, a numeric value rather than an image is returned.
The following does NOT work yet.
imA[100:200, 100:200] <- 1

3.4.2 Component selection


Components of colour or spectral images may be selected using list notation. For example the
different planes of a colour image (IM.RGB type) may be copied as follows.
red <- imCol[[1]]
grn <- imCol[[2]]
blue <- imCol[[3]]
The other list selection methods should also work. For instance,
x <- imCol[[-1]]
produces a 2 component image, i.e removes the first component.

3.4.3 Importing and exporting images


The following command
A <- as.array(imA)
places the contents of the image object into an R array variable. This can be inefficient because
R always represents arrays using 32 or 64 bit quantities while the image may be represented using
8 bit pixels, making the transfer more time consuming because it requires type conversion as well
as increasing the storage requirements. The advantage is that other R functions, such as complex
statistical ones, may be applied to the array.
Similarly an array may be translated to an image using
imB <- as.image(A)

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.

3.5 Image arithmetic rules


Voir image operators attempt to minimise the amount of automated image type promotion. It
was felt that too much automation of this type of thing would be likely to hide logical errors
and ineffeciencies. If an arithmetic operator is applied to two images of the same type then the
output image has the same type. This means that operations on 8 bit images can result in over or
underflow. The exception is that arithmetic operations on binary images result in a char image.
If the two input images are of different types then the output image will have the higher precision
type (e.g. an operation on a char and an int image will produce an int).
There is currently no automatic promotion during literal-on-image operations (e.g image +
5). Thus adding large constants to a char image will result in overflow, so it may be necessary to
manually change the image type to the desired output. The image also controls the output type
as far as precision is concerned, so the following
imB <- A + 1.25
will produce the same result as
imB <- A + 1
if A is not a double image. In these situations the image should be adjusted to produce the
desired result.

3.6 Image type casting


Converting between different image representations (eg 8 bit to 32 bit) can be done using the “im-
setpixtype” command, or, more conveniently the following functions – imbinary, imchar, imshort,
imint or imdouble. These functions return a copy of the image with the pixel representation while
the imsetpixtype function operates in place. (Note that in place operations are discouraged by
the R language, so use of imsetpixtype should probably be restricted.)

3.7 Magic numbers and optional image arguments


The behaviour of a number of Voir functions is controlled by “magic numbers” due to the underly-
ing C implementation. There are constants defined in Voir that should be used in such situations.
More detail about the meaning of these constants can be found in section 3.3. These include

• 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.

3.8 Image assignment and copying


Image assignment is a little unusual in Voir.
a <- b

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

3.9 Image visualisation and interaction


Images in Voir are viewed using imview. Imview runs as a separate process, and the data is
transmitted using a shared memory or socket connection. It is possible for the connection between
R and imview to be a little bit unstable, especially if imview is terminated unexpectedly. In such
cases it is usually a good idea to use imview.new to start a new display window.
The generic print method for images transmits an image to the current imview process, or
starts one if necessary.
A new imview process can be started using imview.new. There are a variety of other com-
mands documented in the online help. The most important are
• imview.overlay - display an image in the overlay plane. This is useful for visualising
segmentation results.
• imview.getpointfile - this returns a list representation of an imview pointfile. Pointfiles are
the best way of getting user interaction with images (see the imview help for more details).
Very useful for creating seeds etc.
• imview.kill - terminates the imview process.

3.10 Pixel operations and drawing operations


Individual pixel values can be retrieved using array subset notation, or the imget/set routines.
x <- Im[100,100]
x <- imgetRCPT(Im, 1, 100, 100, 1, 1)
x <- imgetXYZT(Im, 1, 100, 100, 1, 1)
RCPT stands for row, column, plane, time. The difference between XYZT and RCPT is in
the use of image offsets. imgetRCPT returns the value of the pixel relative to the beginning of the
stored image, ignoring any offsets, while imgetXYZT includes offsets.
Individual pixel values can be set using imsetRCPT and imsetXYZT functions, which operate
in place and return a status.
There are also a variety of drawing operations for lines, ellipses (circles), boxes and text. These
include imdrawline, imdrawline3d, imdrawellipse, imputtextinplace, imbox, which all
operate on images in place and return a status. These functions are able to operate on most pixel
and image types, but will only operate on 3D images if there is “3d” in the name of the function.

3.11 Other image construction methods


The imconstruct* routines can be used to create empty images. Other functions related to image
construction include
• imjoin - combines multiple images together to produce one with several components.

• immult2threeD - translates a multispectral image to a 3D image.

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.

3.12 Building your own functions


The R language supports the creation of functions. Naturally it is possible to build specialised
image analysis functions that utilise any combination of Voir and other R functions. For example,
consider a function that thresholds an image and then retains all regions with areas between two
user supplied values.

thresh.with.area <- function(Im, small.size, big.size)


{
bn <- imqthresh(Im, IM.ALL, 0,05, 0) # automatic threshold
lbl <- imstats(bn) # label and statistics
tbl <- imobjstats(lbl) # fetch table of statistics
kp <- (tbl[,"area"] > small.size) & (tbl[,"area"] < big.size) # process table
nm <- tbl[kp, "number"] # get list of regions we want to keep
res <- imkeepobj(lbl, nm) > 0 # keep them
res # return
}

Such a function can be included in a text file and sourced as required.

3.13 Dark corners


There are a number of dark corners in Voir that may cause trouble. Most relate to the underlying
C and the fact that Voir is largely automatically generated. The most common problems are

• Indexing. C indexing begins at 0, R begins at 1. Voir attempts to do everything the R way,


but there could be some instances of component values not being adjusted properly. If there
are any problems check this first.
• Memory management. Voir objects are linked into the R garbage collection mechanism.
Garbage collection is triggered by Voir when 10M (by default) of image space has been
allocated since the last garbage collection. This can be changed using immaxmemsize().

• 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.

• Documentation - translating the C based documentation. The documentation is largely


generated from the comments in the underlying C code. Not all of the translation is perfect.
Underscores in function or argument names should be ignored. Most argument types apart
from IMAGE* can also be ignored (they are dealt with by the binding code). IMAGE*
refers to an image object in the underlying C code and should always correspond to an image
object in Voir. There is automatic checking so that a function will terminate if a non image
object is passed instead.
Note: use is.image to determine whether an object is an image in Voir.

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")
}

3.14 Image analysis function types


There are a large number of image analysis functions available. Many are morphologically based.
New functions are being added all the time, so it is best to look at the online documentation. The
functions may be divided into the following classes.

• im.3d Functions for manipulation of 3D images.


• im.binary Binary image functions - distance transforms, size transforms, thinning,
pruning etc.
• im.colmv Colour and multivariate functions - bivariate histograms, HLS, pc, mnf.
• im.conncomp Connected component operations.
• im.constants Equivalents to some C macros that are sometimes needed for function
arguments.
• im.detector Experimental motion detector code - written by Keith So.
• im.display Writing text on images, overlaying label images.
• im.euclid Binary morphology and euclidean distance transforms.
• im.fseries Morphology operations using flat structuring elements - erosion, dilation,
opening and closing.
• im.greymm Greyscale morphology type functions, watershed, seeded region growing,
openbat, closebun etc.
• im.greymm3d 3D greyscale morphology.
• im.imgcons Image construction routines - borders, transpose, weld, mirror.
• im.imgsys Image data structure manipulation imconstruct *.

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

Vous aimerez peut-être aussi