文章目录
- 1 问题先行
- 2 nv12介绍
- 2.1 YUV格式
- 2.2 NV12排布
- 3 不同数据格式之间转换实操
- 4 参考链接
1 问题先行
- nv12是什么格式?和常见的rgb/bgr有什么关系吗?他们之间能互相转换吗?
- 如何读取一张图片,然后把图片转换成nv12格式?有代码嘛?
- 部署时,为何要用nv12数据格式作为输入?rgb不行吗?
2 nv12介绍
2.1 YUV格式
YUV格式主要用于优化彩色视频信号的传输。
YUV分为三个分量:Y表示明亮度,也就是灰度值;U和V表示色度,用于描述影像色彩及饱和度,指定像素的颜色。
2.2 NV12排布
NV12图像格式属于YUV颜色空间中的YUV420SP格式,每四个Y分量共用一组U分量和V分量,Y连续排序,U与V交叉排序。
排列方式如下:
3 不同数据格式之间转换实操
读取一张图片,从bgr转成nv12,再从nv12转成yuv44,具体内容看看代码和输出即可。
import cv2
import numpy as np
from PIL import Image
# -------------------------------------------------------#
# 注意: image.shape = (h, w, c)
# nv12数据与YUV_I420的uv分量排列方式不同,具体可参考本文第2章节描述
# -------------------------------------------------------#
def bgr2nv12(image):
image = image.astype(np.uint8)
height, width = image.shape[0], image.shape[1]
yuv420p = cv2.cvtColor(image, cv2.COLOR_BGR2YUV_I420).reshape((height * width * 3 // 2, ))
y = yuv420p[:height * width]
uv_planar = yuv420p[height * width:].reshape((2, height * width // 4))
uv_packed = uv_planar.transpose((1, 0)).reshape((height * width // 2, ))
nv12 = np.zeros_like(yuv420p)
nv12[:height * width] = y
nv12[height * width:] = uv_packed
return nv12
# nv12转yuv444
def nv12Toyuv444(nv12, target_size):
height = target_size[0]
width = target_size[1]
nv12_data = nv12.flatten()
yuv444 = np.empty([height, width, 3], dtype=np.uint8)
yuv444[:, :, 0] = nv12_data[:width * height].reshape(height, width)
u = nv12_data[width * height::2].reshape(height // 2, width // 2)
yuv444[:, :, 1] = Image.fromarray(u).resize((width, height),resample=0)
v = nv12_data[width * height + 1::2].reshape(height // 2, width // 2)
yuv444[:, :, 2] = Image.fromarray(v).resize((width, height),resample=0)
return yuv444
if __name__=='__main__':
img = cv2.imread("./zebra_cls.jpg") # bgr hwc
print("cv2读图shape:", img.shape)
# 直接resize,其它缩放图片方式个性化使用
img = cv2.resize(img,(672,672)) # bgr hwc
print("resize后的图片shape:", img.shape)
# 将bgr的数据格式转换成nv12的数据格式
# 注意上方转换函数写的时候,输入img需要是(h, w, c)的layout排布
nv12 = bgr2nv12(img)
# 677376=672x672x3/2,这儿为什么除以2,参考本文第1章理解理解~
print("nv12的shape:", nv12.shape)
# 将nv12的数据保存下来供给模型,作为真实输入
nv12.tofile("nv12_input_data.bin")
# nv12转yuv444
img = nv12Toyuv444(nv12, (672,672))
print("yuv444的shape:", img.shape)
# 变换数据排布layout
img = img.transpose(2,0,1)
print("yuv444 transpose之后的shape:", img.shape)
# 增加一个N维度
img = img[np.newaxis,:,:,:]
print("增加一个N维度的shape:",img.shape)
输出:
cv2读图shape: (376, 376, 3)
resize后的图片shape: (672, 672, 3)
nv12的shape: (677376,)# 677376=672x672x3/2,为什么除以2,参考本文第2章理解理解~
yuv444的shape: (672, 672, 3)
yuv444 transpose之后的shape: (3, 672, 672)
增加一个N维度的shape: (1, 3, 672, 672)
注:部分代码有参考地平线OE包中的内容。
之所以用nv12作为部署时的数据输入,是因为其数据量是rgb/bgr等格式的一半,减少模型load输入数据的时间。
4 参考链接
1. https://developer.horizon.ai/forumDetail/118364000835765839