รูปขนาดย่อที่มีความหมายสำหรับวิดีโอโดยใช้ FFmpeg


80

FFmpeg สามารถจับภาพจากวิดีโอที่สามารถใช้เป็นภาพขนาดย่อเพื่อแสดงวิดีโอ วิธีที่พบมากที่สุดของการทำที่ถูกจับในFFmpeg วิกิพีเดีย

แต่ฉันไม่ต้องการเลือกเฟรมสุ่มในบางช่วงเวลา ฉันพบตัวเลือกบางตัวที่ใช้ตัวกรองบน ​​FFmpeg เพื่อจับการเปลี่ยนแปลงของฉาก:

ตัวกรองthumbnailพยายามค้นหาเฟรมตัวแทนมากที่สุดในวิดีโอ:

ffmpeg -i input.mp4 -vf  "thumbnail,scale=640:360" -frames:v 1 thumb.png

และคำสั่งต่อไปนี้เลือกเฉพาะเฟรมที่มีการเปลี่ยนแปลงมากกว่า 40% เมื่อเทียบกับก่อนหน้า (และอาจจะเป็นการเปลี่ยนฉาก) และสร้างลำดับ 5 PNG

ffmpeg -i input.mp4 -vf  "select=gt(scene\,0.4),scale=640:360" -frames:v 5 thumb%03d.png

เครดิตข้อมูลสำหรับคำสั่งข้างต้นเพื่อFabio Sonnati ภาพที่สองดูดีขึ้นเพราะฉันสามารถรับภาพและเลือกที่ดีที่สุดได้ ฉันลองแล้วมันก็สร้างภาพเดียวกัน 5 ครั้ง

การตรวจสอบเพิ่มเติมบางอย่างทำให้ฉันไปที่:

ffmpeg -i input.mp4 -vf "select=gt(scene\,0.5)" -frames:v 5 -vsync vfr  out%02d.png

-vsync vfrให้แน่ใจว่าคุณได้รับภาพที่แตกต่าง นี่ยังคงเลือกเฟรมแรกของวิดีโอเสมอส่วนใหญ่เฟรมแรกคือเครดิต / โลโก้และไม่มีความหมายดังนั้นฉันจึงเพิ่ม-ss3 เพื่อละทิ้ง 3 วินาทีแรกของวิดีโอ

คำสั่งสุดท้ายของฉันดูเหมือนว่า:

ffmpeg -ss 3 -i input.mp4 -vf "select=gt(scene\,0.5)" -frames:v 5 -vsync vfr out%02d.jpg

นี่คือสิ่งที่ดีที่สุดที่ฉันสามารถทำได้ ฉันสังเกตว่าตั้งแต่ฉันเลือกวิดีโอเพียง 5 วิดีโอพวกเขาส่วนใหญ่มาจากจุดเริ่มต้นของวิดีโอและอาจพลาดฉากสำคัญที่เกิดขึ้นในภายหลังในวิดีโอ

ฉันต้องการที่จะเลือกสมองของคุณสำหรับตัวเลือกที่ดีกว่าอื่น ๆ


ตัวอย่างคำสั่งที่ดี FWIW ฉันไม่พบปัญหาใด ๆ กับภาพ JPEG ที่สร้างจาก FFmpeg ใน OS X (10.8, FFmpeg 1.1 และต่ำกว่า) คำสั่งที่สองถึงครั้งสุดท้ายของคุณทำงานได้ดีสำหรับฉัน - และสุดท้าย - และไม่มีผลลัพธ์เหล่านี้ในไฟล์ JPG เปล่า ฉันไม่ได้รวบรวมกับlibopenjpeg.. ไม่แน่ใจว่าจะสร้างความแตกต่าง
slhck

ขอบคุณ slhck แก้ไขคำถามด้วยรายละเอียดการกำหนดค่า / รุ่น ffmpeg ฉันไม่ได้อัปเกรดเป็น 1.1 ในเครื่องนี้ ฉันจะทำเช่นนั้นและดูว่ามันเปลี่ยนผลลัพธ์ใด ๆ
d33pika

