LV01-图像-02-色彩空间-03-YUV

本文主要是色彩空间——YUV的相关笔记,若笔记中有错误或者不合适的地方,欢迎批评指正😃。

点击查看使用工具及版本
PC端开发环境 Windows Windows11
Ubuntu Ubuntu20.04.6的64位版本
VMware® Workstation 17 Pro 17.0.0 build-20800274
终端软件 MobaXterm(Professional Edition v23.0 Build 5042 (license))
Win32DiskImager Win32DiskImager v1.0
Linux开发板环境 Linux开发板 正点原子 i.MX6ULL Linux 阿尔法开发板
uboot NXP官方提供的uboot,NXP提供的版本为uboot-imx-rel_imx_4.1.15_2.1.0_ga(使用的uboot版本为U-Boot 2016.03)
linux内核 linux-4.15(NXP官方提供)
点击查看本文参考资料
点击查看相关文件下载
笔记相关文件链接链接:https://pan.baidu.com/s/1EWXfeCOHXaujSE_WwATfdQ?pwd=39w1 提取码:39w1

其实这一节的笔记是为后面的视频学习做铺垫,视频数据也是由一帧一帧的图像组成,在国内,一般都是使用25fps,就是1秒钟25帧图像,由于人眼的视觉停留,所以我们看到的画面就是运动的了。在视频原始数据中,常见的采样格式有YUV444、YUV420、RGB等。

一、YUV简介

1. 什么是YUV?

YUV,是一种颜色编码方法。常使用在各个影像处理元件中。之前了解的RGB 色彩空间更适合图像采集和显示, YUV 空间用于编码和存储则比较好。在存储和编码之前,RGB 图像要转换为 YUV 图像,而 YUV 图像在 显示之前通常有必要转换回 RGB。

YUV 色彩空间在音视频开发,编码压缩领域更加常用。常用的原因主要是涉及到 HVS (Human Visual System)人类视觉系统 对 色彩空间的感知能力。

视觉心理学研究表明,人的视觉系统对光的感知程度可以用两个属性来描述:亮度(luminance)色度(chrominance),这里的色度也叫做 饱和度或彩度,总之 色度的叫法有很多,要注意上下文来区分语义。

然后 色度感知 包含两个维度:色调(Hue)和 色饱和度(saturation)。色调是由光波的峰值定义的,描述的是光的颜色。色饱和度是由光波的谱宽定义的,描述的是光的纯度。

因此 HVS 对色彩的感知主要有 3个属性:亮度(luminance),色调(Hue)和 色饱和度(saturation)。也就是 YUV 色彩空间,Y 代表 亮度,U代表色调,V代表色饱和度。

经过大量研究实验表明,视觉系统 对 色度 的敏感度 是远小于 亮度的。所以可以对 色度 采用更小的采样率来压缩数据,对亮度采用正常的采样率即可,这样压缩数据不会对视觉体验产生太大的影响。简单来说就是用更少的数据/信息来表达 色度(chroma),用更多的数据/信息来表达 亮度(luminance)。

2. HVS 是怎么感知 YUV?

首先我们需要一张YUV图片:meigui_yuv_444.rar - 蓝奏云 (lanzouj.com),下载完毕后解压,我们会得到这样一张yuv格式的图片,但是是打不开的:

image-20240622101759453

用什么打开?我们需要用支持YUV数据查看的软件,如YUVviewer: YUVviewer (gitee.com)YUV Player7yuv等,7yuv这个软件好像是要收费,功能比较多,网上随便找找,都有绿色版本,YUVviewer还带自己编译,YUV Player的话只能单独查看Y分量吧我记得,反正后来没有用。最后我用的是这个7zyuv:

image-20240622110512701

打开meigui_yuv_444这个文件,打开后要配置一下,左边的Format中选择YUV444 planar,长宽选择650x487,右侧的YUV全部勾选,就可以看到彩色的图片啦。我们若是只勾选了 Y 分量显示,可以看到是一个黑白图像,Y 是亮度,黑色越亮就会变成灰色,灰色越亮就会变成白色。

image-20240622110713382

然后我们只勾选 Y 跟 U 两个分量,注意看叶子跟花朵,可以看出来,已经能看到绿色跟红色了,但是他们非常原始,是暗红跟暗绿的颜色。

image-20240622110752252

最后,把 V (色饱和度)也勾上,可以看到,暗红 变成了玫瑰红,暗绿 变成了 青绿色。

