YUV格式介绍

索引地址:系列教程索引地址

最近一直在搞视频解码这一块的东西,为了方便,我整合一下所有的关于YUV相关的内容,方便以后查找。

YUV是编译true-color颜色空间(color space)的种类,Y’UV, YUV, YCbCr,YPbPr等专有名词都可以称为YUV,彼此有重叠。“Y”表示明亮度(Luminance或Luma),也就是灰阶值,“U”和“V”表示的则是色度(Chrominance或Chroma),作用是描述影像色彩及饱和度,用于指定像素的颜色。

YUV

那么YUV又从何而来呢?在现代彩色电视系统中,通常采用三管彩色摄像机或彩色CCD摄像机进行摄像,然后把摄得的彩色图像信号经分色、分别放大校正后得到RGB,再经过矩阵变换电路得到亮度信号Y和两个色差信号R-Y(即U)、B-Y(即V),最后发送端将亮度和色差三个信号分别进行编码,用同一信道发送出去。这种色彩的表示方法就是所谓的YUV色彩空间表示。

采用YUV色彩空间的重要性是它的亮度信号Y和色度信号U、V是分离的。如果只有Y信号分量而没有U、V分量,那么这样表示的图像就是黑白灰度图像。彩色电视采用YUV空间正是为了用亮度信号Y解决彩色电视机与黑白电视机的兼容问题,使黑白电视机也能接收彩色电视信号。

YUV420

YUV420格式是指,每个像素都保留一个Y(亮度)分量,而在水平方向上,不是每行都取U和V分量,而是一行只取U分量,则其接着一行就只取V分量,以此重复(即4:2:0, 4:0:2, 4:2:0, 4:0:2 …),所以420不是指没有V,而是指一行采样只取U,另一行采样只取V。在取U和V时,每两个Y之间取一个U或V。但从4x4矩阵列来看,每4个矩阵点Y区域中,只有一个U和V,所以它们的比值是4:1。所以对于一个像素,RGB需要8 * 3 = 24位,即占3个字节;而YUV420P,8 + 8/4 + 8/4 = 12位,即占2个字节,其中8指Y分量,8/4指U和V分量。

从这里也可以看出,YUV要比RGB节省存储空间。

这里为什么一个分量是8位呢?

不管是R G B还是 Y U V他们每个分量的取值都是0-255,而计算机都是用二进制来存储的。巧了,一个字节(8bit)刚好可以记录0-255的数,所以刚好就是这样存了吧。

对于所有YUV420图像,它们的Y值排列是完全相同的,因为只有Y的图像就是灰度图像。YUV420sp与YUV420p的数据格式它们的UV排列在原理上是完全不同的。420p它是先把U存放完后,再存放V,也就是说UV它们是连续的。而420sp它是UV、UV这样交替存放的。

U为Cb,V为Cr。

首先要知道YUV究竟有多少种格式,我从FFmpeg和mpp库中提取了它们所支持的所有YUV格式。FFmpeg头文件中libavutil/pixfmt.h,64行开始是显示格式相关的。包括:YUV420P/YUYV422/YUV422P/YUV444P/YUV444P/YUV410P/YUV411P/YUVJ420P/YUVJ422P/YUVJ444P/UYVY422/UYYVUU411/NV12/NV21/YUV440P/YUVJ440P/YUVA420P/NV16/NV20/YVYU422/,同时也包括一些10bit等等之类的版本。

其中SP表示Semi-Planar,表示YUV不是分成3个平面而是分成2个平面。Y数据一个平面,UV数据合用一个平面。UV平面的数据格式是UVUVUV。

P有两种:打包(packed)格式和平面(planar)格式。对于planar的YUV格式,先连续存储所有像素点的Y,紧接着存储所有像素点的U,随后是所有像素点的V。对于packed的YUV格式,每个像素点的Y,U,V是连续交叉存储的。前者将YUV分量存放在同一个数组中,通常是几个相邻的像素组成一个宏像素(macro-pixel)而后者使用三个数组分开存放YUV三个分量

YUV420P(planar格式)在ffmpeg中存储是在struct AVFrame的data[]数组中

1
2
3
data[0]-------Y分量
data[1]------U分量
data[2]-------V分量

6*4的图片为例。

YUV420

每四个Y共用一组UV分量,一个YUV占8+2+2 = 12bits 1.5个字节。

YUV420SP(NV12)

像素排列:YYYYYYYY UVUV

每四个Y共用一组UV分量,一个YUV占8+2+2 = 12bits 1.5个字节。

nv12

图像大小为w * h,Y分量占用内存为w * h,UV占用w * h / 4。

那么整个YUV分量占用内存为w * h+(w * h / 4) * 2 = w * h * 3/2字节;

在运算中涉及到除法,而在读取数据中不可能读取0.5个字节,或者读取一个字节的部分数据。那么w和h必须为2的倍数,这样在运算中就不会出现异常。

YUV420SP_VU(NV21)

像素排列:YYYYYYYY VUVU

每四个Y共用一组UV分量,一个YUV占8+2+2 = 12bits 1.5个字节。

nv21

图像大小为w * h,Y分量占用内存为w * h,UV占用w * h / 4。

那么整个YUV分量占用内存为w * h+(w * h / 4) * 2 = w * h * 3/2字节;

YUV420P(I420/YU12)

像素排列:YYYYYYYY… UU… VV…

每四个Y共用一组UV分量,一个YUV占8+2+2 = 12bits 1.5个字节。

i420

图像的大小为w * h,Y分量占用大小为w * h,UV分量各占w * h / 4。

那么整个YUV分量占用内存为w * h + (w * h/4) * 2 = w * h * 3/2。

示例1:FFmpeg4入门系列教程7:解码视频并保存为YUV格式文件(YUV420P/YUV420SP)
示例2:FFmpeg4入门系列教程9:软解并使用QOpenGL播放视频(YUV420P->OpenGL)

YUV420P_VU(YV12)

像素排列:YYYYYYYY VV UU

每四个Y共用一组UV分量,一个YUV占8+2+2 = 12bits 1.5个字节。

yv12

YUV422

基于YUV 4:2:2采样,每两个Y共用一组UV分量,一个YUV占8+4+4 = 16bits 2个字节。

YUV422SP(NV16)

YUV422P

像素排列:YYYYYYYY VVVV UUUU

YUV444P

基于YUV 4:4:4采样,每一个Y对应一组UV分量,一个YUV占8+8+8 = 24bits 3个字节。

友情链接


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!