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

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')

问题原因与解决说明

  1. mask变量未重置:原代码在循环外初始化mask,每次循环都会向同一个mask中添加新的maxima点,导致markers累积了之前图像的标记,最终watershed输出的标签可能出现重复值。解决方法是将mask的初始化移到for循环内部,每次处理新图像时重新创建空的mask。
  2. 多余的ndi.label调用:watershed函数的输出本身就是已经标记好的区域(每个粒子对应唯一的标签值),不需要再用ndi.label处理。ndi.label会将图像中所有相同数值的区域视为同一个标签,这就导致了原本属于不同粒子但标签值重复的区域被合并,出现你看到的错误。直接使用watershed的输出即可得到正确的标记结果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 11:39:47