YUV是指亮度参量和色度参量分开表示的像素格式,其中“Y”表示明亮度(Luminance或Luma),也就是灰度值;而“U”和“V”表示的则是色度(Chrominance或Chroma),作用是描述影像色彩及饱和度,用于指定像素的颜色。
Y: 表示明亮度(Luminance或Luma)
U和V: 色度(Chrominance或者Chroma), 作用是描述影像色彩及饱和度,用于指定像素的颜色。
YCbCr其中Y是指亮度分量,Cb指蓝色色度分量,而Cr指红色色度分量。
YCbCr 则是在世界数字组织视频标准研制过程中作为ITU - R BT.601 建议的一部分,其实是YUV经过缩放和偏移的翻版。其中Y与YUV 中的Y含义一致,Cb,Cr 同样都指色彩,只是在表示方法上不同而已。在YUV 家族中,YCbCr 是在计算机系统中应用最多的成员,其应用领域很广泛,JPEG、MPEG均采用此格式。一般人们所讲的YUV大多是指YCbCr。YCbCr 有许多取样格式,如4∶4∶4,4∶2∶2,4∶1∶1 和4∶2∶0。
色度通道的采样率可以低于亮度通道,而不会显著降低感知质量。
4:4:4 表示完全取样。
4:2:2 表示2:1的水平取样,垂直完全采样。
4:2:0 表示2:1的水平取样,垂直2:1采样。
4:1:1 表示4:1的水平取样,垂直完全采样。
最常用Y:UV记录的比重通常1:1或2:1,Video是以YUV4:2:0的方式记录,也就是我们俗称的I420,YUV4:2:0并不是说只有U(即Cb),V(即Cr)一定为0,而是指U:V互相援引,时见时隐,也就是说对于每一个行,只有一个U或者V分量,如果一行是4:2:0的话,下一行就是4:0:2,再下一行是4:2:0…以此类推。至于其他常见的YUV格式有YUY2、YUYV、YVYU、UYVY、AYUV、Y41P、Y411、Y211、IF09、IYUV、YV12、YVU9、YUV411、YUV420等。
为了方便举例说明,这里使用ffmpeg生成一个320x320分辨率的yuvj444p
# 用ffmpeg testsrc 生成一个完全取样的的YUV文件 yuvj444p
ffmpeg -f lavfi -i testsrc -frames 10 -pix_fmt yuvj444p -s 320x320 yuvj444p_320x320.yuv
# 基于yuvj444p转换成422、420、411等
ffmpeg -pix_fmt yuvj444p -s 320x320 -i yuvj444p_320x320.yuv -pix_fmt yuvj420p yuvj420p_320x320.yuv
ffmpeg -pix_fmt yuvj444p -s 320x320 -i yuvj444p_320x320.yuv -pix_fmt yuv422p yuv422p_320x320.yuv
ffmpeg -pix_fmt yuvj444p -s 320x320 -i yuvj444p_320x320.yuv -pix_fmt yuvj411p yuvj411p_320x320.yuv
完全取样,每个像素都有独立的Y/U/V值
为了方便对比,我们挑画面下方横条渐变色块6x5个像素放大40倍,看像素的YUV值(其它采样也取相同位置)。
从如下图所示,可以看出相邻的像素点的Y/U/V值不相等也可以看出每个像素都有独立的U/V值
每两个Y共用一对U/V值
422采样,水平方向每两个像素共用一对U/V值,下如图绿色框(U channel)和蓝色框(V channel)标记的一个框在内存中只有一个值。
每四个Y共用一对U/V值
420采样,因为是相邻的4个像素共用一对U/V,所以会出现如下图所示,每四个相邻的像素就出现4个相同的UV值。
与YUV 4:2:0类似,都是四个每四个Y共用一对U/V值,区别是4:1:1是水平方向的4个Y共享一对U/V,如下图所示,第1-4个Y使用同一对U/V值,第5-8个Y使用同一对U/V值,依次类推。。。
这里就不截图举例了,由于411采样的不太常用的以致于一般工具都不支持播放,有了422的例子其实也好更多,411相当于在422的基础上再在水平方向下采样,即水平方向每连续4个像素共用一对UV。
将YUV三个分量的素数值放在同一个阵列中,存储为单个阵列宏像素
将每个像素点的Y/U/V连续交叉存储
以UYVY、YUYV为例,由两个像素的Y/U/V组成一个宏像素,依次排列
每个分量存储为单独的数组,最终图像是三个单独平面的整合
以I420为例Y/U/V排列如下:
width: 图像分辨率的宽
height: 分辨率高
n = width * height
m = width * height / 4
Y0Y1Y2Y3Y4Y5…Yn U0U1U2U3…Um V0V1V2V3…Vm
介于Pakced和Planar之间,即Y分量为一个阵列,UV交叉存储
NV12
width: 图像分辨率的宽
height: 分辨率高
n = width * height
m = width * height / 4
Y0Y1Y2Y3Y4Y5…Yn U0V0U1V1U2V2U3V3…UmVm
Note:
格式的名称以“ p”结尾的一般都是planar格式,如在ffmpeg 中的yuvj420p格式
格式的名称以“ sp”结尾的一般都是semi-planar格式, 如
如下图,树的第四层只是列举部分并非全部,理论上树的第4层可以通过YUV的排列、位深、色彩范围(full range和limited range)等自由组合出来非常多的格式。
一般来讲,我们把YUV、Y‘UV、YCbCr, YPbPr包含在YUV颜色模型的范围内,其中Y都表示亮度,UV表示两个色度分量,但是具体的颜色模型的用途又各不相同,当然,他们与RGB的互转公式也就不相同。在电视系统发展的早期,YUV和Y’UV都是颜色信息的模拟信号编码形式,虽然Y和Y’都表示亮度,但是两种亮度的意义却天差地别,Y用来代指luminance,表示的是自然颜色的亮度,而Y‘代指luma,表示的是经过伽马压缩之后电信号的强度。在现在的计算机系统中,YUV一般用来代指YCbCr,用来表示文件的编码格式,用于数字视频的编码,而YPbPr颜色模型常常用在模拟分量视频中。所以YUV颜色模型到RGB颜色模型的转换,应该对应两种方式,分别是模拟YUV->模拟RGB、数字YUV->数字RGB。不过因为标清、高清、以及超清幅面,YUV转RGB的权重值各不相同,需要将模拟信号和数字信号再做一次幅面划分,就出现了6种转换公式。
Y、Cr、Cb信号的限制信号的限制
Y、Cr、Cb信号形式的数字编码可以表示比那些由R,、G、B信号相应范围支持的范围更大的信号值范围。正因为这样,作为电子图像生成或信号处理的结果,产生Y、CR、CB信号是可能的,尽管只是个别有效,但当转变为R、G、B时,将导致值超出范围。通过应用Y、CR、CB信号的限制,它将比在这些信号成为R、G、B形式之前一直等待来防止值超出范围更加方便和有效。限制还能在保持亮度和色调值的方法中应用,通过仅仅牺牲饱和度,来最大限度地降低主观缺陷。
Kr + Kb +Kg = 1
以下参数由 ITU-R Recommendation BT.xxx 可得
BT.601:
Kr = 0.299
Kg = 0.587
Kb = 0.114
BT.709:
Kr = 0.2126
Kg = 0.7152
Kb = 0.0722
BT.2020:
Kr = 0.2627
Kg = 0.678
Kb = 0.0593
Kr + Kb +Kg = 1
Umax = Vmax = 0.5
Y = Kr * R + Kg * G + Kb * B
Pb = Umax * (B - Y) / (1 - Kb)
Pr = Vmax * (R - Y) / (1 - Kr)
Kr + Kb +Kg = 1
Umax = Vmax = 0.5
Y = 16 + 219 * (Kr * R + Kg * G + Kb * B) / 255
Cb = 128 + 224 * (Umax * (B - Y) / (1 - Kb)) / 255
Cr = 128 + 224 * (Vmax * (R - Y) / (1 - Kr)) / 255
公式直接跳到下一节,以BT.601 为例,计算过程:
代入数值
Y = 0.299 * R + 0.587 * G + 0.114 * B
Pb = 0.5 * (B - Y) / (1 - 0.114)
Pr = 0.5 * (R - Y) / (1 - 0.299)
化简
Pb = 0.5 * (B - (0.299 * R + 0.587 * G + 0.114 * B)) / (1 - 0.114)
= 0.5 * (B - (0.299 * R + 0.587 * G + 0.114 * B)) / 0.886
= 0.5 * (B - 0.299 * R - 0.587 * G - 0.114 * B) / 0.886
= 0.5 * (0.299 * R - 0.587 * G + 0.886 * B) / 0.886
= (0.1495 * R - 0.2935 * G + 0.443 * B) / 0.886
≈ \approx ≈ 0.168 * R - 0.331 * G + 0.5 * B
Pr = 0.5 * (R - (0.299 * R + 0.587 * G + 0.114 * B)) / (1 - 0.299)
= 0.5 * (R - 0.299 * R - 0.587 * G - 0.114 * B) / 0.701
= 0.5 * (0.701 * R - 0.587 * G - 0.114 * B) / 0.701
= (0.3505 * R - 0.2935 * G - 0.057 * B) / 0.701
≈ \approx ≈ 0.5 * R - 0.419 * G - 0.081 * B
# RGB to YUV
Y = 0.299 * R + 0.587 * G + 0.114 * B
Pb =-0.169 * R - 0.331 * G + 0.500 * B
Pr = 0.500 * R - 0.439 * G - 0.081 * B
# YUV to RGB
R = Y + 1.402* Pr
G = Y - 0.344 * Pb - 0.792* Pr
B = Y + 1.772 * Pb
RGB to YUV
Y = 0.213 * R + 0.715 * G + 0.072 * B
Pb =-0.115 * R - 0.385 * G + 0.500 * B
Pr = 0.500 * R - 0.454 * G - 0.046 * B
# YUV to RGB
R = Y + 1.402* Cr
G = Y - 0.344 * Cb - 0.792* Cr
B = Y + 1.772 * Cb
# RGB to YUV
Y = 0.2627 * R + 0.678 * G + 0.0593 * B
Pb = -0.1396 * R - 0.3604 * G + 0.5 * B
Pr = 0.5 * R - 0.4598 * G - 0.0402 * B
# RGB2YUV
Y = 16 + 0.257 * R + 0.504 * G+ 0.098 * B
Cb = 128 - 0.148 * R - 0.291 * G+ 0.439 * B
Cr = 128 + 0.439 * R - 0.368 * G - 0.071 * B
# YUV2RGB
R = 1.164 *(Y - 16) + 1.596 *(Cr - 128)
G = 1.164 *(Y - 16) - 0.392 *(Cb - 128) - 0.812 *(Cr - 128)
B = 1.164 *(Y - 16) + 2.016 *(Cb - 128)
# RGB2YUV
Y = 16 + 0.183 * R + 0.614 * G + 0.062 * B
Cb = 128 - 0.101 * R - 0.339 * G+ 0.439 * B
Cr = 128 + 0.439 * R - 0.399 * G- 0.040 * B
#YUV2RGB
R = 1.164 *(Y - 16) + 1.792 *(Cr - 128)
G = 1.164 *(Y - 16) - 0.213 *(Cb - 128) - 0.534 *(Cr - 128)
B = 1.164 *(Y - 16) + 2.114 *(Cb - 128)
Cb = 128 + 224 * (0.5 * (B - Y) / 0.9407) / 255
Cr = 128 + 224 * (0.5 * (R - Y) / 0.7373) / 255
//TODO 有空再断续推导
不管是YUV转RGB还是RGB转YUV都会有图像质量的损失。
对于不同位深或不同采样率的转换质量损失都好理解,但对于相同位深相同采样率的转换图像质量损失就要从计算公式来理解了,如I444和RGB24都是8bit位深未经压缩处理全采样数据,无论是RGB转YUV,还是YUV转RGB都会有少量的图像质量的损失,从转换公式来看这个由于浮点计算带来的损失,可以说是微乎其微的肉眼基本上看不出来的损失。
用ffmpeg来做一验证,将yuvj444p转换成rgb24再转回yuvj444p,对比两个yuvj444p文件的差异
# 1. 用ffmpeg testsrc 生成一个完全取样的的YUV文件 yuvj444p
ffmpeg -f lavfi -i testsrc -frames 10 -pix_fmt yuvj444p -s 320x320 yuvj444p_320x320.yuv
# 2. 将生成的yuvj444p转换成rgb24
ffmpeg -pix_fmt yuvj444p -s 320x320 -i yuvj444p_320x320.yuv -pix_fmt rgb24 yuv2rgb_320x320.rgb
# 3. 再将rgb24转成yuvj444p
ffmpeg -s 320x320 -pix_fmt rgb24 -i yuv2rgb_320x320.rgb -pix_fmt yuvj444p -s 320x320 rgb2yuvj444p_320x320.yuv
使用yuvj444p_320x320.yuv和rgb2yuvj444p_320x320.yuv这两个YUV对比,这两者应该是有差异的
播放YUV
ffplay -pix_fmt yuvj444p -s 320x320 rgb2yuvj444p_320x320.yuv
ffplay -pix_fmt yuvj444p -s 320x320 yuvj444p_320x320.yuv
如下图两个文件,肉眼看不出有差别
但再对比文件差异时,如下图,可以看到红色高亮的少数的16进制数有差异,如第一个差异的数字原始的文件中是98,经过yuv2rgb再rgb2yuv后,变成了96
由于YUV格式是未经压缩并且只存储了Y/U/V三个通道的数据,播放或编码必须要知道分辨率和YUV具体的格式(如nv12/i420/yuvj420ple), 因此在YUV文件命名时建议名字包含YUV格式名称和分辨率信息
这里计算文件大小或者计算帧数中的采样率和位深可由YUV格式得到
已知YUV采样率、分辨率、和帧数
文件大小=宽 * 高 * 采样率 * 向上取整(位深/8) * 帧数
file size(byte) = width * height * rate * Ceil(bitdepth/8) * frames
以最常用的nv12/i420等8bit位深的420为例
文件大小 = 宽 * 高 * 1.5 * 帧数
YUV帧数的计算和文件大小的计算类似
要求已知文件大小、采样率、分辨率
YUV帧数=文件大小/(宽 * 高 * 采样率 * 向上取整(位深/8))
YUV frames = file size(byte) / (width * height * rate * Ceil(bitdepth/8))
sample | rate |
---|---|
4:4:4 | 3 |
4:2:2 | 2 |
4:2:0 | 1.5 |
4:1:1 | 1.5 |
当位深超过8bit时存在大小端模式的情况
big-edian(大端序): 低地址存放高位
little-endian(小端序): 低地址存放低位
格式名称以le为小端序,格式名称以be为小端序
相同名称只是后缀不一样的两种格式YUV排列是完全一样的, 如,yuv420p10le与yuv420p10be
YUV格式名称比较多在不同的地方不同的名称有可能代表的是同一种格式,如在ffmpeg中的yuyv422与gstreamer 中的yuy2,以及其它不它的格式名称YUY2/YUYV/YUNV, 都是代表同一种YUV格式
ffmpeg pix_fmt | gstreamer format | Duplicate formats | number of components | Bits per pixel | remark |
---|---|---|---|---|---|
yuvj420p | i420 | IYUV/YU12 | 3 | 12 | full range |
yuv420p | - | 3 | 12 | limited range , 排列方式与yuvj420p完全一致,只是像素颜色范围是[16,235], 16表示黑色,235表示白色; UV范围[16,240] | |
nv12 | nv12 | 3 | 12 | - | |
nv21 | nv21 | 3 | 12 | - | |
yuyv422 | yuy2 | YUY2/YUYV/YUNV | 3 | 16 | YUYV 4:2:2 |
uyvy422 | uyvy | UYVY/IUYV/HDYC/ UYNV/Y422 | 3 | 16 | UYVY 4:2:2 |
yuv420p10le | i420-10le | 3 | 15 | 10 bit yuv | |
p010le | p010-10le | 3 | 15 | 10 bit yuv | |
yv12 | - | 3 | 12 | YV12 (3-planar) ——These formats are identical to YU12 except that the U and V plane order is reversed. |
Define:
s = width * height
n = width * height // 4
m = width * height // 2
- I420/IYUV/YU12: yuv420 planar 的一种, 排列方式: y1y2y3…ysu1u2u3…unv1v2v3…vn
- nv12: 8bit YUV420 Semi-Planar的一种格式, 排列方式: y1y2y3…ysu1v1u2v2u3v3…unvn
- nv21: 8bit YUV420 Semi-Planar的一种格式, 排列方式: y1y2y3…ysv1u1v2u2…vnun
- i420-10le: 10bit YUV420 Planar的一种格式, 排列方式与i420一样, 只是每个值都用10bit低字节序来存储
- p010-10le: 10bit YUV420 Semi-Planar的一种格式, 排列方式与nv12一样, 只是每个值都用高10bit低字节序来存储
- YUY2/YUYV/YUNV: 8bit YUV 4:2:2格式, 排列方式: y1u1y2v1 y3u2y4v2 y5u3y6v3…yn-1umynvm
- UYVY/IUYV/HDYC/UYNV/Y422: 8bit YUV 4:2:2格式, 排列方式: u1y1v1Y2 u2y3v2y4 u3y5v3y6…umyn-1vmyn
- yv12: YUV420 Planar的一种,UV的顺序与i420相反, 排列方式: y1y2y3y…ynv1v2v3…vnu1u2u3…un
- YUV422P/I422: y1y2y3…ysu1u2u3…umv1v2v3…vm
- nv16: yuv422 Semi-Planar的一种: y1y2y3…ys u1v1u2v2u3v3…umvm
- nv61: 与nv16类似,只是u/v的位置互换(V前U后)
- yv16: yuv422 Planar的一种: y1y2y3…ysu1u2u3…umv1v2v3…vm
- yuvj444p: Planar的一种: y1y2y3y…ys u1u2u3…us v1v2v3…vs
其它4:1:1采样的格式一般不太常见
- Y41P: 是一种4:1:1packed格式,其中U和V每四个像素水平采样一次。每个宏像素在三个字节中包含8个像素,并具有以下字节布局:U0 Y0 V0 Y1 U4 Y2 V4 Y3 Y4 Y5 Y6 Y7
- Y41T与Y41P相同,除了每个Y样本的最低有效位指定色度键(0 =透明,1 =不透明)。
- AI44是一种已标准化的YUV格式,每个样本8位。每个样本在4个最高有效位(MSB)中包含一个索引,在4个最低有效位(LSB)中包含一个alpha值。索引引用YUV调色板条目的数组,必须在该格式的媒体类型中定义。此格式主要用于子图片图像。
…
参考:
[1]: https://docs.microsoft.com/en-us/windows/win32/medfound/recommended-8-bit-yuv-formats-for-video-rendering
[2]:https://www.fourcc.org/yuv.php
[3]: https://baike.baidu.com/item/YUV/3430784?fr=aladdin
[4]: https://www.itu.int/rec/R-REC-BT.601
[5]: https://www.itu.int/rec/R-REC-BT.709
[6]: https://www.itu.int/rec/R-REC-BT.2020