image-20240622110815174

为什么 RGB 色彩空间不符合 HVS 的感知能力

我们来看一张图片juren.rar - 蓝奏云 (lanzouj.com),里面是 RGB24 真彩色数据。然后同样用刚才的7yuv打开:

image-20240622112910361

我们分别只勾选RGB,来看一下效果:

image-20240622113318726

可以看到蓝色明显更暗,其他两个更亮一些,这 3 个 分量都跟 亮度密切相关,所以针对 HVS 的压缩技巧,在 RGB 色彩空间 不方便使用。

3. YUV的分类?

在网上还会看到一些其他的描述:Y’UV、YUV、YCbCr、YPbPr 等。由于历史关系,Y’UV、YUV 主要是用在彩色电视中,用于模拟信号表示。YCbCr 是用在数字视频、图像的压缩和传输,如 MPEG、JPEG。今天我们所讲的 YUV 其实就是指 YCbCr。其中 Y 表示亮度(luma),CbCr 表示色度(chroma)。其实 Y 是明亮度,用来表示像素的灰度值,U、V 分别是影像色彩与饱和度,用来表示像素的颜色。总的来说它其实与RGB一样表示一个像素点的颜色,RGB和YUV之间是可以互相转换的。

分量 说明
Y 表示亮度分量,如果只显示Y的话,图像看起来会是一张黑白照。
U(Cb) 表示蓝色色度分量:是照片蓝色部分去掉亮度(Y)。
V(Cr) 表示红色色度分量:是照片红色部分去掉亮度(Y)。

总的来说,YUV 其实目前有 三种分类:

  • YIQ,适用于NTSC彩色电视制式
  • YUV,适用于PAL和SECAM彩色电视制式
  • YCbCr,适用于计算机用的显示器

互联网音视频开发中 一般说的 YUV 是 指 YCbCr ,U 就是 Cb,V 就是 Cr。我们会经常在一些音视频书籍看到 YCbCr ,把它当成是 YUV 就行。实际上 YCbCr 才是比较准确的术语,JPEG、MPEG 标准 用的也是 YCbCr 。后面学习的 YUV 也是指 YCbCr ,不是指 用于PAL和SECAM彩色电视 的 YUV。

4. YCbCr中的CbCr

我们来看一下CbCr 这两个通道信息。YUV 里面的 U 就是 Cb ,术语是 色调(Hue)。V 就是 Cr ,术语是 色饱和度(saturation)。实际上可以把 UV 看成是 ,colour difference (色彩的差异),可以看下面三个公式:

1
2
3
Cb = Blue - Y
Cr = Red - Y
Cg = Green - Y

Cb 代表 蓝色 色度的分量,是通过 RGB 里面的 B 的值 减去 Y 的值得到的。Cr 代表 红色 色度的分量,是通过 RGB 里面的 R 的值 减去 Y 的值得到的。Cg 代表 绿色色 色度的分量,是通过 RGB 里面的 G 的值 减去 Y 的值得到的。Cb 跟 Cr 的颜色空间 如下图:

YCbCr-CbCr_Scaled_Y50

为了直观感受 CbCr 值的影响,需要使用一个 YUV 调色板来演示一下,如下图:

点击查看YUV调色板软件下载方式

下载链接:YUV调色板 提取码:coeu
这个调色板是 岳麓吹雪 用MFC 写的(原文章在这里YUV调色板软件_yuv在线调色板-CSDN博客),需要安装 VS2017 跟 MFC 组件,因为这个项目比较旧,需要改一下配置,如下图,把 Platform Toolset 换成 v2017:

img

我没装这些组件,后面也没试,等有需要再说吧。

img

上图中,YUV 的值都是 1 ~ 255 ,所以 128 就是上图 x y轴的中心。可以试着把 Y 从 0 改成 255,会越来越 ,直到变成白色。调色板里面的 U 就是 Cb,这个值 就是 彩色空间 x 轴的偏移位置,也就是差值,偏移这么多就能达到想要的颜色。但是 还有 Y 轴,Y 轴是 Cr。Cb 跟 Cr 是组合的,会互相影响最后的颜色。所以, Cr 跟 Cb 在 X Y 轴的图片上看,就会很容易理解他们的作用。

二、RGB与YUV相互转换

前面我们知道R,G,B,3个分量都跟 亮度密切相关,也就是 3个分量里面都有大量的亮度信息。

