วิธีลบเฟรมที่สองออกจาก gif ที่เคลื่อนไหวได้อย่างไร


22

ฉันมีโฟลเดอร์ที่เต็มไปด้วยวิดีโอที่ฉันต้องการแปลงเป็น gif แบบเคลื่อนไหว ffmpeg / avconv ทำงานได้ไม่ดีในการทำโดยตรงดังนั้นฉันจึงแปลงวิดีโอเป็น gif โดยการแสดงผลแต่ละเฟรมเป็น png ก่อนจากนั้นแปลงกลับเป็น gif โดยใช้ imagemagick ปัญหาคือว่าสิ่งนี้ส่งผลให้ GIF ขนาดใหญ่ในแง่ของขนาดไฟล์ เพื่อแก้ปัญหานี้ฉันต้องการที่จะ "ลดลง" ทุกวินาทีหรือเฟรมที่ n จาก gif โดยการข้ามไฟล์ภาพทุกไฟล์เมื่อแปลงเป็น gif หรือโดยการลบเฟรมออกจาก gif ฉันจะทำสิ่งนี้บน Ubuntu (13.04) โดยใช้ imagemagick หรือโปรแกรมอรรถประโยชน์บรรทัดคำสั่งอื่นได้อย่างไร

คำตอบ:


14

ใช้สคริปต์ทุบตี

การทำเช่นนี้จากบรรทัดคำสั่งคุณสามารถใช้ยูทิลิตี้ที่เรียกว่า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"จะทำได้ในการโทรครั้งเดียว
Ilmari Karonen

ที่จริงฉันไม่รู้วิธีเรียกใช้สคริปต์นี้จากบรรทัดคำสั่ง ฉันพยายามบันทึกเป็นไฟล์ gifdrop.sh และเรียกใช้ตามคำแนะนำในการใช้งาน (./gifdrop.sh in.gif out.gif) บน gif ที่เรียกว่า in.gif และได้กล่าวคำสั่งที่ไม่รู้จัก gifdrop
mheavers

@mavers คุณสร้างไฟล์ที่ปฏิบัติการได้หรือไม่? 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 จะบ่นเกี่ยวกับมัน)

หมายเหตุบางส่วน:

  • -Uสวิทช์จะผสานเฟรมในการเคลื่อนไหวการป้อนข้อมูลกับคนที่ก่อนหน้านี้เพื่อให้แต่ละเฟรมยืนอยู่คนเดียวและไม่ได้ขึ้นอยู่ที่คนอื่น ๆ ใด ๆ คุณต้องการทำสิ่งนี้จริงๆก่อนที่จะทำอะไรกับอนิเมชันมิฉะนั้นคุณอาจได้ผลลัพธ์ที่ยุ่งเหยิง (หากภาพเคลื่อนไหวอินพุตของคุณไม่ได้เพิ่มประสิทธิภาพแล้ว gifsicle อาจพิมพ์คำเตือนเกี่ยวกับเรื่องนี้ แต่สิ่งนี้ก็ไม่เป็นอันตรายเช่นกัน)

  • ในทางกลับกัน-O2สวิตช์จะปรับเอนิเมชั่นเอาต์พุตใหม่เพื่อลดขนาดไฟล์ ด้วยแอนิเมชันตัวอย่างของ JohnB มันย่อขนาดเอาต์พุตลง 27%

  • seqคำสั่งเพียง outputs ลำดับของตัวเลข 0-99 ที่นับขึ้นมาในขั้นตอนของการ 2. -f "#%g"ทำให้พิมพ์#ก่อนที่แต่ละหมายเลขซึ่งทำให้ gifsicle เข้าใจว่ามันเป็นตัวเลือกกรอบแทนชื่อไฟล์ backticks ( `) รอบคำสั่ง seq ทำให้เอาต์พุตรวมเป็นพารามิเตอร์ในบรรทัดคำสั่ง gifsicle

หากคุณไม่ต้องการ GIF เพื่อเพิ่มความเร็วคุณสามารถใช้gifsicle -I input.gifเพื่อให้ได้ความล่าช้ากรอบปัจจุบันคูณด้วย 2 gifsicle -d ${delay} ...และการใช้งาน


ทำได้ดีมาก! หากคุณต้องการจริงๆคุณสามารถใช้ grep จากสคริปต์ของฉันเพื่อให้จำนวนเฟรมที่ถูกต้อง (และทำให้หนึ่ง behemoth ของคำสั่ง) หรืออาจจะมีวิธีที่ง่ายกว่าในการคืนจำนวนเฟรมใน GIF เคลื่อนไหว?
JohnB

3
ฉันสิ้นสุดการทำ behemoth ของคำสั่ง @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 = spec_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,2,166) DO echo "# %% i" >> input.bat หลังจาก แก้ไขบันทึก test.bat ...

จากนั้นเริ่มต้น process.cmd และภาพเคลื่อนไหวที่ครอบตัดด้วยเฟรมคี่ทั้งหมดจะถูกประมวลผลเป็นไฟล์ input.gif

PS ข้อดีของวิธีนี้คือคุณสามารถควบคุมสิ่งที่คุณต้องการลบจาก gif (ทุกเฟรมที่สอง (1,2,166) หรือทุก ๆ สาม (1,3,166)) และเปลี่ยนหมายเลขกลางใน บรรทัดแบทช์ แต่โปรดทราบว่าถ้าคุณระบุ (1,3,166) คุณควรเปลี่ยน -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 -

กระบวนการ 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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.