1. Developing S4 Classes
for Medical Imaging Data
Initial Experience(s)
Brandon Whitcher, PhD
GlaxoSmithKline
Clinical Imaging Centre
2. Acknowledgements
• S4 Classes and Methods
– Slides by F. Leisch and P. Murrell
– Software for Data Analysis by J. Chambers
– R Programming for Bioinformatics by R. Gentlemen
– R packages
• nlme
• kernlab
• EBImage
2
3. OOP and Classes in R
• One identifies real objects, and the operations on them,
that are interesting.
– These operations can be systematically implemented.
• A basic principle (hope) is that by faithfully
representing the objects we get easier-to-implement
functions.
• A class is an abstract definition of a concrete real-world
object.
• A class system is a software infrastructure that is
designed to help construct classes and to provide
programmatic support for dealing with classes.
3
4. Why (S4) Classes for Medical
Imaging Data?
• Context of imaging data
• Interface with data standards and third-party
software
• Numerous processing steps involved
– Multiple information sources
• Audit trail (internal and external agencies)
• Too easy to make mistakes!
4
5. Data Analysis Pipeline
Test statistics
Motion correction Model building
p-values
Warping Parameter
Multiple
Co-registration estimation
comparisons
Data
Mathematical Statistical
Pre-processing
Modelling Analysis
Results
5
6. Medical Imaging Data
Slice Thickness; e.g. 5mm
Z
Y
X
X
Chosen parameters depend
Spatial Resolution
on many factors: application, Size = X × Y; e.g. 256×256
scanner, local practice,
radiologist preferences, etc. e.g. 0.4mm 6
9. The nifti Class
• Inherits from class array
• Contains 44 “slots” (not counting .Data)
– both numeric and character strings [348 bytes]
setClass(“nifti”, representation(“sizeof_hdr”=“numeric”,
“data_type”=“character”,
...),
prototype(“sizeof_hdr”=348,
“data_type”=“”,
...),
contains=“array”)
• Also created function nifti() for user-defined slots.
• Similar class has been defined for ANALYZE data.
9
10. Method “show” for nifti Class
setMethod(“show”, “nifti”, function(object) {
cat(“NIfTI-1 file format”, fill=TRUE)
cat(...)
cat(...)
})
> ffd
NIfTI-1 format
Type : nifti
Data Type : 4 (INT16)
Bits per Pixel : 16
Slice Code : 0 (Unknown)
Intent Code : 0 (None)
Qform Code : 1 (Scanner_Anat)
Sform Code : 0 (Unknown)
Dimension : 64 x 64 x 21 x 180
Pixel Dimension : 4 x 4 x 6 x 3
Voxel Units : mm
Time Units : sec
10
11. Validity Checking for nifti Class
setValidity(“nifti”, function(object) {
retval <- NULL
...
if (object@”sizeof_hdr” != 348)
retval <- c(retval, “sizeof_hdr != 348”)
if (!object@datatype %in% c(2^(1:11),768,1280,1536,1792))
retval <- c(retval, “datatype not recognized”)
...
if (!all(object@”dim_”[indices] == dim(object@.Data)))
retval <- c(retval, “dim/img mismatch”)
...
if (is.null(retval))
return(TRUE)
else
return(retval)
})
11
12. Manipulation of Slots
• The nifti header allows limited text information
– descrip (80 characters) and aux_file (24 characters)
Slots Acessor functions
> mniLR@”aux_file” > aux.file(mniLR)
[1] "none " [1] "none "
> mni@”descrip” > descrip(mniLR)
[1] "FSL3.2beta" [1] "FSL3.2beta"
– Replacement functions
setMethod(“descrip”, “nifti”, function(object) { object@descrip })
setGeneric(“descrip<-”, function(x, value) { standardGeneric(“descrip<-”) })
setReplaceMethod(“descrip”, “nifti”,
function(x, value) {
x@descrip <- value
x
})
12
13. Additional Methods
• readNIfTI() and writeNIfTI()
– IO functions for NIfTI data (100% R)
– Affine transformations
• image()
– Forces S3 method into proper generic method
– Equivalent to a “lightbox” representation
• overlay()
– Essentially, the image function for two input arrays
• orthographic()
– 2×2 matrix of plots: coronal, sagittal, axial
– Utilizes “pixel dimension” slot
13
15. mni <- readNIfTI(“avg152T1_LT_nifti.nii.gz”)
orthographic(mni, zlim=range(mni))
> mniLR
NIfTI-1 format
Type : nifti
Data Type : 2 (UINT8)
Bits per Pixel : 8
Slice Code : 0 (Unknown)
Intent Code : 0 (None)
Qform Code : 0 (Unknown)
Sform Code : 4 (MNI_152)
Dimension : 91 x 109 x 91
Pixel Dimension : 2 x 2 x 2
Voxel Units : mm
Time Units : sec
15
16. Coercion and Extensions
• Coercion
– Implicit since nifti class is built on the array class.
> A <- array(1:8^3, rep(8,3))
> B <- as(A, “nifti”)
> dim(B)
[1] 8 8 8
> B@”dim_”
[1] 0 0 0 0 0 0 0 0
– But... it will fail validObject().
• Allow extensions via the NIfTI-1.1 mechanism.
– Define new class “niftiExtension”
– Implement full audit trail
• XML document – library(“XML”)
16
17. Conclusions
• S4 classes are powerful
– Robust framework
– Generics and methods
– Validity checking
– Inheritance
• ... and difficult
– Documentation (lack thereof)
– Examples (lack thereof)
– Slower than S3 (?)
17
18. Todo List
• Integrate S4 class into image analysis functions.
– Modification of .Data causes modification of slot(s)
• Use cniftilib to be 100% NIfTI compliant
– Rniftilib by Oliver Granert <o.granert@neurologie.uni-kiel.de>
• Medical_Imaging task view
– Seven packages in current version.
18