EBImage provides general purpose functionality for image processing and analysis. In the context of (high-throughput) microscopy-based cellular assays, EBImage offers tools to segment cells and extract quantitative cellular descriptors. This allows the automation of such tasks using the R programming language and facilitates the use of other tools in the R environment for signal processing, statistical modeling, machine learning and visualization with image data.
EBImage is an R package distributed as part of the Bioconductor project. To install the package, start R and enter:
source("http://bioconductor.org/biocLite.R")
biocLite("EBImage")
Once EBImage is installed, it can be loaded by the following command.
library("EBImage")
Basic EBImage functionality includes reading, writing, and displaying of images. Images are read using the function readImage
, which takes as input a file name or an URL. To start off, let us load a sample picture distributed with the package.
f = system.file("images", "sample.png", package="EBImage")
img = readImage(f)
EBImage currently supports three image file formats: jpeg
, png
and tiff
. This list is complemented by the RBioFormats package providing support for a much wider range of file formats including proprietary microscopy image data and metadata.
The image which we just loaded can be visualized by the function display
.
display(img)
When called from an interactive R session, display
opens the image in a JavaScript viewer in your web browser. Using the mouse or keyboard shortcuts, you can zoom in and out of the image, pan, and cycle through multiple image frames. Alternatively, the image can be displayed using R’s build-in plotting facilities by calling display
with the argument method = "raster"
. The image is then drawn on the current device. This allows to easily combine image data with other plotting functionality, for instance, add text labels.
display(img, method="raster")
text(x = 20, y = 20, label = "Parrots", adj = c(0,1), col = "orange", cex = 2)
The graphics displayed in an R device can be saved using base R functions dev.print
or dev.copy
. For example, lets save our annotated image as a JPEG file and verify its size on disk.
filename = "parrots.jpg"
dev.print(jpeg, filename = filename , width = dim(img)[1], height = dim(img)[2])
png
2
file.info(filename)$size
[1] 37858
If R is not running interactively, e.g. for code in a package vignette, "raster"
becomes the default method in display
. The default behavior of display
can be overridden globally be setting the "options("EBImage.display")
to either "browser"
or "raster"
. This is useful, for example, to preview images inside RStudio.
It is also possible to read and view color images,
imgcol = readImage(system.file("images", "sample-color.png", package="EBImage"))
display(imgcol)
or images containing several frames. If an image consists of multiple frames, they can be displayed all at once in a grid arrangement by specifying the function argument all = TRUE
,
nuc = readImage(system.file("images", "nuclei.tif", package="EBImage"))
display(nuc, method = "raster", all = TRUE)
or we can just view a single frame, for example, the second one.
Images can be saved to files using the writeImage
function. The image that we loaded was a PNG file; suppose now that we want to save this image as a JPEG file. The JPEG format allows to set a quality value between 1 and 100 for its compression algorithm. The default value of the quality
argument of writeImage
is 100, here we use a smaller value, leading to smaller file size at the cost of some reduction in image quality.
writeImage(imgcol, "sample.jpeg", quality = 85)
Similarly, we could have saved the image as a TIFF file and set which compression algorithm we want to use. For a complete list of available parameters see ?writeImage
.
EBImage uses a package-specific class Image
to store and process images. It extends the R base class array
, and all EBImage functions can also be called directly on matrices and arrays. You can find out more about this class by typing ?Image
. Let us peek into the internal structure of an Image
object.
str(img)
Formal class 'Image' [package "EBImage"] with 2 slots
..@ .Data : num [1:768, 1:512] 0.447 0.451 0.463 0.455 0.463 ...
..@ colormode: int 0
The .Data
slot contains a numeric array of pixel intensities. We see that in this case the array is two-dimensional, with 768 times 512 elements, and corresponds to the pixel width and height of the image. These dimensions can be accessed using the dim
function, just like for regular arrays.
dim(img)
[1] 768 512
Image data can be accessed as a plain R array
using the imageData
accessor,
imageData(img)[1:3, 1:6]
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 0.4470588 0.4627451 0.4784314 0.4980392 0.5137255 0.5294118
[2,] 0.4509804 0.4627451 0.4784314 0.4823529 0.5058824 0.5215686
[3,] 0.4627451 0.4666667 0.4823529 0.4980392 0.5137255 0.5137255
and the as.array
method can be used to coerce an Image
to an array
.
is.Image( as.array(img) )
[1] FALSE
The distribution of pixel intensities can be plotted in a histogram, and their range inspected using the range
function.
hist(img)
range(img)
[1] 0 1
A useful summary of Image
objects is also provided by the show
method, which is invoked if we simply type the object’s name.
img
Image
colorMode : Grayscale
storage.mode : double
dim : 768 512
frames.total : 1
frames.render: 1
imageData(object)[1:5,1:6]
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 0.4470588 0.4627451 0.4784314 0.4980392 0.5137255 0.5294118
[2,] 0.4509804 0.4627451 0.4784314 0.4823529 0.5058824 0.5215686
[3,] 0.4627451 0.4666667 0.4823529 0.4980392 0.5137255 0.5137255
[4,] 0.4549020 0.4666667 0.4862745 0.4980392 0.5176471 0.5411765
[5,] 0.4627451 0.4627451 0.4823529 0.4980392 0.5137255 0.5411765
For a more compact representation without the preview of the intensities array use the print
method with the argument short
set to TRUE
.
print(img, short=TRUE)
Image
colorMode : Grayscale
storage.mode : double
dim : 768 512
frames.total : 1
frames.render: 1
Let’s now have a closer look a our color image.
print(imgcol, short=TRUE)
Image
colorMode : Color
storage.mode : double
dim : 768 512 3
frames.total : 3
frames.render: 1
It differs from its grayscale counterpart img
by the property colorMode
and the number of dimensions. The colorMode
slot turns out to be convenient when dealing with stacks of images. If it is set to Grayscale
, then the third and all higher dimensions of the array are considered as separate image frames corresponding, for instance, to different z-positions, time points, replicates, etc. On the other hand, if colorMode
is Color
, then the third dimension is assumed to hold different color channels, and only the fourth and higher dimensions—if present—are used for multiple image frames. imgcol
contains three color channels, which correspond to the red, green and blue intensities of the photograph. However, this does not necessarily need to be the case, and the number of color channels is arbitrary.
The “frames.total” and “frames.render” fields shown by the object summary correspond to the total number of frames contained in the image, and to the number of rendered frames. These numbers can be accessed using the function numberOfFrames
by specifying the type
argument.
numberOfFrames(imgcol, type = "render")
[1] 1
numberOfFrames(imgcol, type = "total")
[1] 3
Image frames can be extracted using getFrame
and getFrames
. getFrame
returns the i-th frame contained in the image y. If type
is "total"
, the function is unaware of the color mode and returns an xy-plane. For type="render"
the function returns the i-th image as shown by the display function. While getFrame
returns just a single frame, getFrames
retrieves a list of frames which can serve as input to lapply
-family functions. See the “Global thresholding” section for an illustration of this approach.
Finally, if we look at our cell data,
nuc
Image
colorMode : Grayscale
storage.mode : double
dim : 510 510 4
frames.total : 4
frames.render: 4
imageData(object)[1:5,1:6,1]
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 0.06274510 0.07450980 0.07058824 0.08235294 0.10588235 0.09803922
[2,] 0.06274510 0.05882353 0.07843137 0.09019608 0.09019608 0.10588235
[3,] 0.06666667 0.06666667 0.08235294 0.07843137 0.09411765 0.09411765
[4,] 0.06666667 0.06666667 0.07058824 0.08627451 0.08627451 0.09803922
[5,] 0.05882353 0.06666667 0.07058824 0.08235294 0.09411765 0.10588235
we see that it contains 4 total frames that correspond to the 4 separate greyscale images, as indicated by “frames.render”.
As described in the previous section, the class Image
extends the base class array
and uses colorMode
to store how the color information of the multi-dimensional data should be handled. The function colorMode
can be used to access and change this property, modifying the rendering mode of an image. For example, if we take a Color
image and change its mode to Grayscale
, then the image won’t display as a single color image anymore but rather as three separate grayscale frames corresponding to the red, green and blue channels. The function colorMode
does not change the actual content of the image but only changes the way the image is rendered by EBImage.
colorMode(imgcol) = Grayscale
display(imgcol, all=TRUE)
Color space conversions between Grayscale
and Color
images are performed using the function channel
. It has a flexible interface which allows to convert either way between the modes, and can be used to extract color channels. Unlike colorMode
, channel
changes the pixel intensity values of the image.
Color
to Grayscale
conversion modes include taking a uniform average across the RGB channels, and a weighted luminance preserving conversion mode better suited for display purposes.
The asred
, asgreen
and asblue
modes convert a grayscale image or array into a color image of the specified hue.
The convenience function toRGB
promotes a grayscale image to RGB color space by replicating it across the red, green and blue channels, which is equivalent to calling channel
with mode set to rgb
. When displayed, this image doesn’t look different from its grayscale origin, which is expected because the information between the color channels is the same. To combine three grayscale images into a single rgb image use the function rgbImage
.
The function Image
can be used to construct a color image from a character vector or array of named R colors (as listed by colors()
) and/or hexadecimal strings of the form “#rrggbb” or “#rrggbbaa”.
colorMat = matrix(rep(c("red","green", "#0000ff"), 25), 5, 5)
colorImg = Image(colorMat)
colorImg
Image
colorMode : Color
storage.mode : double
dim : 5 5 3
frames.total : 3
frames.render: 1
imageData(object)[1:5,1:5,1]
[,1] [,2] [,3] [,4] [,5]
[1,] 1 0 0 1 0
[2,] 0 1 0 0 1
[3,] 0 0 1 0 0
[4,] 1 0 0 1 0
[5,] 0 1 0 0 1
display(colorImg, interpolate=FALSE)
Being numeric arrays, images can be conveniently manipulated by any of R’s arithmetic operators. For example, we can produce a negative image by simply subtracting the image from its maximum value.
img_neg = max(img) - img
display( img_neg )