python----RGB to YUV420

import numpy as np
import cv2


def bgr2nv21(bgr):
    i420 = cv2.cvtColor(bgr, cv2.COLOR_BGR2YUV_I420)
    height = bgr.shape[0]
    width = bgr.shape[1]

    u = i420[height: height + height // 4, :]
    u = u.reshape((1, height // 4 * width))
    v = i420[height + height // 4: height + height // 2, :]
    v = v.reshape((1, height // 4 * width))
    uv = np.zeros((1, height // 4 * width * 2))
    uv[:, 0::2] = v
    uv[:, 1::2] = u
    uv = uv.reshape((height // 2, width))
    nv21 = np.zeros((height + height // 2, width))
    nv21[0:height, :] = i420[0:height, :]
    nv21[height::, :] = uv
    return nv21


if __name__ == "__main__":
    bgr = cv2.imread(r"/home/linux/a.jpg")
    nv21 = bgr2nv21(bgr)
    #写入文件
    nv21.astype("int8").tofile(r"a.yuv")

一、YUV 简介
YUV:是一种颜色编码方法,常使用在各个视频处理组件中

Y'UV(模拟), YCbCr(数字), YPbPr等专有名词都可以称为 YUV,彼此有重叠
Y表示明亮度(单取此通道即可得灰度图),U和V则是描述图像的色彩饱和度,用于指定像素的颜色
编解码:采集到的视频数据一般是 RGB24,为了节省带宽,一般需要经过 编码转换(RGB2YUV) 为 NV12 进行传输;应用时一般需要经过 解码转换(YUV2RGB) 为 RGB 用于显示或后续算法

YUV 采样方式及原理:根据人眼的特点,将人眼相对不敏感的色彩信息进行压缩采样(亮度保持不变),得到相对小的文件进行播放和传输

YUV4:2:0 数据,每四个 Y 共用一组 UV 分量,在内存中的长度是 h * w + h * w / 4 + h * w / 4 = h * w *1.5,是 RGB(h * w * 3) 格式视频数据内存的一半,每个像素的 Y 数据保留, 两个像素数据只保留一个 U 或者 V 数据
YUV4:2:2 数据,每两个 Y 共用一组 UV 分量,在内存中的长度是 h * w + h * w / 2 + h * w / 2 = h * w *2,是 RGB(h * w * 3) 格式视频数据内存 2/3,每两个相邻的像素,一个丢弃 V 数据,一个丢弃 U 数据
YUV4:4:4 数据,每一个 Y 共用一组 UV 分量,在内存中的长度是 h * w + h * w + h * w = h * w *3,与 RGB(h * w * 3) 格式视频数据内存一样

YUV 存储格式:

packed(打包格式):每个像素点的 Y,U,V 是连续交叉存储的(YUVYUVYUVYUV)
planar(平面格式):先连续存储所有像素点的 Y,紧接着存储所有像素点的 U,随后是所有像素点的V(YYYYUUVV)
semi-planar(半平面格式):先连续存储所有像素点的 Y,紧接着连续交叉存储所有像素点的U,V(YYYYUV)

YUV444 & RGB 相互转换:

图形显示时常用 RGB 模型,而 YUV 常用在数据传输场景,所以这两种颜色模型之间经常需要进行转换
可以根据其采样格式来从码流中还原每个像素点的 YUV 值,进而通过 YUV 与 RGB 的转换公式提取出每个像素点的 RGB 值,然后显示出来