Comment supprimer chaque seconde image d'un gif animé?

22

J'ai un dossier plein de vidéos que je veux convertir en gifs animés. ffmpeg / avconv fait un mauvais travail de le faire directement, donc je convertis plutôt la vidéo en gif en sortant d'abord chaque image au format png puis en les reconvertissant en gif en utilisant imagemagick. Le problème est que cela se traduit par un grand gif en termes de taille de fichier. Pour résoudre ce problème, je veux "supprimer" chaque seconde ou nième image du gif, soit en sautant chaque fichier image lors de la conversion en gif, soit en supprimant les images d'un gif. Comment puis-je faire cela sur Ubuntu (13.04) en utilisant imagemagick ou un autre utilitaire de ligne de commande?

hellocatfood
la source

Réponses:

14

Utiliser un script bash

Pour ce faire à partir de la ligne de commande, vous pouvez utiliser un utilitaire appelé Gifsicle . Il n'y a pas de méthode intégrée pour supprimer toutes les autres images, vous devrez donc vous salir les mains avec des scripts.

Voici un script rapide que j'ai fait pour ne faire qu'un seul 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

Je l'ai testé avec un simple GIF de compte à rebours:

entrez la description de l'image ici

Et voici le résultat après l'avoir exécuté à travers le script:

entrez la description de l'image ici

Ce script n'est bien sûr pas à l'épreuve des balles, mais il devrait vous conduire dans la bonne direction.

JohnB
la source
Notez que votre boucle de suppression peut être simplifiée simplementlet i=0; while [[ $i -lt $(($numframes / 2)) ]]; do gifsicle $2 --delete "#$i" -o $2; let i=i+1; done
Ilmari Karonen
1
En fait, vous n'avez pas du tout besoin d'une boucle: le gifsicle "$1" --unoptimize $(seq -f "#%g" 0 2 $numframes) -O2 -o "$2"fera en un seul appel.
Ilmari Karonen du
En fait, je ne sais pas comment exécuter ce script à partir de la ligne de commande. J'ai essayé de l'enregistrer en tant que fichier gifdrop.sh et de l'exécuter comme indiqué dans l'utilisation (./gifdrop.sh in.gif out.gif) sur un gif appelé in.gif et il a dit la commande inconnue gifdrop
mheavers
@mheavers avez-vous rendu le fichier exécutable? chmod +x gifdrop.sh
JohnB
1
Fonctionne mieux sur macOS: github.com/colindean/hejmo/blob/master/scripts/… - ma version qui utilise perl au lieu de grep pour qu'elle fonctionne sur macOS qui n'a pas GNU grep installé par défaut. Gère également les espaces dans les noms de fichiers.
Colin Dean
27

Voici une solution plus simple utilisant gifsicle que le script de JohnB:

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

Cette commande devrait fonctionner dans la plupart des shells Unix; Je l'ai testé en bash. Remplacez input.gifet output.gifpar les noms des fichiers d'entrée et de sortie, et 99par le nombre d'images dans votre animation. (C'est OK d'utiliser un plus grand nombre, mais gifsicle s'en plaindra.)

Quelques notes:

  • Le -Ucommutateur fusionnera les images de l'animation d'entrée avec les précédentes, afin que chaque image soit autonome et ne dépende d'aucune autre. Vous voulez vraiment le faire avant de faire à peu près n'importe quoi avec des animations, sinon vous risquez d'obtenir des résultats désordonnés. (Si votre animation d'entrée n'est pas encore optimisée, gifsicle peut afficher un avertissement à ce sujet, mais cela est également totalement inoffensif.)

  • Inversement, le -O2commutateur réoptimise l'animation de sortie pour minimiser la taille du fichier. Avec l'exemple d'animation de JohnB, il réduit la taille de sortie de 27%.

  • La seqcommande sort juste une séquence de nombres de 0 à 99, en comptant par étapes de 2. Le -f "#%g"fait imprimer un #avant chaque numéro, ce qui permet à gifsicle de le comprendre comme une sélection de trame au lieu d'un nom de fichier. Les backticks ( `) autour de la commande seq font que sa sortie est incluse en tant que paramètres dans la ligne de commande gifsicle.

