Bagaimana cara menghapus setiap bingkai kedua dari gif animasi?

22

Saya memiliki folder yang penuh dengan video yang ingin saya konversi menjadi gif animasi. ffmpeg / avconv melakukan pekerjaan yang buruk dengan melakukannya secara langsung, jadi saya alih-alih mengkonversi video ke gif dengan terlebih dahulu mengeluarkan setiap frame sebagai png dan kemudian mengonversi kembali ke gif menggunakan imagemagick. Masalahnya adalah ini menghasilkan gif besar dalam hal ukuran file. Untuk mengatasi ini saya ingin "menjatuhkan" setiap detik atau frame ke-n dari gif, baik dengan melewatkan setiap file gambar saat mengkonversi ke sebuah gif atau dengan menghapus frame dari sebuah gif. Bagaimana saya bisa melakukan ini di Ubuntu (13.04) menggunakan imagemagick atau utilitas baris perintah lainnya?

makanan hellocatfood
sumber

Jawaban:

14

Menggunakan skrip bash

Untuk melakukan ini dari baris perintah, Anda bisa menggunakan utilitas yang disebut Gifsicle . Tidak ada metode bawaan untuk menghapus setiap bingkai lainnya, jadi Anda harus membuat tangan Anda kotor dengan beberapa skrip.

Berikut ini skrip cepat yang saya buat hanya untuk satu 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

Saya mengujinya dengan hitungan mundur GIF sederhana:

masukkan deskripsi gambar di sini

Dan inilah hasilnya setelah menjalankannya melalui skrip:

masukkan deskripsi gambar di sini

Skrip ini tentu saja tidak anti peluru, tetapi harus mengarahkan Anda ke arah yang benar.

JohnB
sumber
Perhatikan bahwa loop penghapusan Anda dapat disederhanakan menjadi hanyalet i=0; while [[ $i -lt $(($numframes / 2)) ]]; do gifsicle $2 --delete "#$i" -o $2; let i=i+1; done
Ilmari Karonen
1
Bahkan, Anda tidak perlu loop sama sekali: gifsicle "$1" --unoptimize $(seq -f "#%g" 0 2 $numframes) -O2 -o "$2"akan melakukannya dalam satu panggilan.
Ilmari Karonen
Saya sebenarnya tidak tahu cara menjalankan skrip ini dari baris perintah. Saya mencoba untuk menyimpannya sebagai file gifdrop.sh dan menjalankannya seperti yang diperintahkan dalam penggunaan (./gifdrop.sh in.gif out.gif) pada gif bernama in.gif dan dikatakan perintah tidak dikenal gifdrop
mheavers
@ mheavers apakah Anda membuat file dapat dieksekusi? chmod +x gifdrop.sh
JohnB
1
Bekerja lebih baik di macOS: github.com/colindean/hejmo/blob/master/scripts/… - versi saya yang menggunakan perl bukan grep sehingga berfungsi pada macOS yang tidak memiliki grep GNU yang terinstal secara default. Juga, menangani spasi di nama file.
Colin Dean
27

Berikut ini solusi sederhana menggunakan gifsicle daripada skrip JohnB:

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

Perintah ini harus bekerja di sebagian besar shell Unix; Saya sudah mengujinya di bash. Ganti input.gifdan output.gifdengan nama file input dan output, dan 99dengan jumlah bingkai dalam animasi Anda. (Tidak apa-apa menggunakan nomor yang lebih besar, tetapi gifsicle akan mengeluh tentang hal itu.)

Beberapa catatan:

  • The -Uswitch akan menggabungkan frame dalam animasi masukan dengan yang sebelumnya, sehingga setiap frame berdiri sendiri dan tidak tergantung pada orang lain. Anda benar-benar ingin melakukan ini sebelum melakukan hampir semua hal dengan animasi, jika tidak Anda akan mendapatkan hasil yang berantakan. (Jika animasi input Anda sudah tidak dioptimalkan, gifsicle dapat mencetak peringatan tentang itu, tetapi ini juga sama sekali tidak berbahaya.)

  • Sebaliknya, -O2sakelar kembali mengoptimalkan animasi keluaran untuk meminimalkan ukuran file. Dengan sampel animasi JohnB, ukuran output menyusut sebesar 27%.

  • The seqperintah hanya output urutan angka dari 0 sampai 99, menghitung sampai di langkah 2. -f "#%g"merek itu mencetak #sebelum setiap nomor, yang membuatnya gifsicle memahaminya sebagai pilihan bingkai bukan nama file. Backticks ( `) di sekitar perintah seq menyebabkan outputnya dimasukkan sebagai parameter dalam baris perintah gifsicle.

