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

如何快速将2D NumPy数组(灰度图像)重塑为3D堆叠数组?

问题

我有一个形状为(M, N)的2D图像,希望将其重塑为(M//m * N//n, m, n)的形状,即将图像的小补丁堆叠成3D数组。目前我使用两层for循环实现了该功能,代码如下:

import numpy as np
a = np.arange(16).reshape(4,4)
b = np.zeros( (4,2,2))

# a = array([[ 0,  1,  2,  3],
#       [ 4,  5,  6,  7],
#       [ 8,  9, 10, 11],
#       [12, 13, 14, 15]])


row_step = 2
col_step = 2
row_indices = np.arange(4, step = 2)
col_indices = np.arange(4, step = 2)

for i, row_idx in enumerate(row_indices):
    for j, col_idx in enumerate(col_indices):
        b[i*2+j, :,:] = a[row_idx:row_idx+row_step, col_idx:col_idx+col_step]

# b = array([[[ 0.,  1.],
#        [ 4.,  5.]],
#
#       [[ 2.,  3.],
#        [ 6.,  7.]],
#
#       [[ 8.,  9.],
#        [12., 13.]],
#
#       [[10., 11.],
#        [14., 15.]]])

请问有没有更快的实现方法?非常感谢!

更快的实现方法

方法1:reshape + transpose 矢量化操作

完全避免Python循环,利用numpy内置的数组变形和转置操作,底层是优化后的C实现,效率远超循环:

import numpy as np
a = np.arange(16).reshape(4,4)
m, n = 2, 2

# 1. 拆分成块结构:(M//m, m, N//n, n)
temp = a.reshape(a.shape[0]//m, m, a.shape[1]//n, n)
# 2. 调整维度顺序:(M//m, N//n, m, n)
temp = temp.transpose(0, 2, 1, 3)
# 3. 合并前两个维度得到目标形状
b = temp.reshape(-1, m, n)

print(b)
# 输出结果与循环实现完全一致

方法2:np.lib.stride_tricks.as_strided(零拷贝内存视图)

如果追求极致性能,可以用as_strided创建原数组的内存视图,无需额外拷贝数据,但必须确保原数组维度能被m、n整除,否则会触发内存越界:

import numpy as np
from numpy.lib.stride_tricks import as_strided

a = np.arange(16).reshape(4,4)
m, n = 2, 2
M, N = a.shape

# 计算各维度的内存步长(单位:字节)
strides = (a.strides[0]*m, a.strides[1]*n, a.strides[0], a.strides[1])
# 定义块结构的形状
shape = (M//m, N//n, m, n)

# 创建内存视图
temp = as_strided(a, shape=shape, strides=strides)
# 合并前两个维度
b = temp.reshape(-1, m, n)

print(b)
# 输出结果一致

方法对比

  • reshape+transpose:代码可读性高,操作安全,适合绝大多数场景,性能足够优秀。
  • as_strided:零拷贝,速度最快,但需要手动计算步长,使用不当易引发内存问题,仅适合对性能要求极高且能保证维度合法性的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 19:45:49