FFmpeg kullanan bir Video için anlamlı küçük resimler


72

FFmpeg, videoyu temsil etmek için küçük resimler olarak kullanılabilecek videolardan görüntüler alabilir. Bunu yapmanın en yaygın yolları FFmpeg Wiki .

Ancak, bazı aralıklarla rasgele kareler seçmek istemiyorum. Sahne değişikliklerini yakalamak için FFmpeg'deki filtreleri kullanarak bazı seçenekler buldum:

Filtre thumbnail videodaki en temsili çerçeveleri bulmaya çalışır:

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

ve aşağıdaki komut yalnızca öncekine kıyasla değişikliklerin% 40'ından fazlasına sahip kareleri seçer (ve muhtemelen sahne değişiklikleridir) ve 5 PNG dizisi oluşturur.

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

Yukarıdaki komutlar için bilgi kredisi Fabio Sonnati . İkincisi n görüntüleri alıp en iyisini seçebildiğim için daha iyi görünüyordu. Denedim ve aynı görüntüyü 5 kez üretti.

Biraz daha araştırma beni yönlendirdi:

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

-vsync vfr Farklı görüntüler elde etmenizi sağlar. Bu, yine de her zaman videonun ilk karesini seçer, çoğu durumda ilk kare krediler / logodur ve anlamlı değildir, bu yüzden bir -ss Videonun ilk 3 saniyesini atmak için 3.

Son emrim şöyle gözüküyor:

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

Yapabileceğim en iyisiydi. Yalnızca 5 video seçtiğimden beri, hepsinin çoğunlukla videonun başlangıcından geldiğini ve videonun ilerleyen bölümlerinde meydana gelen önemli sahneleri kaçırabileceğini fark ettim.

Diğer daha iyi seçenekler için beynini seçmek istiyorum.


Güzel komut örnekleri. FWIW, OS X'te FFmpeg tarafından oluşturulan JPEG resimlerle herhangi bir sorun yaşamadım (10.8, FFmpeg 1.1 ve altı). En son ikinci komutunuz benim için iyi çalışıyor - sonuncusu da aynı - bu sonuçların hiçbiri boş JPG dosyalarında değil. İle derledim libopenjpeg.. bunun bir fark yaratıp yaratmadığından emin değilim.
slhck

Sağol slhck. Soruyu ffmpeg config / version details ile düzenledi. Bu makinede 1.1'e yükseltme yapmadım. Bunu yapacağım ve sonuçları değiştirip değiştirmeyeceğini göreceğim.
d33pika

1
Demek Ubuntu'dasın? En son Git Master versiyonunu deneyebilir misiniz? statik yapı veya kendinizi derleyip tekrar çalıştırmak Ya da en son kararlı. Ben sadece kontrol ettim, kullanır mjpeg benim için kodlayıcı ve ben de kontrol jpegoptim ve exiv2Her ikisi de benim için iyi çalışıyor, örnek komutlarınızdaki tüm JPG sonuçları.
slhck

1
Güncelledim ve şimdi çalışıyor! Sanırım önceki sürümde bazı hatalar vardı.
d33pika

Yeni versiyonda, tercihen karşılaştığınız ve ardından yeni versiyon ile düzelttiğim hatayı gösteren changelog bağlantısıyla devam edip yayınlayabilir misiniz?
Lizz

Yanıtlar:


24

İdeal olarak, zaman aralıklarının videonun 1., 2., 3., 4. ve 5.% 20'si olduğu 5 zaman diliminin her birinde ilk>% 40 değişim çerçevesini aramaya ne dersiniz?

Ayrıca, 6 zaman dilimine ayırabilir ve kredilerden kaçınmak için birinciyi ihmal edebilirsiniz.

Uygulamada, bu, sahne değişikliği kontrolünüzü ve videonun ilk bitini atmak için argümanınızı uygularken, fps'yi düşük bir sayıya ayarlamak anlamına gelir.

...gibi bir şey:

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

Evet, bu, Videonun farklı bölümlerinden küçük resimlerin toplanmasına yardımcı olur. Teşekkürler!
d33pika

1
Tamamen siyah veya beyaz görüntüler alındı. Bunları nasıl önleyebilirim?
d33pika

