视频相关--YUV

266 阅读4分钟

本文的主角是多媒体领域非常重要的一个概念:YUV。

简介

YUV,是一种颜色编码方法,跟RGB是同一个级别的概念,广泛应用于多媒体领域中。

也就是说,图像中每1个像素的颜色信息,除了可以用RGB的方式表示,也可以用YUV的方式表示。

vs RGB

对比RGB,YUV有哪些不同和优势呢?

体积更小

  • 如果使用RGB
  • 比如RGB888(R、G、B每个分量都是8bit)
  • 1个像素占用24bit(3字节)
  • 如果使用YUV
  • 1个像素可以减小至平均只占用12bit(1.5字节)
  • 体积为RGB888的一半

组成

RGB数据由R、G、B三个分量组成。

YUV数据由Y、U、V三个分量组成,现在通常说的YUV指的是YCbCr

  • Y:表示亮度(Luminance、Luma),占8bit(1字节)
  • CbCr:表示色度(Chrominance、Chroma)
  • Cb(U):蓝色色度分量,占8bit(1字节)
  • Cr(V):红色色度分量,占8bit(1字节)

兼容性

image.png

image.png

根据上面的图片,不难看出:

  • Y分量对呈现出清晰的图像有着很大的贡献
  • Cb、Cr分量的内容不太容易识别清楚

此外,你是否感觉:Y分量的内容看着有点眼熟?其实以前黑白电视的画面就是长这样子的。

YUV的发明处在彩色电视与黑白电视的过渡时期。

  • YUV将亮度信息(Y)与色度信息(UV)分离,没有UV信息一样可以显示完整的图像,只不过是黑白的
  • 这样的设计很好地解决了彩色电视与黑白电视的兼容性问题,使黑白电视也能够接收彩色电视信号,只不过它只显示了Y分量
  • 彩色电视有Y、U、V分量,如果去掉UV分量,剩下的Y分量和黑白电视相同

转换

公式1

Y = 0.257R + 0.504G + 0.098B + 16``U = -0.148R - 0.291G + 0.439B + 128``V = 0.439R - 0.368G - 0.071B + 128 R = 1.164(Y - 16) + 2.018(U - 128)``G = 1.164(Y - 16) - 0.813(V - 128) - 0.391(U - 128)``B = 1.164(Y - 16) + 1.596(V - 128)

公式2

Y = 0.299R + 0.587G + 0.114B``U = 0.564(B - Y) = -0.169R - 0.331G + 0.500B``V = 0.713(R - Y) = 0.500R - 0.419G - 0.081B R = Y + 1.403V``G = Y - 0.344U - 0.714V``B = Y + 1.770U

公式3

Y = 0.299R + 0.587G + 0.114B``U = -0.169R - 0.331G + 0.500B + 128``V = 0.500R - 0.419G - 0.081B + 128 R = Y + 1.403(V - 128)``G = Y - 0.343(U - 128) - 0.714(V - 128)``B = Y + 1.770(U - 128)

格式转换

其他图片格式转YUV

ffmpeg -i ``in``.png -s 512x512 -pix_fmt yuv420p out.yuv

上述命令生成的yuv文件大小是:393216字节 = 512 * 512 * 1.5字节。

  • -s

  • 设置图片的尺寸

  • 可以用一些固定字符串表示尺寸,比如hd720表示1280x720

  • 如果不设置此选项,默认会跟随输入图片的尺寸

  • -pix_fmt

  • 设置像素格式

  • 可以通过ffmpeg -pix_fmts查看FFmpeg支持的像素格式

  • 如果不设置此选项,默认会跟随输入图片的像素格式

    • 比如可能是rgb24rgba8pal8
    • 可以通过ffprobe查看某图片的像素格式,比如ffprobe in.png

YUV转其他图片格式

ffmpeg -s 512x512 -pix_fmt yuv420p -i ``in``.yuv out.jpg
  • 这里必须得设置YUV的尺寸(-s)、像素格式(-pix_fmt
  • 这就类似于:对pcm进行编码时,必须得设置采样率(-ar)、声道数(-ac)、采样格式(-f

显示YUV

完整的YUV

可以通过ffplay显示YUV数据。

  • YUV中直接存储的是所有像素的颜色信息(可以理解为是图像的一种原始数据)
  • 必须得设置YUV的尺寸(-s)、像素格式(-pix_fmt)才能正常显示
  • 这就类似于:播放pcm时,必须得设置采样率(-ar)、声道数(-ac)、采样格式(-f
ffplay -s 512x512 -pix_fmt yuv420p ``in``.yuv # 在ffplay中``# -s已经过期,建议改为:-video_size``# -pix_fmt已经过期,建议改为:-pixel_format``ffplay -video_size 512x512 -pixel_format yuv420p ``in``.yuv

单个分量

可以使用过滤器(filter)显示其中的单个分量(r、g、b、y、u、v)。

# 只显示r分量``ffplay -vf extractplanes=r in.png # 只显示g分量``ffplay -vf extractplanes=g in.png # 只显示b分量``ffplay -vf extractplanes=b in.png # 只显示y分量``ffplay -video_size 512x512 -pixel_format yuv420p -vf extractplanes=y in.yuv``# 只显示u分量``ffplay -video_size 512x512 -pixel_format yuv420p -vf extractplanes=u in.yuv``# 只显示v分量``ffplay -video_size 512x512 -pixel_format yuv420p -vf extractplanes=v in.yuv
  • -vf
  • 设置视频过滤器
  • 等价写法:-filter:v
  • extractplanes
  • 抽取单个分量的内容到灰度视频流中