Como remover cada segundo quadro de um gif animado?

22

Eu tenho uma pasta cheia de vídeos que quero converter em gifs animados. O ffmpeg / avconv faz um trabalho ruim ao fazê-lo diretamente, então, em vez disso, converto o vídeo em um gif, primeiro exibindo cada quadro como png e depois convertendo-o novamente em gif usando o imagemagick. O problema é que isso resulta em um grande gif em termos de tamanho do arquivo. Para resolver isso, quero "soltar" cada segundo ou enésimo quadro do gif, pulando todos os arquivos de imagem ao converter para um gif ou removendo os quadros de um gif. Como posso fazer isso no Ubuntu (13.04) usando o imagemagick ou algum outro utilitário de linha de comando?

hellocatfood
fonte

Respostas:

14

Usando um script bash

Para fazer isso na linha de comando, você pode usar um utilitário chamado Gifsicle . Não existe um método interno para excluir todos os outros quadros; portanto, você precisará sujar as mãos com alguns scripts.

Aqui está um script rápido que eu fiz para criar apenas um único 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

Testei-o com uma simples contagem regressiva GIF:

insira a descrição da imagem aqui

E aqui está o resultado depois de executá-lo através do script:

insira a descrição da imagem aqui

Obviamente, esse script não é à prova de balas, mas deve levá-lo na direção certa.

JohnB
fonte
Note-se que o seu ciclo eliminação pode ser simplificada para apenaslet i=0; while [[ $i -lt $(($numframes / 2)) ]]; do gifsicle $2 --delete "#$i" -o $2; let i=i+1; done
Ilmari Karonen
1
Na verdade, você não precisa de um loop: gifsicle "$1" --unoptimize $(seq -f "#%g" 0 2 $numframes) -O2 -o "$2"fará isso em uma chamada.
Ilmari Karonen
Na verdade, eu não sei como executar esse script na linha de comando. Tentei salvá-lo como arquivo gifdrop.sh e executá-lo conforme as instruções de uso (./gifdrop.sh in.gif out.gif) em um gif chamado in.gif e ele disse desconhecido comando gifdrop
mheavers
@mheavers você tornou o arquivo executável? chmod +x gifdrop.sh
JohnB
1
Funciona melhor no macOS: github.com/colindean/hejmo/blob/master/scripts/… - minha versão que usa perl em vez de grep para funcionar no macOS que não possui o GNU grep instalado por padrão. Além disso, lida com espaços nos nomes de arquivos.
Colin Dean
27

Aqui está uma solução mais simples usando gifsicle do que o roteiro de JohnB:

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

Este comando deve funcionar na maioria dos shells do Unix; Eu testei no bash. Substitua input.gife output.gifpelos nomes dos arquivos de entrada e saída e 99pelo número de quadros na sua animação. (Não há problema em usar um número maior, mas os gifs se queixam disso.)

Algumas notas:

  • A -Uopção mesclará os quadros na animação de entrada com os anteriores, de modo que cada quadro fique sozinho e não dependa de outros. Você realmente deseja fazer isso antes de fazer praticamente qualquer coisa com animações, caso contrário, provavelmente obterá resultados confusos. (Se sua animação de entrada já não estiver otimizada, o gifsicle pode imprimir um aviso sobre ela, mas isso também é totalmente inofensivo.)

  • Por outro lado, o -O2switch otimiza novamente a animação de saída para minimizar o tamanho do arquivo. Com a animação de amostra de JohnB, reduz o tamanho da saída em 27%.

  • O seqcomando apenas gera uma sequência de números de 0 a 99, contando as etapas de 2. O -f "#%g"faz imprimir um #antes de cada número, o que faz com que o gifsicle o entenda como uma seleção de quadro em vez de um nome de arquivo. Os backticks ( `) ao redor do comando seq fazem com que sua saída seja incluída como parâmetros na linha de comando do gifsicle.

Se você não quiser que o gif acelere, use gifsicle -I input.gifo atraso de quadro atual, multiplique-o por 2 e use-o gifsicle -d ${delay} ....

Ilmari Karonen
fonte
Bem feito! Se você realmente quisesse, poderia usar o grep do meu script para fornecer com precisão o número de quadros (e fazer um gigante de um comando). Ou talvez haja uma maneira mais simples de retornar o número de quadros em um GIF animado?
JohnB
3
Acabei fazendo um comando gigantesco, @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
No Windows 7 x64 com versão 1.71, eu tenho: useless unoptimization-related input option. Então eu fiz isso em duas etapas (de dentro do 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

NOTA : Esta resposta foi postada antes que houvesse um requisito de linha de comando / código aberto, mas estou deixando assim, pois isso pode ajudar outra pessoa no futuro


Usando o Photoshop

Esta não é uma solução de código aberto ou de linha de comando, mas você pode fazer isso com o Photoshop:

ArquivoimportaçãoVídeo Frames em camadas ...

Importar vídeo

" Limitar a todos os quadros __ " fará o truque para você

JohnB
fonte
0

Aqui está minha solução usando o processamento de script em lote ...

Primeiro copie o gif animado capturado e original para o arquivo input.gif e inicie o interpretador de comandos e digite:

gifsicle input.gif -I "# -1"> input.txt

consulte input.txt e veja qual é o tamanho da animação - quantos quadros ela contém ...

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

em seguida, edite-crie test.bat e altere o valor da variável len = especifique_length_number_from_input.txt e salve 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

finalmente inicie process1.bat e process2.bat e a animação cortada com cada quadro ímpar será processada no arquivo 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"
Marko Ribar
fonte
0

Eu acho que preciso de uma nova explicação mais sofisticada (o atraso de quadros também é uma coisa importante que deve ser considerada também) ... Para esse novo processo, você precisará baixar o JREPL.BAT neste link: http://www.dostips.com /forum/viewtopic.php?t=6044

Primeiro copie o gif capturado no arquivo input.gif e inicie o interpretador de comandos e digite:

gifsicle input.gif -I "# -1"> input.txt

olhe para input.txt e veja qual é o comprimento da animação - quantos quadros ele contém ... também olhe para o atraso do quadro e se é 0,07s significa que você deve colocar a opção -d14 (7msec * 2) nessa linha em process.cmd: gifsicle -b -U -d14 input.gif, após editar, salve process.cmd

edite test.bat e altere o valor da variável 166 dessa linha para corresponder ao número de quadros de animação: para / L %% i IN (1,2,166) DO echo "# %% i" >> input.bat, depois editar salvar test.bat ...

então inicie process.cmd e a animação cortada com todos os quadros ímpares será processada no arquivo input.gif

PS A vantagem desse método também é que você tem controle total do que deseja excluir do gif (a cada segundo quadro (1,2,166) ou a cada terceiro (1,3,166)), e assim por diante, basta alterar o número do meio em linha de lote, mas lembre-se de que, se você especificar (1,3,166), deverá alterar -d14 (opção de atraso) de process.cmd para refletir a alteração (7msec * 3/2 = 10), portanto, em vez de (7msec * 2 / 1 = 14), a opção de atraso deve ser -d10 ...

Outros arquivos (por exemplo, removendo cada segundo quadro): 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"

E o arquivo leia-me auxiliar 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
Marko Ribar
fonte