图像处理YUV的详解

Posted 美好心境

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了图像处理YUV的详解相关的知识,希望对你有一定的参考价值。

1. 前言

  端午节在慕课网看了李超老师的课程关于YUV的讲解,这里把所学的内容,加上自己的理解进行了整理加工,在这里做个分享。
  图像有两种表达方式:RGB和YUV,RGB比较简单,这里不做赘述,今天重点讲YUV,那么既然有了RGB,为什么还需要YUV呢?原因主要有两个:

  • YUV中的Y是亮度信号,英文名叫luma,(顺便说一句,亮度的单位是流明),也就是灰阶值,可以直接给黑白电视机使用,兼容了黑白电视,所以我们小时候看的无线广播电视时,同样的频道,用黑白电视和彩色电视都能播放。
  • YUV中的UV表示色度(ChrominanceChroma),作用是描述影像色彩及饱和度,用于指定像素的颜色。人对于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.299R+0.587G+0.114BU=0.147R0.289G+0.436B=0.492(BY)V=0.615R0.515G0.100B=0.877(RY)

在代码中如果要将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.2990.4180.6150.5870.2890.5150.1140.4370.100RGB

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.140VG=Y0.394U0.581VB=Y+2.032U

在播放视频的时候,我们需要将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=11100.3952.0321.1400.5810YUV

读到这里大家可能会有疑惑,怎么突然就得到转换的矩阵了,其中的系数是怎么推导出来的?我差了下资料,会设计很多协议,比如: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:4:4模式下,对每个格子对YUV所有分量都采样,相对RGB等于是无损转换。

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=Y1.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)

色彩管理YUV色彩模式详解

RGB、CMY、CMYK、YUV、HSV、HSI、LAB颜色空间详解

详解YUV系列----YUV420

详解YUV系列--YUV422

如何将yuv编码为h264,自己编码或者ffmpeg都可以。