RGB 转 YUV 的过程实际上就是 把 RGB 3分量里面的亮度信息 提取出来,放到 Y 分量。再把 RGB 3分量里面的 色调 ,色饱和度 信息提取出来放到 U 跟 V 分量。所以这是一个信息提取过程,需要经过大量的实验。

1. RGB2YCbCr

1.1 Y 的计算

提取 Y 亮度信息的公式如下:
$$
Y=K_r \times R+K_g \times G+K_b \times B
$$
上面公式中的 K 是一个权重因子,Kr 代表 红色通道的权重,Kg 代表 绿色通道的权重,Kb 代表 蓝色通道的权重,这三个权重加起来等于 1,如下:
$$
K_r+K_g+K_b=1
$$
Cb 的定义是 B - Y 的差值、Cr 的定义是 R - Y 的差值,Cg 的定义是 G - Y 的差值:
$$
C_b=B-Y \newline
C_r=R-Y \newline
C_g=G-Y
$$
上面的 Cb 就是 U 分量,Cr 是 V 分量。我们实际编码存储,或者传输的时候,是不需要用到 Cg 的。

从上面的公式可以看出,只需要知道 Y 跟 Cb 就能求 B 的值,知道 Y 跟 Cr 就能求 R 的值。知道 Y ,R 跟 B 就能根据第一条公式求到 G 的值。所以 Cg 没必要存储或者传输。

Cr + Cb + Cg 其实是一个常量。

因为 K 权重因子是需要经过大量的实验才能得到,经过实验研究后发现,K 权重因子 会影响压缩率,所以产生了以下标准。

  • BT.601标准[1]——标清数字电视(SDTV)

$$
Y=0.299R+0.587G+0.114B
$$

  • BT.709标准[2]——高清数字电视(HDTV)

$$
Y=0.2126R+0.7152G+0.0722B
$$

  • BT.2020标准[3]——超高清数字电视(UHDTV)

$$
Y=0.2627R+0.6780G+0.0593B
$$

因为某些原因,亮度这个信息,不能完完全全 从 RGB 里面提取出来,总会残留一些亮度信息在 RGB 里面没提取到。所以 K 权重因子 根据不同标准也是不同的。

T.2020标准 生成的 YUV 数据在 编码系统里面的压缩率 是比 BT.709 小的,虽然现在还没开始进行编码压缩,但是确确实实,K权重因子会影响压缩效果。

这节的笔记主要是学习 BT.601 标准里面的计算公式。前面学习色彩基础的时候会发现维基百科给出的公式也是和这个。

根据 ITU BT.601 标准 的定义,Kb = 0.114 ,Kr = 0.299 ,所以 Kg = 0.587 ,Y 的计算公式如下:
$$
Y=0.299R+0.587G+0.114B
$$
以这么理解上面这个公式,Kr + Kg + Kb 一定是等于1的。上面这个公式认为,在 R 通道里面有 29.9% 的亮度信息,在 G通道 有 58.7% 的亮度信息,在 B通道 有 11.4% 的亮度信息。

1.2 Cr(V) 的计算

Cr 的计算过程如下:
$$
\begin{align}\label{2}
Cr&=R−Y \newline
&=R−0.299R−0.587G−0.114B\newline
&=0.701R−0.587G−0.114B
\end{align}
$$
由于 R,G,B 的取值范围是 0 ~ 1,所以当 R = 1,G = 0,B = 0 时,R - Y 能得到最大的值,如下:
$$
\begin{align}
Cr&=R−Y\newline
&=0.701 \times 1−0.587 \times 0−0.114 \times 0 \newline
&=0.701 \text{(max_value)}\newline
\end{align}
$$
当 R = 0,G = 1,B = 1时,R - Y 能得到最小的值,如下:
$$
\begin{align}
Cr&=R−Y\newline
&=0.701 \times 0−0.587 \times 1−0.114 \times 1 \newline
&=-0.701 \text{(min_value)}\newline
\end{align}
$$
因此 Cr 的空间范围是 -0.701 ~ 0.701,范围大小是 1.402,但是由于 Cr 需要跟 Y 一起传输,而 Y 的空间范围大小是 1。所以 Cr = R - Y 要做归一化操作,就是除以 1.402。所以就有下面的公式了:
$$
\begin{align}
Cr&=\frac{(R−Y)}{1.402}\newline
&=(R-Y) \times 0.713 \newline
&=(0.701R−0.587G−0.114B) \times 0.713\newline
&=0.500R-0.419G-0.081B
\end{align}
$$

