在视频处理中,将视频帧转为图像,再对图像处理后拼成视频,是非常常见的操作。在一些应用,我们还需要将图片单独保存,例如需要调用第三方接口处理图片,或者算法推理需要依赖原始帧。

通常, 我们使用ffmpeg将视频转为图片, 但在这个过程中 JPG 图片经常会出现色差问题。

JPG图片出现色差

视频帧转换对比图

以上是原视频,以及视频首帧转存为 PNG 和 JPG 的三个画面对比。可以看到,JPG的手部偏红, 出现了明显色差。

为何会有色差

视频转为图片命令

ffmpeg -i input.mp4 -frames:v 1 00001.jpg

大致执行了以下步骤 FFmpeg处理流程图

色差主要出现在图像编码环节,FFmpeg的JPG编码库libjpeg默认使用 BT.601 矩阵进行 RGB→YCbCr 转换。,也就是说:

  • 如果输入 YUV 是 BT.601,矩阵匹配,色彩准确。

  • 如果输入 YUV 是 BT.709/BT.2020,则矩阵不匹配,导致偏色。

目前大多数流行1080p以上的视频使用:

format=YUV420P, colorspace=BT709, color_range=tv

因此直接转 JPG 就容易出现偏色。

如何解决JPG色差问题

方案一:提前转换YUV色域

既然libjpeg默认使用 BT.601 矩阵,可以在编码前,将 YUV 数据强制转换为 BT.601

ffmpeg -i input.mp4 -vf "colorspace=all=bt601-6-625:iall=bt709,format=yuvj420p" -frames:v 1 1.jpg
  • bt601-6-625 表示使用 BT.601 矩阵(PAL 系列)。

  • iall=bt709 表示原视频是 BT.709,需要转换。

  • yuvj420p 是 JPEG 全范围 YUV420P 格式,保证色彩范围正确。

效果如下: 色域转换后效果对比

方案二: 使用其他图片格式

  • PNG, 无损压缩、支持透明通道、色彩还原准确, 但解码速度比JPEG慢3-10倍
  • WEBP, Google开发的一种现代图像格式,支持有损与无损压缩两种模式,同时支持透明通道和动画。解码效率介于 JPG 和 PNG 之间。无损模式通常比 PNG 小20%~30%.
  • JPEG2000:ISO/IEC 2000 年发布,采用小波变换压缩,支持有损/无损,高保真、色彩还原好,支持多分辨率编码。但编码解码速度较慢,文件体积较大。
  • NVJPEG2000:NVIDIA 提供的 GPU 加速 JPEG2000 编解码库,提高JPEG2000编解码性能。

下面是不同格式在4K图像下的性能及画面对比:

图片格式(4k) 编码速度(ms) 解码速度(ms) 图片体积(kb)
JPEG 27.76 52.47 571.4
PNG 647.78 200.94 3367.5
WEBP 758.44 75.30 254.7
JPEG2000 1018.06 540.71 2427.3
NVJPEG2000 1018.06 42.10 2427.3

不同图片格式色彩对比 可以看到 WEBP 和 JPEG2000(jp2) 与原视频基本没有色差

结论

色差主要来自 YUV→RGB 矩阵不匹配 和 色彩范围。 JPEG 本身不支持 BT709/BT2020 矩阵,必须先转换为 BT601 才能保证色彩一致。

  • 方案一(提前转换 YUV 色域)可以直接使用 JPEG,简单且兼容性好,是推荐方案。

  • 方案二(使用其他图片格式)适合对图片体积或色彩保真度有要求的项目,例如使用 WEBP 或 JPEG2000。