Site icon R-bloggers

Basic manipulation of GIF frames with magick

[This article was first published on R – Statistical Odds & Ends, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

The magick package is a really powerful package for image processing in R. The official vignette is a great place to start learning how to use the package.

I’ve been playing around with using magick for manipulating GIFs and found some tips and tricks that don’t seem to be documented anywhere. Since the NBA restart is upon us, I’ll illustrate these tips with a GIF featuring one of the greatest of all time:

library(magick)

img_path <- paste0("https://media3.giphy.com/media/3o72F9VC4WjFDCPTag/",
                   "giphy.gif?cid=ecf05e470ceb6cd8542e8c243d0e0a2282c3390e5c",
                   "72fd17&rid=giphy.gif")
img <- magick::image_read(img_path)
img

If you print img, you will see that the GIF is represented as a tibble, with each row representing a single frame in the GIF:

print(img)
# # A tibble: 44 x 7
#    format width height colorspace matte filesize density
#    <chr>  <int>  <int> <chr>      <lgl>    <int> <chr>  
#  1 GIF      480    266 sRGB       TRUE   2617620 72x72  
#  2 GIF      480    266 sRGB       TRUE   2617620 72x72  
#  3 GIF      480    266 sRGB       TRUE   2617620 72x72  
#  4 GIF      480    266 sRGB       TRUE   2617620 72x72  
#  5 GIF      480    266 sRGB       TRUE   2617620 72x72  
#  6 GIF      480    266 sRGB       TRUE   2617620 72x72  
#  7 GIF      480    266 sRGB       TRUE   2617620 72x72  
#  8 GIF      480    266 sRGB       TRUE   2617620 72x72  
#  9 GIF      480    266 sRGB       TRUE   2617620 72x72  
# 10 GIF      480    266 sRGB       TRUE   2617620 72x72  
# # … with 34 more rows

Use the length() function to determine how many frames there are in the GIF:

length(img)
# [1] 44

You can index GIFs as you would with a vector. For example, img[12] returns the 12th frame of the GIF:

You can, of course, put more than one frame index in the square brackets. For example, img[44:1] will run the GIF in reverse (this can also be achieved with rev(img)):

This is a little more elaborate:

img[c(1:44, rep(c(rep(44, times = 5), 43:30, 
                  rep(30, times = 5), 31:43), 
                times = 2))]

Slowing down the dunk action:

img[c(1:30, rep(31:44, each = 3))]

We can replace a single frame with a different image too:

logo <- image_read("https://jeroen.github.io/images/Rlogo.png") %>%
  image_resize("480x266!")
img[25] <- logo
img

I don’t know if there is a clean way to insert the R logo as the 25th frame and push the original 25-44th frames down one frame (that would be a neat functionality to have). The below is a workaround but it feels inelegant:

img <- img[c(1:25, 25:44)]
img[25] <- logo

To leave a comment for the author, please follow the link and comment on their blog: R – Statistical Odds & Ends.

R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.