1
ดังนั้นคุณอยู่บน Ubuntu หรือ คุณสามารถลองรุ่น Git Master ล่าสุดจากสแตติกประกอบหรือคอมไพล์ด้วยตัวคุณเองและทำงานอีกครั้งได้หรือไม่? หรือล่าสุดมั่นคง ฉันเพิ่งตรวจสอบมันใช้โปรแกรมเปลี่ยนmjpegไฟล์สำหรับฉันเช่นกันและฉันก็ตรวจสอบjpegoptimและexiv2ทั้งสองอย่างนี้ทำงานได้ดีสำหรับฉันด้วยผลลัพธ์ JPG ทั้งหมดจากคำสั่งตัวอย่างของคุณ
slhck

1
ฉันอัปเดตแล้วและใช้งานได้ทันที! ฉันเดารุ่นก่อนหน้านี้มีข้อบกพร่องบางอย่าง
d33pika

คุณสามารถไปข้างหน้าและโพสต์เวอร์ชั่นใหม่โดยเฉพาะอย่างยิ่งลิงค์ไปยังรายการเปลี่ยนแปลงที่แสดงข้อผิดพลาดที่คุณพบและแก้ไขด้วยเวอร์ชันใหม่ในภายหลังได้หรือไม่
Lizz

คำตอบ:


29

วิธีการเกี่ยวกับการมองหาเฟรมแรก> 40% -change ภายในแต่ละช่วงเวลา 5 ช่วงเวลาที่ช่วงเวลาคือ 1, 2, 3, 4 และ 5% ของวิดีโอ

คุณสามารถแบ่งออกเป็น 6 ช่วงเวลาโดยไม่สนใจอันดับที่หนึ่งเพื่อหลีกเลี่ยงเครดิต

ในทางปฏิบัตินี่หมายถึงการตั้งค่า fps ให้เป็นจำนวนที่ต่ำในขณะที่ใช้การตรวจสอบการเปลี่ยนแปลงฉากของคุณและการโต้เถียงของคุณในการโยนวิดีโอบิตแรก

...สิ่งที่ต้องการ:

ffmpeg -ss 3 -i input.mp4 -vf "select=gt(scene\,0.4)" -frames:v 5 -vsync vfr -vf fps=fps=1/600 out%02d.jpg

1
รับภาพขาวดำอย่างสมบูรณ์ฉันจะหลีกเลี่ยงได้อย่างไร
d33pika