1.3 Cb(U) 的计算

Cb 的计算过程如下:
$$
\begin{align}
Cb&=B−Y \newline
&=B−0.299R−0.587G−0.114B\newline
&=-0.299R−0.587G+0.886B
\end{align}
$$
由于 R,G,B 的取值范围是 0 ~ 1,所以当 R = 0,G = 0,B = 1 时,B - Y 能得到最大的值,如下:
$$
\begin{align}
Cb&=B−Y\newline
&=−0.299 \times 0−0.587 \times 0+0.886 \times 1 \newline
&=0.886 \text{(max_value)}\newline
\end{align}
$$
当 R = 1,G = 1,B = 0 时,B - Y 能得到最小的值,如下:
$$
\begin{align}
Cb&=B−Y\newline
&=−0.299 \times 1−0.587 \times 1+0.886 \times 0 \newline
&=-0.886 \text{(min_value)}\newline
\end{align}
$$
因此 Cb 的空间范围是 -0.886 ~ 0.886,范围大小是 1.772,但是由于 Cb 需要跟 Y 一起传输,而 Y 的空间范围大小是 1。所以 Cb = B - Y 要做归一化操作,就是除以 1.772。所以就有下面的公式:
$$
\begin{align}
Cb&=\frac{(B-Y)}{1.772}\newline
&=(B-Y) \times 0.564 \newline
&=(−0.299R−0.587G+0.886B) \times 0.564\newline
&=-0.169R-0.331G+0.500B
\end{align}
$$

2. YCbCr2RGB

YCrCb 这 3个是已知值。

2.1 R 的计算

Cr = 0.713 * (R - Y) ,所以换算一下,把 R 移到左边,如下:
$$
\begin{align}
Cr&=(R-Y) \times 0.713\newline
R-Y&=\frac{Cr}{0.713}\newline
R&=\frac{Cr}{0.713}+Y\newline
&=1.402 \times Cr+Y
\end{align}
$$

2.2 B 的计算

Cb = 0.564 * (B - Y) ,所以换算一下,把 B 移到左边,如下:
$$
\begin{align}
Cb&=(B-Y) \times 0.546\newline
B-Y&=\frac{Cb}{0.546}\newline
R&=\frac{Cb}{0.546}+Y\newline
&=1.772 \times Cb+Y
\end{align}
$$

2.3 G 的计算

R 跟 B 已经求出来了。把R 跟 B 套进去以下公式:
$$
\begin{align}
Y&=0.299R+0.587G+0.114B \newline
&=0.299 \times (1.402 \times Cr+Y)+0.587G+0.114 \times (1.772 \times Cb+Y)\newline
&=(0.419Cr+0.299Y)+0.587G+(0.202Cb+0.114Y)\newline
&=0.419Cr+0.587G+0.202Cb+0.413Y\newline
\newline
0.587Y&=0.419Cr+0.587G+0.202Cb
\end{align}
$$
到这里,把 G 移到左边,如下:
$$
\begin{align}
0.587G&=0.587Y−0.419Cr−0.202Cb\newline
G&=Y−0.713Cr−0.344Cb
\end{align}
$$

3. 转换说明

上面两个小节的转换是BT.601标准的,网上还有一些不一样的转换方式,也有带常数的,自己也没搞太懂,后续再补充吧。

不管是YUV转RGB还是RGB转YUV都会有图像质量的损失。
对于不同位深或不同采样率的转换质量损失都好理解,但对于相同位深相同采样率的转换图像质量损失就要从计算公式来理解了,如I444和RGB24都是8bit位深未经压缩处理全采样数据,无论是RGB转YUV,还是YUV转RGB都会有少量的图像质量的损失,从转换公式来看这个由于浮点计算带来的损失,可以说是微乎其微的肉眼基本上看不出来的损失。

三、YUV的格式

1. 采样模式

1.1 采样模式有哪些?

YUV 有 4 种采样模式:

  • YUV4:4:4 ,表示完全采样,一个像素 占 3 个字节。
  • YUV4:2:2,表示2:1的水平采样,垂直完全采样,平均一个像素占 2 个字节。
  • YUV4:2:0,表示2:1的水平采样,垂直2:1采样,平均一个像素占 1.5 个字节。
  • YUV4:1:1,表示4:1的水平采样,垂直完全采样,但是这种我只是在维基百科的词条中看到有,实际并没有接触过。

