无循环快速提取NumPy数组中目标点的有效邻域方法问询
向量化实现Moore邻域有效点查找(无循环)
问题背景
给定10×10的测试数组,其中部分位置设为1:
import numpy as np test_arr = np.zeros((10, 10), dtype=int) test_arr[[0, 1, 4], [0, 0, 8]] = 1 # 设置非零值点 indices_r, indices_c = np.nonzero(test_arr)
同时定义测试掩码:
test_mask = np.zeros((10, 10), dtype=bool) test_mask[[2, 4], [0, 8]] = 1
需要找到所有非零点的**Moore邻域(3×3范围)**中满足以下条件的点:
- 坐标在数组边界内(0 ≤ 行/列索引 ≤ 9)
- 对应测试掩码位置为
True
要求完全不使用for循环,最终得到可直接用于test_arr[indices]的索引数组格式。
向量化解决方案
利用NumPy的广播机制实现全向量化操作,步骤如下:
1. 定义Moore邻域偏移量
列出3×3邻域相对于中心点的所有偏移组合:
# Moore邻域的所有行/列偏移对 neigh_offsets = np.array([ [-1, -1], [-1, 0], [-1, 1], [0, -1], [0, 0], [0, 1], [1, -1], [1, 0], [1, 1] ])
2. 生成所有候选邻域点
将非零点的行、列索引扩展维度,和偏移量做广播相加,得到所有可能的邻域点坐标:
# 将非零点索引转为二维数组,方便广播 r = indices_r[:, np.newaxis] c = indices_c[:, np.newaxis] # 广播生成所有邻域点的行、列坐标 all_neigh_r = r + neigh_offsets[:, 0] all_neigh_c = c + neigh_offsets[:, 1] # 把所有候选点合并为N×2的数组(N为总候选数) all_candidates = np.stack([all_neigh_r.flatten(), all_neigh_c.flatten()], axis=1)
3. 筛选有效点
通过布尔索引过滤满足条件的点:
# 条件1:坐标在数组边界内 in_bounds = (all_candidates[:, 0] >= 0) & (all_candidates[:, 0] < 10) & \ (all_candidates[:, 1] >= 0) & (all_candidates[:, 1] < 10) # 条件2:对应掩码位置为True mask_valid = test_mask[all_candidates[in_bounds, 0], all_candidates[in_bounds, 1]] # 合并条件,得到最终有效点 valid_neighs = all_candidates[in_bounds][mask_valid]
4. 整理为目标索引格式
最终的valid_neighs是N×2的数组,可直接用于索引:
# 示例:用有效点索引访问test_arr print(test_arr[valid_neighs[:, 0], valid_neighs[:, 1]])
完整代码
import numpy as np # 初始化测试数组和掩码 test_arr = np.zeros((10, 10), dtype=int) test_arr[[0, 1, 4], [0, 0, 8]] = 1 indices_r, indices_c = np.nonzero(test_arr) test_mask = np.zeros((10, 10), dtype=bool) test_mask[[2, 4], [0, 8]] = 1 # 1. 定义邻域偏移量 neigh_offsets = np.array([ [-1, -1], [-1, 0], [-1, 1], [0, -1], [0, 0], [0, 1], [1, -1], [1, 0], [1, 1] ]) # 2. 生成所有候选邻域点 r = indices_r[:, np.newaxis] c = indices_c[:, np.newaxis] all_neigh_r = r + neigh_offsets[:, 0] all_neigh_c = c + neigh_offsets[:, 1] all_candidates = np.stack([all_neigh_r.flatten(), all_neigh_c.flatten()], axis=1) # 3. 筛选有效点 in_bounds = (all_candidates[:, 0] >= 0) & (all_candidates[:, 0] < 10) & \ (all_candidates[:, 1] >= 0) & (all_candidates[:, 1] < 10) mask_valid = test_mask[all_candidates[in_bounds, 0], all_candidates[in_bounds, 1]] valid_neighs = all_candidates[in_bounds][mask_valid] # 输出结果 print("有效邻域点索引:") print(valid_neighs)
内容的提问来源于stack exchange,提问作者LionCereals
相关产品推荐
相关产品推荐

