Як видалити кожен другий кадр з анімованого gif?


22

У мене папка, повна відео, яку я хочу перетворити в анімовані gif-файли. ffmpeg / avconv робить погану роботу безпосередньо, тому я замість цього конвертую відео у gif, спочатку виводячи кожен кадр у вигляді png, а потім перетворюючи назад у gif за допомогою Imagemagick. Проблема полягає в тому, що це призводить до великого gif у розмірі файлу. Щоб вирішити це, я хочу "скинути" кожен другий або n-й кадр з gif, або пропустивши кожен файл зображення при переході в gif, або видаливши кадри з gif. Як я можу це зробити на Ubuntu (13.04) за допомогою Imagemagick або іншої утиліти командного рядка?

Відповіді:


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"буде робити за один дзвінок.
Ільмарі Каронен

Я фактично не знаю, як запустити цей скрипт з командного рядка. Я спробував зберегти його як файл 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; Я перевірив це в баші. Замініть input.gifі output.gifназви вхідних, і вихідних файлів, і 99на кількість кадрів у вашій анімації. (Добре використовувати більшу кількість, але gifsicle скаржиться на це.)

Деякі примітки:

  • The -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

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:

ФайлІмпортВідеорамки на шари ...

Імпорт відео

" Обмежитись до кожного __ кадрів " зробить трюк для вас


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 = speci_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,216) DO echo "# %% i" >> input.bat, після редагувати зберегти test.bat ...

тоді запустіть process.cmd і обрізану анімацію з кожним непарним кадром буде оброблено у файл input.gif

PS Перевага цього методу полягає також у тому, що ви маєте повний контроль над тим, що ви хочете видалити з gif (кожен другий кадр (1,216) або кожен третій (1,316)), і так далі просто змініть середнє число в пакетний рядок, але майте на увазі, що якщо ви вкажете (1,316), вам слід відповідно змінити -d14 (варіант затримки) з process.cmd, щоб відобразити зміни (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"

І файл довідкового файлу read.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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.