主流的采样模式就是前面三种,YUV444、YUV422和YUV420。这些是什么意思?后面会详细学习,这样的采样模式主要是因为由于人眼对 Y 的敏感度远超于对 U 和 V 的敏感,所以有时候可以多个 Y 分量共用一组 UV,这样既可以极大得节省空间,又可以不太损失质量。这三种格式就是按照人眼的特性制定的。

我们可以准备一张图片,使用FFmpeg转换一下,分别得到YUV444、YUV422和YUV420格式的图片,方便后面分析。可以直接在这里下载:yuv-picture.zip - 蓝奏云 (lanzouj.com)

image-20240622144924936

我们也可以自己找一张jpg图片,转换一下,相关命令如下所示:

1
2
3
ffmpeg.exe -i juren.jpg -s 1920*1080 -pix_fmt yuvj444p juren_yuv_444.yuv
ffmpeg.exe -i juren.jpg -s 1920*1080 -pix_fmt yuvj422p juren_yuv_422.yuv
ffmpeg.exe -i juren.jpg -s 1920*1080 -pix_fmt yuvj420p juren_yuv_420.yuv

从上图可以看到,yuv420 比 yuv444 的 数据量少了一半,我们用 7yuv 看一下图片质量的差异:

  • juren_yuv_444.yuv(注意格式那里选YUV444 planar)
image-20240622145436099
  • juren_yuv_420.yuv(注意格式那里选YUV420 planar I420)
image-20240622145820134

观察上面两张图,至少我是没有觉察到有什么变化,所以重点:YUV420 比 YUV444 少了一半数据,视觉体验几乎没有变化。

1.2 YUV444

YUV 4:4:4 采样,意味着 Y、U、V 三个分量的采样比例相同,因此在生成的图像里,每个像素的三个分量信息完整,都是 8 bit,也就是一个字节。

这种格式占用空间最大,每个像素点有一个Y分量 + 一个U分量 + 一个V分量所以和 RGB 一样每个像素点占用3个字节!但是根据UV存储顺序不一样,又可能会有两种不同的格式,这种的就属于存储格式了,后面再说。

image-20240622151410707

如上图所示,YUV444就是每个像素点都包含了三个完整的YUV分量,每一个Y分量用一组UV分量,所以

1
2
单个像素点占用的空间为: pixel = 1Byte(Y) + 1Byte(U) + 1Byte(V) = 3Byte
一帧图像占用的空间为 : frameSize = (frameWidth * frameHeight * 3)Byte

例如

假如图像像素为:[Y0 U0 V0]、[Y1 U1 V1]、[Y2 U2 V2]、[Y3 U3 V3]
那么采样的码流为:Y0 U0 V0 Y1 U1 V1 Y2 U2 V2 Y3 U3 V3
最后映射出的像素点依旧为 [Y0 U0 V0]、[Y1 U1 V1]、[Y2 U2 V2]、[Y3 U3 V3]

1.3 YUV422

YUV 4:2:2 采样,意味着 UV 分量是 Y 分量采样的一半,Y 分量和 UV 分量按照 2 : 1 的比例采样。如果水平方向有 10 个像素点,那么采样了 10 个 Y 分量,而只采样了 5 个 UV 分量。

image-20240622152441039

YUV422就是UV分量是Y分量的一半,按照上图的样子,应该是相邻两个Y共用一个UV:

image-20240622152936392
1
2
单个像素点占用的空间为: pixel = 1Byte(Y) + 1Byte(U)/2 + 1Byte(V)/2 = 2Byte
一帧图像占用的空间为 : frameSize = (frameWidth * frameHeight * 2)Byte

1.4 YUV420

这个格式也是应用最广泛的,视频会议,数字电视,DVD,都用的 YUV420 格式。YUV 4:2:0 采样,并不是指只采样 U 分量而不采样 V 分量。而是指,在每一行扫描时,只扫描一种色度分量(U 或者 V),和 Y 分量按照 2 : 1 的方式采样。比如,第一行扫描时,YU 按照 2 : 1 的方式采样,那么第二行扫描时,YV 分量按照 2:1 的方式采样。对于每个色度分量来说,它的水平方向和竖直方向的采样和 Y 分量相比都是 2:1 。

image-20240622153406035

