Змістовні мініатюри для відео за допомогою 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

Інформація за вищезазначені команди Фабіо Соннаті . Другий здався кращим, оскільки я міг отримати n зображень і вибрати найкраще. Я спробував це, і воно генерувало те саме зображення 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

Чи можете ви продовжити та опублікувати нову версію рішення, бажано, щоб посилання на журнал змін показало помилку, з якою ви стикалися, а згодом виправили нову версію?
Лізз

Відповіді:


29

Як щодо ідеального пошуку першого> 40% -кадрового кадру в межах кожного з 5-ти часових проміжків, де проміжки часу - це 1-й, 2-й, 3-й, 4-й та 5-й 20% відео.

Ви також можете розділити його на 6 часових проміжків і нехтувати першим, щоб уникнути кредитів.

На практиці це означатиме встановлення низької кількості кадрів у кадрі при застосуванні перевірки зміни сцени та вашого аргументу викинути перший біт відео.

...щось на зразок:

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 ). Ви не зможете перетворити жоден з них у свій зростаючий однолінійний, але ви, безумовно, повинні мати змогу викреслити чорні рамки (окремий крок) і витягти мініатюри з отриманого відео.
AM

5
Що стосується білих кадрів, то тепер це стає складним, але все одно виглядає, що існує спосіб: 1. викреслити чорні рамки 2. заперечити (білі перетворитись на чорні); (Якщо вам вдасться викреслити чорні або білі рамки, особливо в одному рядку, чи можете ви їх опублікувати тут? Я можу додати це до відповіді для майбутніх читачів. ... чи власне ви можете створити нове запитання та відповідь . це я точно upvote його).
AM

3
Щоб уникнути нудних зображень, таких як звичайні чорно-білі: генеруйте більше ескізів, ніж вам потрібно, стисніть їх jpeg та виберіть зображення з більшим розміром файлу. Це несподівано добре працює саме по собі, щоб отримати гідні ескізи.
Сем Уоткінс

2
Ця команда не спрацювала, я отримав помилку Unable to find a suitable output format for 'fps=fps=1/600'. Рішення полягає в тому, щоб додати -vfцей аргумент (див. Stackoverflow.com/questions/28519403/ffmpeg-command-issue )
Джон Вісман,

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 - часова точка мініатюри

Просто вище записано центральний кадр ключових кадрів кожного розділу фільму. Наприклад, якщо фільм триває 300, і ви хочете 3 ескізи, то він займає один ключовий кадр після 50-х, 150-х та 250-х. Для 5 мініатюр це було б 30-ті, 90-ті, 150-ті, 210-ті, 270-ті. Ви можете налаштувати N залежно від тривалості фільму D, наприклад, що 5-хвилинний фільм матиме 3 ескізи, але за 1 годину - 20 мініатюр.

Продуктивність

Кожне виклик вищезгаданої ffmpegкоманди займає частку секунди (!) Для ~ 1 Гб H.264. Це тому, що воно моментально стрибає на <time>позицію (розум -ssраніше -i) і приймає перший ключовий кадр, який практично є повним JPEG. Немає витраченого часу на візуалізацію фільму, щоб відповідати точній часовій позиції.

Подальша обробка

Ви можете змішати вище з scaleбудь-яким іншим способом зміни розміру. Ви також можете видалити суцільні кольорові рамки або спробувати змішати їх з іншими фільтрами thumbnail.


2
вау, переїзд -ss Nдо цього -i- дивовижна порада. спасибі!
Апінштейн

2

Я колись робив щось подібне, але експортував усі кадри відео (в 1 кадр в секунду) і порівняв їх з утилітою Perl, яку я виявив, яка обчислює різницю між зображеннями. Я порівнював кожен кадр з попередніми мініатюрами, і якщо він відрізнявся від усіх мініатюр, я додав його до колекції мініатюр. Перевага тут полягає в тому, що якщо ваше відео переміститься зі сцени A в B і вони повернуться до A, ffmpeg експортує 2 кадри A.


Які фактори використовували для порівняння двох зображень?
d33pika

На жаль, не пам'ятаю, це було досить давно. Спочатку потрібно визначити, який метод порівняння використовувати, а потім зробити кілька тестів, щоб знайти правильний коефіцієнт. Це не повинно зайняти багато часу.
Еран Бен-Натан

Я просто думаю вголос, але хіба це не гірший варіант? Якщо порівнювати 2 експортовані зображення з відео, ви вже втратили з нього деяку інформацію. Я маю на увазі, простіше обчислити подібність з інформацією про кодек, ніж це з 2 картинок, чи не так? Нещодавно я розглядав деякі алгоритми / бібліотеки для порівняння зображень, і вони працюють не так добре, як може знадобитися.
Самуїл

Ну, за допомогою ffmpeg ви можете витягти кадри без втрати якості, використовуючи прапор того ж_quality. Якщо ви використовуєте інформацію про кодек, вам потрібно переконатися, що ви просто не отримуєте Iframes. У всякому разі ця утиліта Perl працювала для мене чудово, і вона дуже настроюється. Подивіться тут: search.cpan.org/~avif/Image-Compare-0.3/Compare.pm
Еран Бен-Натан

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

Я шукаю протилежне рішення: вибрати більше кадрів з періодів, коли камера стабільніша і не рухається? (де різниця між послідовними кадрами менша, не більша). Чи є спосіб це зробити?
Тіна 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 хвилин.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.