5
Beyaz karelere gelince, şimdi oldukça karmaşık bir hal alıyor, ancak yine de bir yol var gibi görünüyor: 1. siyah kareleri çıkarın 2. olumsuzlayın (beyaz siyaha döner) 3. beyaz kareleri çıkarın 4. tekrar olumsuzlayın (Siyah veya beyaz kareleri özellikle bir satırda çıkarmayı başarırsanız, buraya geri gönderebilir misiniz? Gelecekteki okuyucular için cevaba ekleyebilirim. ... ya da aslında yeni bir soru ve cevap oluşturabilirsiniz. Kesinlikle.
A.M.

3
Düz siyah beyaz gibi sıkıcı resimlerden kaçınmak için: ihtiyacınız olandan daha küçük resimler oluşturun, bunları jpeg ile sıkıştırın ve daha büyük dosya boyutuna sahip görüntüleri seçin. Bu, küçük resimleri almak için şaşırtıcı derecede iyi çalışır.
Sam Watkins

2
Bu komut işe yaramadı, bir hata aldım Unable to find a suitable output format for 'fps=fps=1/600'. Çözüm eklemektir -vf bu argümandan önce (bkz. stackoverflow.com/questions/28519403/ffmpeg-command-issue )
John Wiseman

6

tanımlanması anlamlı zordur, ancak N küçük resimlerin tamamını tüm video dosyasını kapsayan verimli bir şekilde büyütmek istiyorsanız, kullanıcı tarafından yüklenen içerikle üretimde küçük resimler oluşturmak için kullandığım şey budur.

Sözde kod

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`

Nerede:

  • D - videodan okuma süresi ffmpeg -i <movie> yalnız ya da ffprobe güzel JSON çıktı yazar btw olan
  • N - istediğiniz küçük resim sayısı
  • X - 1 - N arasında küçük resim numarası
  • T - küçük resim için zaman noktası

Basitçe yukarıdaki, filmin her bölümünün merkez anahtar karesini yazar. Örneğin. Film 300s uzunluğundaysa ve 3 küçük resim istiyorsanız, 50s, 150s ve 250s sonra bir anahtar kare alır. 5 küçük resim için 30, 90, 150, 210, 270. Film süresi D'ye bağlı olarak N'yi ayarlayabilirsiniz; 5 dakikalık filmin 3 küçük resmi olacak, ancak 1 saatin üzerinde 20 küçük resmi olacak.

performans

Yukarıdaki her başvuru ffmpeg komut ~ 1GB H.264 için ikinci (!) bir kısmını alır. Çünkü anında atlar <time> pozisyon (zihin -ss önce -i ) ve JPEG olarak pratik olan ilk ana kareyi alır. Filmi tam zaman konumuyla eşleştirmek için boşa harcanan zaman yoktur.

Rötuş

İle karıştırıp yukarıda scale veya başka herhangi bir yeniden boyutlandırma yöntemi. Ayrıca düz renkli çerçeveleri kaldırabilir veya diğer filtrelerle karıştırmayı deneyebilirsiniz. thumbnail.


2
vay hareketli -ss N önceye -i inanılmaz bir ipucu. teşekkür ederim!
apinstein

2

Bir zamanlar benzer bir şey yaptım ama videonun tüm karelerini (1 fps cinsinden) dışa aktardım ve bunları görüntüler arasındaki farkı hesaplayan bir perl yardımcı programı ile karşılaştırdım. Her kareyi önceki küçük resimlerle karşılaştırdım ve bütün küçük resimlerden farklıysa, küçük resimler koleksiyonuna ekledim. Buradaki avantaj, videonuz sahne A'dan B'ye geçip A'ya dönerse, ffmpeg 2 A karesini dışa aktarır.


2 görüntüyü karşılaştırmak için hangi faktörleri kullandınız?
d33pika

Ne yazık ki hatırlamıyorum, çok uzun zaman önceydi. Önce hangi karşılaştırma yönteminin kullanılacağına karar vermeniz ve ardından doğru faktörü bulmak için bazı testler yapmanız gerekir. Bu uzun sürmemeli.
Eran Ben-Natan

Burada yüksek sesle düşünüyorum ama bu daha kötü seçenek değil mi? Videodan verilen 2 görüntüyü karşılaştırdığınızda, ondan bazı bilgileri zaten kaybettiniz. Kodek bilgisinden benzerliği hesaplamak 2 resimden daha kolay, değil mi? Son zamanlarda görüntüleri karşılaştırmak için bazı algoritmalara / kütüphanelere baktım ve istenildiği kadar iyi çalışmadılar.
Samuel

Peki, ffmpeg ile aynı_kaliteli bayrağını kullanarak kareleri kalite kaybı olmadan çıkarabilirsiniz. Kodek bilgisini kullanırsanız, sadece Iframe'leri almadığınızı kontrol etmeniz gerekir. Her neyse, bu Perl yardımcı programı benim için iyi çalıştı ve çok yapılandırılabilir. Buraya bak: search.cpan.org/~avif/Image-Compare-0.3/Compare.pm
Eran Ben-Natan

2

Bunu dene

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

Bu komutu kullanarak videonun tamamını temsil eden gerekli sayıda küçük resim oluşturabilirim.


İçin doğru formül olmaz mı fps olmak (no_of_frames_req * fps_of_vid) / total_video_frames?
flolilolilo

Karşıt bir çözüm arıyorum: kameranın daha sabit durduğu ve hareket etmediği dönemlerden daha fazla kare seç? (ardışık kareler arasındaki farkın daha az olduğu, daha yüksek olmadığı yerlerde). Bunu yapmanın bir yolu var mı?
Tina J

1

İşte poster olarak kullanmak üzere canlı m3u8 akışları için periyodik bir küçük resim oluşturmak için yaptığım şey. Sadece küçük resimler oluşturmak için sürekli bir ffmpeg görevi çalıştırırken tüm CPU'umu yiyordum, bu yüzden bunun yerine her 60 saniyede bir cronjob çalıştırıyorum, bu da akışlarım için tüm küçük resimleri oluşturur.

#!/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 saniyeden daha sık (cronjob sınırlaması) yapmanız gerekiyorsa, o zaman while betiğinde döngü ve sonsuza kadar yürütecektir. Sadece eklemek sleep 30 frekansı 30 saniyeye değiştirmek için Önceki video bir sonraki başlamadan önce tamamlanamayabilir, ancak bunu çok sayıda video ile yapmanız önerilmez.

İdeal olarak cronjob ile her 5 dakikada bir çalıştırıyorum.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.