如上图,假设第一行扫描了 U 分量,第二行扫描了 V 分量,那么需要扫描两行才能够组成完整的 UV 分量。所以四个像素点才能包含一组完整的YUV信息:

image-20240622153518831

第一行的第1,第2 像素,第二行的 第1,第2 像素共用一组 UV,以此类推。为什么不是 第一行的 第 1~ 4 个像素共享 一组 UV?这是因为如果这样搞,空间距离太远,容易造成体验不太好。换行共享 UV 的空间距离短,画面过渡会自然一些。所以四个Y分量共用一组UV分分量:

1
2
单个像素点占用的空间为: pixel = 1Byte(Y) + 1Byte(U)/4 + 1Byte(V)/4 = 1.5Byte
一帧图像占用的空间为 : frameSize = (frameWidth * frameHeight * 1.5)Byte

比如:
假如图像像素为:[Y0 U0 V0]、[Y1 U1 V1]、[Y2 U2 V2]、[Y3 U3 V3]
那么采样的码流为:Y0 U0 Y1 V1 Y2 U2 Y3 V3
其中,每采样过一个像素点,都会采样其 Y 分量,而 U、V 分量就会间隔一个采集一个。
最后映射出的像素点为 [Y0 U0 V1]、[Y1 U0 V1]、[Y2 U2 V3]、[Y3 U2 V3]

这些 UV 值都是新值,是以前的 4 个像素的 U 值加起来 除以4 的平均值。其实有好几种求 UV 值算法:

(1)平均值,4 个像素的 U 值加起来 除以 4。

(2)加权,例如,第一第二个像素的 U 权重大点,第三第四个像素的 U 权重小一点。

(3)直接丢弃 第二,第三,第四个像素的 U 值,取 第一个 像素的 U 值。V 值同理。

1.5 总结

image-20221101140216424

如上图所示:

YUV格式 每个像素所占字节数 说明
YUV444 pixel_size=$1Byte(Y)+1Byte(U)+1Byte(V)=3Byte$ 每个Y对应一组UV
YUV422 pixel_size=$[2Byte(Y)+1Byte(Y)+1Byte(V)]/2=2Byte$ 每2个Y对应一组UV
YUV420 pixel_size=$[4Byte(Y)+1Byte(Y)+1Byte(V)]/4=1.5Byte$ 每4个Y对应一组UV

2. 存储格式

2.1 大概有哪些格式?

上面了解了采样模式了,那采样结束肯定需要存储的啊,怎么存?YUV存储方式主要分为三种:压缩格式(Packed formats) 、平面格式(Planar formats)和半平面(semi-Planar)。

存储格式说明
P:Planner按平面分开存放,先把Y存完,再存U,再存V,就是先连续存储所有像素点的Y,紧接着存储所有像素点的U,随后是所有像素点的V,即YYY UUU VVV 这样
SP:semi-Planar按半平面存放,只有Y是一个平面,UV数据共用一个平面,UV分量交叉存储。
Packed打包格式,就是把YUV三种分量按顺序存储,即YUV YUV YUV ... 这样

所以不同的采样方式加上不同的存储方式就会有多种不同的YUV编码方式。

YUV格式

2.2 YUV420

YUV420是使用很多的,它结合不同的存储方式,常用的会有YUV420P和YUV420SP。

2.2.1 YUV420P

YUV420P属于YUV420采样,planar存储,它又会分为YU12(也叫 l420)、YV12两种,YU12 和 YV12 格式都属于 YUV 420P 类型,即先存储 Y 分量,再存储 U、V 分量,区别在于:YU12 是先 Y 再 U 后 V,而 YV12 是先 Y 再 V 后 U 。

image-20240622171227455

I420(属于 YUV 420 Plannar) I420 是 YUV 420 Planar 的一种,YUV 分量分别存放,先是 w * h 长度的 Y,后面跟 w * h * 0.25 长度的 U, 最后是 w * h * 0.25 长度的 V,总长度为 w * h * 1.5。

YV12(属于 YUV 420 Plannar) YV12 是 YUV 420 Planar 的一种,YUV 分量分别存放,先是 w * h 长度的 Y,后面跟 w * h * 0.25 长度的 V, 最后是 w * h * 0.25 长度的 U,总长度为 w * h * 1.5。与 I420 不同的是,YV12 是先 V 后 U。

2.2.2 YUV420SP

