基于质心居中的Numpy 3D数组分块需求:从中间分割为指定子数组
实现Numpy数组的质心居中分割
我来帮你搞定这个围绕质心居中分割Numpy数组的需求!核心就是要让原数组的中心点精准落在某个子数组的中心,同时保证所有子块均匀分布,咱们一步步来实现。
核心逻辑拆解
首先得明确几个关键数值:
- 原数组的中心点索引:因为原数组各维度都是奇数(比如101、151),直接用每个维度长度整除2就能得到(比如101//2=50,151//2=70),这是咱们分割的基准点。
- 子数组的半长:同样子数组是奇数尺寸,比如21的半长是(21-1)//2=10,这样子数组的中心到边缘的元素数完全一致,方便对齐原数组的中心点。
- 子块分布规则:从中心子块开始,向原数组的前后/左右/上下均匀扩展子块,要么刚好衔接,要么在边缘补全覆盖(如果原数组长度不能被子块尺寸整除的话)。
具体代码实现
咱们直接上可运行的代码,每一步都给你注释清楚:
import numpy as np # ---------------------- 自定义参数 ---------------------- # 原数组的尺寸,这里是题目给出的(101, 151, 101) orig_shape = (101, 151, 101) # 子数组的目标尺寸,示例为(21,21,21),可替换为任意奇数尺寸 sub_shape = (21, 21, 21) # 创建测试用原数组(实际使用时替换成你的真实数组即可) orig_array = np.random.rand(*orig_shape) # ------------------------------------------------------- # 计算原数组各维度的中心点索引(0-based) orig_centers = [dim // 2 for dim in orig_shape] # 计算子数组各维度的半长(中心到边缘的元素个数) sub_halfs = [(sub_dim - 1) // 2 for sub_dim in sub_shape] def get_sub_starts(orig_len, sub_len, orig_center, sub_half): """生成单个维度上所有子块的起始索引,保证中心子块对齐原数组中心""" # 中心子块的起始索引:原中心点 - 子块半长 center_start = orig_center - sub_half # 向左扩展子块:每次往前挪一个子块长度,直到超出数组左边界 left_starts = [] current_start = center_start - sub_len while current_start >= 0: left_starts.append(current_start) current_start -= sub_len # 反转一下,让左半部分的子块从左到右排列 left_starts = left_starts[::-1] # 向右扩展子块:每次往后挪一个子块长度,直到超出数组右边界 right_starts = [] current_start = center_start + sub_len while current_start + sub_len <= orig_len: right_starts.append(current_start) current_start += sub_len # 合并所有起始索引:左半部分 → 中心 → 右半部分 all_starts = left_starts + [center_start] + right_starts # 可选:补全边缘子块,确保覆盖整个原数组 if all_starts[0] != 0: all_starts.insert(0, 0) last_end = all_starts[-1] + sub_len if last_end != orig_len: all_starts.append(orig_len - sub_len) return all_starts # 获取三个维度各自的子块起始索引列表 starts_z = get_sub_starts(orig_shape[0], sub_shape[0], orig_centers[0], sub_halfs[0]) starts_y = get_sub_starts(orig_shape[1], sub_shape[1], orig_centers[1], sub_halfs[1]) starts_x = get_sub_starts(orig_shape[2], sub_shape[2], orig_centers[2], sub_halfs[2]) # 遍历所有起始索引组合,提取所有子数组 sub_arrays = [] for z_start in starts_z: for y_start in starts_y: for x_start in starts_x: # 生成每个维度的切片(左闭右开) z_slice = slice(z_start, z_start + sub_shape[0]) y_slice = slice(y_start, y_start + sub_shape[1]) x_slice = slice(x_start, x_start + sub_shape[2]) # 提取子数组并加入列表 sub_arr = orig_array[z_slice, y_slice, x_slice] sub_arrays.append(sub_arr)
验证与细节说明
验证中心点对齐
你可以运行下面的代码,确认原数组的中心点和中心子数组的中心点完全重合:
# 找到中心子块在列表中的位置 center_z_idx = starts_z.index(orig_centers[0] - sub_halfs[0]) center_y_idx = starts_y.index(orig_centers[1] - sub_halfs[1]) center_x_idx = starts_x.index(orig_centers[2] - sub_halfs[2]) center_sub_idx = center_z_idx * len(starts_y) * len(starts_x) + center_y_idx * len(starts_x) + center_x_idx # 获取中心子数组 center_sub_arr = sub_arrays[center_sub_idx] # 对比原数组中心点和中心子数组中心点的数值 orig_center_val = orig_array[orig_centers[0], orig_centers[1], orig_centers[2]] sub_center_val = center_sub_arr[sub_halfs[0], sub_halfs[1], sub_halfs[2]] print(f"原数组中心点数值: {orig_center_val:.6f}") print(f"中心子数组中心点数值: {sub_center_val:.6f}") print(f"中心点是否对齐: {np.isclose(orig_center_val, sub_center_val)}") # 应该输出True
关键细节
- 灵活性:子数组尺寸可以替换为任意奇数(比如(11,11,11)、(31,31,31)),代码会自动计算对应的半长和起始索引。
- 边缘处理:代码里的补全边缘子块是可选的,如果你的需求不需要覆盖整个原数组,只需要均匀分布的子块,可以去掉那部分判断逻辑。
- 均匀分布:子块之间以子数组尺寸为步长扩展,保证相邻子块的间距一致,实现均匀分布的效果。
内容的提问来源于stack exchange,提问作者ssm
相关产品推荐
相关产品推荐

