如何在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
相关产品推荐
相关产品推荐

