了解过计算机图形图像学的同学应该知道,有两种方式表示图像,RGB和YUV,视频由一帧一帧的图像组成,每一张图片是由一个一个的像素点组成,既然有两种表示像素的方法,那肯定要了解一下两种表示方式的异同以及优缺点。
RGB像素
RGB像素表示法已经广为人知,这里只简单回顾一下。R、G、B分别是Red 红、Green 绿、Blue 蓝的首字母,是颜色的三原色,强度不同的组合可以形成大部分人眼可以看到的颜色。在计算机里,可以用三个字节分别表示RGB的值。一个字节8位(取值范围是0~255),三个字节就是24位,所以这种表示法会被叫做 RGB24 。为了方便表示,我们还常用16进制表示,例如下图的绿色,可以用16进制表示为 #7ba120 ,其中 7b 是红色分量, a1 是绿色分量, 20 是蓝色分量。绿色分量的值比其他分量大,所以显示的颜色偏绿色。RGB表示法简单直观,但很消耗存储资源,一个1024x1024的图像,需要1024x1024x3=3MB的存储空间。
YUV像素
RGB像素表示法很简单,如果你没做过数字图像和视频的开发,可能很少听说过YUV。但在数字图像和视频编码里领域,YUV像素表示法非常流行,有几个原因造成。首先,人眼对亮度更敏感,对颜色的敏感度稍弱,所以使用YUV来表示图像可以节省存储资源。其次由于数字摄像机传感器不能直接采样三原色,所以RGB也不适合硬件处理。因此YUV才如此应用广泛。
那什么是YUV呢?「Y」表示明亮度(Luminance、Luma),「U」和「V」则是色度、浓度(Chrominance、Chroma)。其实YUV是模拟信号的称呼,数字信号应该是表示为YCbCr。Cb是蓝色色度,Cr是红色色度。
上面的图片例子来源https://zh.wikipedia.org/wiki/YCbCr,很能说明YUV的特性,第一张是原图,第二张Y分量的表示图,第三张是U分量的表示图,第四张是V分量的表示图。
当然YUV与RGB之间通过一些公式可以转换的。
YUV相对RGB的优势就是压缩比高,那么YUV的采样就是值得研究的事情。
为什么说YUV可以比较节省存储空间?前面提到,人眼对亮度更敏感,对色度敏感度稍差,所以我们可以用完整的亮度和更少的色度来表示一张图像,也就是采样。用RGB表示每个像素必须用3个字节。但YUV表示一个像素,可能是3个字节,也可能是2个字节(丢掉U或者丢掉V),还可能只有1个字节(丢掉U和V)。占用字节大小的不同因为采用不同的采样方式。
常见YUV有很多规格,例如YUV444,YUV422和YUV420,后面的数字是表示采样的比例。其中YUV420是FFmpeg里最常用的,因为最省资源。
- 4:4:4表示完全取样。
- 4:2:2表示2:1的水平取样,垂直完全采样。
- 4:2:0表示2:1的水平取样,垂直2:1采样。
假设我们有一个4x2像素的图像,用RGB表示为:
YUV444是全采样,也就是跟RGB一样,每个像素都是3个字节。上面的RGB图像可以通过计算,得到YUV444的表示:
YUV422是水平方向对UV进行2:1采样。每个像素只取U或者V,间隔进行,所以YUV422的UV只有YUV444的一半。
YUV420是水平方向和垂直方向都对UV进行2:1采样。例如第一行取U,第二行取V,并且每行的U或者V都是Y的一半,也就是YUV420的YUV是关系是4个Y一个U和一个V。这样YUV420的UV比YUV422的UV少一半,是YUV444的1/4。
上面只是举了一个例子,实际上YUV420有很多种采样方法,只要符合下图的规律,就是YUV420。
小结
YUV和RGB是图像图像编程的基础,了解了YUV的采样,接下来我们做播放器、音视频编辑和直播就少了很多障碍。
参考:微软的一篇介绍YUV的文章:https://docs.microsoft.com/en-us/windows/win32/medfound/recommended-8-bit-yuv-formats-for-video-rendering
FFmpeg源码定义图像格式的代码在libavutil/pixfmt.h中,代码很多,不赘述了。尽情看吧。