在上一篇文章中,我们带大家了解了视频、图像、像素和色彩之间的关系,还初步认识了两种常用的色彩空间,分别是大家比较熟悉的 RGB,以及更受视频领域青睐的 YUV。今天,我们将继续深入学习 RGB、YUV 的相关内容,进一步了解它们的常见采样格式和存储格式。

色彩的采样格式和存储格式影响我们处理图像的方式,只有使用正确的方式,才能呈现正确的图像效果。

RGB 的采样和存储

我们已经知道,图像由像素组成,而像素通过记录色彩空间各分量呈现各种各样的色彩。对于 RGB 色彩空间,其三个分量 R(红)、G(绿)、B(蓝),它们之间具有相关性,对于色彩的表示来说缺一不可。

所以,RGB 的每个像素都会完整采样三个分量,采样比例为 1:1:1(指每个分量的采样数,而非每个分量的数值)。也正是因为这种采样要求,RGB 颜色空间在采集上不好进行数据压缩,不太适用于视频图像的编码、传输。

RGB 三个分量采样后,在内存中是依次排列存储的。但是,它们的存储顺序不一定是字面描述的 R、G、B。不同的应用场景,因处理逻辑差异可能会使用不同的规则。比如,MATLAB 使用的存储顺序为 R、G、B,而 OpenCV 则使用 B、G、R,如下图所示:

R、G、B 顺序

B、G、R 顺序

我们把 RGB 字面描述的分量顺序,称为字面序,将其实际存储的分量顺序,称为字节序。确定好色彩空间存储的字节序,是正确处理图像的前提,如果随意对各分量进行读取,可能会导致处理后的颜色出现异常。下图,即为使用 RGB 顺序读取字节序为 BGR 的图片的效果,此时,由于将 B、R 分量混淆了,得到了错误的图片颜色。

左一:原图,存储格式为 BGR;左二:使用 RGB 格式进行读取

另外,大家还也会接触到 BGRA 这样的存储格式(比如在 iOS、MAC 上处理摄像头数据),其中的 A ,表示在 RGB 三个通道基础上,增加了一个透明度通道 Alpha,用于调整色彩的透明度,实现更丰富的色彩效果。对于增加了透明度的RGB,同样需要留意其实际的存储顺序,常见的有 BGRA、RGBA、ABGR 和 ARGB 等等。

总之,RGB 的采样格式、存储格式相对比较简单,我们也不做过多的展开。正如上篇文章所述,在视频处理领域,YUV 色彩空间才是主角,它的采样格式、存储格式相对于 RGB 也更加复杂

YUV的采样和存储

1、YUV 的采样格式

大家已经知道,区别于 RGB 色彩空间,YUV 色彩空间的三个分量并非都参与颜色的表示,即便仅存在亮度分量 Y,也能呈现黑白灰的图像轮廓。而人眼对于色度分量 U、V 不是特别敏感,减少一些也不会太影响观感。这种特性体现到采样上,意味着允许我们少采集 U、V 分量、甚至于不采集 U、V 分量(黑白图像),从而在采集上实现可观的数据压缩。按 U、V 分量的采集方式不同,主流的 YUV 采样格式有:YUV 4:4:4,YUV 4:2:2 和 YUV 4:2:0 几种。

看到 “ YUV A:B:C ” 这种标识格式,大家是否很容易将其理解为 “ Y:U:V = A:B:C ”?这种理解是符合直觉的,但并不正确。实际上, "A:B:C" 格式并不是将 YUV 拆分为 3 个分量、然后按 A:B:C 的比例采集,而是基于一个 “宽度为 A 个像素、高度为 2 个像素” 的采样区域,将 UV 分量作为一个整体进行采样,然后描述 UV 分量组相对于 Y 分量的采样率。

宽 A 个像素、高 2 个像素的区域

上面的解释可能比较笼统,要理解 YUV A:B:C 的采样逻辑,我们可以将其先进行拆解,整理为清晰可参考的 “规则”,再结合 “规则” 和实际案例进行分析。对于采样格式 YUV A:B:C 相关 “规则” 的一种理解如下:

  • 对于一个宽度为 A 个像素、高度为 2 个像素的采样区域(两行四列)

  • 第一行需要采样 A 个亮度分量 Y,B 个色度分量组 UV

  • 第二行需要采样 A 个亮度分量 Y,C 个色度分量组 UV

  • 如果 C 为0,则表示第二行不再重新采样 UV 分量,而是复用第一行的 UV 采样

