从NumPy数组中高效提取同值区域聚类的实现方案(解决递归方法的性能与栈溢出问题)
高效提取NumPy数组中同值聚类的方案
针对你遇到的递归方法效率低、栈溢出的问题,我推荐使用scikit-image库中的区域分析工具——这是计算机视觉领域处理掩码区域分割的标准方案,完全基于矩阵操作,高效且不易出错。
实现步骤
1. 预处理:将字符串格式数据转为NumPy数组
首先把你给出的字符串列表转换成数值型的NumPy数组,方便后续处理:
import numpy as np from skimage import measure # 你的示例数据 data_str = [ "01110000000000000000000000", "00111110000222222220000000", "01110000000222222200000000", "00000000000222000000000000", "00000000000000000000000000", "00000000000000000000000000", "00003333300000000000000000", "00003333322222000000000000", "00000000022222000000000000", "00000000000000222000000000", "00000000000000222000000000", "00000000000000000000000000", "00000000000000000000000000", "00000000000000000000000000", "00000000000000000000000000", "00000000000000000000000000" ] # 转换为NumPy数值数组 arr = np.array([list(s) for s in data_str], dtype=int)
2. 标记连通区域并提取聚类
使用measure.label标记所有非零连通区域,再通过measure.regionprops提取每个区域的坐标和对应数值:
# 标记连通区域:connectivity=2表示8连通,=1表示4连通,可按需调整 label_img = measure.label(arr, background=0, connectivity=2) # 存储最终聚类结果:键是聚类的数值,值是该数值下所有聚类的坐标列表 clusters = {} # 遍历每个标记的区域 for region in measure.regionprops(label_img, intensity_image=arr): # 获取区域的数值(因为每个聚类仅含相同数字,取第一个像素的值即可) val = region.intensity_mean # 由于区域内值相同,均值等于实际值 val = int(val) # 获取区域所有像素的坐标((行, 列)格式) coords = list(zip(region.coords[:, 0], region.coords[:, 1])) # 按数值分组存储 if val not in clusters: clusters[val] = [] clusters[val].append(coords)
3. 查看结果
打印结果就能看到每个数值对应的所有聚类坐标:
# 输出2的所有聚类 print("数值2的聚类:") for idx, cluster in enumerate(clusters[2], 1): print(f"聚类{idx}: {cluster}") # 输出3的所有聚类 print("\n数值3的聚类:") for idx, cluster in enumerate(clusters[3], 1): print(f"聚类{idx}: {cluster}")
方案优势
- 高效稳定:基于底层矩阵运算,比递归快几个数量级,完全避免栈溢出问题;
- 灵活可控:可通过
connectivity参数选择4连通或8连通的区域判定规则; - 成熟可靠:scikit-image是计算机视觉领域的主流库,处理掩码区域分割的场景经过大量验证。
备选方案(无scikit-image时)
如果无法安装scikit-image,也可以用OpenCV的connectedComponentsWithStats函数,实现逻辑类似:
import cv2 # 转换为uint8格式(OpenCV要求) arr_cv = arr.astype(np.uint8) # 标记连通区域 num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(arr_cv, connectivity=8) clusters_cv = {} for label in range(1, num_labels): # 跳过背景(label=0) # 获取当前区域的坐标 coords = np.where(labels == label) coords = list(zip(coords[0], coords[1])) # 获取区域数值 val = arr[coords[0][0], coords[0][1]] if val not in clusters_cv: clusters_cv[val] = [] clusters_cv[val].append(coords)
内容的提问来源于stack exchange,提问作者Alexey
相关产品推荐
相关产品推荐

