imager is an R package for image processing, based on CImg. This new release brings many new features, including:

  • Support for automatic parallel processing using OpenMP.
  • A new S3 class, imlist, which makes it easy to work with image lists
  • New functions for interactively selecting image regions (grabRect,grabPoint,grabLine)
  • Experimental support for CImg’s byte-compiled DSL via imeval, patch_summary.
  • Improved plotting, API consistency, and documentation

To get started with imager, see the tutorial. Some of the new features are detailed below the fold.

And now, for your viewing pleasure, the following piece of code downloads a random cat picture, and makes a video of a bouncing kitten:

library(rvest)
library(imager)
#Run a search query (returning html content)
search <- read_html("https://www.google.com/search?site=&tbm=isch&q=cat")
#Grab all <img> tags, get their "src" attribute, a URL to an image
urls <- search %>% html_nodes("img") %>% html_attr("src") #Get urls of parrot pictures

#Load the first image, and resize 
sprite <- load.image(urls[1]) %>% resize(150,150)

#We'll use 30 frames
t <- seq(0,1,l=30)

#Equations of motion
xt <- function(t) 250*t
yt <- function(t) 400- 1100*abs(t-.5)
alpha <- function(t) 1-1.8*abs(t-.5)

#An empty frame for our cat
im <- imfill(400,400,val=rep(0,3))

#Let's make our video
vid <- lapply(t,function(t) imdraw(im,sprite,x=xt(t),y=yt(t),opacity=alpha(t))) %>% imappend("z")

play(vid,loop=TRUE,normalise=FALSE)

output

 

A new class for image lists

Image lists (S3 class “imlist”) are simply lists of images, but they come with appropriate generics for plotting, converting, etc. For example, calling imhessian automatically produces an image list

imhessian(boats) %>% plot
imhessian(boats) %>% display
imhessian(boats) %>% as.data.frame %>% head

imlist

There’s also a “map_il” function, inspired by the purrr package. It works essentially like “sapply” but returns an image list:

#View image at different blur levels
map_il(seq(1,14,l=5),~ isoblur(boats,.),.id="v") %>% plot(layout="row")

map_il

To make an image list, run “imlist” on a list of images:

list(a= imnoise(10,10),b= boats) %>% imlist

Parallel processing

If possible, imager now enables CImg’s parallel processing features. “If possible” means you need a compiler that supports OpenMP, which includes recent versions of gcc and very recent versions of clang (>= 3.7.0). Many image processing primitives (filters, transformations, etc.) will run in parallel on CPU cores. See here for more on parallel computations.

Interactive selection of image regions

It’s often useful to be able to select image regions for further processing. You can now do so interactively and easily using grabRect:

r = grabRect(boats)

Here “r” will contain the coordinates of the rectangle you selected. If you want the contents of the rectangle itself, run:

im = grabRect(boats,coord=FALSE)

Experimental support for CImg’s DSL

CImg includes a byte-compiled mini-language that’s well-suited for simple non-linear filters and image generators. It’s documented here.
Here’s a simple box filter you can try:

boxf <- "v=0;for(iy=y-3,iy<y+3,iy++,for(ix=x-3,ix< x+3,ix++,v+=i(ix,iy)));v" imeval(boats,boxf) %>% plot

A more impressive example is due to David Tschumperlé (the creator of CImg): the Julia set

julia <-  "
   zr = -1.2 + 2.4*x/w;
   zi = -1.2 + 2.4*y/h;
   for (iter = 0, zr^2+zi^2<=4 && iter<256, iter++, t = zr^2 - zi^2 + 0.5; (zi *= 2*zr) += 0.2; zr = t ); iter" imfill(500,500) %>% imeval(julia) %>% plot

julia

I’m still not completely sure how useful this is. On the one hand, R is pretty poor at computations that involve looping over every pixel, and CImg’s DSL is much better. On the other, there’s a lot of ways of getting around having to write pixel loops, and I explore some of them here. Feedback appreciated.

Advertisements