Jika Anda tidak ingin gif untuk mempercepat, Anda dapat menggunakan gifsicle -I input.gifuntuk mendapatkan penundaan frame saat ini, kalikan dengan 2 dan gunakan gifsicle -d ${delay} ....

Ilmari Karonen
sumber
Bagus sekali! Jika Anda benar-benar ingin, Anda dapat menggunakan grep dari skrip saya untuk secara akurat memberikan jumlah frame (dan membuat satu raksasa dari sebuah perintah). Atau mungkin ada cara sederhana untuk mengembalikan jumlah frame dalam GIF animasi?
JohnB
3
Saya akhirnya membuat raksasa perintah, @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
Pada Windows 7 x64 dengan versi 1,71, saya punya: useless unoptimization-related input option. Jadi saya melakukannya dalam dua langkah (dari dalam 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

CATATAN : Jawaban ini telah diposting sebelum ada baris perintah / persyaratan sumber terbuka, tapi saya meninggalkannya karena dapat membantu orang lain di masa depan


Menggunakan Photoshop

Ini bukan solusi open source atau command line, tetapi Anda bisa melakukan ini dengan Photoshop:

FileImporBingkai Video ke Lapisan ...

Impor video

" Limit To Every __ Frames " akan melakukan trik untuk Anda

JohnB
sumber
0

Berikut ini solusi saya menggunakan pemrosesan skrip batch ...

Pertama-tama salin gif animasi asli yang ditangkap ke dalam file input.gif kemudian mulai juru bahasa perintah dan ketik:

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

lihat input.txt dan lihat berapa panjang animasi - berapa banyak frame di dalamnya ...

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

kemudian edit-buat test.bat dan ubah nilai variabel len = define_length_number_from_input.txt dan simpan 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

kemudian akhirnya mulai process1.bat dan process2.bat dan potong animasi dengan setiap frame aneh akan diproses menjadi file 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
sumber
0

Saya pikir saya perlu penjelasan baru yang lebih canggih (frame delay juga hal penting yang harus dipertimbangkan juga) ... Untuk proses baru ini Anda perlu mengunduh JREPL.BAT dari tautan ini: http://www.dostips.com /forum/viewtopic.php?t=6044

Pertama-tama salin gif yang ditangkap ke dalam file input.gif kemudian mulai juru bahasa perintah dan ketik:

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

lihat input.txt dan lihat berapa panjang animasi - berapa banyak frame yang dikandungnya ... lihat juga penundaan frame dan apakah 0,07 itu berarti Anda harus meletakkan opsi -d14 (7msec * 2) ke dalam baris ini di process.cmd: gifsicle -b -U -d14 input.gif, setelah mengedit save process.cmd

kemudian edit test.bat dan ubah nilai variabel 166 dari baris ini agar sesuai dengan jumlah frame animasi: untuk / L %% i IN (1,2,166) DO echo "# %% i" >> input.bat, setelah edit save test.bat ...

kemudian mulai process.cmd dan potong animasi dengan setiap frame aneh akan diproses menjadi file input.gif

NB Keuntungan dari metode ini adalah juga bahwa Anda memiliki kontrol penuh atas apa yang ingin Anda hapus dari gif (setiap frame kedua (1,2,166), atau setiap ketiga (1,3,166)), dan sebagainya, cukup ubah nomor tengah di garis bets, tetapi perlu diketahui bahwa jika Anda menentukan (1,3,166), Anda harus mengubah -d14 (opsi penundaan) dari process.cmd untuk mencerminkan perubahan (7msec * 3/2 = 10), jadi alih-alih (7 msec * 2 / 1 = 14), opsi untuk penundaan harus -d10 ...

File lain (misalnya menghapus setiap frame kedua): 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"

Dan file readme pembantu saya 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
sumber