Python 读取 YUV(NV12) 视频文件实例
本文介绍如何使用 Python 和 OpenCV 读取原始 YUV(NV12) 视频文件。YUV 是一种常用的颜色编码,其中 Y 代表亮度,U 和 V 代表色度。文章详细解析了 NV12、NV21 等 YUV420 子采样的内存布局,并提供完整代码示例,展示如何将 NV12 数据逐帧读取、转换为 BGR 格式并保存为图片,适用于视频处理与模型输入准备。
YUV 格式基础与采样方式
一、YUV 简介
YUV 是一种颜色编码方法,广泛应用于各类视频处理组件中。
Y'UV、YCbCr、YPbPr 等专有名词通常统称为 YUV,它们之间存在一定的重叠关系。
其中,Y 表示明亮度(仅取此通道即可得到灰度图),U 和 V 则分别表示色度和浓度。
主流的采样方式主要有三种:YUV4:4:4、YUV4:2:2 以及 YUV4:2:0。
可以根据采样格式从码流中还原每个像素点的 YUV 值,进而通过 YUV 与 RGB 的转换公式提取出每个像素点的 RGB 值,最终显示出来。
YUV4:2:0 数据在内存中的长度计算公式为 3 / 2 * heigth * width,这恰好是 RGB24(heigth * width * 3)格式视频数据内存的一半。
二、YUV420(NV12、NV21、I420、YV12)
YUV420 子采样格式解析
# NV12、NV21 的存储格式为 Y 平面,UV 打包,即:Y 信息存储在一个数组中,UV 信息存储在一个矩阵中。
# 不同点在于 UV 的排列顺序
NV12: YYYYYYYY UVUV => YUV420SP
NV21: YYYYYYYY VUVU => YUV420SP
# I420、YV12 三个分量均为平面格式,即:分别存放在三个 Byte 型数组中
I420: YYYYYYYY UU VV => YUV420P
YV12: YYYYYYYY VV UU => YUV420P
假设一个分辨率为 8X4 的 YUV 图像,它们的存储格式如下图所示:

三、读取 YUV(NV12) 视频文件并保存
Python 实现 YUV 读取与转换
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import cv2
import numpy as np
def yuv2bgr(filename, height, width, startfrm):
"""
:param filename: 待处理 YUV 视频的名字
:param height: YUV 视频中图像的高
:param width: YUV 视频中图像的宽
:param startfrm: 起始帧
:return: None
"""
fp = open(filename, 'rb')
framesize = height * width * 3 // 2 # 一帧图像所含的像素个数
h_h = height // 2
h_w = width // 2
fp.seek(0, 2) # 设置文件指针到文件流的尾部
ps = fp.tell() # 当前文件指针位置
numfrm = ps // framesize # 计算输出帧数
fp.seek(framesize * startfrm, 0)
for i in range(numfrm - startfrm):
Yt = np.zeros(shape=(height, width), dtype='uint8', order='C')
Ut = np.zeros(shape=(h_h, h_w), dtype='uint8', order='C')
Vt = np.zeros(shape=(h_h, h_w), dtype='uint8', order='C')
for m in range(height):
for n in range(width):
Yt[m, n] = ord(fp.read(1))
for m in range(h_h):
for n in range(h_w):
Ut[m, n] = ord(fp.read(1))
for m in range(h_h):
for n in range(h_w):
Vt[m, n] = ord(fp.read(1))
img = np.concatenate((Yt.reshape(-1), Ut.reshape(-1), Vt.reshape(-1)))
img = img.reshape((height * 3 // 2, width)).astype('uint8') # YUV 的存储格式为:NV12(YYYY UV)
# 由于 opencv 不能直接读取 YUV 格式的文件, 所以要转换一下格式
bgr_img = cv2.cvtColor(img, cv2.COLOR_YUV2BGR_NV12) # 注意 YUV 的存储格式
cv2.imwrite('yuv2bgr/%d.jpg' % (i + 1), bgr_img)
print("Extract frame %d " % (i + 1))
fp.close()
print("job done!")
return None
if __name__ == '__main__':
_ = yuv2bgr(filename='xxx.yuv', height=1080, width=1920, startfrm=0)
以上这篇 Python 读取 YUV(NV12) 视频文件实例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持本站。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