接下来,我们针对主流的 YUV 采样格式,依据上述规则作具体解析,来帮助大家理解。

首先,我们来看看 YUV 4:4:4 采样格式。参照上述“规则”,解析如下:

  • 对于一个宽度为 4 个像素、高度为 2 个像素的采样区域

  • 第一行需要采样 4 个亮度分量 Y,4 组色度分量 UV

  • 第二行需要采样 4 个亮度分量 Y,4 组色度分量 UV

除了文字解析外,我们还可以结合图例来观察。如果用空心圆圈表示 Y 分量,实心圆(蓝色)表示 UV 分量,则 YUV 4:4:4 采样逻辑可以表示为下图(图例颜色不代表实际采样颜色):

YUV 4:4:4

参考上面的图文说明,我们发现,在 YUV 4:4:4 采样格式下 ,每采样一个 Y 分量、就要相应地采样一组 UV 分量。显然,此时 UV 分量组相对于 Y 分量在宽度方向(水平)、高度方向(竖直)上均为等采样,不存在降采样的情况,也即 Y:UV = 1:1。这意味着,在 YUV 4:4:4 采样下,每个元素都包含独立、完整的亮度分量和色度分量。

YUV 4:4:4 采样相对还比较简单,大家肯定都能理解,我们再来看看 YUV 4:2:2。

参照“规则”,我们将 YUV 4:2:2 采样解析如下:

  • 对于一个宽度为 4 个像素、高度为 2 个像素的采样区域

  • 第一行需要采样 4 个亮度分量 Y,2 组色度分量 UV

  • 第二行需要采样 4 个亮度分量 Y,2 组色度分量 UV

其对应的图例如下:

YUV 4:2:2

参考图例,YUV 4:2:2 采样中,UV 分量组相对于 Y 分量在宽度方向有降采样,水平每两个 Y 分量将共用一个 UV 分量组,也即 Y : UV = 2 : 1。高度方向上未进行降采样,第二行使用与第一行相同的采样逻辑,重新采样两组独立的 UV 分量。显然,由于宽度方向有降采样,YUV 4:2:2 对 UV 分量的采样比 YUV 4:4:4 更少。但基于 YUV 的特性,虽然少采样了部分 UV 分量,也不会太影响画面的色彩,这就在色彩保真的前提下,实现了采集数据的压缩。

以上,我们利用 “规则”,对 YUV 4:4:4 和 YUV 4:2:2 两种采样格式进行了解析。参考解析的结论,你可能会有一个疑问:目前讨论的两种采样格式,似乎并没有推翻 Y:U:V = A:B:C 的 “猜测” ?我们是否误解了它?

当然不是,我们还一个采样格式没有解析,那就是 YUV 4:2:0。

如果按 Y:U:V = A:B:C 的逻辑,YUV 4:2:0 即表示 “ 仅对 Y、U 分量按 4:2 的比例采样,不采集 V 分量 ”。这是一个错误的结论,YUV 4:2:0 采样中仍然包含 YUV 三种分量,UV 分量并未脱离彼此。究竟该怎么理解 YUV 4:2:0 ,问题越是蹊跷,我们越是要冷静,不妨继续参照“规则”,对 YUV 4:2:0 进行拆解:

  • 对于一个宽度为 4 个像素、高度为 2 个像素的采样区域

  • 第一行需要采样 4 个亮度分量 Y,2 组色度分量 UV

  • 第二行需要采样 4 个亮度分量 Y,0 组色度分量 UV

  • 第二行需要复用第一行采样的色度分量组 UV

先从文字说明上理解,YUV 4:2:0 的采样逻辑相对于 YUV 4:2:2 的不同在于,它不仅在宽度方向上做了降采样,在高度方向上也做了“手脚”。采样区域的第二行,将不再采集独立的 UV 分量组,而是复用第一行的采样结果。

