YUV 数据分析
在 前文中,已经知道 YUV 色彩空间非常适合存储跟传输,本文就用实战的方式来演示一下,YUV 在存储跟传输领域有哪些优点。
首先 YUV 有 3 种采样模式:
1,4:4:4 ,一个像素 占 3 个字节。
2,4:2:2,平均一个像素占 2 个字节。
3,4:2:0,平均一个像素占 1.5 个字节。
请先下载下面要用到的图片资源,百度网盘,提取码:ea7s 。资源文件中的 yuv 图片是我用以下 FFmpeg 命令转出来的,
文件内容如下图:
从上图可以看到,yuv420 比 yuv422 的 数据量少了一半,我们用 7yuv 看一下图片质量的差异,再次推荐一下 7yuv, 这是一个 raw 图片编辑器,RGB ,YUV 数据都能用 7yuv 来查看编辑。
上面两张 图片,大家能看出来有什么区别吗?我个人的感受是没有区别,这就是针对 人眼系统 使用的技巧,他的信息量确确实实 少了一半,但是你的眼睛能看到数据少了一半吗?我们感受不到,感受不到就不算少了。
重点:YUV420 比 YUV444 少了一半数据,视觉体验几乎没有变化。
提醒:使用 7yuv 的时候,Format 跟 宽高 一定要选对,图片才会显示正确。
由于大多数视频编码使用的是 YUV420,所以我们经常说的 视频分辨率,是指他的亮度分辨率,因为只有亮度才是铺满的,UV 不是。
先用 HxD 来看一下 juren_yuv_444.yuv 图片 实际的存储情况,请看下图:
这里我得着重讲一下,YUV 这种格式,我觉得他是 裸数据中的裸数据,太裸了,yuv 格式的文件,不像 BMP 文件,BMP 虽然里面也是 RGB 的裸数据,但只是 BMP 里面有一些头数据,宽高什么的。
但是 yuv 文件格式,没有头信息,没有宽高信息,所以用 7yuv 打开 YUV 文件的时候,需要指定宽高,要指定采样格式是 4:4:4。如果你有一个 yuv 图片,但是你忘记了 它的宽高跟采样格式,那你就无法正常显示这个 yuv 图片。
所以,yuv 图片文件除了 原始的像素数据,什么都没有的。由于 4:4:4 跟 RGB24 一样,每个像素占 3 字节,图片宽高是 1920x1080 ,所以这个 yuv 图片的大小如下:SIZE = 1920 * 1080 *3SIZE=1920∗1080∗3 所以这个 juren_yuv_444.yuv 图片一共是 6075 Kb 大小。
YUV 格式有 3 大类 :
1,planner :平面格式, 先连续存储所有像素点的 Y,紧接着存储所有像素点的 U,随后是所有像素点的 V。
注意:这里的连续存储,不是一行像素里面连续存储,是整张图片的连续存储,例如 本文的 juren_yuv_444.yuv 图片是 6075kb 大小,那第 1~ 2025kb 都是 Y 的数据, 2026 ~ 4050kb 都是 像素点的 U 数据,以此类推。
2,semi-Planar:半平面的 YUV 格式,Y 分量单独存储,但是 UV 分量交叉存储。
3,packed :每个像素点的 Y,U,V 是连续交错存储的。
上面 FFmpeg 把 jpeg
转 yuv
的时候,使用的格式是 yuvj444p
,后面的 p 代表 planner,所以 本文只关注 planner 格式,其他格式不讲。
yuv 图片的像素存储顺序 是从 左上角 到 右下角的。所以如果我们想把 图像的左上角 3 个像素改成 白色,只需要 把前面 3 字节 从 0 改成 255 即可。Y 是亮度,最亮的值就是白色。如下:
用 7yuv 放大图片查看,左上角果然出现了 3 个白色像素。
至此 yuv444p 的存储格式讲解完毕。
下面来讲一下 yuv422p 的存储格式,422 比 444 采样格式 少了 三分之一的数据量。请看下图:
上图 是 用 HxD 打开的效果,前面依然是一堆 00 00 ,因为 是 planner 模式,前面的 2025kb 还是 Y,只是 后面的 UV 少了一半的数据量。
我们知道,YUV 转 RGB 的是时候,肯定需要 知道 Y ,U 跟 V 的值,现在 UV 少了一半,怎么分?
是这样分的,第一个像素跟第二个像素 共享一个 UV。这里要提及一下 422 格式里面的 U 值是新值,是由第一个像素跟第二个像素的 U 值加起来除以 2 得到的,所以 422 格式的 UV 值 其实是平均值。
所以,422 格式,是第一第二个像素共享 一组 UV,第三第四像素共享 一组 UV,以此类推,如下图:
上图中的空白格代表不占空间,画出来只是为了方便理解,图中的存储顺序不是 planner 格式,也是为了方便理解。
大家可以数一下 上面 两张图片的格子(不包含空格子),会发现 YUV422 确实 比 YUV444 少了 三分之一 的格子。
最后讲一下 数据量最少的 YUV420 格式,这个格式也是应用最广泛的的,视频会议,数字电视,DVD,都用的 YUV420 格式。请看下图:
从上图可以看出,第一行的第 1,第 2 像素,第二行的 第 1,第 2 像素共用一组 UV,以此类推。为什么不是 第一行的 第 1~ 4 个像素共享 一组 UV,这是因为如果这样搞,空间距离太远,容易造成体验不太好。换行共享 UV 的空间距离短,画面过渡会自然一些。
这些 UV 值都是新值,是以前的 4 个像素的 U 值加起来 除以 4 的平均值。
其实由好几种求 UV 值算法。
1,平均值,4 个像素的 U 值加起来 除以 4。
2,加权,例如第一第二个像素的 U 权重大点,第三第四个像素的 U 权重小一点。
3,直接丢弃 第二,第三,第四个像素的 U 值,取 第一个 像素的 U 值。V 值同理。
我个人觉得求 平均比较靠谱,FFmpeg 的代码也有这个算法,具体是求平均还是 加权,我要看下源码,这里埋个坑,后面填。
版权声明: 本文为 InfoQ 作者【Loken】的原创文章。
原文链接:【http://xie.infoq.cn/article/4354b0f05c925d2ea4f2bdc5c】。未经作者许可,禁止转载。
评论