YUV编码采用明亮度和色度表示每个像素的颜色,Y表示亮度,UV表示色度,一个Y是1个字节,就是一个黑白像素,UV可以是多个Y共享。
YUV采样的格式有很多,每种格式按存储方式又还有比较细的区分,如YUV4:4:4,YUV 4:2:0,YUV 4:0:2,其中最常用的就是YUV420,而YUV420按存储的方式又可以分为YU12、YU21、NV12、NV21。
我们只需要看YUV420就行了,其中NV12和NV21是ios和安卓摄像头的采样格式,它们都是先存储所有的Y分量,区别在于NV12是UV交替存储,而NV21是VU交替存储。
最最最重要的还是减少带宽占用。
如果是RGB,一张1280*720的图片占用大小:
1280 * 720 * 3 / 1024 / 1024 ≈ 2.64M
如果是YUV420格式,同样大小的图片只占:
(1280 * 720 * 1 + 1280 * 720 * 0.5) / 1024 / 1024 ≈ 1.32M
是RGB大小的一半。
以前YUV格式作为黑白电视和彩色电视的过渡,是非常好的办法。
如果是黑白电视,因为Y和UV是分离的,这样黑白电视就可以只取出Y分量去播放了。
而彩色电视拿到YUV数据后,也要把YUV先转换成RGB数据才能显示图像。
为什么要这么做呢?如果采集到RGB数据,黑白电视直接作个灰度变换也是可以的。
我理解最关键的还是在省带宽,毕竟现在还是以前带宽都不便宜。
而且这里还有个要点,如果RGB像素是我们希望看到的彩色图像,而原始的YUV像素其实是被"压缩"过的,而且是有损压缩。相当于摄像头采集到了YUV数据,而到显示的时候转换成RGB其实像素是被"放大"的(像上面举例,图片大小会变为原来两倍)。
这么做难道不会让画面失真?这里就要说到人类的视网膜了。
人类对颜色的感知程度低于对亮度的感知度,这是由人类的视网膜细胞决定的。视网膜主要包含视网膜杆细胞进和视网膜锥细胞,杆细胞的作用是识别亮度,锥细胞的作用是识别色度,而杆细胞的数量又多于锥细胞。
所以即便是YUV格式转换过来的RGB像素,人类的眼睛也无法察觉,这也是现在摄像头芯片采集到的数据都用YUV编码的一个原因。
上面说到采样格式可以有多种:YUV4:4:4,YUV 4:2:2,YUV 4:2:0,用下面的图可以直观地表示,一个黑点是一个Y分量,白色圆圈是一组UV分量(一组UV分量包含U和V,占2个字节):
所以为什么说YUV420是最主要的采样格式,因为**YUV家族里它是最省带宽的格式之一!**YUV444一个像素点和RGB一样也占3个字节,而YUV422是1个像素点占用2个字节,YUV420是1个像素点占用1.5个字节。
绝大部分场景使用YUV420足够,因为肉眼无法分辨,而YUV444那些是适合高分辨率采样的场景。
说完采样格式,我们再来说下存储的格式。
YUV按存储格式分有两大类:planar和packed,平面式和压缩式。
planar是先连续存储所有像素点的Y,然后再存储所有像素点的U,最后是存储所有像素点的V。
packed是每个像素点的Y,U,V是连续交替存储的,就像RGB。
packed更多用在YUV444这种,完全采样的,planar更多用在YUV422、YUV420这种,也是方便一些黑白电视直接用Y分量。
我们用两张图来看下:
YV12,YU12格式(属于YUV420)
先存储所有的Y分量,再存储Cr(V),最后是Cb(U),Y’00、Y’01、Y’10、Y’11共用Cr00、Cb00,其他依次类推。
NV12、NV21(属于YUV420)
也是先存储所有的Y分量,但UV(CbCr)是交错存储,Y’00、Y’01、Y’10、Y’11共用Cr00、Cb00,其他依次类推。