现在,我们再来看看图例:

YUV 4:2:0

从图例上看,YUV 4:2:0 在宽度方向、高度方向综合起来,每 4 个 Y 分量(2 X 2 的采样区域)将共用一个 UV 分量。

现在,你肯定对 YUV 4:2:0 采样有了更清晰的认识,也明白了为什么 “ Y:U:V = A:B:C ” 是一个错误的“猜测”。同时,参考对 YUV 4:2:2 的分析,我们还可以推断,由于 YUV 4:2:0 进一步降低了对 UV 分量的采样,其采样数据量相对于 YUV 4:2:2 更少,数据得到进一步压缩。

除了以上三种主流的采样格式,YUV 采样格式还有诸如 YUV 4:1:1 等形式,我们就不做展开了。大家只要理解了 “A:B:C” 的规则逻辑,就能举一反三、融汇贯通。虽然 YUV 采样格式众多,但其模型的共性可总结为:每个像素都会采样亮度分量 Y,但N个像素可能会共用一组色度分量 UV,后者的差异也带来了采样数据量的差异。

关于 YUV 的采样格式我们就先了解到这里,确定采样格式对于正确处理 YUV 图像是至关重要的,如果采样格式判定错误,会读取到异常的图像。

如下,为基于 YUV444 采样格式读取 YUV420 格式图片的一种异常效果:

左一:原图,YUV420;左二:基于 YUV444 读取YUV420

了解采样格式后,就需要考虑如何进行存储,YUV 的存储格式也有好几类,并且一种采样格式还可以选择不同的存储格式,不同采样格式搭配不同的存储格式,得到了不同的 YUV 类型,这些知识综合起来还是有一定理解和记忆难度的,大家跟着我的思路继续往下学习。

2、YUV的存储格式

在阐述 RGB 色彩空间的存储格式时,我们重点关注了各个分量存储时的 “排列方式”,依据排列的顺序不同得到了 RGB 和 BGR 两种存储格式。在学习 YUV 的存储时,我们也可以借鉴这个思路。

比较特殊的是,我们现在要引入数组,来表示 YUV 的一种存储结构**:平面(Plane)。我们使用一个数组表示一个存储 “平面” ,N个不同的数组即为 N 个平面。基于平面的概念,再按 YUV 存储时的各分量的排列顺序不同、使用的平面数量不同,我们可以将 YUV 存储格式分为三大类:打包模式(Packed)、平面模式(Planar)和 半平面模式(Semi-Planar)。**

我们先了解下各个模式的规则概述:

  • 打包模式(Packed):使用一个平面进行存储。在平面1上,将每个像素的 Y、U、V 分量打包后连续、交错存储;

  • 平面模式(Planar):使用三个平面进行存储。在平面1上,先连续存储所有像素点的 Y 分量;然后在平面2上,存储所有像素点的 U 分量;最后在平面3上,存储所有像素点的 V 分量( U 和 V 的顺序可以交换);

  • 半平面模式(Semi-Planar):使用两个平面进行存储。在平面1上,先连续存储所有像素点的 Y 分量;然后在平面2上,连续、交错存储所有像素点的 U、V分量( U 和 V 的顺序可以交换)。

以上规则的描述,还是比较清晰的,我们下面结合具体的采样格式,看看不同采样格式、在不同存储格式下的具体表现。为便于理解,我们仍然基于 “宽度为 4 个像素、高度为 2 个像素” 的采样区域作讲述。

2.1 YUV 4:4:4 的存储格式

YUV 4:4:4 采样格式比较简单,相应的,其对应的存储格式也比较好理解。YUV 4:4:4 使用打包模式(Packed)进行存储时,4x2 像素采样区域的存储图示如下:

打包模式仅使用一个平面即可,我们可以将这个存储平面视为一个 12x2 的数组。

YUV 4:4:4 如果使用平面模式(Planar)进行存储,如下图:

可以看到,从打包模式变为平面模式,存储平面增加了两个。YUV 各分量分别存储在不同的平面,每个平面均为一个 4x2 的数组。在 YUV 4:4:4 采样、平面模式存储下,如果按先 Y、再 U 、最后 V 的顺序存储,我们称这种 YUV 类型为 I444。如果调整存储顺序为先 Y、再 V 、最后 U,得到 YUV 类型为 YV24 。

