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) %>% 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)
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
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")
To make an image list, run “imlist” on a list of images:
list(a= imnoise(10,10),b= boats) %>% imlist
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
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.