YUV420SP属于YUV420采样,semi-Planar存储,分为NV12、NV21,YUV420先存储了 Y 分量,但接下来并不是再存储所有的 U 或者 V 分量,而是把 UV 分量交替连续存储。NV12 是 IOS 中有的模式,它的存储顺序是先存 Y 分量,再 UV 进行交替存储。NV21 是 安卓中有的模式,它的存储顺序是先存 Y 分量,在 VU 交替存储。

image-20240622171938988

NV12(属于 YUV 420 Semi-Planar) NV12 是 YUV 420 Semi-Planar 的一种,Y 分量单独存放,UV 分量交错存放,UV 在排列的时候,从 U 开始。总长度为 w * h * 1.5。

NV21(属于 YUV 420 Semi-Planar) NV21 是 YUV 420 Semi-Planar 的一种,Y 分量单独存放,UV 分量交错存放,与 NV12 不同的是,UV 在排列的时候,从 V 开始。总长度为 w * h * 1.5。

2.3 YUV422

2.3.1 YUV422P

YUV422P属于YUV422采样,它的存储格式是planar,分YU16和YV16两种:

image-20240622183344449

I422(属于 YUV 422 Plannar,也叫YU16) I422 是 YUV 422 Planar 的一种,YUV 分量分别存放,先是 w * h 长度的 Y,后面跟 w * h * 0.5 长度的 U, 最后是 w * h * 0.5 长度的 V,总长度为 w * h * 2。

YV16(属于 YUV 422 Plannar) YV16 是 YUV 422 Planar 的一种,YUV 分量分别存放,先是 w * h 长度的 Y,后面跟 w * h * 0.5 长度的 V, 最后是 w * h * 0.5 长度的 U,总长度为 w * h * 2。与 I422 不同的是,YV16 是先 V 后 U。

2.3.2 YUV422SP

YUV422SP 属于YUV422采样,分为NV16、NV61两种:

image-20240622183615587

NV16(属于 YUV 422 Semi-Planar) NV16 是 YUV 422 Semi-Planar 的一种,Y 分量单独存放,UV 分量交错存放,UV 在排列的时候,从 U 开始。总长度为 w * h * 2。

NV61(属于 YUV 422 Semi-Planar) NV61 是 YUV 422 Semi-Planar 的一种,Y 分量单独存放,UV 分量交错存放,UV 在排列的时候,从 V 开始。总长度为 w * h * 2。

2.3.3 Packed格式

image-20240622191314632

YUVY(属于 YUV 422 Interleaved) YUVY 属于 YUV 422 Interleaved 的一种。事实上,Interleaved 是属于 Packed 的,但是在 422 中,用 Interleaved 更加形象一些。在 Packed 内部,YUV 的排列顺序是 Y U V Y,两个 Y 共用一组 UV。

UYVY(属于 YUV 422 Interleaved) UYVY 属于 YUV 422 Interleaved 的一种。在 Packed 内部,YUV 的排列顺序是 UYVY,两个 Y 共用一组 UV。

四、YUV图片数据

YUV 这种格式的文件,不像 BMP 文件,BMP 虽然里面也是 RGB 的裸数据,但是 BMP 里面有一些头数据,宽高什么的。

但是 YUV文件格式,没有头信息,没有宽高信息,所以用 7yuv 打开 YUV 文件的时候,需要指定宽高,要指定采样格式是 4:4:4。如果我们有一个 YUV图片,但是忘记了 它的宽高跟采样格式,那就无法正常显示这个 YUV图片。

所以,YUV图片文件除了 原始的像素数据,什么都没有的。由于 4:4:4 跟 RGB24 一样,每个像素占 3 字节,图片宽高是 1920x1080 ,所以这个 YUV图片的大小如下:

1
SIZE=1920x1080x3=6075KB

可以看到,它的大小确实也是6075KB左右:

image-20240622193154796

我们用notpad++打开juren_yuv_444.yuv文件,这里还需要用插件来查看十六进制数据才行。

image-20240622193503749

会发现开头数据大量是0,看一下图片会发现开头大部分都是全黑的像素点,那我们来修改一下这个YUV文件,在最开始修改的话不是很好改,我们大概确定一个位置,我们想在第20行开始将像素点全部改为FF,这样起始地址大概就是1920x3x20=115200=1C200,我们大概就从这个地址附近选一个开始,直接插入FF数据,我们放大一点看:

image-20240622194845908

发现确实出现了白线。