Making a movie in R from still images

2 minute read

Making a movie in R from still images

This summer I was doing some hydrogeophysics at a mountain fen to better understand the role biogenic gasses play in determining flowpaths on those ecosystems. As part of that endeavour I setup a field camera to take a photo every hour. I then used R, ImageMagick, and FFmpeg to stitch those photos into a movie. Below is the code for the movie (without sound):

#Note: this script requires both ImageMagick and FFmpeg to be installed
# on your computer to work properly. (It may not even need ImageMagick, but I
# had already set that up prior, and the magick package makes calls to that program.)

library(magick)
library(animation)

#This tells the animation package where FFmpeg lives on my computer.
#FFmpeg is what is actually doing all the heavy lifting.
animation::ani.options(ffmpeg = shortPathName("C:/ffmpeg/bin/ffmpeg.exe"))

#The working directory in which the photos are located. This is also where I'm
# going to create the final video.
setwd("C:/LargeFiles/PhD/SLF Geophysics Photos")

#A vector containing all the photo names. All images contain the string: MDGC.
SLF.photos <- list.files(pattern = "MDGC", all.files = TRUE, ignore.case = TRUE)

#This extracts the underlying height, width, and type of image.
img.height <- magick::image_info(image_read(SLF.photos[1]))$height
img.width <- magick::image_info(image_read(SLF.photos[1]))$width
img.type <- magick::image_info(image_read(SLF.photos[1]))$format

#This tells FFmpeg that each picture should be displayed for 0.25 seconds,
# the height of the image, the width of the image, and the appropriate
# image engine to use.
#Note: tolower() converts uppercase letters to lowercase letters.
animation::ani.options(interval = 0.25,
ani.height = img.height,
ani.width = img.width,
ani.dev = tolower(img.type),
ani.type = tolower(img.type))

#By default the input dimensions of the image (designated here by img.height
# and img.width) dictate the output resolution. Below, I'm increasing the
# video dimensions to improve the image quality.
opts <- paste("-s ", img.height * 2, "x", img.width * 2, sep = "")

animation::saveVideo(
#Loop through all the photos, adding them one at a time. Not sure if this
# is the most efficient way of doing things, but it works.
for(i in 1:length(SLF.photos)){
#Read in an image.
SLF.image <- magick::image_read(SLF.photos[i])
#Plot the image.
plot(SLF.image)
},
#Designate the name of the image within the working directory.
video.name = "AnimationSLFGeo.avi",
#The extra image quality parameters indicated earlier.
other.opts = opts
)

Here is a YouTube version of the resultant video, after I added some music to it:

Updated: