如何从动画gif中删除每隔一帧?


22

我有一个充满视频的文件夹,我想将其转换为GIF动画。ffmpeg / avconv直接将其做为不好的工作,因此,我通过首先将每个帧输出为png,然后使用imagemagick转换回gif,将视频转换为gif。问题在于,就文件大小而言,这将导致较大的gif。为了解决这个问题,我想通过转换为gif时跳过每个图像文件或从gif中删除帧,来从gif中“掉落”第二或第n帧。如何在Ubuntu(13.04)上使用imagemagick或其他命令行实用程序执行此操作?

Answers:


14

使用bash脚本

要从命令行执行此操作,可以使用名为Gifsicle的实用程序。没有内置的方法可以删除所有其他框架,因此您需要动手编写一些脚本。

这是我制作的一个快速脚本,仅需一个GIF:

#!/bin/bash
# This script will take an animated GIF and delete every other frame
# Accepts two parameters: input file and output file
# Usage: ./<scriptfilename> input.gif output.gif

# Make a copy of the file
cp $1 $2

# Get the number of frames
numframes=`gifsicle $1 -I | grep -P "\d+ images" --only-matching | grep -P "\d+" --only-matching`

# Deletion
let i=0
while [[ $i -lt $numframes  ]]; do
    rem=$(( $i % 2 ))

    if [ $rem -eq 0 ]
    then
        gifsicle $2 --delete "#"$(($i/2)) -o $2 
    fi

    let i=i+1 
done

我用一个简单的倒计时GIF进行了测试:

在此处输入图片说明

这是通过脚本运行后的结果:

在此处输入图片说明

该脚本当然不是防弹的,但它可以引导您朝正确的方向前进。


请注意,您的删除循环可以简化为let i=0; while [[ $i -lt $(($numframes / 2)) ]]; do gifsicle $2 --delete "#$i" -o $2; let i=i+1; done
Ilmari Karonen

1
实际上,您根本不需要循环:gifsicle "$1" --unoptimize $(seq -f "#%g" 0 2 $numframes) -O2 -o "$2"只需一个调用即可完成循环。
Ilmari Karonen

我实际上不知道如何从命令行运行此脚本。我尝试将其保存为gifdrop.sh文件,并按照用法说明(./gifdrop.sh in.gif out.gif)在名为in.gif的gif上运行,并说未知命令gifdrop
mheavers

@mheavers使文件可执行吗?chmod +x gifdrop.sh
JohnB 2015年

1
在macOS上更好地工作:github.com/colindean/hejmo/blob/master/scripts/…-我的版本使用perl而不是grep,因此它可以在默认情况下未安装GNU grep的macOS上工作。另外,处理文件名中的空格。
Colin Dean

27

下面是使用一个简单的解决方案gifsicle比JohnB的脚本:

gifsicle -U input.gif `seq -f "#%g" 0 2 99` -O2 -o output.gif

该命令应该在大多数Unix shell中都可以使用。我已经在bash中对其进行了测试。用输入和输出文件名以及动画中的帧数替换input.gif和。(可以使用更大的数字,但是gifsicle会对此抱怨。)output.gif99

一些注意事项:

  • -U交换机将与前面的那些输入动画合并帧,使每帧代表单独的,并不依赖于任何人。您真的想在对动画进行几乎所有操作之前先执行此操作,否则您可能会得到混乱的结果。(如果您的输入动画尚未进行优化,则gifsicle可能会对此发出警告,但这完全是无害的。)

  • 相反,该-O2开关会重新优化输出动画以最小化文件大小。使用JohnB的示例动画,它可以将输出大小缩小27%。

  • seq命令仅输出一个从0到99的数字序列,以2为步长进行计数。-f "#%g"使该命令#在每个数字之前打印一个,这使gifsicle将其理解为帧选择而不是文件名。`seq命令周围的反引号()导致其输出作为参数包含在gifsicle命令行中。

如果您不希望gif加快速度,则可以使用gifsicle -I input.gif来获取当前的帧延迟,将其乘以2并使用gifsicle -d ${delay} ...


做得很好!如果您确实需要,可以使用脚本中的grep准确给出帧数(并制作一个命令的庞然大物)。还是有一种更简单的方法来返回动画GIF中的帧数?
JohnB 2013年

