R: Image Analysis using EBImage

Currently, I am taking Statistics for Image Analysis on my masteral, and have been exploring this topic in R. One package that has the capability in this field is the EBImage from Bioconductor, which will be showcased in this post.

Installation

123
source(“http://bioconductor.org/biocLite.R”)
biocLite()
biocLite(“EBImage”)
view rawEBIm3.R hosted with ❤ by GitHub

For those using Ubuntu, you may likely to encounter this error:

123
In file included from common.c:1:0:
common.h:5:18: fatal error: tiff.h: No such file or directory
#include <tiff.h>
view rawimageErr.R hosted with ❤ by GitHub

It has something to do with the tiff.h C header file, but it’s not that serious since mytechscribblings has an effective solution for this, do check that out.

Importing Data

To import a raw image, consider the following codes:

123
# Reading Image
Image <- readImage(‘~/Documents/R Files/Image Analysis/tinago.JPG’)
display(Image)
view rawEBIm1.R hosted with ❤ by GitHub
Output of display(Image).

Yes, this is the photo that we are going to use for our analysis. Needless to say, that’s me and my friends. In the proceeding section we will do image manipulation and other processing.

Image Properties

So what do we get from our raw image? To answer that, simply runprint(Image). This will return the properties of the image, including the array of pixel values. With these information, we apply mathematical and statistical operations to do enhancement on the image.

1234567891011121314151617
print(Image)
#OUTPUT
Image
colormode: Color
storage.mode: double
dim: 1984 1488 3
nb.total.frames: 3
nb.render.frames: 1
imageData(object)[1:5,1:6,1]:
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 0.3647059 0.3843137 0.3803922 0.3490196 0.3215686 0.3058824
[2,] 0.4196078 0.4000000 0.3921569 0.4039216 0.3843137 0.3254902
[3,] 0.4784314 0.4705882 0.4705882 0.4666667 0.4117647 0.3411765
[4,] 0.4901961 0.5647059 0.5960784 0.5411765 0.4392157 0.3843137
[5,] 0.4509804 0.5686275 0.6549020 0.6392157 0.5607843 0.4901961
view rawEBIm4.R hosted with ❤ by GitHub

There are two sections (Summary and array of the pixels) in the above output, with the following entries for the first section:

CODE VALUE DESCRIPTION
Table 1: Information from 1st section of print(Image).
colormode Color The type (Color/Grayscale) of the color of the image.
storage.mode double Type of values in the array.
dim 1984 1488 3 Dimension of the array, (x, y, z).
nb.total.frames: 3 Number of channels in each pixel, z entry in dim.
nb.render.frames 1 Number of channels rendered.

The second section is the obtained values from mapping pixels in the image to the real line between 0 and 1 (inclusive). Both extremes of this interval [0, 1], are black and white colors, respectively. Hence, pixels with values closer to any of these end points are expected to be darker or lighter, respectively. And because pixels are contained in a large array, then we can do all matrix manipulations available in R for processing.

Adjusting Brightness

It is better to start with the basic first, one of which is the brightness. As discussed above, brightness can be manipulated using + or -:

1234
# Brightness
Image1 <- Image + 0.2
Image2 <- Image 0.2
display(Image1); display(Image2)
view rawEBIm2.R hosted with ❤ by GitHub
LIGHTER DARKER
Table 2: Adjusting Brightness.
Output of display(Image1).
Output of display(Image2).

Adjusting Contrast

Contrast can be manipulated using multiplication operator(*):

123
Image3 <- Image * 0.5
Image4 <- Image * 2
display(Image3); display(Image4)
view rawEBIm5.R hosted with ❤ by GitHub
LOW HIGH
Table 3: Adjusting Contrast.
Output of display(Image3).
Output of display(Image4).

Gamma Correction

Gamma correction is the name of a nonlinear operation used to code and decode luminance or tristimulus values in video or still image systems, defined by the following power-law expression: begin{equation}nonumber V_{mathrm{out}} = AV_{mathrm{in}}^{gamma} end{equation} where $A$ is a constant and the input and output values are non-negative real values; in the common case of $A = 1$, inputs and outputs are typically in the range 0-1. A gamma value $gamma< 1$ is sometimes called an encoding gamma (Wikipedia, Ref. 1).

123
Image5 <- Image ^ 2
Image6 <- Image ^ 0.7
display(Image5); display(Image6)
view rawEBIm6.R hosted with ❤ by GitHub
$GAMMA = 2$ $GAMMA = 0.7$
Table 4: Adjusting Gamma Correction.
Output of display(Image5).
Output of display(Image6).

Cropping

Slicing array of pixels, simply mean cropping the image.

1
display(Image[289:1547, 669:1406,])
view rawEBIm7.R hosted with ❤ by GitHub
Output of the above code.

Spatial Transformation

Spatial manipulation like rotate (rotate), flip (flip), and translate (translate) are also available in the package. Check this out,

12
Imagetr <- translate(rotate(Image, 45), c(50, 0))
display(Imagetr)
view rawEBIm8.R hosted with ❤ by GitHub

Color Management

Since the array of pixels has three axes in its dimension, for example in our case is 1984 x 1488 x 3. The third axis is the slot for the three channels: Red, Green and Blue, or RGB. Hence, transforming the color.mode from Color toGrayscale, implies disjoining the three channels from single rendered frame (three channels for each pixel) to three separate array of pixels for red, green, and blue frames.

123456789101112131415161718
colorMode(Image) <- Grayscale
print(Image)
#OUTPUT
Image
colormode: Grayscale
storage.mode: double
dim: 1984 1488 3
nb.total.frames: 3
nb.render.frames: 3
imageData(object)[1:5,1:6,1]:
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 0.3647059 0.3843137 0.3803922 0.3490196 0.3215686 0.3058824
[2,] 0.4196078 0.4000000 0.3921569 0.4039216 0.3843137 0.3254902
[3,] 0.4784314 0.4705882 0.4705882 0.4666667 0.4117647 0.3411765
[4,] 0.4901961 0.5647059 0.5960784 0.5411765 0.4392157 0.3843137
[5,] 0.4509804 0.5686275 0.6549020 0.6392157 0.5607843 0.4901961
view rawEBIm9.R hosted with ❤ by GitHub
ORIGINAL RED CHANNEL
Table 5: Color Mode Transformation.
GREEN CHANNEL BLUE CHANNEL

To revert the color mode, simply run

1
colorMode(Image) <- Color
view rawEBIm12.R hosted with ❤ by GitHub

Filtering

In this section, we will do smoothing/blurring using low-pass filter, and edge-detection using high-pass filter. In addition, we will also investigate median filter to remove noise.

LOW-PASS (BLUR)
Table 6: Image Filtering.
1234
fLow <- makeBrush(21, shape= ‘disc’, step=FALSE)^2
fLow <- fLow/sum(fLow)
Image.fLow <- filter2(Image, fLow)
display(Image.fLow)
view rawEBIm10.R hosted with ❤ by GitHub
HIGH PASS
1234
fHigh <- matrix(1, nc = 3, nr = 3)
fHigh[2, 2] <- -8
Image.fHigh <- filter2(Image, fHigh)
display(Image.fHigh)
view rawEBIm11.R hosted with ❤ by GitHub

 

ORIGINAL FILTERED
Table 7: Median Filter.
From Google, Link Here.
Output of display(medFltr)

 

123
Image <- readImage(“~/Documents/R Files/Image Analysis/peppersalt.jpg”)
medFltr <- medianFilter(Image, 1.1)
display(medFltr)
view rawEBIm13.R hosted with ❤ by GitHub

For comparison, I run median filter on first-neighborhood in Mathematica, and I got this

Clearly, Mathematica has better enhancement than R for this particular filter. But R has a good foundation already, as we witness with EBImage. There are still lots of interesting functions in the said package, that is worth exploring, I suggest you check that out.

For the meantime, we will stop here, but hoping we can play more on this topic in the succeeding post.

References

  1. Gamma Correction. Wikipedia. Retrieved August 31, 2014.
  2. Gregoire Pau, Oleg Sklyar, Wolfgang Huber (2014). Introduction to EBImage, an image processing and analysis toolkit for R.