Si vous ne voulez pas que le gif accélère, vous pouvez utiliser gifsicle -I input.gifpour obtenir le retard d'image actuel, le multiplier par 2 et utiliser gifsicle -d ${delay} ....

Ilmari Karonen
la source
Bien fait! Si vous le vouliez vraiment, vous pouvez utiliser le grep de mon script pour donner avec précision le nombre d'images (et faire un monstre d'une commande). Ou peut-être existe-t-il un moyen plus simple de renvoyer le nombre d'images dans un GIF animé?
JohnB
3
J'ai fini par faire un monstre d'une commande, @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
Sous Windows 7 x64 avec la version 1.71, je suis arrivé: useless unoptimization-related input option. Je l'ai donc fait en deux étapes (depuis 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

REMARQUE : Cette réponse a été publiée avant qu'il n'y ait une exigence de ligne de commande / open source, mais je la laisse car elle pourrait aider quelqu'un d'autre à l'avenir


Utilisation de Photoshop

Ce n'est pas une solution open source ou en ligne de commande, mais vous pouvez le faire avec Photoshop:

FichierImporterCadres vidéo dans les calques ...

Importer une vidéo

" Limit To Every __ Frames " fera l'affaire pour vous

JohnB
la source
0

Voici ma solution en utilisant le traitement par script batch ...

Copiez d'abord le gif animé capturé-original dans le fichier input.gif puis lancez l'interpréteur de commandes et tapez:

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

regardez input.txt et voyez quelle est la durée de l'animation - combien d'images elle contient ...

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

puis éditez-créez test.bat et changez la valeur de la variable len = specify_length_number_from_input.txt et enregistrez 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

puis démarrez enfin process1.bat et process2.bat et l'animation recadrée avec chaque image impaire sera traitée dans le fichier 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
la source
0

Je pense que j'ai besoin d'une nouvelle explication plus sophistiquée (le retard de trame est également une chose importante qui doit également être prise en compte) ... Pour ce nouveau processus, vous devrez télécharger JREPL.BAT à partir de ce lien: http://www.dostips.com /forum/viewtopic.php?t=6044

Copiez d'abord le gif capturé dans le fichier input.gif puis lancez l'interpréteur de commandes et tapez:

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

regardez dans input.txt et voyez quelle est la durée de l'animation - combien d'images il contient ... regardez également le retard de l'image et si ses 0,07 s cela signifie que vous devez mettre l'option -d14 (7 msec * 2) dans cette ligne dans process.cmd: gifsicle -b -U -d14 input.gif, après modification enregistrer process.cmd

puis éditez test.bat et changez la valeur de la variable 166 à partir de cette ligne pour qu'elle corresponde au nombre d'images d'animation: pour / L %% i IN (1,2,166) FAITES écho "# %% i" >> input.bat, après modifier enregistrer test.bat ...

puis démarrez process.cmd et l'animation recadrée avec chaque image impaire sera traitée dans le fichier input.gif

PS L'avantage de cette méthode est également que vous avez le contrôle total de ce que vous voulez supprimer du gif (chaque seconde trame (1,2,166), ou chaque troisième (1,3,166)), et ainsi de suite il suffit de changer le numéro du milieu dans ligne de traitement par lots, mais sachez que si vous spécifiez (1,3,166), vous devez en conséquence modifier -d14 (option de délai) de process.cmd pour refléter le changement (7 ms * 3/2 = 10), donc au lieu de (7 ms * 2 / 1 = 14), l'option de délai doit être -d10 ...

Autres fichiers (par exemple pour supprimer une trame sur deux): 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"

Et aidez le fichier 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
Marko Ribar
la source