Simon Barthelmé (GIPSA-lab, CNRS)

If R isn’t fast enough for your needs, it may be worth using the CImg C++ API directly. Imager provides some wrappers that makes the process relatively convenient (if anything involving C++ can ever be called convenient).

Here’s a basic example: we define a C++ function inline, call cppFunction, and the function becomes magically accessible.

library(imager)
library(Rcpp)

#Some C++ code as a character string
#The function takes an image, applies blur and erode operations, and returns the result
foo.inline <- "
NumericVector foo(NumericVector inp)
{
    CImg<double> img = as<CImg<double> >(inp);
    img.blur(3).erode(4);
    return wrap(img);
} "

#Compile the function. The compiler may issue a number of warnings which you can all ignore
cppFunction(foo.inline,depends="imager")


im <- load.image(system.file('extdata/Leonardo_Birds.jpg',package='imager'))

#Function foo is now accessible
foo(im) %>% plot

Going through the C++ code in more detail:

NumericVector foo(NumericVector inp)

cimg objects are passed from R to C++ as vectors of doubles with a dimension attribute of length 4 (corresponding to the x,y,z,c axes). We use the NumericVector class defined by Rcpp for that purpose.

CImg<double> img = as<CImg<double> >(inp);

Cimg is a templated library, and here we instantiate a CImg object (representing an image) with type double. The as function handles the conversion from NumericVector to CImg.

img.blur(3).erode(4);

This is a straightforward call to the CImg API, using chaining syntax. Note that operations are done in-place.

return wrap(img);

Use a custom wrap function that takes a CImg object and turns into into a NumericVector object with the right attributes. The result will show up in R as a cimg object.

To learn more about CImg, see the website or these slides.