用R制作gif动态图以及从gif中提取图片

浏览: 2009

作者:辉小宝同学

微信公众号:R语言和Python学堂

知乎:https://www.zhihu.com/people/zoro-3-92/posts

简书:https://www.jianshu.com/u/981ba7d6b4a6


熟悉R的朋友,肯定知道 animation包,它可将一系列用R绘制的静态图转化为各种格式的动图或视频(比如:gif, mp4, avi等格式)。事实上,它是通过R去调用一些图片或视频处理程序(比如:ImageMagick, GraphicsMagick, FFmpeg等)来实现这些功能的,因此如果要使用这些功能,相应外部程序也必须要安装。关于 animation包的详情可参考https://cran.r-project.org/web/packages/animation/

由于 animation包只能将R绘制的静态图转化为动图,它不能处理外部图片以及gif动态图。因此我将在这篇博客教大家如何用R从gif中提取图片以及如何将外部图片制作成gif动态图,我将以下面的gif动图为例:

1. 下载ImageMagick

ImageMagick是一款功能强大、稳定而且免费开源的图片处理工具集,可以用来读、写和处理超过200种不同格式的图片文件,详情可参考其官网https://www.imagemagick.org

这里我们也将通过R来调用ImageMagick来实现我们的功能。我们用的是ImageMagick的Windows portable版(便携版,也即免安装版),我将安装压缩包已上传至百度网盘(包括32位和64位系统的,解压就可以用,无需安装),你也可从官网下载https://www.imagemagick.org/script/download.php

2. 从gif动图中提取每帧图片

在ImageMagick中可通过命令行模式来实现这个功能,其一般命令为convert test.gif-coalesce result_d.png。下面通过R来调用这个命令,我将其封装成一个叫 gif2frames()的函数,其各参数的意义见函数内部的注释:

  1. gif2frames <- function(pathIn='',

  2.                       pathOut='',

  3.                       ImageMagick_path='',

  4.                       frameFormat='png',

  5.                       prefixFrame='/frame_d.'){

  6.  ##### arguments

  7.  # pathIn: gif文件所在路径

  8.  # pathOut: 图片保存路径

  9.  # ImageMagick_path: ImageMagick convert命令所在路径

  10.  # frameFormat: 图片保存的格式类型

  11.  # prefixFrame: 图片文件名的格式

  12.  ##### return

  13.  # None

  14.  if(!dir.exists(pathOut))  ##自动创建保存图片的文件夹

  15.    dir.create(pathOut)

  16.  command <- paste(ImageMagick_path, pathIn, '-coalesce', paste0(pathOut, prefixFrame, frameFormat))

  17.  #system('F:R_tutorials/gif/ImageMagick-7.0.8-64bit/convert test.gif -coalesce ./frames/frame_d.png')

  18.  system(command)  ##调用外部的ImageMagick程序

  19. }

从上面代码可知,最后我们通过R中的 system()函数来调用外部ImageMagick程序来实现所需功能。

来测试一下:

  1. pathIn <- 'test.gif'

  2. pathOut <- './frames/'

  3. ImageMagick_path <- './ImageMagick-7.0.8-64bit/convert'


  4. gif2frames(pathIn, pathOut, ImageMagick_path)

运行完上面代码后, test.gif动图中的每一帧都保存在 frames文件夹下,如下图:

用R提取gif中的每帧图片就算实现了,是不是很简单!!!

3. 制作gif

