Значимые миниатюры для видео с использованием FFmpeg

59280
d33pika

FFmpeg может захватывать изображения из видео, которые можно использовать в качестве эскизов для представления видео. Наиболее распространенные способы сделать это описаны в FFmpeg Wiki .

Но я не хочу выбирать случайные кадры через определенные промежутки времени. Я нашел несколько вариантов использования фильтров в 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 видео, все они в основном с начала видео и могут упускать важные сцены, которые происходят позже в видео

Я хотел бы выбрать ваши мозги для любых других лучших вариантов.

71
Хорошие примеры команд. FWIW, я не столкнулся с какими-либо проблемами с изображениями JPEG, созданными FFmpeg на OS X (10.8, FFmpeg 1.1 и ниже). Ваша вторая до последней команды отлично работает - как и последняя - и ни один из этих результатов не приводит к пустым файлам JPG. Я скомпилировал с `libopenjpeg` .. не уверен, что это имеет значение. slhck 11 лет назад 0
Спасибо, slhck. Отредактировал вопрос с подробностями конфигурации / версии ffmpeg. Я не обновился до 1.1 на этой машине. Я сделаю это и посмотрю, изменит ли это какие-либо результаты. d33pika 11 лет назад 0
Так ты на Ubuntu? Можете ли вы попробовать последнюю версию Git Master из [статической сборки] (http://ffmpeg.org/download.html) или скомпилировать себя и запустить снова? Или последняя стабильная. Я только что проверил, он также использует для меня кодер `mjpeg`, и я также проверил` jpegoptim` и `exiv2`, оба из которых отлично работают для меня со всеми результатами JPG из ваших примеров команд. slhck 11 лет назад 1
Я обновился, и теперь это работает! Я думаю, в предыдущей версии были некоторые ошибки. d33pika 11 лет назад 1
Можете ли вы опубликовать решение - новую версию, желательно со ссылкой на журнал изменений, показывающий ошибку, с которой вы столкнулись, и впоследствии исправленную в новой версии? Lizz 11 лет назад 0
Привет @Lizz, те же команды выше возвращали пустые изображения в более старой версии FFmpeg. Нет, я на последних версиях и все команды работают! d33pika 11 лет назад 0
Мой подход состоит в том, чтобы генерировать, возможно, дюжину миниатюр jpeg в разное время и выбирать тот, который имеет наибольший размер файла. Самый большой файл имеет тенденцию быть более «сложным» и интересным, он редко будет размытым изображением и никогда не будет скучным изображением, таким как простая черная рамка. Этот подход не может быть идеальным для вас, но, возможно, вы можете использовать его вместе с другими методами. Sam Watkins 8 лет назад 0
Это отличные команды, но есть ли еще способ снизить качество? Мне нравятся размеры, но его по-прежнему 400 КБ для загрузки. Может быть, что-то размером 100 КБ было бы хорошо. chovy 8 лет назад 0
Я ищу противоположное решение: выбрать больше кадров из периодов, когда камера более стабильна и не движется? (где разница между последовательными кадрами меньше, а не выше). Есть способ сделать это? Tina J 5 лет назад 0

5 ответов на вопрос

23
A.M.

How about looking for, ideally, the first >40%-change frame within each of 5 time spans, where the time spans are the 1st, 2nd, 3rd, 4th, and 5th 20% of the video.

You could also split it into 6 time spans and disregard the 1st one to avoid credits.

In practice, this would mean setting the fps to a low number while applying your scene change check and your argument to throw out the first bit of the video.

...something like:

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 
Да, это помогает в выборе миниатюр из разных разделов видео. Спасибо! d33pika 10 лет назад 0
Получаются полностью черные или белые изображения. Как их избежать? d33pika 10 лет назад 1
Существуют фильтры для обнаружения черных рамок и их последовательности (http://www.ffmpeg.org/ffmpeg-filters.html#blackframe или http://www.ffmpeg.org/ffmpeg-filters.html#blackdetect). Вы не сможете использовать ни одну из них в своей растущей однострочнике, но вы определенно должны быть в состоянии вырезать черные рамки (отдельный шаг) и извлечь миниатюры из полученного видео. A.M. 10 лет назад 0
Что касается белых рамок, то теперь все становится сложнее, но все равно выглядит, что есть способ: 1. вырезать черные рамки 2. отменить (белые превращаются в черные) 3. убрать белые рамки 4. отменить снова 5. извлечь миниатюры (Если вам удастся удалить черные или белые рамки, особенно в одну строку, вы можете разместить их здесь? Я могу добавить их в ответ для будущих читателей ... ... или на самом деле вы можете создать новый вопрос и ответ это. Я определенно приветствовал бы это.) A.M. 10 лет назад 5
Можно ли будет снимать кадры на несколько секунд после начала каждой выбранной сцены? Liam 10 лет назад 0
Чтобы избежать скучных изображений, таких как черно-белое изображение, создайте больше миниатюр, чем нужно, сожмите их с помощью JPEG и выберите изображения с большим размером файла. Это работает на удивление хорошо само по себе, чтобы получить приличные эскизы. Sam Watkins 8 лет назад 3
@ SamWatkins, это отличная идея! 8 лет назад 0
Эта команда не сработала, я получил сообщение об ошибке «Невозможно найти подходящий формат вывода для« fps = fps = 1/600 ». Решение состоит в том, чтобы добавить `-vf` перед этим аргументом (см. Http://stackoverflow.com/questions/28519403/ffmpeg-command-issue) John Wiseman 8 лет назад 2
Я вижу, что кто-то отредактировал мой ответ, чтобы добавить этот кусочек к моему первоначальному удару. Это должно работать так, как написано в ответе сейчас. A.M. 6 лет назад 0
Вы знаете способ, которым я мог бы также иметь секунды в выходном имени файла, которое представляет количество секунд, прошедших в видео? Я также спросил это на SO: https://stackoverflow.com/questions/51007328/get-the-second-on-which-the-thumbnail-was-generated Suhail Gupta 5 лет назад 0
Я ищу противоположное решение: выбрать больше кадров из периодов, когда камера более стабильна и не движется? (где разница между последовательными кадрами меньше, а не выше). Есть способ сделать это? Tina J 5 лет назад 0
6
gertas

Defining meaningful is hard but if you want to make N thumbnails efficiently spanning whole video file this is what I use to generate thumbnails on production with user uploaded content.

Pseudo-code

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` 

Where:

  • D - video duration read from ffmpeg -i <movie> alone or ffprobe which has nice JSON output writer btw
  • N - total number of thumbnails you want
  • X - thumbnail number, from 1 to N
  • T - time point for tumbnail

Simply the above writes down center key-frame of each partition of the movie. E.g. if movie is 300s long and you want 3 thumbnails then it takes one key frame after 50s, 150s and 250s. For 5 thumbnails it would be 30s, 90s, 150s, 210s, 270s. You can adjust N depending on movie duration D, that e.g. 5 minute movie will have 3 thumbnails but over 1 hour will have 20 thumbnails.

Performance

Each invocation of above ffmpeg command takes a fraction of second (!) for ~1GB H.264. That is because it instantly jumps to <time> position (mind -ss before -i) and takes first key frame which is practically complete JPEG. There is no time wasted for rendering the movie to match exact time position.

Post-processing

You can mix above with scale or any other resize method. You can also remove solid color frames or try to mix it with other filters like thumbnail.

wow, передвигающий `-ss N` до` -i`, - удивительный совет. благодарю вас! apinstein 8 лет назад 2
2
Eran Ben-Natan

I once did something similar, but I exported all frames of the video (in 1 fps) and compared them with a perl utility I found which computes the difference between images. I compared each frame to previous thumbnails, and if it was different from all thumbnails, I added it to the thumbnails collection. The advantage here is that if your video moves from scene A to B and them returns to A, ffmpeg will export 2 frames of A.

Какие факторы вы использовали для сравнения 2 изображений? d33pika 11 лет назад 0
К сожалению, я не помню, это было довольно давно. Вам нужно сначала решить, какой метод сравнения использовать, а затем выполнить несколько тестов, чтобы найти правильный коэффициент. Это не должно занять много времени. Eran Ben-Natan 11 лет назад 0
Я просто думаю здесь вслух, но разве это не хуже? Когда вы сравниваете 2 экспортированных изображения из видео, вы уже потеряли некоторую информацию из него. Я имею в виду, что проще вычислить сходство по информации кодека, чем по 2 рисункам, не так ли? Недавно я посмотрел некоторые алгоритмы / библиотеки для сравнения изображений, и они не работают так, как того требуют. Samuel 10 лет назад 0
Что ж, с помощью ffmpeg вы можете извлекать кадры без потери качества, используя флаг same_quality. Если вы используете информацию о кодеках, вам нужно убедиться, что вы не просто получаете Iframes. В любом случае, эта утилита perl работала для меня просто отлично, и ее можно было легко настроить. Смотрите здесь: http://search.cpan.org/~avif/Image-Compare-0.3/Compare.pm Eran Ben-Natan 10 лет назад 0
2
LostPuppy

Попробуй это

 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`? flolilolilo 6 лет назад 0
Я ищу противоположное решение: выбрать больше кадров из периодов, когда камера более стабильна и не движется? (где разница между последовательными кадрами меньше, а не выше). Есть способ сделать это? Tina J 5 лет назад 0
1
chovy

Here's what I do to generate a periodic thumbnail for live m3u8 streams to use as a poster. I found running a continuous ffmpeg task just to generate thumbnails eats up all my CPU, so instead I run a cronjob every 60 seconds that generates all the thumbnails for my streams.

#!/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"' \ {} \; 

If you need to do more frequently than 60 seconds (limitation of cronjob), then you can do a while loop in your script and it'll execute forever. Just add a sleep 30 to change the frequency to 30 seconds. I don't recommend doing this with large number of videos though, as the previous run may not complete before the next one starts.

Ideally with cronjob I just run it every 5 minutes.

Похожие вопросы