Как убрать каждый второй кадр из анимированного GIF?

22

У меня есть папка с видео, которую я хочу преобразовать в анимированные GIF-файлы. ffmpeg / avconv плохо справляется с работой напрямую, поэтому вместо этого я конвертирую видео в gif, сначала выводя каждый кадр в формате png, а затем конвертируя обратно в gif, используя imagemagick. Проблема в том, что это приводит к большому GIF с точки зрения размера файла. Чтобы решить эту проблему, я хочу «удалить» каждый второй или n-й кадр из GIF, либо пропуская каждый файл изображения при преобразовании в GIF, либо удаляя кадры из GIF. Как я могу сделать это в Ubuntu (13.04), используя imagemagick или другую утилиту командной строки?

hellocatfood
источник

Ответы:

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:

введите описание изображения здесь

И вот результат после запуска через скрипт:

введите описание изображения здесь

Этот сценарий, конечно, не пуленепробиваемый, но он должен привести вас в правильном направлении.

Johnb
источник
Обратите внимание, что ваш цикл удаления может быть упрощен до всего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"он сделает это за один вызов.
Ильмари Каронен,
Я на самом деле не знаю, как запустить этот скрипт из командной строки. Я попытался сохранить его как файл gifdrop.sh и запустить его в соответствии с инструкциями по использованию (./gifdrop.sh in.gif out.gif) для gif с именем in.gif, и он сказал неизвестную команду gifdrop
mheavers
@mheavers ты сделал файл исполняемым? chmod +x gifdrop.sh
JohnB
1
Лучше работает на macOS: github.com/colindean/hejmo/blob/master/scripts/… - моя версия, использующая perl вместо grep, так что она работает на macOS, где GNU grep не установлен по умолчанию. Также обрабатывает пробелы в именах файлов.
Колин Дин
27

Вот более простое решение с использованием gifsicle, чем сценарий JohnB:

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

Эта команда должна работать в большинстве оболочек Unix; Я проверял это в bash. Замените input.gifи output.gifна имена входных и выходных файлов, и 99на количество кадров в вашей анимации. (Можно использовать большее число, но Gifsicle будет жаловаться на это.)

Некоторые заметки:

  • -UКоммутатор будет объединить кадры во входной анимации с предыдущими, так что каждая из кадров стоит отдельно и не зависит ни в каких других. Вы действительно хотите сделать это, прежде чем делать что-либо с анимацией, иначе вы можете получить грязные результаты. (Если ваша входная анимация уже неоптимизирована, gifsicle может напечатать предупреждение об этом, но это также совершенно безвредно.)

  • И наоборот, -O2коммутатор повторно оптимизирует выходную анимацию, чтобы минимизировать размер файла. С образцом анимации JohnB, он уменьшает размер вывода на 27%.

  • Команда seqпросто выводит последовательность чисел от 0 до 99, считая с шагом 2. Она -f "#%g"заставляет печатать #перед каждым числом, что позволяет gifsicle понимать его как выбор кадра вместо имени файла. Функция backticks ( `) вокруг команды seq приводит к тому, что ее вывод включается в качестве параметров в командную строку gifsicle.

Если вы не хотите, чтобы изображение ускорялось, вы можете использовать, gifsicle -I input.gifчтобы получить текущую задержку кадра, умножить ее на 2 и использовать gifsicle -d ${delay} ....

Илмари Каронен
источник
Красиво сделано! Если вы действительно хотите, вы можете использовать grep из моего скрипта, чтобы точно указать количество кадров (и сделать одного бегемота из команды). Или, может быть, есть более простой способ вернуть количество кадров в анимированном GIF?
JohnB
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
11

ПРИМЕЧАНИЕ . Этот ответ был опубликован до того, как появилось требование командной строки / открытого исходного кода, но я оставляю его, поскольку он может помочь кому-то еще в будущем.


Использование Photoshop

Это не решение с открытым исходным кодом или командная строка, но вы можете сделать это с помощью Photoshop:

ФайлИмпортВидеокадры в слои ...

Импортировать видео

" Limit To Every __ Frames " поможет вам

Johnb
источник
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 = define_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.07 с, это означает, что вы должны поместить опцию -d14 (7 мс * 2) в эту строку в process.cmd: gifsicle -b -U -d14 input.gif, после редактирования сохраните process.cmd

затем отредактируйте test.bat и измените значение переменной 166 из этой строки, чтобы оно соответствовало количеству кадров анимации: for / L %% i IN (1,2,166) DO echo "# %% i" >> input.bat, после редактировать сохранить test.bat ...

затем запустите process.cmd и обрезанная анимация с каждым нечетным кадром будет обработана в файле input.gif

PS Преимущество этого метода также в том, что у вас есть полный контроль над тем, что вы хотите удалить из GIF (каждый второй кадр (1,2166) или каждый третий (1,3,166)) и т. Д. Просто измените среднее число в в пакетном режиме, но имейте в виду, что если вы укажете (1,3166), вам следует соответственно изменить -d14 (опция задержки) из process.cmd, чтобы отразить изменение (7 мсек * 3/2 = 10), поэтому вместо (7 мсек * 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"

И вспомогательный readme файл 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
Марко Рибар
источник