图像处理YUV的详解
Posted 美好心境
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了图像处理YUV的详解相关的知识,希望对你有一定的参考价值。
文章目录
1. 前言
端午节在慕课网看了李超老师的课程关于YUV的讲解,这里把所学的内容,加上自己的理解进行了整理加工,在这里做个分享。
图像有两种表达方式:RGB和YUV,RGB比较简单,这里不做赘述,今天重点讲YUV,那么既然有了RGB,为什么还需要YUV呢?原因主要有两个:
- YUV中的Y是亮度信号,英文名叫
luma
,(顺便说一句,亮度的单位是流明),也就是灰阶值,可以直接给黑白电视机使用,兼容了黑白电视,所以我们小时候看的无线广播电视时,同样的频道,用黑白电视和彩色电视都能播放。 - YUV中的UV表示色度(
Chrominance
或Chroma
),作用是描述影像色彩及饱和度,用于指定像素的颜色。人对于UV的敏感性小于亮度,这样适当减小UV分量,不影响人的视觉感官。
所以,采用YUV的设计既兼容了黑白电视,而且编码过程还可以压缩UV分量,占用更少的频宽。因为对UV分量的下采样方式不同,所以出现了不同的格式,如:YUV4:4:4,YUV4:2:2,YUV4:2:0,我们将会在下文中详细讲解。
讲到这里,我们再引入一个名词 Y’CbCr,是YUV的一个压缩版本,不同之处在于Y’CbCr用于数字图像领域,而YUV用于模拟信号领域,我们平时说的MPEG、DVD、摄像机中常说的YUV其实是Y’CbCr,Y’为亮度,Cb,Cr分量代表当前颜色对蓝色和红色的偏移程度。
这里可能会对刚入门的朋友产品一定的混淆,我们再详细说明一下,“Y”表示明亮度(Luminance或Luma),也就是灰阶值;而“U”和“V”表示的则是色度(Chrominance或Chroma),作用是描述影像色彩及饱和度,用于指定像素的颜色。“亮度”是通过RGB输入信号来创建的,方法是将RGB信号的特定部分叠加到一起。“色度”则定义了颜色的两个方面—色调与饱和度,分别用Cr和CB来表示。其中,Cr反映了RGB输入信号红色部分与RGB信号亮度值之间的差异。而CB反映的是RGB输入信号蓝色部分与RGB信号亮度值之同的差异; YUV经常有另外的名字,YCbCr ,其中Y与YUV 中的Y含义一致,Cb , Cr同样都指色彩,,只是在表示方法上不同而已,Cb Cr 就是本来理论上的“分量/色差”的标识。C代表分量(是component的缩写)Cr、Cb分别对应r(红)、b(蓝)分量信号,Y除了g(绿)分量信号,还叠加了亮度信号。
到这里,我不禁有个问题,颜色空间YUV中,为什么没有单独的绿色色差信号输入?而是把绿色和亮度叠加到了一起。我没有找到答案,在知乎上看到一个回答感觉比较有道理:
生物学上,人眼有四种细胞,视杆细胞(亮度/黑白)加上红绿蓝三中视锥细胞(极其少数女性有四种视锥细胞)。其中,视杆细胞和绿色视锥细胞共用一根视神经。
CbCr分量坐标
2. Y’CbCr详解
下面我们用实际的图片来说明Y’CbCr三个分量的直观体验,如果输出Y’CbCr三个分量的值,也就是原图,如下:
原图(包含Y'CbCr分量)
下面这张图是仅包含了Y’分量,可以看出就是一张黑白图像,除了没有颜色外,不影响观看图片。
仅包含Y'分量
下面这张图是仅包含了Cb分量的图片,模模糊糊的看到一些蓝黄色的色彩。
仅包含Cb分量的图
下面这张图是仅包含了Cr分量的图片,模模糊糊的看到一些红绿色的色彩。
仅包含Cr分量的图
3. Y’CbCr的编解码
图片编解码流程
从上图我们可知,摄像头采集后的数据是编码为RGB格式的,数字显示器显示的时候也是RGB格式的,而中间是把RGB编码为YUV格式,进程传输的,接收后又将YUV解码为RGB格式进行显示。有了上述的总体了解后,我们需要探讨两个问题:YUV的采样问题和YUV与RGB的转换问题。也就是说RGB用于屏幕图像的展示,YUV用于采集与编码
3.1 YUV采样
YUV的一个优点是色度通道可以具有比Y通道更低的采样率而不会显著降低感知质量,称为A:B:C表示法的符号用于描述U和V相对于Y的采样率,主要的采样格式有YUV4:2:0,YUV4:2:2和YUV4:4:4。其中YUV4:2:0是最标准的格式,也是最为广泛使用的格式,大多数播放器都可以播放YUV4:2:0。
小例子:有一个文件是MP4的格式,但是播放器确怎么也播放不出来,经过观察视频信息后发现,是YUV4:4:4的格式,然后转换成YUV4:2:0的MP4文件就成功播放了。
3.2 RGB转YUV
了解了YUV的采样后,接下去我们研究一下RGB与YUV的转换,公式如下:
{
Y
=
0.299
∗
R
+
0.587
∗
G
′
+
0.114
∗
B
U
=
−
0.147
∗
R
−
0.289
∗
G
+
0.436
∗
B
=
0.492
∗
(
B
−
Y
)
V
=
0.615
∗
R
−
0.515
∗
G
−
0.100
∗
B
=
0.877
∗
(
R
−
Y
)
\\begin{cases} Y=0.299*R+0.587*G^{'}+0.114*B \\\\ U=-0.147*R-0.289*G+0.436*B=0.492*(B-Y) \\\\ V=0.615*R-0.515*G-0.100*B=0.877*(R-Y) \\\\ \\end{cases}
⎩⎪⎨⎪⎧Y=0.299∗R+0.587∗G′+0.114∗BU=−0.147∗R−0.289∗G+0.436∗B=0.492∗(B−Y)V=0.615∗R−0.515∗G−0.100∗B=0.877∗(R−Y)
在代码中如果要将RGB进行转换为YUV,就可以套用上面的公式进行转换,也可以写成矩阵的形式:
[ Y U V ] = [ 0.299 0.587 0.114 − 0.418 − 0.289 0.437 0.615 − 0.515 − 0.100 ] [ R G B ] \\left[ \\begin{matrix} Y\\\\U \\\\V \\end{matrix} \\right]=\\left[ \\begin{matrix} 0.299&0.587&0.114\\\\-0.418&-0.289&0.437\\\\0.615&-0.515&-0.100 \\end{matrix} \\right]\\left[ \\begin{matrix} R\\\\G\\\\B \\end{matrix} \\right] ⎣⎡YUV⎦⎤=⎣⎡0.299−0.4180.6150.587−0.289−0.5150.1140.437−0.100⎦⎤⎣⎡RGB⎦⎤
3.3 YUV转RGB
{ R = Y + 1.140 ∗ V G = Y − 0.394 ∗ U − 0.581 ∗ V B = Y + 2.032 ∗ U \\begin{cases} R=Y+1.140*V \\\\ G=Y-0.394*U-0.581*V \\\\ B=Y+2.032*U \\end{cases} ⎩⎪⎨⎪⎧R=Y+1.140∗VG=Y−0.394∗U−0.581∗VB=Y+2.032∗U
在播放视频的时候,我们需要将YUV的数据转为RGB格式,就可以采用上面的公式进行转换,也可以写成矩阵的形式。
[ R G B ] = [ 1 0 1.140 1 − 0.395 − 0.581 1 2.032 0 ] [ Y U V ] \\left[ \\begin{matrix} R\\\\G\\\\B \\end{matrix} \\right]=\\left[ \\begin{matrix} 1&0&1.140\\\\1&-0.395&-0.581\\\\1&2.032&0\\end{matrix} \\right]\\left[ \\begin{matrix} Y\\\\U\\\\V\\end{matrix} \\right] ⎣⎡RGB⎦⎤=⎣⎡1110−0.3952.0321.140−0.5810⎦⎤⎣⎡YUV⎦⎤
读到这里大家可能会有疑惑,怎么突然就得到转换的矩阵了,其中的系数是怎么推导出来的?我差了下资料,会设计很多协议,比如:BT601,BT709,BT2020,RP177,NTSC色域等,本文就不展开了,大家记住结论就好。不过这里值得注意的是这里的RGB转YUV是有损的,这个也不难理解,毕竟因为进行了下采样了。
思考一个问题:当YUV分量全部为零的时候,屏幕会显示绿色,这是为什么呢?
3.4 YUV常见格式
- YUV4:4:4 这个和RGB是等价的,一些播放器兼容性问题,无法播放。
- YUV4:2:2
- YUV4:2:0,重点,最标准,应用最广泛
YUV4:2:0并不意味着只有Y,Cb两个分量,而没有Cr分量,它实际指的是对每行扫描线来说,只有一种色度的分量,它以2:1的抽样率存储,相邻的扫描行存储不同的色度分量,也就是说,如果一行是4:2:0的话,下一行就是4:0:2,再下一行是4:2:0…以此类推。
下面通过图的方式更加清楚的展示说明:
YUV4:4:4格式
YUV4:2:2
YUV4:2:2模式下,每个格子都对Y分量进行采样,但是UV分量是每两个点采一次,UV分量有2:1的压缩比。
YUV4:2:0
YUV4:2:0模式下,每个格式都对Y分量进行采样,但UV分量每两个点采集一次,相比于YUV4:4:4,UV分量有4:1的压缩比,我们可以得到以下结论:
{
Y
U
V
=
Y
∗
1.5
Y
U
V
=
R
G
B
/
2
\\begin{cases} YUV=Y*1.5 \\\\ YUV=RGB/2 \\end{cases}
{YUV=Y∗1.5YUV=RGB/2
因此YUV4:2:0的模式下,数据量是RGB的一半,这个其实也不难理解,上图左上角四个点中,如果用RGB的话,会采样4*3=12个点,而YUV4:2:1模式下,只采集了6个点,因此压缩比就是一半。
3.5 YUV的存储格式
这里我们主要关注的是YUV4:2:0的存储格式,要注意以下几点:
- 是按照分层进行存储的,从上图可知,上面几层都是Y的信息,最后两层分别是U和V的信息。这样的存储格式特别适合于和黑白电视相兼容,黑白电视只需要读取前面Y相关的信息即可。
- 每4个Y有一个U或者V,这个我们在上面已经讲过。
实际应用中呢,又更加复杂一些,主要分planar(平面)
和packed(打包)
两种:
3.5.1 planar(平面)
I420:YYYYYYYY UU VV => YUV420P
YV12:YYYYYYYY VV UU => YUV420P(ios)
3.5.2 packed(打包)
NV12:YYYYYYYY UVUV => YUV420SP
NV21:YYYYYYYY VUVU => YUV420SP(android)
我们可以看到其实这几种主要区别就是UV的顺序不同而已,IOS中用的是YV12,而Android中用的是NV21.
4. YUV实战
说完上面的理论知识后,下面我们来进行实战部分,我们可以执行FFmpeg命令:
ffmepg -i input.mp4 -an -c:v rawvideo -pix_fmt yuv420p out.yuv
其中-a表示audio音频,-n表示null,合起来就表示没有音频,就是把音频给过滤掉,接下去播放YUV文件。
ffplay -pix_fmt yuv420p -s 608*368 out.yuv
下面的命令我们提取Y分量。
ffplay -pix_fmt yuv420p -s 608*368 -vf extractplanes='y' out.yuv
播放Y分量命令,效果就是黑白色的视频:
ffplay -s 608*368 -vf extract planes='y' out.yuv
5. 参考文档
- [1] https://blog.csdn.net/weixin_43752854/article/details/84841514
- [2] https://en.wikipedia.org/wiki/YUV
以上是关于图像处理YUV的详解的主要内容,如果未能解决你的问题,请参考以下文章
详解 YUV 格式(I420/YUV420/NV12/NV12/YUV422)