音视频系列9:BGR、YUV420和YUV422编码格式

视频流转码的时候遇到了点麻烦,下面分析一下。

1 BGR vs YUV

BGR格式的shape为(width, height, 3),最后的3按照blue、green、red排列。
YUV格式中的Y、UV分别代表Luma、Chroma。UV分别描述色彩和饱和度。
YUV的好处是,将亮度与颜色分离,即使丢弃UV,仍然能够正常显示黑白图片。
下面是一个例子:
在这里插入图片描述

2. 各种YUV编码方式

YUV码流的存储格式有2个关键点:
1)Y与UV的采样,主流的采样方式有三种,YUV4:4:4,YUV4:2:2,YUV4:2:0。
YUV 4:4:4采样,每一个Y对应一组UV分量。YUV 4:2:2采样,每两个Y共用一组UV分量。 YUV 4:2:0采样,每四个Y共用一组UV分量。
2)Y与UV的编排。有两大类:planar和packed。
对于planar的YUV格式,先连续存储所有像素点的Y,紧接着存储所有像素点的U,随后是所有像素点的V。
对于packed的YUV格式,每个像素点的Y,U,V是连续交*存储的。
这里先介绍两个项目中用到的:

2.1 I420

亮度(行×列) + U(行×列/4) + V(行×列/4)
在这里插入图片描述

2.2 nv12

NV12属于YUV420格式,是一种two-plane模式,即Y和UV分为两个Plane,但是UV(CbCr)为交错存储,而不是分为三个plane。其提取方式与上一种类似,即Y’00、Y’01、Y’10、Y’11共用Cr00、Cb00。python版本的代码如下:

# I420转为nv12
img_nv12 = list(img_I420[:w,:]) # Y
for wi in range(w//4):
    d = []
    for hi in range(h//2):
        d.append(img_I420[w+wi,hi])
        d.append(img_I420[w//4*5+wi,hi])   
    img_nv12.append(np.array(d))
    d = []
    for hi in range(h//2):
        d.append(img_I420[w+wi,h//2+hi])
        d.append(img_I420[w//4*5+wi,h//2+hi])    
    img_nv12.append(np.array(d))
img_nv12 = np.array(img_nv12)
io.imshow(img_nv12)

在这里插入图片描述
C++版本代码如下:

void swapYUV_I420toNV12(unsigned char* i420bytes, unsigned char* nv12bytes, int width, int height)
{
    int nLenY = width * height;
    int nLenU = nLenY / 4;

    memcpy(nv12bytes, i420bytes, width * height);

    for (int i = 0; i < nLenU; i++)
    {
        nv12bytes[nLenY + 2 * i] = i420bytes[nLenY + i];                    // U
        nv12bytes[nLenY + 2 * i + 1] = i420bytes[nLenY + nLenU + i];        // V
    }
}

我们可以尝试恢复成BGR格式看一下:
在这里插入图片描述
和原图一模一样

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值