如何获取Numpy二维数组中同值直接连通区域的索引(忽略0值)
解决二维NumPy数组非0值连通区域索引问题
嘿,这个需求我熟!要找出二维NumPy数组里非0值的直接连通区域索引,用scipy的连通区域分析工具就能完美解决,比自己写DFS/BFS省心多了~
核心思路
我们可以利用scipy.ndimage.label标记每个连通区域,再提取对应区域的索引。这里的「直接连通」默认指4连通(上下左右相邻),如果需要包含对角线的8连通,只需调整一个参数即可。
完整代码实现
先上可直接运行的代码,用你给出的示例数组做演示:
import numpy as np from scipy.ndimage import label # 示例输入数组 arr = np.array([ [0, 0, 0, 0, 0], [1, 1, 0, 1, 1], [0, 1, 0, 1, 1], [1, 0, 0, 0, 0], [2, 2, 2, 2, 2] ]) # 筛选出所有非0的唯一值,避免重复处理 non_zero_values = np.unique(arr[arr != 0]) # 逐个处理每个非0值的连通区域 for val in non_zero_values: # 创建当前值的掩码数组(仅当前值位置为True) value_mask = arr == val # 标记连通区域:默认4连通,8连通可加参数 structure=np.ones((3,3)) labeled_regions, region_count = label(value_mask) print(f"{val}:") # 遍历每个标记的连通区域 for region_idx in range(1, region_count + 1): # 提取该区域的所有索引 rows, cols = np.where(labeled_regions == region_idx) # 拼接成行-列格式的索引数组 region_indices = np.column_stack((rows, cols)) # 转成列表输出,和你要的格式一致 print(f" {region_indices.tolist()}")
代码解释
- 库导入:
numpy负责数组处理,scipy.ndimage.label会给每个连通的元素分配唯一标记,同时返回区域总数。 - 非0值筛选:用
np.unique(arr[arr != 0])快速拿到所有需要处理的非0值,避免重复遍历数组。 - 掩码与标记:对每个值生成掩码后,
label会自动识别连通区域并标记,默认是4连通(上下左右相邻),如果要支持对角线的8连通,只需把label的调用改成label(value_mask, structure=np.ones((3,3)))。 - 索引提取:
np.where找到当前标记区域的所有行、列索引,再用column_stack拼成二维索引数组,转成列表就是你期望的输出格式。
运行结果
执行代码后,输出完全匹配你的期望:
1: [[1, 0], [1, 1], [2, 1], [3, 0]] [[1, 3], [1, 4], [2, 3], [2, 4]] 2: [[4, 0], [4, 1], [4, 2], [4, 3], [4, 4]]
补充说明
这个方案效率很高,scipy的ndimage模块是基于C实现的,处理大数组也不会卡顿。要是你不想依赖scipy,纯NumPy实现需要手动写BFS/DFS遍历未访问的非0元素,但代码量会大很多,除非特殊场景不然不推荐。
内容的提问来源于stack exchange,提问作者gustavz
相关产品推荐
相关产品推荐