下面我将使用上一步提取到的图片(即 frames文件夹下的170帧图片)为例,来介绍如何制作gif,这可以看作为上一步的逆过程。我也将其封装成一个叫 frames2gif的函数:

  1. frames2gif <- function(pathIn='',

  2.                       pathOut='',

  3.                       ImageMagick_path='',

  4.                       resize_ratio=1,

  5.                       delay=40,

  6.                       frameFormat='png',

  7.                       everyFrame=1){

  8.  ##### arguments

  9.  # pathIn: 图片所在路径

  10.  # pathOut: 生成的gif所保存的路径

  11.  # ImageMagick_path: ImageMagick convert命令所在路径

  12.  # resize_ratio: 调节gif的尺寸,默认为1。如果为0.5,gif的长度和宽度将是图片尺寸的一半

  13.  # delay: 设置帧与帧之间的时间间隔,默认为40(表示0.4s)。如果为200,那么时间间隔即为2s

  14.  # frameFormat: 图片的格式

  15.  # everyFrame: 如果为3,只使用pathIn文件夹下的第1, 4, 7,10,13帧,.....图片来制作gif,默认使用所有图片

  16.  ##### return

  17.  # None


  18.  ## create temp dir to store frames used to create gif.

  19.  tempdir <- paste0(pathIn, '/temp')

  20.  dir.create(tempdir)

  21.  files <- list.files(pathIn, pattern=paste0('*.', frameFormat), recursive=FALSE, full.names=TRUE)

  22.  index <- seq(1, length(files), by=everyFrame)

  23.  file.copy(files[index], tempdir)

  24.  command <- paste(ImageMagick_path,

  25.                   '-resize', paste0(as.integer(100L*resize_ratio), '%'),

  26.                   '-delay', delay,

  27.                   paste0(tempdir,'/*.', frameFormat),

  28.                   pathOut)

  29.  #system('F:R_tutorials/gif/ImageMagick-7.0.8-64bit/convert -resize 90% -delay 40 *.png result.gif')

  30.  system(command)

  31.  ## delete temp dir

  32.  unlink(tempdir, recursive=TRUE, force=TRUE)

  33. }

来测试一下:

1. 设置 delay参数为 2(也即帧与帧之间的时间间隔为0.02s),使动画变得更快。

  1. pathIn <- './frames/'

  2. pathOut <- 'fast.gif'

  3. ImageMagick_path <- './ImageMagick-7.0.8-64bit/convert'


  4. frames2gif(pathIn, pathOut,

  5.           ImageMagick_path,

  6.           delay=2)

结果如下图:

2. 设置 resize_ratio参数为 0.5,使动画尺寸大小变为原来的一半。

  1. pathOut <- 'small.gif'


  2. frames2gif(pathIn, pathOut,

  3.           ImageMagick_path,

  4.           resize_ratio=0.5,

  5.           delay=4)

结果如下图:

3. 设置 everyFrame参数为 2,使动画的总帧数变为原来的1/2。

  1. pathOut <- 'small_frames.gif'


  2. frames2gif(pathIn, pathOut,

  3.           ImageMagick_path,

  4.           everyFrame=2,

  5.           delay=4)

结果如下图:

从上图可知,减少动画总帧数,其效果相当于缩短动画时间。

通过以上三个例子,我们知道如何使用 frames2gif()函数来制作gif动图了。

以上就是本文的全部内容,希望对大家的学习有所帮助。如果觉得文章不错,动手转发支持一下哦!

公众号后台回复关键字即可学习

回复 爬虫             爬虫三大案例实战  
回复 Python        1小时破冰入门

回复 数据挖掘      R语言入门及数据挖掘
回复 人工智能      三个月入门人工智能
回复 数据分析师   数据分析师成长之路 
回复 机器学习      机器学习的商业应用
回复 数据科学      数据科学实战
回复 常用算法      常用数据挖掘算法

推荐 0
本文由 R语言中文社区 创作,采用 知识共享署名-相同方式共享 3.0 中国大陆许可协议 进行许可。
转载、引用前需联系作者,并署名作者且注明文章出处。
本站文章版权归原作者及原出处所有 。内容为作者个人观点, 并不代表本站赞同其观点和对其真实性负责。本站是一个个人学习交流的平台,并不用于任何商业目的,如果有任何问题,请及时联系我们,我们将根据著作权人的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。

0 个评论

要回复文章请先登录注册