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

基于skimage的分水岭算法目标分割:技术选型与步骤指导问询

真实物体(垃圾/乌鸦)分割:流程梳理与后续操作指导

我完全理解你面对skimage五花八门的分割技术时的困惑——真实场景里的目标(比如你要检测的垃圾、乌鸦)和教程里的硬币、合成数据差异太大,不存在“一招鲜”的通用方法,但我们可以搭建一套可快速迭代调整的传统CV流程,核心思路是「降噪→突出目标特征→形态学修正→提取标记」,下面一步步帮你理清楚:

一、先把你的现有步骤按逻辑排序优化

首先纠正顺序,真实场景下的操作逻辑是先降噪再做特征提取,不然噪声会严重干扰阈值或边缘检测:

import skimage.io
import skimage.color
import skimage.filters
import skimage.morphology
import skimage.measure
import matplotlib.pyplot as plt
import numpy as np

# 1. 读取图像
img = skimage.io.imread('image.jpeg')
# 2. 转灰度图(RGB图像必做,单通道跳过)
gray = skimage.color.rgb2gray(img)
# 3. 去噪:这一步非常必要!真实场景的噪声会把后续分割搞乱
# 优先选双边滤波:能保留目标边缘同时去掉背景噪声,比高斯滤波更适合分割场景
filtered_img = skimage.restoration.denoise_bilateral(gray, sigma_color=0.05, sigma_spatial=15)
# 如果双边滤波速度太慢,再换高斯滤波:filtered_img = skimage.filters.gaussian(gray, sigma=1.5)
# 4. 特征突出:优先用Otsu阈值二值化,Sobel作为辅助补漏
# 注意:要根据目标的亮暗调整>或<——比如乌鸦是深色,就用filtered_img < otsu_thresh
otsu_thresh = skimage.filters.threshold_otsu(filtered_img)
binary_img = filtered_img > otsu_thresh  # 亮目标用>,暗目标用<
# 可选:如果Otsu分割出来的边缘不完整,结合Sobel边缘增强
sobel_img = skimage.filters.sobel(filtered_img)
binary_img = (binary_img | (sobel_img > 0.1))  # 把边缘和二值图合并

二、接下来的核心操作:形态学修正 + 目标标记

这一步是解决真实场景分割“碎块”“漏检”“粘连”的关键:

1. 形态学操作修复二值图

分割后的二值图往往会有小噪点、目标内部孔洞、目标断裂,用形态学操作修复:

  • 闭运算:先膨胀再腐蚀,填补目标内部的小孔洞、连接断裂的部分(特别适合垃圾、乌鸦这类不规则形状的目标)
  • 开运算:先腐蚀再膨胀,去掉背景里的小噪点
  • 可以组合使用,先开后闭:
# 创建结构元素:根据目标大小调整,比如5x5圆盘适合中等大小的物体
selem = skimage.morphology.disk(5)
# 开运算去除背景噪点
binary_cleaned = skimage.morphology.binary_opening(binary_img, selem)
# 闭运算填补目标孔洞、连接断裂部分
binary_cleaned = skimage.morphology.binary_closing(binary_cleaned, selem)
# 可选:如果目标还是断裂,用膨胀扩大;如果有多余部分,用腐蚀缩小
# binary_cleaned = skimage.morphology.binary_dilation(binary_cleaned, selem)

2. 处理粘连目标(可选)

如果图像里有多个目标粘连(比如一群乌鸦、一堆垃圾),用距离变换+分水岭算法分离:

# 计算距离变换:每个前景像素到背景的距离
distance = skimage.morphology.distance_transform_edt(binary_cleaned)
# 找距离变换的局部极大值作为分割种子点
local_max = skimage.feature.peak_local_max(distance, indices=False, footprint=np.ones((3, 3)), labels=binary_cleaned)
# 标记种子点
markers = skimage.measure.label(local_max)
# 分水岭分割粘连目标
labels = watershed(-distance, markers, mask=binary_cleaned)

3. 标记目标并可视化

最后把检测到的目标标记在原图上,还能过滤掉太小的噪点区域:

# 用label标记连通区域(如果用了分水岭,直接用上面的labels即可)
labels = skimage.measure.label(binary_cleaned)
# 获取每个区域的属性(面积、位置等)
regions = skimage.measure.regionprops(labels)

# 在原图上绘制标记
fig, ax = plt.subplots(figsize=(10, 8))
ax.imshow(img)
for region in regions:
    # 跳过太小的区域(过滤噪点,阈值根据目标大小调整)
    if region.area < 100:
        continue
    # 获取目标的外接矩形坐标
    minr, minc, maxr, maxc = region.bbox
    # 绘制红色矩形框
    rect = plt.Rectangle((minc, minr), maxc - minc, maxr - minr, fill=False, edgecolor='red', linewidth=2)
    ax.add_patch(rect)
    # 可选:标注目标编号和面积
    ax.text(minc, minr, f'Obj {region.label}\nArea: {region.area}', color='white', fontsize=9)
plt.axis('off')
plt.show()

三、针对垃圾/乌鸦的特殊调整建议

  • 乌鸦:深色、轮廓清晰,建议用filtered_img < otsu_thresh生成二值图,然后用闭运算连接羽毛缝隙的断裂部分
  • 垃圾:形态多样,可能需要调大双边滤波的sigma_spatial参数,或者尝试结合Sobel边缘和Otsu阈值,再用形态学操作修正
  • 如果传统方法效果始终不好,可以试试skimage的skimage.segmentation.watershed,或者考虑轻量的预训练语义分割模型,但传统方法是快速验证效果的首选

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 17:58:12