最后,我们再来看看 YUV 4:4:4 使用半平面模式(Semi-Planar)存储的效果:

半平面模式下,存储平面为两个,分别存储 Y 分量和 UV 分量。其中存储 Y 分量的平面为 4 x 2 的数组,存储 UV 分量的平面为 8 x 2 的数组。YUV 4:4:4 采样、半平面模式存储下,如果第二个平面按 U、V 的顺序存储,对应的 YUV 类型为 NV24。若使用 V、U 的顺序存储,则为 NV42。

以上,即为 YUV 4:4:4 采样在不同存储格式的表现,以及各种采样格式、存储格式搭配得到的不同 YUV 类型。接下来,按照相同的思路,我们看看 YUV 4:2:2、YUV 4:2:0 的表现。

2.2 YUV 4:2:2 的存储格式

YUV 4:2:2 下各个分量的采样逻辑已经讨论过,结合上文,可简要概括为 “ Y分量全采集,宽度方向每两个 Y 分量共用一组 UV 分量,高度方向每行独立采集 UV 分量 ”,如果你对此不是很理解,可以回到 2.1 节再复习一下。

YUV 4:2:2 使用打包模式(Packed)存储,效果如下图(浅蓝色填充的每组 UV 分量,属于左右两个 Y 分量共用的采样):

YUV 4:2:2 打包模式存储下,唯一平面为 8x2 的数组,每个 Packed 内部的顺序为 Y U V Y,并且遵循两个 Y 共用一组 UV 的特征,其得到的 YUV 格式为 YUVY(和 Packed 内顺序一致)。类似的,按照 Packed 内各分量顺序不同,还可以得到 YUV 类型 VYUY 和 UYVY。

YUV 4:2:2 使用平面模式(Planar)存储,效果如下:

YUV 4:2:2 平面模式存储下,三个平面分别为 4x2、2x2、2x2 的数组,若后两个平面先存 U 后存 V ,则得到 YUV 类型 I422。若先存 V 后存 U ,则得到 YUV 类型 YV16。

YUV 4:2:2 使用半平面模式(Semi-Planar)存储,效果如下:

YUV 4:2:2 半平面模式存储下,两个平面均为 4x2 的数组,第二个平面内,若按 U、V 顺序交错存储,则得到 YUV 类型 NV16。若按 V、U 顺序交错存储,则得到 YUV 类型 NV61。

2.3 YUV 4:2:0 的存储格式

以上,YUV 4:4:4 和 YUV 4:2:2 的主要存储格式已介绍完毕,最后我们再来看看最常用的采样格式 YUV 4:2:0 的存储。YUV 4:2:0 主要使用平面模式(Planar)和 半平面模式(Semi-Planar)。

结合上文,YUV 4:2:0 采样可简要概括为 “ Y 分量全采集,宽度方向和高度方向每四个 Y 分量共用一组 UV 分量,即第二行复用第一行的 UV 采样”,如果你对此不是很理解,可以再回到 2.1 复习一下。

YUV 4:2:0 使用平面模式(Planar)存储:

YUV 4:2:0 平面模式存储下,三个平面分别为 4x2、2x1、2x1 的数组,若后两个平面先存 U 后存 V ,则得到 YUV 类型 I420。若先存 V 后存 U ,则得到 YUV 类型 YV12。

YUV 4:2:0 使用半平面模式(Semi-Planar)存储:

YUV 4:2:0 半平面模式存储下,两个平面分别为 4x2、4x1 的数组,第二个平面若按 U、V 顺序交错存储,则得到 YUV 类型 NV12。若按 V、U 顺序交错存储,则得到 YUV 类型 NV21。

以上,即为 YUV 主流采样格式在不同存储模式下的表现,以及各种组合搭配得到的不同 YUV 类型。值得一提的是,在诸多 YUV 类型中,NV21 是 Android 系统相机使用的类型,而 NV12 被 iOS、MAC 系统相机使用(前面提到,iOS 和 MAC 也会使用 BGRA),大家今后会经常遇到它们,可以优先熟悉熟悉。

