Извлекайте Y-канал каждого I-кадра из фильма MPEG4 максимально без потерь

633
Goat-Anti-Rabbit

Я работаю над экспериментом по отслеживанию видео и застрял с видео, которое сильно сжато с помощью кодека MPEG4 DivX 5x / 6x. Я довольно плохо знаком с форматами изображений, кодеками и сжатием, но, думаю, я понял, что застрял с этим качеством, если не нарушу второй закон термодинамики.

Теперь для отслеживания моих насекомых (да, это то, что я делаю), меня интересуют только I кадры (частота кадров достаточно высока), и меня не интересуют цветовые каналы U и V, поскольку они имеют только одно значение для каждого блока и, следовательно, не дает мне разрешение, которое я хочу. Это Y-канал, который содержит всю интересующую меня информацию. Я сам написал свой трекер, и он не может анализировать видео, поэтому ему нужна папка с кадрами.

Теперь мой вопрос: как я могу извлечь все I-кадры в изображения в оттенках серого (только Y-канал) БЕЗ какой-либо дальнейшей потери качества? Я работаю в Ubuntu 14.04 и предпочитаю использовать ffmpeg или imageJ, так как они уже присутствуют в моем конвейере. Где я сейчас нахожусь:

Я думаю, я понял, что каждый второй кадр - это I-кадр, но я не уверен в этом. Я использовал:

ffprobe -show_frames movie.avi | grep -A2 "video" | grep "key_frame"  output:  key_frame=1 key_frame=0 key_frame=1 key_frame=0 key_frame=1 key_frame=0 key_frame=1 key_frame=0 key_frame=1 key_frame=0  -- this goes on for exactly the number of frames, as this bit of code tells me:  ffprobe -show_frames movie.avi | grep -A2 "video" | grep -c "key") 13369 

Теперь я подумал, как выяснить, как извлечь каждый кадр:

ffmpeg -i movie.avi -vf '[in]select=eq(pict_type\,I)[out]' /picture%d.jpg 

Но, похоже, вернул мне все кадры.

ls *jpg | wc -l 133370 

Что я делаю неправильно? Вот что выводит ffmpeg:

ffmpeg version N-77455-g4707497 Copyright (c) 2000-2015 the FFmpeg developers built with gcc 4.8 (Ubuntu 4.8.4-2ubuntu1~14.04) configuration: --extra-libs=-ldl --prefix=/opt/ffmpeg --mandir=/usr/share/man --enable-avresample --disable-debug --enable-nonfree --enable-gpl --enable-version3 --enable-libopencore-amrnb --enable-libopencore-amrwb --disable-decoder=amrnb --disable-decoder=amrwb --enable-libpulse --enable-libdcadec --enable-libfreetype --enable-libx264 --enable-libx265 --enable-libfdk-aac --enable-libvorbis --enable-libmp3lame --enable-libopus --enable-libvpx --enable-libspeex --enable-libass --enable-avisynth --enable-libsoxr --enable-libxvid --enable-libvo-aacenc --enable-libvidstab libavutil 55. 11.100 / 55. 11.100 libavcodec 57. 20.100 / 57. 20.100 libavformat 57. 20.100 / 57. 20.100 libavdevice 57. 0.100 / 57. 0.100 libavfilter 6. 21.101 / 6. 21.101 libavresample 3. 0. 0 / 3. 0. 0 libswscale 4. 0.100 / 4. 0.100 libswresample 2. 0.101 / 2. 0.101 libpostproc 54. 0.100 / 54. 0.100  Guessed Channel Layout for Input Stream #0.1 : stereo Input #0, avi, from 'movie.avi': Duration: 00:08:54.76, start: 0.000000, bitrate: 3006 kb/s Stream #0:0: Video: mpeg4 (Simple Profile) (DX50 / 0x30355844), yuv420p, 720x576 [SAR 16:15 DAR 4:3], 1462 kb/s, 25 fps, 25 tbr, 25 tbn, 25 tbc Stream #0:1: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 48000 Hz, 2 channels, s16, 1536 kb/s [swscaler @ 0x3c2e920] deprecated pixel format used, make sure you did set range correctly Output #0, image2, to './picture%d.jpg': Metadata: encoder : Lavf57.20.100 Stream #0:0: Video: mjpeg, yuvj420p(pc), 720x576 [SAR 16:15 DAR 4:3], q=2-31, 200 kb/s, 25 fps, 25 tbn, 25 tbc Metadata: encoder : Lavc57.20.100 mjpeg Side data: unknown side data type 10 (24 bytes)  Stream mapping: Stream #0:0 -> #0:0 (mpeg4 (native) -> mjpeg (native)) Press [q] to stop, [?] for help  frame=13370 fps=506 q=24.8 Lsize=N/A time=00:08:54.80 bitrate=N/A dup=6685 drop=0 speed=20.2x  video:157591kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown 

