Most programmers may use R as a tool for statistics or ‘conventional’ data analyses. Granted, as a researcher, this is often what I use it for too.

But the power of R extends much further, helped by a range of packages that greatly expand its functionality. Combine this with the capacity for functional programming, and solutions to a wider array of problems are plentiful.

The magick package is a great example of this. A wrapper of the C++ library ImageMagick, this package provides a variety of straightforward ways to edit and manipulate images. On its own, it can handle file conversion, multi-layer image editing, and even animation in a way that’s pretty intuitive even to an R newcomer.

But why does this matter?

Image manipulation tools are everywhere. Pretty much any device comes with image editing software right out of the box, and cropping and adjusting a photo is second nature to most tech users. When would there be a need to load up an R project to do any of this?

The real power of programmatic image manipulation is the ability to manipulate loads of images at once, meanwhile creating a shareable source file. Although editors like Photoshop can do batch manipulation, these solutions aren’t as reproducible. Not to mention, they come at the cost of purchasing software.

In contrast, an R script can be uploaded to a public repository and then accessed by anyone, anywhere, at no cost to the user or creator. This creates a degree of transparency which is desirable in many use cases. Personally, it helps my science become easier for others to reproduce. Since I was after concise code on top of this, batching my image edits with magick was a no-brainer.

A Real Example, Explained

Here’s some code I wrote as a research assistant to edit hundreds of .pdf images for use in an experiment.

library(magick)
library(tidyverse)

imgnames <- list.files(path=paste0(getwd(), "/input_folder/"))
images <- map(imglist, ~ image_read_pdf(paste0(getwd(), "/input_folder/", .x))) %>%  
    map(~ image_scale(.x, "500")) %>%  
    map(~ image_modulate(.x, saturation = 0))
output_names <- paste0(1:length(imglist), ".jpg")
map2(images, output_names, ~ image_write(.x, path=paste0(getwd(), "/output_folder/", .y), format = "jpeg")

This script needed to accomplish three things:

  1. Scale each image to a uniform size (500 px wide)
  2. Desaturate each image
  3. Convert each image from .pdf format to .jpeg format

To do this, I used functions from the magick and tidyverse packages. Although I’ll explain the script step by step, I’ll assume some prior understanding about the key principles of the tidyverse, especially the pipe operator (%>%). This will come into its own when writing neat R code of all kinds, and deserves a standalone read.

First, I start by reading in all my unedited images and storing them in a list (images). I can do this by storing all the filenames from my folder of unedited images into a vector (imgnames).

#r #functional-programming #image-processing #tidyverse #data-science #function

Batch Editing Images with R
1.35 GEEK