与 RGB 一样,我们只有确认了 YUV 图像的存储格式,才能对其进行正确地处理,使用错误的格式会导致颜色异常。

如下,原图为使用平面模式存储、先存 U 平面、再存 Y 平面的 YUV420 图像(I420),如果按 YV12 格式读取(平面模式存储、先存 V 平面、再存 U 平面)将得到图2。

左一:原图,I420;左二:基于 YV12 读取 I420

为方便查阅,我们再将上面提及的,不同采样格式、存储模式、UV 存储顺序以及 YUV 类型的匹配关系,通过表格整理一下:

总结

不得不说,相较于 RGB,YUV 的采样格式和存储格式还是比较复杂的,组合得到的 YUV 类型也是眼花缭乱,你此时或许已云里雾里。这么多格式和类型,该如何去记忆呢?

答案是:无需死记硬背某种具体格式、类型的细节,当我们需要用到的时候,再查阅资料即可。我们需要重点掌握的,是对 “采样格式”、“存储格式” 概念规则的理解,在理解概念规则的基础上,对于任何种 YUV 类型,我们都可以按 “确认采样格式 → 确认存储格式 → 确认 UV 存储顺序” 的思路进行分析,如前面所说,做到融会贯通方可举一反三。

最后,我们通过一个思维导图,梳理一下本篇文章的知识脉络:

本期思考题

请参照 YUV 采样格式的“规则”,说明 YUV 4:1:1 的采样逻辑?

(下期揭秘)

上期思考题 揭秘 ️

问:

RGB颜色空间也能表示黑白色和彩色,为什么还需要YUV来解决黑白电视和彩色电视之间的兼容互通问题呢?

答:

在黑白电视向彩色电视的过渡期,两种类型的电视系统需要共存互通。RGB 色彩空间可以满足彩色电视的显示需求,也完全能胜任黑白画面的显示任务,但是如果统一使用RGB色彩空间,会存在如下问题:

1、RGB 即使只表示黑白,也需要存储三个分量,只不过各分量的值均是0或1。而黑白电视作为旧系统,只能处理一个亮度分量,无法向前兼容RGB;

2、RGB 必须使用三个通道,会极大增加传输带宽的压力。

而 YUV 很好地解决了上述问题:

1、黑白电视可以仅接收 Y 信号、忽略 U、V 信号,向后兼容;

2、YUV 可以与 RGB 无损转换,向前兼容;

3、YUV 可以对 UV 分量进行降采样,降低数据量同时色彩保真,节省带宽。