Итак, пара вопросов:

  • Что я делаю неправильно? Почему он возвращает мне все кадры?
  • Будет ли JPEG привести к дальнейшим потерям? Или это такое же сжатие, как и внутрикадровое в mpeg4? Должен ли я использовать TIFF вместо этого?
  • Как мне извлечь только Y-канал?
  • Это нормально, я получаю I-кадр каждый второй кадр? Я немного читал в кодировке MPEG4, и кажется, что в качестве ссылки используются не целые кадры, а скорее блоки? Я тогда извлекаю все кадры, которые содержат такие блоки? Есть ли более высокий уровень с «реальными» целыми системами отсчета?
  • Я думаю, что нет способа восстановить больше качества?

Большое, большое спасибо за вашу помощь!

С наилучшими пожеланиями,

Рик Вердонк

1

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

4
Gyan

ffmpeg неявно использует частоту кадров источника, если явно не указано иное. Если количество кадров, подаваемых декодером / фильтром, отличается от этой скорости, то кадры дублируются или отбрасываются для достижения этого. Это можно исправить, создав новые временные метки для каждого выбранного кадра или указав частоту кадров, которая соответствует частоте I-кадров в 1 секунду видео. Безопаснее сделать первым.

Вы можете использовать TIFF или PNG или BMP вместо JPEG, чтобы избежать дальнейшего сжатия. Не уверены, одинаковы ли схемы прогнозирования для кодеков JPEG и MPEG.

I-кадр каждый второй кадр необычен для кодека MPEG-4, но вы сказали, что он был плохо закодирован. Кто-то установил либо GOP, т. Е. Интервал ключевого кадра, равный 2, либо очень низкий порог смены сцены, вероятно, первый.

В итоге, используйте

ffmpeg -i movie.avi -vf "select=eq(pict_type\,I),setpts=N/25/TB" -pix_fmt gray /picture%d.png 

отредактированный

Для прямого извлечения компонента Y используйте

ffmpeg -i movie.avi -vf "select=eq(pict_type\,I),setpts=N/25/TB,extractplanes=y" -pix_fmt gray /picture%d.png 
Выглядит хорошо. Знаете ли вы, если `-pix_fmt grey` напрямую соответствует компоненту Y ввода? slhck 8 лет назад 0
Я так и думал, но, кажется, применен какой-то фильтр - расширение диапазона, похоже. Добавлена ​​прямая команда подъема. Gyan 8 лет назад 0
Привет, Малвя, спасибо за помощь. Кажется, это работает, но я получаю вывод в моем терминале, который немного беспокоит меня. Выглядит это так: `Длительность в прошлом 0.999992 слишком велика Последнее сообщение повторено 30 раз Длительность в прошлом 0.999992 слишком великаN / A время = 00: 00: 11.36 битрейт = Н / Д скорость = 22.7x Последнее сообщение повторяется 33 раза Длительность в прошлом 0.999992 слишком великаN / Время = 00: 00: 23,48 битрейт = N / A скорость = 23,5x `Повторяется около 20 раз. Goat-Anti-Rabbit 8 лет назад 0
Игнорируй это. Не имеет значения в выводе. Gyan 8 лет назад 0

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