3
我最终作出命令的庞然大物,@JohnB -gifsicle input.gif `seq -f "#%g" 0 2 $(identify input.gif | tail -1 | cut -d "[" -f2 - | cut -d "]" -f1 -)` --unoptimize -O2 -o output.gif
Kasra Rahjerdi

在Windows 7 x64版本1.71上,我得到了:useless unoptimization-related input option。因此,我分两步(从Git Bash内部)进行了操作:1. gifsicle -U -o unoptimized.gif input.gif2.gifsicle unoptimized.gif `seq -f "#%g" 0 2 99` -O2 -o output.gif
feklee 2014年

11

注意此答案是在没有命令行/开源要求之前发布的,但我将其保留,因为它可能会在将来对其他人有所帮助


使用Photoshop

这不是开源或命令行解决方案,但是您可以使用Photoshop做到这一点:

文件导入视频帧到图层...

导入视频

限制每个__帧 ”将为您解决问题


0

这是我使用批处理脚本处理的解决方案...

首先将捕获的原始动画gif复制到input.gif文件中,然后启动命令解释器并键入:

gifsicle input.gif -I“#-1”> input.txt

查看input.txt,看看动画的长度是多少-它包含多少帧...

input.txt:

* input.gif 166 images
  logical screen 1366x768
  global color table [256]
  background 15
  loop forever
  + image #165 1x1 at 1365,767 transparent 15
    disposal asis delay 0.07s

然后编辑创建test.bat并更改变量len = specify_length_number_from_input.txt的值并保存test.bat ...

test.bat:

@echo off
set /A len=166
set /A i=1
set /A ii=0
:loop
if %i%==%len% goto :eof
if %ii%==0 (set /A ii=1) else (set /A ii=0)
set /A iii=%ii%*%i%
if %i%==%iii% echo gifsicle -b input.gif --delete "#1" --done
set /A i=%i%+1
goto :loop

然后最终启动process1.bat和process2.bat,并将每个奇数帧的裁剪后的动画处理到文件input.gif中。

process1.bat:

gifsicle -b -U input.gif
test.bat > input.bat

process2.bat:

call "input.bat"
gifsicle -b -O2 input.gif
erase "input.bat"

0

我认为我需要新的更复杂的解释(帧延迟也是也应考虑的重要问题)...对于此新过程,您需要从以下链接下载JREPL.BAT:http : //www.dostips.com /forum/viewtopic.php?t=6044

首先将捕获的gif复制到input.gif文件中,然后启动命令解释器并键入:

gifsicle input.gif -I“#-1”> input.txt

查看input.txt,看看动画的长度是多少-它包含多少帧...,还查看帧的延迟,如果其值为0.07s,则意味着您应该在此行中放入-d14选项(7msec * 2)在process.cmd中:gifsicle -b -U -d14 input.gif,编辑后保存process.cmd

然后编辑test.bat并从此行更改变量166的值以匹配动画的帧数:对于/ L %% i IN(1,2,166)DO echo“#%% i” >> input.bat,之后编辑保存test.bat ...

然后启动process.cmd,每个奇数帧的裁剪后的动画将被处理成文件input.gif

PS此方法的优点还在于,您可以完全控制要从gif中删除的内容(每第二帧(1,2,166)或每三帧(1,3,166)),依此类推,只需更改批处理行,但是请注意,如果您指定(1,3,166),则应从process.cmd中相应地更改-d14(延迟选项)以反映更改(7msec * 3/2 = 10),而不是(7msec * 2) / 1 = 14),延迟选项应为-d10 ...

其他文件(例如,每隔一帧删除一次):test.bat:

@echo off
echo gifsicle -b input.gif --delete>> input.bat
for /L %%i IN (1,2,166) DO echo  "#%%i">> input.bat
echo  --done>> input.bat
call jrepl.bat "\n" "" /x /m /f input.bat /o -

process.cmd:

gifsicle -b -U -d14 input.gif
call "test.bat"
call "input.bat"
gifsicle -b -O3 input.gif
erase "input.bat"

和帮助程序自述文件input.txt:

* input.gif 166 images
  logical screen 1366x768
  global color table [256]
  background 15
  loop forever
  + image #165 1x1 at 1365,767 transparent 15
    disposal asis delay 0.07s
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.