如何使用PIL或yuv420格式的数据写入图像

时间:2018-08-15 07:01:20

标签: python-3.x ffmpeg python-imaging-library pixel yuv

我有一个yuv420p像素格式的视频。 最初,我尝试使用管道和像素格式(如rgb24)读取每个帧的字节。我用PIL制作图像。 但是,以rgb24格式读取的帧似乎失去了一点质量。

以下是读取具有rgb24像素格式的帧的命令:

    ffmpeg -y -i input.mp4 -vcodec rawvideo -pix_fmt rgb24 -an -r 25 -f rawvideo pipe:1
    frame_data = self.process.stdout.read(1920*1080*3)

然后我尝试以yuv420p像素格式阅读它。

    ffmpeg -y -i input.mp4 -vcodec rawvideo -pix_fmt yuv420p -an -r 25 -f rawvideo pipe:1
    frame_data = self.process.stdout.read(1920*1080*3/2)

一个单帧包含rgb24帧的一半字节。在1920 * 1080 yuv420p帧中为3110400字节。我把这些数据扔进了PIL:

    Image.frombytes('YCbCr', (1920, 1080), frame_data)

但是PIL会引发图像数据不足的错误。 我查找了PIL支持从字节写入的模式,它们都不是12位像素。 我还尝试将yuv数据转换为rgb数据,但是要花很长的时间才能处理,所以花了比以前更多的时间。

我做错什么了吗?有什么办法可以在没有任何变换的情况下用原始的yuv数据写入图像?

1 个答案:

答案 0 :(得分:1)

您的 YUV420p 是色度子采样和 “平面”。二次采样意味着 U 和 V 通道各是全分辨率 Y 通道宽度的一半和高度的一半。因此,它们每个都是正常大小的 1/4。所以,因为它是平面的,你实际上会收到:

  • 整个 Y 通道,然后是
  • 1/4 尺寸的 U 通道,其次是
  • 1/4 尺寸 V 形通道

这意味着。相对于 RGB 图像,您将有 1 个完整的通道和 2 个四分之一大小的通道,即 1.5 个通道,这是拥有 3 个完整 RGB 通道时的​​一半……这就是为什么它需要每像素 12 位而不是超过 24 位。

PIL 自然不支持子采样色度。因此,为了读取您的数据,您可以:

  • 将全分辨率 Y 通道读入 PIL L 模式图像
  • 将 h/2 x w/2 分辨率的 U 通道读入 PIL L 模式图像,并将大小调整为两倍
  • 将 h/2 x w/2 分辨率的 V 通道读入 PIL L 模式图像,并将大小调整为两倍

然后将这三个单通道图像合并为三通道图像。

我不清楚您为什么要使用 PIL。如果您只想将未经处理的原始 YUV420p 流写入磁盘,请让 ffmpeg 自行完成。