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

如何在Python中拆分稀疏二维数组为连通子数组?

问题描述

我希望找到一种方法,圈选稀疏表格中所有连通/相邻的非零值,输出多个新的子数组。只要值是连通的,就应归为同一个子数组。

例如,输入稀疏数组:

[[0 0 0 1 1 0 0 0 1 1 1 1 0 0 0 0 0 0 0]
 [0 0 0 1 1 0 0 0 1 1 1 1 1 0 0 1 1 0 0]
 [0 0 0 0 0 0 0 0 1 1 1 0 0 0 1 1 1 1 0]
 [0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0]]

算法需识别出连通区域并标记,结果如下:

[[0 0 0 1 1 0 0 0 2 2 2 2 0 0 0 0 0 0 0]
 [0 0 0 1 1 0 0 0 2 2 2 2 2 0 0 3 3 0 0]
 [0 0 0 0 0 0 0 0 2 2 2 0 0 0 3 3 3 3 0]
 [0 0 0 0 0 0 0 2 0 0 0 0 0 3 0 0 0 0 0]]

最终输出每个连通区域对应的子数组,示例如下:

[[1 1]
 [1 1]]
[[0 1 1 1 1 0]
 [0 1 1 1 1 1]
 [0 1 1 1 0 0]
 [1 0 0 0 0 0]]
[[0 0 1 1 0]
 [0 1 1 1 1]
 [1 0 0 0 0]]

我试过sk-image,但功能不完全匹配。后来发现scipy.ndimage.label功能接近,但默认会把角落相邻的区域拆分成独立数组,不符合需求。之后意识到structure参数正是解决问题的关键,现将实现方法整理如下。

解决方案

步骤1:使用scipy.ndimage.label标记连通区域

scipy.ndimage.label可以识别数组中的连通区域,默认采用4邻域(仅上下左右相邻)的连通规则。如果需要包含8邻域(含对角线/角落相邻)的连通判断,需通过structure参数指定自定义的连通结构。

示例代码:

import numpy as np
from scipy.ndimage import label

# 输入稀疏数组
input_array = np.array([
    [0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0],
    [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0]
])

# 定义8邻域连通结构(包含所有方向的相邻)
structure = np.array([
    [1, 1, 1],
    [1, 1, 1],
    [1, 1, 1]
])

# 标记连通区域
labeled_array, num_features = label(input_array, structure=structure)

运行后,labeled_array即为标记好的区域数组(与示例标记结果一致),num_features表示识别出的连通区域总数(此处为3)。

步骤2:提取每个连通区域的子数组

对每个标记的区域,先找到其最小包围矩形的边界,再从原数组中截取该矩形范围的子数组,保留原数组的0和非零值。

示例代码:

# 遍历每个连通区域
for label_num in range(1, num_features + 1):
    # 获取当前标记区域的所有坐标
    rows, cols = np.where(labeled_array == label_num)
    
    # 计算最小包围矩形的上下左右边界
    min_row, max_row = rows.min(), rows.max()
    min_col, max_col = cols.min(), cols.max()
    
    # 截取对应子数组
    sub_array = input_array[min_row:max_row+1, min_col:max_col+1]
    
    # 输出结果
    print(f"连通区域 {label_num}:")
    print(sub_array)
    print("\n")

运行这段代码即可得到示例中的三个子数组输出。

完整代码

import numpy as np
from scipy.ndimage import label

# 输入稀疏数组
input_array = np.array([
    [0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0],
    [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0]
])

# 定义8邻域连通结构
structure = np.array([
    [1, 1, 1],
    [1, 1, 1],
    [1, 1, 1]
])

# 标记连通区域
labeled_array, num_features = label(input_array, structure=structure)

# 提取并输出每个连通区域的子数组
for label_num in range(1, num_features + 1):
    rows, cols = np.where(labeled_array == label_num)
    min_row, max_row = rows.min(), rows.max()
    min_col, max_col = cols.min(), cols.max()
    sub_array = input_array[min_row:max_row+1, min_col:max_col+1]
    print(f"连通区域 {label_num}:")
    print(sub_array)
    print()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 00:30:17