YUV 详解

面向对象

本文解决的问题:Python处理YUV数据,读取YUV数据并保存为其他类型的图片
简述下起因:
网上找了很多资料,基本都是大同小异,但是当时自己无法理解,直到现在才算是理解了,故而希望能深入浅出的讲清楚

YUV简介

“Y”表示明亮度(Luminance、Luma),“U”和“V”则是色度、浓度 --维基百科

YUV分类

https://juejin.cn/post/6920848468797816846

如何理解YUV

我会从三个方面讲:YUV排列格式,YUV数据个数,YUV bits。

必须得承认YUV的格式非常的繁多复杂,可能是由于曾经大家都闭门造车导致一家一个格式,YUV有一个特殊的格式400,也就是只有Y分量。在彩色电视出现以前,是黑白电视,YUV解决了这样一个问题,这个问题是RGB无法处理的。

当用户的电视机是彩色的时候,YUV和RGB都能正常显示,但是当用户的电视机是黑白的时候,就需要去除颜色信息,YUV400格式就是黑白图像,当只有Y输入的时候就是黑白图,所以当用户是黑白电视机的时候可以直接舍弃UV分量。

YUV就是int类型的数据,可以理解为纯二进制数据。

YUV文件存储的是0,1两个数字的排列。如果YUV是一张图,那么我们必须知道YUV图片的宽高信息,然后还需要知道YUV的排列格式,最后还需要知道YUV是8bits还是10bits保存的。

举例:
如果一张yuv图片,是8bits的,那么 numpy 中可以这样读取 yuv_data = np.fromfile(yuv_filepath, np.uint8)
此时我们有了yuv的数据,然后就是处理这些数据

我们以Y为基准,Y的数据量必然是:width * height (宽乘以高),即数据个数。

如果是422格式,那么意味着,U的数据量是Y的一半,V的数据量也是Y的一半,在程序中我们对一个正整数进行右移一位就代表着除以2,所以U的数据个数是:width * (height>>1),这里 (width>>1)*height 是一样的,int(width * height/2),注意Python中但凡有除,必定浮点。

如果是420格式,并不是说Y:U:V=4:2:0,而是Y:U:V=4:1:1,同理Y的数据量还是:width * height,U的数据量就是1/4的Y的数据量。

我们刚刚讨论的是数据点数,YUV422的数据个数是width * height * 2,YUV420是 width * height * 1.5。我在这里告诉各位一个观点就是Y数据个数必定是图片的宽高乘积,这点我是在很久之后才理解的,因为当时没有人告诉我,以至于和后面的排列方式一起,导致脑子混乱。

到了这里我想你应该清楚了 422,420,444,400 这些数字的含义,关于 YUV 的排列,我想最后再聊,因为这个比较复杂。我先谈谈bits。前面提到过8bits和10bits,这是什么意思呢?

先理解一个概念,学过计算机的应该都清楚,一个字节=8个bits,几乎所有的编程语言,读取数据的时候都不是按照bits读取的,而是按照字节读取的,np.uint8 是numpy定义的数据类型,对应c语言中的char(一个字节)。

如果YUV是8bits,但是按照10bits来读取会发生什么呢?

假设数据是UYVY交错排布的,是8bits的,那么前4个字节取出来后,依次代表U Y V Y,但是当我们按照错误的bits去读取的时候就会出现偏差,10bits超过了一个字节,事实上10bits,12bits,14bits,16bits都是读取两个字节,代码会读取两个字节,把这16个bits解析成一个数据,那么10bits读取会导致读取四个字节我们只得到了两个数据,并理解成U Y,事实上它不是U Y。所以我们必须知道 YUV 数据的存储格式是8bits还是10bits,通常就是这两种,当然你愿意24bits也是没问题的。

既然有8bits,为什么要10bits呢?8bits所能表示的范围(0,255)2 ^ 8 = 256 ,10bits所能表示的范围(0,1023)2 ^ 10 = 1024,10bits表达更细,精确度更高,12,14,16bits同理。10bits占用两个字节也就是16个bits,那么剩下的6个bits是怎么处理的呢?两个字节的时候,我们通常把一个字节叫高8位,另一个叫低8位,可以这样理解,做10个字节表示数据,右边6个低位数据补0,在使用的时候只需要进行移位操作就可以了,num >> 6 ,右移6位就可以得到真实数据,这也就意味着当我们读取10bitsYUV时候,我们读取了两个字节后需要移位来获取真实的数据。

相信到了这里你应该理解了YUV的bits的区别。简单来讲就是我们必须要知道该怎么去解读二进制数据。

最后就是YUV的排列方式了。

  1. 平铺排列(Planar),Y U V 依次排列,先排Y再排U最后V,这种最容易理解
  2. 交错排列(Packed),即 YUYV或者UYVY,YVYU,VYUY,反正你随便组合就行YUV UYV VUY,高数学过排列组合吧,随便折腾就是了。
  3. 特殊排列(Semi-Planar),这一类其实也是交错排列,只是它特殊一些。例如,先排Y,然后UV交错。
    总之都是YUV三个排列组合,他们有些习惯名称NV12,NV21(可以理解为绰号),一般来讲形如yuv420p,yuv422p,这种命名带p的就是平铺排列。通常如果不确定就网上搜一下,你就可以得到他们的"真名"。

YUV422UYVY,YUV422YUYV,YUV422p,YUV422(SemiPlanar Y U V 或者 Y V U)

小结

YUV数据本质就是二进制数据,和Raw图一样,都是0,1,0,1这种东西。

我们必须知道YUV是8bits还是10bits解析数据的,
我们必须知道YUV图片的长宽,这个和bits共同确定YUV的数据量,即告诉我们这张YUV图多少数据量。
我们必须知道YUV的数据是怎么排布的,否则我们无法正确把YUV三个分量提取出来

课外拓展

我们可能经常会在搜索YUV相关代码时候看到frame这个东西,YUV也可以是一个视频,它有很多帧(frame),我们之所以要知道YUV是以8bits还是10bits保存的,图片的宽高,就是因为如果一个YUV文件有10张YUV图,那么我们把多少数据作为一张YUV图呢?这也就是必须知道YUV图的数据量。

YUV convert RGB,由于YUV图非常难以观看,需要指定的参数太多了,看一张YUV图太费劲,所以我们可以考虑把YUV转换成RGB,这样就可以直接保存为jpg,pnm,bmp这类我们常见的图片格式。但是这里有一个问题,我们先前说过YUV可以是8bits,10bits,12bits,甚至是24bits,你开心怎么都无所谓,但是rgb是0,255,也就是2 ^ 8 =256。这也就是说,如果是8bits的YUV,可以直接使用颜色空间转换,转换成RGB,有转换公式,较为复杂。10bits就没法直接处理了,通常的做法是直接右移两位变成8bits,在进行颜色空间转换,转换成RGB。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值