Watershed分割后ndi.label标记错误问题(Python)
问题:Watershed分割后ndi.label标记区域出现重复标签
我使用skimage.segmentation.watershed对粒子进行分割,分割效果良好,粒子能被正确分离。但使用ndi.label对不同区域标记时,部分已分割的粒子被赋予相同标签(如左上角粒子)。刚接触Python,不知如何解决,恳请提供帮助。以下是我使用的代码:
导入依赖库
# import hyperspy for reading directly ser or emd files import hyperspy.api as hs # The scikit image library will be used for segmenting the images from skimage.exposure import histogram from skimage.color import label2rgb from skimage import data, io, filters from skimage.filters import threshold_local, threshold_yen, threshold_li from skimage.filters import try_all_threshold from skimage.filters import gaussian from skimage.feature import peak_local_max from skimage.feature import canny from skimage import measure from skimage.morphology import label from skimage.morphology import remove_small_objects from skimage.draw import ellipse from skimage.measure import label, regionprops, regionprops_table from skimage.transform import rotate from skimage.segmentation import watershed # matplotlib for performing plots import matplotlib as mpl import matplotlib.pyplot as plt import matplotlib.patches as mpatches # Basic packages (math and statistics) import pandas as pd import numpy as np from scipy import ndimage as ndi from scipy import stats import math import glob import seaborn as sns
数据加载与预处理
# load data s=hs.load(folder+'*.emi',stack=True) # threshold thresh=threshold_li(s.data) binary=s>thresh # Cleaning cleaned=remove_small_objects(binary.data, min_size=5)
分割代码
# Define variables needed water=np.zeros([cleaned.shape[0],cleaned.shape[1],cleaned.shape[1]]) water_particles=np.zeros([cleaned.shape[0],cleaned.shape[1],cleaned.shape[1]]) eq_diam_total=np.array([]) # for loop for segmenting all the images using watershed. # I will use the commented "for i in range (cleaned.shape[0])" # once I manage to solve the segmentation issue: # for i in range (cleaned.shape[0]): for i in range(2,3): dist = ndi.distance_transform_edt(cleaned[i,:,:]) # make distance map maxima=peak_local_max(gaussian(dist, sigma=1.5),threshold_rel=None, min_distance=5) # find local maxima print('maxima',maxima.shape) # 关键修改:在循环内初始化mask,避免累积之前的标记点 mask=np.zeros(dist.shape, dtype=bool) mask[tuple(maxima.T)]=True markers,_=ndi.label(mask) print('markers',markers.shape) # segment water[i,:,:]=watershed(-dist, markers,mask=cleaned[i,:,:]) print('water', water.shape) # 错误点:watershed输出已经是标记好的区域,无需再用ndi.label # 原代码的这一步会把相同数值的区域合并,导致标签重复 # 直接使用water[i,:,:]作为标记结果即可 water_particles[i,:,:] = water[i,:,:] # 统计标签数量可以用np.unique water_labels = len(np.unique(water_particles[i,:,:])) - 1 # 减去背景0 print('water_labels',water_labels)
绘图代码
%matplotlib inline from skimage import color fig,axes=plt.subplots(1, 2, sharey=True) axes[0].imshow(color.label2rgb(water[i,:,:])) axes[0].axis('off') axes[0].set_title('After watershed segmentation') axes[1].imshow(color.label2rgb(water_particles[i,:,:])) axes[1].axis('off') axes[1].set_title('After label')
问题原因与解决说明
- mask变量未重置:原代码在循环外初始化
mask,每次循环都会向同一个mask中添加新的maxima点,导致markers累积了之前图像的标记,最终watershed输出的标签可能出现重复值。解决方法是将mask的初始化移到for循环内部,每次处理新图像时重新创建空的mask。 - 多余的ndi.label调用:
watershed函数的输出本身就是已经标记好的区域(每个粒子对应唯一的标签值),不需要再用ndi.label处理。ndi.label会将图像中所有相同数值的区域视为同一个标签,这就导致了原本属于不同粒子但标签值重复的区域被合并,出现你看到的错误。直接使用watershed的输出即可得到正确的标记结果。
内容的提问来源于stack exchange,提问作者Miquel Vega
相关产品推荐
相关产品推荐

