You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何加速Python中NV12转YUV444操作 替代原生for循环实现高效转换

NV12格式转YUV444的高效实现方案

我最初的NV12转YUV444采用Python原生双层for循环实现,代码如下:

for h in range(self.img_shape[0]):
    # 为推理框架规整YUV444数据
    for w in range(self.img_shape[1]):
        yuv444_res[h][w][0] = (nv12_y_data[h * self.img_shape[1] +w]).astype(np.int8)
        yuv444_res[h][w][1] = (nv12_u_data[int(h / 2) * int(self.img_shape[1] / 2) +int(w / 2)]).astype(np.int8)
        yuv444_res[h][w][2] = (nv12_v_data[int(h / 2) * int(self.img_shape[1] / 2) +int(w / 2)]).astype(np.int8)

由于Python原生for循环运行速度远低于NumPy向量化运算,我希望找到基于NumPy的优化实现方案。


2021年6月15日更新

我基于花式索引实现了优化版本,参考公开技术资料编写,代码如下:

yuv444 = np.empty([self.height, self.width, 3], dtype=np.uint8)
yuv444[:, :, 0] = nv12_data[:self.width * self.height].reshape(
    self.height, self.width)
u = nv12_data[self.width * self.height::2].reshape(
    self.height // 2, self.width // 2)
yuv444[:, :, 1] = Image.fromarray(u).resize((self.width, self.height))
v = nv12_data[self.width * self.height + 1::2].reshape(
    self.height // 2, self.width // 2)
yuv444[:, :, 2] = Image.fromarray(v).resize((self.width, self.height))

data[0] = yuv444.astype(np.int8)

使用PIL的resize方法替代已废弃的imresize接口后,该代码运行结果与原有for循环实现100%匹配。


2021年6月19日更新

参考Rotem提供的实现方案后,我找到了运行速度更快的OpenCV实现版本,代码如下:

# nv12_data已被重塑为一维数组
y = nv12_data[:self.width * self.height].reshape(
    self.height, self.width)
shrunk_u = nv12_data[self.width * self.height::2].reshape(
    self.height // 2, self.width // 2)
shrunk_v = nv12_data[self.width * self.height + 1::2].reshape(
    self.height // 2, self.width // 2)
u = cv2.resize(shrunk_u, (self.width, self.height),
               interpolation=cv2.INTER_NEAREST)
v = cv2.resize(shrunk_v, (self.width, self.height),
               interpolation=cv2.INTER_NEAREST)
yuv444 = np.dstack((y, u, v))

我对1000张图片的处理进行了耗时对比,结果显示OpenCV方案速度更快,且运算结果和原生实现完全一致:

cv time: 4.417593002319336, pil time: 5.395732164382935

2021年6月25日更新

经测试发现,Pillow的resize方法在不同版本中的默认resample参数值存在差异:

  • 5.1.0版本:
def resize(self, size, resample=NEAREST, box=None):
  • 8.1.0版本:
def resize(self, size, resample=BICUBIC, box=None, reducing_gap=None):

因此调用resize接口时最好显式指定重采样策略,避免不同版本运行结果不一致的问题。


内容的提问来源于stack exchange,提问作者Johnzy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.17 14:15:03