Adapted from: https://www.bioconductor.org/packages/release/bioc/vignettes/EBImage/inst/doc/EBImage-introduction.html
On Ubuntu install requires
sudo apt install r-cran-fftwtools
from marutter’s ppa
install.packages("BiocManager")
BiocManager::install("EBImage")
library(EBImage)
Reading
- Let’s look at some microscope images of cells
nuclei_file <- system.file("images", "nuclei.tif", package="EBImage")
nuclei_img <- readImage(nuclei_file)
nuclei_img
- Image object includes information on
- Color mode - Gray scale
- Dimensions - 510 x 510 pixels
- Frame is like a layer in spatial data
- Can be frames in a movie, different images, or different color bands
- If this was a single color image would have
frames.total = 3
for red, green, blueframes.render = 1
for a single combined image
- Images are encoded as numbers for each pixel
- For grayscale: range from 0 (black) to 1 (white)
- Data is stored in a 3D matrix
- x
- y
- frame
Display
- Can show image using
plot
ordisplay
plot
makes a simple graph of the first frame
plot(nuclei_img)
display
allows interactive viewing
display(nuclei_img)
Cropping
- Because an image is just a matrix of numbers
- Cropping is like subsetting a matrix
nuclei_img_cropped <- nuclei_img[200:300, 350:450, 1]
display(nuclei_img_cropped)
- Just work with one image for simplicity
- Get all rows and columns for a single frame
nuclei_img = nuclei_img[,,1]
nuclei_img
Thresholding
- Distinguish between background and objects
- We can see which areas are nuclei and which aren’t
- But the computer just sees continuous numbers
- Even in areas that appear clearly black the numbers aren’t zero
nuclei_img[220:225, 220:225]
- Thresholding makes pixels binary
- True or False
- Part of a nuclei or not
- Can do this manually
nuclei_thresh <- nuclei_img > 0.5
display(nuclei_thresh)
- But determining the right threshold can be tricky
- Our first try left some nuclei out
- Try a lower threshold
nuclei_thresh <- nuclei_img > 0.1
display(nuclei_thresh)
-
Leaves too many pixels in
-
Automatically select threshold with Otsu’s method
- Clusters pixels by intensity to get a better result
threshold <- otsu(nuclei_img)
nuclei_thresh <- nuclei_img > threshold
display(nuclei_thresh)
- Adaptive thresholding- vary threshold by location in image
Image segmentation
- Split the image up into unique objects
- One simple way is to group all contiguous threshold pixels into an object
nuclei_segmented <- bwlabel(nuclei_thresh)
- Labels each distinct nuclei with a different number (class)
nuclei_segmented
nuclei_segmented@.Data[1:15, 1:15]
- Can them display them with different colors
display(colorLabels(nuclei_segmented))
Counting objects
- With this segmentation we can then count the number of nuclei
- One unique number for each nuclei so the biggest number is the number of nuclei
max(nuclei_segmented)
- 98 nuclei in this image
Measuring
- Measure the location and features of the objects
computeFeatures
- Information on shape and size
computeFeatures.shape(nuclei_segmented)
- Information on location
computeFeatures(nuclei_segmented, nuclei_img)
- Measures are in pixels
- Include an object of known size to convert to meaningful units
Conclusions
- Threshold -> Segment
- Lets us count and measure objects in an image