如何基于面积阈值移除4连通区域(岛屿)?
移除面积小于指定阈值的4连通区域(岛屿)
需求说明
移除所有面积小于指定阈值的4连通区域(岛屿),其中岛屿定义为4连通结构——仅上下左右四个方向相邻的1构成同一岛屿。
输入示例
输入数组代码实现:
import matplotlib.pyplot as plt import numpy as np array = np.array( [[1, 1, 1, 1, 0, 1, 1, 0, 0, 0], [0, 1, 0, 1, 0, 0, 1, 1, 0, 1], [0, 1, 1, 1, 0, 0, 0, 0, 1, 1], [1, 1, 0, 1, 0, 1, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 1, 0, 1, 0, 1, 1, 1], [0, 0, 0, 0, 0, 0, 1, 1, 1, 0], [1, 1, 1, 1, 0, 1, 1, 0, 1, 1], [1, 0, 1, 0, 0, 0, 0, 1, 1, 1], [1, 1, 1, 0, 0, 1, 0, 1, 0, 1]]) plt.matshow(array)
输入可视化效果:背景为黑色(值为0),分布多个大小不一的白色岛屿(值为1的区域)。
预期输出(阈值设为5)
阈值设为5时,所有面积小于5的岛屿需被置为0,预期输出数组代码:
expected = np.array( [[1, 1, 1, 1, 0, 0, 0, 0, 0, 0], [0, 1, 0, 1, 0, 0, 0, 0, 0, 0], [0, 1, 1, 1, 0, 0, 0, 0, 0, 0], [1, 1, 0, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1, 1, 1], [0, 0, 0, 0, 0, 0, 1, 1, 1, 0], [1, 1, 1, 1, 0, 1, 1, 0, 1, 1], [1, 0, 1, 0, 0, 0, 0, 1, 1, 1], [1, 1, 1, 0, 0, 0, 0, 1, 0, 1]]) plt.matshow(expected)
预期输出可视化效果:仅保留面积≥5的大型白色岛屿,小型岛屿全部转为黑色(值为0)。
解决方案实现
借助scipy.ndimage工具包快速实现区域标记与面积过滤:
import numpy as np from scipy.ndimage import label, sum as ndi_sum def remove_small_islands(arr, threshold, connectivity=1): # 标记4连通区域(connectivity=1对应上下左右四方向) labeled_arr, num_features = label(arr, structure=np.ones((3,3)) * connectivity) # 统计每个标记区域的面积(即区域内1的数量) area = ndi_sum(arr, labeled_arr, range(num_features + 1)) # 生成掩码:仅保留面积≥阈值的区域 mask = np.isin(labeled_arr, np.where(area >= threshold)[0]) # 应用掩码,将小型岛屿置为0 return arr * mask # 测试验证 result = remove_small_islands(array, threshold=5) print(np.array_equal(result, expected)) # 输出True # 可视化处理结果 plt.matshow(result) plt.show()
代码说明
label函数:对数组中的4连通区域进行标记,每个岛屿分配唯一的标签值。ndi_sum:按标签统计每个区域的面积,即区域内值为1的单元格总数。- 掩码生成:通过
np.isin筛选出符合面积要求的区域标签,生成布尔掩码后与原数组相乘,直接过滤掉小型岛屿。
内容的提问来源于stack exchange,提问作者AMA
相关产品推荐
相关产品推荐