音视频开发进阶——YUV与RGB的采样与存储格式的更多相关文章

  1. Android 音视频开发学习思路

    Android 音视频开发这块目前的确没有比较系统的教程或者书籍,网上的博客文章也都是比较零散的.只能通过一点点的学习和积累把这块的知识串联积累起来. 初级入门篇: Android 音视频开发(一) ...

  2. 音视频开发-FFmpeg

    音视频开发是个非常复杂的,庞大的开发话题,初涉其中,先看一下结合 OEIP(开源项目) 新增例子. 可以打开flv,mp4类型文件,以及rtmp协议音视频数据,声音的播放使用SDL. 把采集的麦/声卡 ...

  3. Python音视频开发:消除抖音短视频Logo和去电视台标

    ☞ ░ 前往老猿Python博文目录 ░ 一.引言 对于带Logo(如抖音Logo.电视台标)的视频,有三种方案进行Logo消除: 直接将对应区域用对应图像替换: 直接将对应区域模糊化: 通过变换将要 ...

  4. 堪称教科书级别的Android音视频入门进阶学习手册,开源分享!

    概述 随着整个互联网的崛起,数据传递的形式也在不断升级变化,总的流行趋势如下: 纯文本的短信,QQ -> 空间,微博,朋友圈的图片文字结合 -> 微信语音 -> 各大直播软件 -&g ...

  5. Android音视频开发(1):H264 基本原理

    前言 H264 视频压缩算法现在无疑是所有视频压缩技术中使用最广泛,最流行的.随着 x264/openh264 以及 ffmpeg 等开源库的推出,大多数使用者无需再对H264的细节做过多的研究,这大 ...

  6. Android IOS WebRTC 音视频开发总结(八十五)-- 使用WebRTC广播网络摄像头视频(下)

    本文主要介绍WebRTC (我们翻译和整理的,译者:weizhenwei,校验:blacker),最早发表在[编风网] 支持原创,转载必须注明出处,欢迎关注我的微信公众号blacker(微信ID:bl ...

  7. Android IOS WebRTC 音视频开发总结(八十三)-- 使用WebRTC广播网络摄像头视频(上)

    本文主要介绍WebRTC (我们翻译和整理的,译者:weizhenwei,校验:blacker),最早发表在[编风网] 支持原创,转载必须注明出处,欢迎关注我的微信公众号blacker(微信ID:bl ...

  8. Android IOS WebRTC 音视频开发总结(四六)-- 从另一个角度看国内首届WebRTC大会

    文章主要从开发者角度谈国内首届WebRTC大会,支持原创,文章来自博客园RTC.Blacker,支持原创,转载必须说明出处,更多详见www.rtc.help. -------------------- ...

  9. Android IOS WebRTC 音视频开发总结(六)-- iOS开发之含泪经验

    前段时间在搞webrtc iOS开发,所以将标题改为了Android IOS WebRTC 音视频开发总结, 下面都是开发过程中的经验总结,转载请说明出处(博客园RTC.Blacker): 1. IO ...

  10. WebRTC 音视频开发

    WebRTC 音视频开发 webrtc   Android IOS WebRTC 音视频开发总结(七八)-- 为什么WebRTC端到端监控很关键? 摘要: 本文主要介绍WebRTC端到端监控(我们翻译 ...

随机推荐

  1. VMware另一个程序锁定文件的一部分,进程无法访问

    问题描述:搭建RAC11g,在做共享磁盘的时候,节点2要共享节点1的磁盘,但是有一个问题,节点2关机之后,再打开,是有一个访问节点1的磁盘的过程,如果访问失败,就会开不了机器 rac1加的三个磁盘: ...

  2. MySQL(四)用户与权限管理

    用户与权限管理 用户管理 MySQL用户分为普通用户和root用户,提供了许多语句来管理包括登录.退出MySQL服务器.创建用户.删除用户.密码管理和权限管理等内容. 登录MySQL服务器 mysql ...

  3. Kubuesphere部署Ruoyi(三):持久化存储配置

    按照如下教程配置NFS 先服务器: https://kubesphere.io/zh/docs/v3.3/reference/storage-system-installation/nfs-serve ...

  4. 开心档之MySQL 连接

    MySQL 连接 使用mysql二进制方式连接 您可以使用MySQL二进制方式进入到mysql命令提示符下来连接MySQL数据库. 实例 以下是从命令行中连接mysql服务器的简单实例: [root@ ...

  5. JavaScript基础语法-变量

    JavaScript JavaScript - 变量 1. 概念 变量是用于存放数据的容器 通过变量名可以获取数据 并且数据是可修改的 2. 使用 声明变量 只声明不赋值 直接调用 程序会输出unde ...

  6. 利用Velero对K8S备份还原与集群迁移实战

    一.简介 Velero 是一款云原生时代的灾难恢复和迁移工具,采用 Go 语言编写,并在 github 上进行了开源,利用 velero 用户可以安全的备份.恢复和迁移 Kubernetes 集群资源 ...

  7. java递归算法之老鼠找路

    (上图出自B站韩顺平教育) 从上图的(1,1)处,寻找到(6,5)处的路线,红色格子是障碍 public class MiGong { public static void main(String[] ...

  8. Mybatis 坑(1)

    org.apache.ibatis.executor.ExecutorException: No constructor found in xxxx [Integer,String] 这种情况一般是类 ...

  9. Mapstruct使用报java: Couldn't retrieve @Mapper annotation

    检查代码报错 java: Couldn't retrieve @Mapper annotation jar包冲突,去掉一个Mapstructjar包.

  10. node服务端

    一,node起服务+数据交互+中间件 什么是node express koa node是js在后端运行时的一个环境 express,koa是基于node的框架,快速构建web应用 前后端交互方式 1. ...