在看这篇文章的时候,我们需要带着几个问题。
- 什么是YUV?
- 为什么视频采集要用YUV而不用RGBA?
- RGB和YUV的区别以及关联?
RGB(A)颜⾊编码
三原色指色彩中不能再分解的三种基本颜色,我们通常说的三原色,是色彩三原色以及光学三原色。而光学三原色就指的是红(R),绿(G),蓝(B)
。由RGB可以组成任何颜色。
在图像显示中,一张图片可以分解成无数个像素点
组成,而这个像素点就可以用RGB来表示。而A表示的透明度Alpha
,通常来说在视频的播放中透明度为1,所以我们这里不讨论A。
如上图所示,图中的某个像素点是用RGB组成,假如一张图片的尺寸为
1280 * 720
,那么这个图片的大小是多少呢?
RGB 图像中,每个像素点都有红、绿、蓝三个原⾊,其中每种原⾊都占⽤8 bit
,也就是⼀个字节,那么⼀个像素点也就占⽤ 24 bit
,也就是三个字节。
那么这个图片的小就是:
//图片大小
1280 * 720 * 3 / 1024 / 1024 = 2.63 MB
竟然有2.63M,这还只是1帧,那么一个小时的电影,一秒有60帧没,那么视频将会占用无比巨大空间,所以用RGBA格式保存视频是不可取的。
YUV颜色编码
定义
YUV 颜⾊编码采⽤的是 明亮度 和 ⾊度 来指定像素的颜⾊。其中,Y 表示明亮度(Luminance、Luma)
,⽽ U 和 V 表示⾊度(Chrominance、Chroma)
。⽽⾊度⼜定义了颜⾊的两个⽅⾯:⾊调
和饱和度
。
和 RGB 表示图像类似,每个像素点都包含 Y、U、V 分量。但是它的Y 和 UV 分量是可以分离的,如果没有 UV 分量⼀样可以显示完整的图像,只不过是⿊⽩的。
4:4:4采样格式
YUV 4:4:4采样意味着 Y、U、V 三个分量的采样⽐例相同,即每个像素点都会采样Y、U、V分量
蓝色的⭕️代表Y分量,☆代表UV分量。
假如有A,B,C,D4个点像素为[Y0,U0,V0],[Y1,U1,V1],[Y2,U2,V2],[Y3,U3,V3]
那么最终还原的结果还是为[Y0,U0,V0],[Y1,U1,V1],[Y2,U2,V2],[Y3,U3,V3]
此时采样的数据大小和RGB采样方式的并没有差别,所以我们一般不用4:4:4的采样方式
4:2:2采样格式
YUV 4:2:2 采样,意味着 UV 分量是 Y 分量采样的⼀半,Y 分量和 UV 分量按照 2 : 1 的⽐例采样。如图所示,假如一行有4个像素点,那么Y分量则是4个,而UV分量则是2个,Y:UV = 2:1
。
蓝色的⭕️代表Y分量,☆代表UV分量。
假如有A,B,C,D4个点像素为[Y0,U0,V0],[Y1,U1,V1],[Y2,U2,V2],[Y3,U3,V3]
那么按照YUV4:2:2 采样的码流为: Y0,U0,Y1,V1,Y2,U2,Y3,V3
那么最终还原的结果还是为[Y0,U0,V0],[Y1,U1,V1],[Y2,U2,V2],[Y3,U3,V3]
假如一张图片的尺寸为1280 * 720
,那么这个图片的大小是多少呢?
//图片大小
(1280 * 720 * 8 + 1280 * 720 * 0.5 * 8 * 2)/ 8 / 1024 / 1024 = 1.76 MB
可以看到比RGB采样的方式节省了大约1/3的内存,而且传输时的带宽也能节省。
4:2:0采样格式
YUV 4:2:0 采样,并不是指只采样 U 分量⽽不采样 V 分量。⽽是指,在每⼀⾏扫描时,只扫描⼀种⾊度分量(U 或者 V),和 Y 分量按照 2 : 1 的⽅式采样。⽐如,第⼀⾏扫描时,YU 按照 2 : 1 的⽅式采样,那么第⼆⾏扫描时,YV 分量按照 2:1 的⽅式采样。对于每个⾊度分量来说,它的⽔平⽅向和竖直⽅向的采样和 Y 分量相⽐都是 2:1 。假设第⼀⾏扫描了 U 分量,第⼆⾏扫描了 V 分量,那么需要扫描两⾏才能够组成完整的 UV 分量。
如上图所示,4:2:0的扫描方式,在第一行隔列扫描U点,比如A点扫描U0,C点扫描U1点;在第二行隔列扫描V点,比如E点扫描V0,G点扫描V1点。所以ABEF点共用了U0、V0,CDGH共用了U1、V1。
假如原始像素点为[Y0 U0 V0],[Y1 U1 V1],[Y2 U2 V2],[Y3 U3 V3],[Y5 U5 V5],[Y6 U6 V6],[Y7 U7 V7],[Y8 U8 V8]
那么按照YUV4:2:2 采样的码流为: Y0,U0,Y1,Y2,U2,Y3,Y5,V5,Y6,Y7,V7,Y8
最后映射还原的像素点为: [Y0 U0 V5],[Y1 U0 V5],[Y2 U2 V7],[Y3 U2 V7],[Y5 U0 V5],[Y6 U0 V5],[Y7 U2 V7],[Y8 U2 V7]
假如一张图片的尺寸为1280 * 720
,那么这个图片的大小是多少呢?
//图片大小
(1280 * 720 * 8 + 1280 * 720 * 0.25 * 8 * 2)/ 8 / 1024 / 1024 = 1.32 MB
可以看到用4:2:0的方式,能节省更多的 内存。
RGB与YUV之间的转换
RGB 到 YUV 的转换,就是将图像所有像素点的 R、G、B 分量转换到 Y、U、V 分量。
公式如下:
- RGB转YUV
Y = 0.299 * R + 0.587 * G + 0.114 * B
U = -0.147 * R - 0.289 * G + 0.436 * B
V = 0.615 * R - 0.515 * G - 0.100 * B
- YUV转RGB
R = Y + 1.14 * V
G = Y - 0.39 * U - 0.58 * V
B = Y + 2.03 * U
总结
通过实际的代码,我们可以看到用YUV的编码方式,从采集源头做起,可以节省相当可观的内存,这些节省的内存不论是对存储还是对传输都有相当大的意义。