尽可能无损地从 MPEG4 电影中提取每个 I 帧的 Y 通道

尽可能无损地从 MPEG4 电影中提取每个 I 帧的 Y 通道

我正在进行视频跟踪实验,但遇到了使用 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

现在,我想我已经知道如何提取每个 I 帧了:

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

ffmpeg 隐式使用源的帧速率,除非另有明确指定。如果解码器/过滤器提供的帧数与该速率不同,则将复制或丢弃帧以达到该速率。可以通过为每个选定帧生成新的时间戳或指定与每秒视频 I 帧频率匹配的帧速率来解决此问题。第一种方法更安全。

您可以使用 TIFF 或 PNG 或 BMP 代替 JPEG 以避免进一步压缩。不确定 JPEG 和 MPEG 编解码器的预测方案是否相同。

对于 MPEG-4 编解码器来说,每隔一帧出现一个 I 帧是不常见的,但您确实说过这些编码很糟糕。有人设置了 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   

相关内容