1
มีตัวกรองเพื่อตรวจสอบเฟรมสีดำและลำดับของพวกเขา ( ffmpeg.org/ffmpeg-filters.html#blackframeหรือffmpeg.org/ffmpeg-filters.html#blackdetect ) คุณทำให้คุณไม่สามารถทำงานอย่างใดอย่างหนึ่งในการเติบโตแบบหนึ่งเที่ยวบิน แต่คุณควรจะสามารถแยกเฟรมสีดำ (ขั้นตอนแยกต่างหาก) และแยกภาพขนาดย่อจากวิดีโอที่ได้
น.

5
สำหรับกรอบสีขาวตอนนี้มันซับซ้อน แต่ก็ดูเหมือนว่ามีวิธี: 1. ตัดกรอบสีดำออก 2. คัดค้าน (กลายเป็นสีขาวดำ) 3. ตัดกรอบสีขาวออก 4. คัดค้านอีกครั้ง 5. แยกภาพขนาดย่อ (หากคุณจัดการเพื่อแยกกรอบสีดำหรือสีขาวโดยเฉพาะในหนึ่งบรรทัดคุณสามารถโพสต์กลับมาที่นี่ได้หรือไม่ฉันสามารถเพิ่มลงในคำตอบสำหรับผู้อ่านในอนาคต ... หรือจริง ๆ แล้วคุณสามารถสร้างคำถามและคำตอบใหม่ . มันแน่นอนฉันจะ upvote มัน).
AM

3
เพื่อหลีกเลี่ยงภาพที่น่าเบื่อเช่นภาพขาวดำธรรมดา: สร้างภาพขนาดย่อมากกว่าที่คุณต้องการบีบอัดภาพด้วย jpeg และเลือกภาพที่มีขนาดไฟล์ใหญ่ขึ้น วิธีนี้ใช้งานได้ดีอย่างน่าประหลาดใจเพื่อให้ได้ภาพขนาดย่อที่เหมาะสม
Sam Watkins

2
Unable to find a suitable output format for 'fps=fps=1/600'คำสั่งนี้ไม่ได้ทำงานผมได้ข้อผิดพลาด วิธีแก้ไขคือเพิ่ม-vfก่อนอาร์กิวเมนต์นั้น (ดูstackoverflow.com/questions/28519403/ffmpeg-command-issue )
John Wiseman

7

การกำหนดความหมายนั้นยาก แต่ถ้าคุณต้องการทำให้ภาพขนาดย่อของ N ครอบคลุมไฟล์วิดีโอทั้งหมดอย่างมีประสิทธิภาพนี่คือสิ่งที่ฉันใช้เพื่อสร้างภาพขนาดย่อในการผลิตด้วยเนื้อหาที่ผู้ใช้อัปโหลด

หลอกรหัส

for X in 1..N
  T = integer( (X - 0.5) * D / N )  
  run `ffmpeg -ss <T> -i <movie>
              -vf select="eq(pict_type\,I)" -vframes 1 image<X>.jpg`

ที่ไหน:

  • D - ระยะเวลาวิดีโออ่านได้ffmpeg -i <movie>อย่างเดียวหรือffprobeมีตัวเขียนเอาต์พุต JSON ที่ดี btw
  • N - จำนวนภาพขนาดย่อทั้งหมดที่คุณต้องการ
  • X - หมายเลขภาพย่อจาก 1 ถึง N
  • T - เวลาจุดสำหรับ tumbnail

เพียงแค่ข้างต้นเขียนคีย์เฟรมกลางของแต่ละพาร์ติชันของภาพยนตร์ เช่นถ้าภาพยนตร์มีความยาว 300 วินาทีและคุณต้องการภาพขนาดย่อ 3 ภาพก็จะใช้กรอบหนึ่งเฟรมหลังจาก 50s, 150s และ 250s สำหรับภาพขนาดย่อ 5 ภาพจะเป็น 30s, 90s, 150s, 210s, 270s คุณสามารถปรับ N ได้ตามระยะเวลาภาพยนตร์ D เช่นเช่นภาพยนตร์ 5 นาทีจะมีภาพขนาดย่อ 3 ภาพ แต่เกิน 1 ชั่วโมงจะมีภาพขนาดย่อ 20 ภาพ

ประสิทธิภาพ

การเรียกffmpegใช้คำสั่งด้านบนแต่ละครั้งใช้เวลาเพียงเสี้ยววินาที (!) สำหรับ ~ 1GB H.264 นั่นเป็นเพราะมันกระโดดไปที่<time>ตำแหน่ง (ใจ-ssก่อน-i) และใช้เฟรมหลักแรกซึ่งเป็น JPEG ที่สมบูรณ์ ไม่เสียเวลาในการเรนเดอร์ภาพยนตร์ให้ตรงกับเวลาที่แน่นอน

การโพสต์

คุณสามารถผสมข้างต้นกับscaleหรือวิธีการปรับขนาดอื่น ๆ นอกจากนี้คุณยังสามารถลบเฟรมสีทึบหรือพยายามที่จะผสมกับฟิลเตอร์อื่น ๆ thumbnailเช่น


2
ว้าวที่จะย้าย-ss Nไปก่อนหน้า-iนี้เป็นเคล็ดลับที่น่าตื่นตาตื่นใจ ขอขอบคุณ!
apinstein

2

ฉันเคยทำสิ่งที่คล้ายกัน แต่ฉันส่งออกทุกเฟรมของวิดีโอ (ใน 1 fps) และเปรียบเทียบพวกเขากับโปรแกรมอรรถประโยชน์ perl ฉันพบที่คำนวณความแตกต่างระหว่างภาพ ฉันเปรียบเทียบแต่ละภาพกับภาพย่อก่อนหน้านี้และถ้ามันแตกต่างจากภาพขนาดย่อทั้งหมดฉันเพิ่มลงในคอลเลกชันภาพขนาดย่อ ข้อได้เปรียบที่นี่คือถ้าวิดีโอของคุณย้ายจากฉาก A ไป B และพวกเขากลับไปที่ A, ffmpeg จะส่งออก 2 เฟรมของ A


คุณใช้ปัจจัยอะไรในการเปรียบเทียบภาพ 2 ภาพ
d33pika

น่าเสียดายที่ฉันจำไม่ได้นานมาแล้ว คุณต้องตัดสินใจก่อนว่าจะเปรียบเทียบวิธีการใช้งานอย่างไรจากนั้นทำการทดสอบเพื่อค้นหาปัจจัยที่ถูกต้อง สิ่งนี้ใช้เวลาไม่นาน
Eran Ben-Natan

ฉันแค่คิดออกมาดังที่นี่ แต่นี่ไม่ใช่ตัวเลือกที่แย่กว่านี้หรือ เมื่อคุณเปรียบเทียบภาพที่ส่งออก 2 ภาพจากวิดีโอคุณได้สูญเสียข้อมูลบางส่วนไปแล้ว ฉันหมายถึงมันง่ายกว่าที่จะคำนวณความคล้ายคลึงกันจากข้อมูลตัวแปลงสัญญาณมากกว่าจากภาพ 2 ภาพใช่ไหม? เมื่อเร็ว ๆ นี้ฉันได้ดูอัลกอริธึม / ไลบรารีบางอย่างเพื่อเปรียบเทียบรูปภาพและพวกมันใช้งานไม่ได้อย่างที่ควรจะเป็น
ซามูเอล

ด้วย ffmpeg คุณสามารถแยกเฟรมได้โดยไม่สูญเสียคุณภาพโดยใช้แฟล็ก same_quality หากคุณใช้ข้อมูลตัวแปลงสัญญาณคุณต้องตรวจสอบว่าคุณไม่ได้รับ Iframes อย่างไรก็ตามยูทิลิตี้ Perl นั้นใช้งานได้ดีสำหรับฉันและสามารถกำหนดค่าได้มาก ดูที่นี่: search.cpan.org/~avif/Image-Compare-0.3/Compare.pm
Eran Ben-Natan

2

ลองสิ่งนี้

 ffmpeg -i input.mp4 -vf fps= no_of_thumbs_req/total_video_time out%d.png

การใช้คำสั่งนี้ฉันสามารถสร้างรูปขนาดย่อที่ต้องการซึ่งเป็นตัวแทนของวิดีโอทั้งหมด


สูตรที่ถูกต้องfpsจะ(no_of_frames_req * fps_of_vid) / total_video_framesใช่ไหม
flolilo

ฉันกำลังมองหาวิธีแก้ปัญหาตรงข้าม: เลือกเฟรมเพิ่มเติมจากช่วงเวลาที่กล้องมีเสถียรภาพมากขึ้นและไม่เคลื่อนไหว? (ที่ความแตกต่างระหว่างเฟรมต่อเนื่องน้อยกว่าไม่สูงกว่า) มีวิธีทำเช่นนั้นหรือไม่?
Tina J

1

นี่คือสิ่งที่ฉันทำเพื่อสร้างภาพขนาดย่อเป็นระยะเพื่อสตรีม m3u8 สดเพื่อใช้เป็นโปสเตอร์ ฉันพบว่าทำงาน ffmpeg อย่างต่อเนื่องเพียงเพื่อสร้างรูปขนาดย่อกินซีพียูของฉันทั้งหมดดังนั้นฉันจึงเรียกใช้ cronjob ทุก ๆ 60 วินาทีที่สร้างรูปขนาดย่อทั้งหมดสำหรับกระแสของฉัน

#!/usr/bin/env bash

## this is slow but gives better thumbnails (takes about 1+ minutes for 20 files)
#-vf thumbnail,scale=640:360 -frames:v 1 poster.png

## this is faster but thumbnails are random (takes about 8 seconds for 20 files)
#-vf scale=640:360 -frames:v 1 poster.png
cd ~/path/to/streams

find . -type f \
  -name "*.m3u8" \
  -execdir sh -c 'ffmpeg -y -i "$0" -vf scale=640:360 -frames:v 1 "poster.png"' \
  {} \;

หากคุณต้องทำบ่อยกว่า 60 วินาที (ข้อ จำกัด ของ cronjob) คุณสามารถwhileวนซ้ำในสคริปต์ของคุณและมันจะทำงานตลอดไป เพียงเพิ่ม a sleep 30เพื่อเปลี่ยนความถี่เป็น 30 วินาที ฉันไม่แนะนำให้ทำเช่นนี้เพราะมีวิดีโอจำนวนมากเนื่องจากการเล่นครั้งก่อนอาจไม่สมบูรณ์ก่อนที่วิดีโอถัดไปจะเริ่ม

นึกคิดกับ cronjob ฉันแค่เรียกใช้ทุก ๆ 5 นาที

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