理解YUV

作者: 村口大白杨 | 来源:发表于2019-03-28 16:23 被阅读0次
    一、什么是 YUV

    和 RGB 和 CMYK 一样,YUV 也是一种颜色编码方法,被广泛用于多媒体领域中。YUV 本身有多种变种,比如 Y'UV,、YUV、YCbCr、YPbPr 等都可以称为 YUV。其中 Y 都表示亮度,UV 表示两个色度分量,但是具体颜色编码的用途又各不相同。在电视系统发展的早期,YUV 和 Y'UV 都是颜色信息的模拟信号编码形式,虽然 Y 和 Y’ 都表示亮度,但是两种亮度的意义却天差地别,Y 表示的是自然颜色的亮度,而 Y’ 表示的是经过伽马压缩之后电信号的强度。在现在的计算机系统中,YUV 一般用来代指 YCbCr ,用来表示图像的编码格式,用于数字视频、图像的压缩和传输。而 YPbPr 常常用在模拟分量视频中。本文将主要讨论计算机系统中的 YUV,也就是 YCbCr。

    YUV 数据是由 Y、U、V 三个分量组成。Y 表示明亮度(Luminance、Luma),占 8 bit(1 字节),YUV 从颜色属性上来说是亮色分离的,亮度信号 Y 和色度信号 UV 是分离开来的,Y 是透过 RGB 输入信号来建立的,方法是将 RGB 信号的特定部分叠加到一起。U 和 V 则表示色度、浓度(Chrominance、Chroma),作用是描述影像色彩及饱和度,用于指定像素的颜色;Cb(U):蓝色色度分量,占 8 bit(1 字节),Cr(V):红色色度分量,占 8 bit(1 字节),其中 Cr 反映了RGB 输入信号红色部分与 RGB 信号亮度值之间的差异。而 Cb 反映的是 RGB 输入信号蓝色部分与 RGB 信号亮度值之间的差异。

    为了了解 YUV 格式的优点,不妨先简单和我们熟悉的 RGB 格式做一个对比。

    二、什么是 RGB

    RGB 数据由 R、G、B 三个分量组成。R(红色)、G(绿色)、B(蓝色)即我们所说的三原色。RGB 是从颜色的原理来设计制定的,采用混色法把 RGB 进行不同权重的混叠就可以得到不同的颜色。通俗点说它的颜色混合方式就好像有红、绿、蓝三盏灯,当它们的光相互叠合的时候,色彩相混,而亮度却等于两者亮度之总和,越混合亮度越高,即加法混合。红、绿、蓝三个颜色分量每种色各分为 256 阶亮度,在 0 时“灯”最弱是关掉的,而在 255 时“灯”最亮。当三色灰度数值相同时,产生不同灰度值的灰色调,即三色灰度都为 0 时,是最暗的黑色调;三色灰度都为 255 时,是最亮的白色调。用数学的排列组合来算的话,RGB 能表示 256 * 256 * 256 = 16777216 种颜色,也就是 1600 万色,即通常所说的24位真彩色。

    三、YUV 和 RGB 的优缺点

    1、采用 YUV 数据格式的图像体积更小,传输时占用更少的频宽。

    平时我们所看到的图像,是由一个个像素点组成的,像素格式用 RGB 方式表示的图像,每一个像素点都是由 R、G、B 三种颜色分量表示的。比如 RGB888(R、G、B 每个分量都占 8 bit),所以用 RGB888 表示的每个像素点就占用 24 bit(3 字节)。那么对于一张像素 512x512,采用 RGB888 像素格式的图片,所占用的大小就是 512 x 512 x 3 = 786432 字节。这是针对于 JPG,如果是 PNG 图片,还会多出一个透明分量,同样分辨率的图片,所占用的内存会更大一些。

    如果使用 YUV 格式数据去表示像素点,我们可以在不影响画质的基础上对人眼不敏感的色度信息 UV 进行压缩,那么压缩后每个像素可以减小至平均只占用 12 bit(1.5 字节),后面色度二次采样中将详细介绍;所以对于同样一张像素大小的图片,使用 YUV 像素格式表示或存储,体积将是采用 RGB888 像素格式图片的一半。

    2、YUV 比 RGB 兼容性更好。

    YUV 的发明是处在彩色电视和黑白电视的过渡时期。早期技术不发达时,黑白电视机只能实现黑白的灰度显示,所以 Y 数据就成了标准。之后有了彩色电视机,此时有些家庭用的是黑白电视机,有些家庭用的是彩色电视机,如何给两种电视提供信号呢?如果分开处理的话,给黑牌电视机提供一种信号,给彩色电视机提供另一种信号。针对不同电视提供不同信号,成本必然会有点高。有没有办法给黑白电视机和彩色电视机提供同一种信号呢?为了兼容之前的黑白数据,厂商发明了 UV 数据。YUV 一起就可以实现彩色,单独使用 Y 可以实现黑白,这样一套数据格式就同时兼容了黑白电视机和彩色电视机。使黑白电视也能够接收彩色电视机信号,只不过它只显示了 Y 数据分量。

    RGB 缺乏与早期黑白显示系统的兼容性。

    不管是存储传输还是兼容性, YUV 比 RGB 更有优势,那为什么还要保留 RGB 格式呢?由于所有的显示器都采用 RGB 值来驱动,所以在显示每个像素之前,需要把 YUV 值转换成 RGB 值。接下来介绍 YUV 和 RGB 的转换。

    四、YUV 和 RGB 相互转换

    一般解码后的视频格式是 YUV 格式,但是渲染格式一般是 RGB 格式,所以需要对二者进行转换。这里涉及到 Color Range 这个概念,Color Range 分为两种,一种是 Full Range,另一种是 Limited Range。Full Range 的 R、G、B 取值范围都是 0~255。而 Limited Range 的 R、G、B 取值范围是 16~235。对于每种 Color Range 来说,还有不同的转换标准,常见的标准主要是 BT601 和 BT709(BT601 是标清的标准,BT709 是高清的标准,BT.2020 是超清画幅的标准)。所以不同 Color Range 和 BT601、BT709 两种标准,组合起来就有 4 种转换公式。

    BT.601 标准 - Limited Range:

    Y = 0.299R + 0.587G + 0.114B
    U = -0.127R - 0.339G + 0.511B + 128 
    V = 0.411R - 0.428G - 0.083B + 128 
    
    R = Y + 1.371(V - 128)
    G = Y - 0.336(U - 128) - 0.698(V - 128)
    B = Y + 1.732(U - 128)
    

    BT.601 标准 - Full Range:

    Y = 0.257R + 0.504G + 0.098B + 16 
    U = -0.148R - 0.291G + 0.439B + 128 
    V = 0.439R - 0.368G - 0.071B + 128 
    
    R = 1.164(Y - 16) + 1.596(V - 128) 
    G = 1.164(Y - 16) - 0.392(U - 128) - 0.812(V - 128) 
    B = 1.164(Y - 16) + 2.016(U - 128)
    

    BT.709 标准 - Limited Range:

    Y = 0.213R + 0.715G + 0.072B
    U = -0.117R - 0.349G + 0.511B + 128
    V = 0.511R - 0.464G - 0.047B + 128
    
    R = Y + 1.540(V - 128)
    G = Y - 0.183(U - 128) - 0.459 (V - 128)
    B = Y + 1.186(U - 128)
    

    BT.709 标准 - Full Range

    Y = 0.183R + 0.641G + 0.062B + 16
    U = -0.101R - 0.339G + 0.439B + 128 
    V = 0.439R - 0.339G - 0.040B + 128 
    
    R = 1.164(Y-16) + 1.792(V - 128) 
    G = 1.164(Y-16) - 0.213(U - 128) - 0.534(V - 128) 
    B = 1.164(Y-16) + 2.114(U - 128)
    

    RGB 转 YUV 可以认为是一种压缩,这是不影响视觉的压缩,对画质没有影响 ,但是这不是最终的压缩,可以进一步的压缩,比如使用 libx264 可以压缩到更小。

    五、色度二次采样

    前面提到了,我们可以对色度信息 UV 进行压缩,其原理是我们的人眼视网膜上分布着两种感光细胞,视杆细胞和视锥细胞。视杆细胞可以感知光线的强弱,但是没有色彩识别功能,主要负责夜间非彩色视觉。视锥细胞可以感知颜色,主要负责白天彩色视觉,那么如果视锥细胞发育不正常,数量太少,感知颜色就会受阻,可能会导致色弱。人眼中有上亿个感光细胞,其中视杆细胞占 95%,而视锥细胞仅占 5%。因此,人眼对亮度的敏感程度要高于对色度的敏感程度,人眼对于亮度的分辨率要比对颜色的分辨率精细一些。如果把图像的色度减少一些,人眼也丝毫感觉不到变化和差异。

    如果在色度分量 UV 上进行较低分辨率的采样(相对于亮度分量 Y),也就是存储较多的细节、较少的色度细节,这样就在不明显降低画面质量的同时减小图像的体积。这个过程称为色度二次采样(Chroma Subsampling)。

    1、采样格式

    采样格式通常用 A:B:C 的形式表示,比如 4:4:4、4:2:2、4:2:0 等,其中我们最关注的是 4:2:0。
    A:一块 A * 2 像素的概念区域,一般都是 4
    B:第 1 行的色度采样数目
    C:第 2 行的色度采样数目(C 的值一般要么等于 B,要么等于 0)


    色度二次采样

    上图中,不管是那种采样格式,Y 分量都是全水平、全垂直分辨率采样的,每一个像素都有自己独立的 Y 分量。

    2、4:4:4

    第一行采集 4 组 CbCr 分量,第 2 行采集 4 组 CbCr 分量;
    每 1 个像素都有自己独立的 1 组 CbCr 分量 ;
    Y 分量与 CbCr 分量的水平方向比例是 1:1;
    Y 分量与 CbCr 分量垂直方向比例是 1:1;
    Y 分量与 CbCr 分量的总比例是 1:1;
    1 个像素占用 24 bit(3 字节),24bpp(bits per pixel)。这种格式是没有进行二次采样的。


    4:4:4

    叉号代表亮度;
    圆圈代表色度;

    3、4:2:2

    第 1 行采集 2 组 CbCr 分量,第 2 行采集 2 组 CbCr 分量;
    水平方向相邻的 2 个像素(1 行 2 列)共用 1 组 CbCr 分量;
    Y 分量与 CbCr 分量水平方向的比例是 2:1;
    Y 分量与 CbCr 分量垂直方向的比例是 1:1;
    Y 分量与 CbCr 分量的总比例是 2:1;
    1 个像素平均占用 16 bit(2 字节),16bpp,因为 2 个像素共占用 32 bit(4 字节 = 2 个 Y 分量 + 1 个 Cb 分量 + 1 个 Cr 分量)

    4:2:2

    4、4:2:0

    第 1 行采集 2 组 CbCr 分量,第 2 行不采集 CbCr 分量,第 2 行共享第 1 行的 CbCr 分量;
    相邻的 4 个像素(2 行 2 列)共用 1 组 CbCr 分量;
    Y 分量与 CbCr 分量水平方向的比例是 2:1;
    Y 分量与 CbCr 分量垂直方向的比例是 2:1;
    Y 分量与 CbCr 分量的总比例是 4:1;
    1 个像素平均占用 12 bit(1.5 字节),12bpp,因为 4 个像素共占用 48 bit(6 字节 = 4 个 Y 分量 + 1 个 Cb 分量 + 1 个 Cr 分量)


    4:2:0
    六、存储格式

    存储格式,决定了 YUV 数据是如何排列和存储的。本文只介绍一些常见的存储格式。

    1、存储格式分类

    YUV 的存储格式可以分为 3 大类:

    Planar(平面):
    Y、U、V 分量分开单独存储;
    名称通常以字母 p 结尾。

    Semi-Planar(半平面):
    Y 分量单独存储,U、V 分量交错存储 。

    Packed(紧凑):
    或者叫 Interleaved(交错);
    Y、U、V 分量交错存储。

    存储格式
    2、采样格式排列方式 存储格式排列方式

    可能会遇到一些图片的像素格式是 yuvj444p,yuvj444p 和 yuv444p 摆放是一样的,分量取值范围不一样。

    七、格式转换

    1、其他图片格式转 YUV:

    $ ffmpeg -i in.png -s 512x512 -pix_fmt yuv420p out.yuv
    

    上述命令生成的 YUV 文件大小是 512 x 512 x 1.5 字节 = 393216 字节

    -s
    设置图片的尺寸;
    可以用一些固定字符串表示,比如 hd720 表示 1280x720(Video-size文档:https://ffmpeg.org/ffmpeg-all.html#Video-size);
    如果不设置此选项,默认会跟随输入图片的尺寸。

    -pix_fmt
    设置像素格式;
    可以通过命令 $ ffmpeg -pix_fmts 查看 FFmpeg 支持的像素格式;
    如果不设置此选项,默认会跟随输入图片的像素格式,比如可能是 rgb24、rgba8、pal8 等。可以通过 ffprobe 查看某图片的像素格式。

    2、YUV 转其他图片格式

    $ ffmpeg -s 512x512 -pix_fmt yuv420p -i in.yuv out.jpg
    

    这里必须设置 YUV 输入文件的尺寸(-s)、像素格式(-pix_fmt)

    八、显示 YUV

    可以通过 ffplay 显示 YUV 数据。YUV 中直接存储的是所有像素的颜色信息(可以理解为是图像的一种原始数据)

    必须设置 YUV 输入文件的尺寸(-s)、像素格式(-pix_fmt)才能正常显示。

    $ ffplay -s 512x512 -pix_fmt yuv420p in.yuv 
    
    # 在ffplay中
    # -s已经过期,建议改为:-video_size
    # -pix_fmt已经过期,建议改为:-pixel_format
    $ ffplay -video_size 512x512 -pixel_format yuv420p in.yuv
    

    可以使用过滤器(filter)显示其中的单个分量(R、G、B、Y、U、V),FFmpeg 文档:https://ffmpeg.org/ffmpeg-filters.html

    # 只显示 R 分量
    $ ffplay -vf extractplanes=r in.png 
    
    # 只显示 G 分量
    $ ffplay -vf extractplanes=g in.png 
    
    # 只显示 B 分量
    $ ffplay -vf extractplanes=b in.png
    
    # 只显示 Y 分量
    $ ffplay -video_size 512x512 -pixel_format yuv420p -vf extractplanes=y in.yuv 
    
    # 只显示 U 分量
    $ ffplay -video_size 512x512 -pixel_format yuv420p -vf extractplanes=u in.yuv 
    
    # 只显示 V 分量
    $ ffplay -video_size 512x512 -pixel_format yuv420p -vf extractplanes=v in.yuv
    

    -vf
    设置视频过滤器,等价写法:-filter:v,后面可以跟上一些命令,比如 -vf extractplanes=r;(同样也会有 -af,等价写法:-filter:a

    extractplanes
    extrac 意思是抽取,planes 意思是平面,用来抽取单个分量的内容到灰度视频流中。

    每个分量展示出来的效果是灰度图,灰度图体现了分量值的大小。通过我们刚刚导出的灰度图,我们可以发现(图片本身分辨率是 w * h):

    1、RGB888 格式
    R 分量灰度图的分辨率是 w * h
    G 分量灰度图的分辨率是 w * h
    B 分量灰度图的分辨率是 w * h

    2、YUV 4:4:4 采样格式
    Y 分量灰度图的分辨率是 w * h;(全水平分辨率,全垂直分辨率)
    U 分量灰度图的分辨率是 w * h;(全水平分辨率,全垂直分辨率)
    V 分量灰度图的分辨率是 w * h。(全水平分辨率,全垂直分辨率)

    3、YUV 4:2:2 采样格式
    Y 分量灰度图的分辨率是 w * h;(全水平分辨率,全垂直分辨率)
    U 分量灰度图的分辨率是 w/2 * h;(1/2 水平分辨率,全垂直分辨率)
    V 分量灰度图的分辨率是 w/2 * h。(1/2 水平分辨率,全垂直分辨率)

    4、YUV 4:2:0 采样格式
    Y 分量灰度图的分辨率是 w * h;(全水平分辨率,全垂直分辨率)
    U 分量灰度图的分辨率是 w/2 * h/2;(1/2 水平分辨率,1/2垂直分辨率)
    V 分量灰度图的分辨率是 w/2 * h/2。(1/2 水平分辨率,1/2垂直分辨率)

    相关文章

      网友评论

        本文标题:理解YUV

        本文链接:https://www.haomeiwen.com/subject/rdzfbqtx.html