opencv进阶学习笔记14:分水岭算法 实现图像分割

基础版学习笔记目录:
python3+opencv学习笔记汇总目录(适合基础入门学习)
进阶版笔记目录链接:
python+opencv进阶版学习笔记目录(适合有一定基础)

分水岭算法原理

分水岭算法是一种图像区域分割法,在分割的过程中,它会把跟临近像素间的相似性作为重要的参考依据,从而将在空间位置上相近并且灰度值相近的像素点互相连接起来构成一个封闭的轮廓,封闭性是分水岭算法的一个重要特征。
其他图像分割方法,如阈值,边缘检测等都不会考虑像素在空间关系上的相似性和封闭性这一概念,彼此像素间互相独立,没有统一性。分水岭算法较其他分割方法更具有思想性,更符合人眼对图像的印象。

任意的灰度图像可以被看做是地质学表面,高亮度的地方是山峰,低亮度的地方是山谷。给每个孤立的山谷(局部最小值)不同颜色的水(标签),当水涨起来,根据周围的山峰(梯度),不同的山谷也就是不同的颜色会开始合并,要避免这个,你可以在水要合并的地方建立障碍,直到所有山峰都被淹没。你所创建的障碍就是分割结果,这个就是分水岭的原理,但是这个方法会分割过度,因为有噪点,或者其他图像上的错误。所以OpenCV实现了一个基于掩模的分水岭算法,你可以指定哪些是要合并的点,哪些不是,这是一个交互式的图像分割,我们要做的是给不同的标签。给我们知道是前景或者是目标用一种颜色加上标签,给我们知道是背景或者非目标加上另一个颜色,最后不知道是什么的区域标记为0. 然后使用分水岭算法。

距离变换

先将图像进行距离变换使出现山峰和山谷

API实现

1图像二值化

import cv2 as cv
import numpy as np

def watershed_demo():
    # remove noise if any
    print(src.shape)#图像维度(348, 500, 3)
    blurred = cv.pyrMeanShiftFiltering(src, 10, 100)#边缘保留滤波去噪
    # gray\binary image
    gray = cv.cvtColor(blurred, cv.COLOR_BGR2GRAY)#转换为灰度图
    ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)#二值化
    cv.imshow("binary-image", binary)
print("--------- Python OpenCV Tutorial ---------")
src = cv.imread("coins.jpg")
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE)
cv.imshow("input image", src)
watershed_demo()
cv.waitKey(0)
cv.destroyAllWindows()

2形态学操作

import cv2 as cv
import numpy as np

def watershed_demo():
    # remove noise if any
    print(src.shape)#图像维度(348, 500, 3)
    blurred = cv.pyrMeanShiftFiltering(src, 10, 100)#均值偏移滤波去噪
    # gray\binary image
    gray = cv.cvtColor(blurred, cv.COLOR_BGR2GRAY)#转换为灰度图
    ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)#二值化
    #cv.imshow("binary-image", binary)
    # 形态学变换
    kernel = cv.getStructuringElement(cv.MORPH_RECT, (3, 3))#卷积核
    mb = cv.morphologyEx(binary, cv.MORPH_OPEN, kernel, iterations=2)#开运算
    sure_bg = cv.dilate(mb, kernel, iterations=3)#对开运算结果膨胀
    cv.imshow("mor-opt", sure_bg)
print("--------- Python OpenCV Tutorial ---------")
src = cv.imread("coins.jpg")
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE)
cv.imshow("input image", src)
watershed_demo()
cv.waitKey(0)
cv.destroyAllWindows()

3对开运算结果进行距离变换
先不管膨胀结果,对开运算结果进行距离计算

def distanceTransform(src, distanceType, maskSize, dst=None, dstType=None)

src:输入的图像,一般为二值图像
distanceType:所用的求解距离的类型(CV_DIST_L1, CV_DIST_L2 , CV_DIST_C)
maskSize:距离变换掩模的大小

我们需要对distanceTransform返回的结果进行归一化处理,使用normalize

import cv2 as cv
import numpy as np

def watershed_demo():
    # remove noise if any
    print(src.shape)#图像维度(348, 500, 3)
    blurred = cv.pyrMeanShiftFiltering(src, 10, 100)#均值偏移滤波去噪
    # gray\binary image
    gray = cv.cvtColor(blurred, cv.COLOR_BGR2GRAY)#转换为灰度图
    ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)#二值化
    #cv.imshow("binary-image", binary)

    # m形态学操作
    kernel = cv.getStructuringElement(cv.MORPH_RECT, (3, 3))#卷积核
    mb = cv.morphologyEx(binary, cv.MORPH_OPEN, kernel, iterations=2)#开运算
    sure_bg = cv.dilate(mb, kernel, iterations=3)#对开运算结果膨胀
    #cv.imshow("mor-opt", sure_bg)

    # 对开运算结果距离变换
    dist = cv.distanceTransform(mb, cv.DIST_L2, 3)
    dist_output = cv.normalize(dist, 0, 1.0, cv.NORM_MINMAX)
    cv.imshow("distance-t", dist_output * 50)

print("--------- Python OpenCV Tutorial ---------")
src = cv.imread("coins.jpg")
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE)
cv.imshow("input image", src)
watershed_demo()
cv.waitKey(0)

cv.destroyAllWindows()

4生成种子

import cv2 as cv
import numpy as np

def watershed_demo():
    # remove noise if any
    print(src.shape)#图像维度(348, 500, 3)
    blurred = cv.pyrMeanShiftFiltering(src, 10, 100)#均值偏移滤波去噪
    # gray\binary image
    gray = cv.cvtColor(blurred, cv.COLOR_BGR2GRAY)#转换为灰度图
    ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)#二值化
    #cv.imshow("binary-image", binary)

    # m形态学操作
    kernel = cv.getStructuringElement(cv.MORPH_RECT, (3, 3))#卷积核
    mb = cv.morphologyEx(binary, cv.MORPH_OPEN, kernel, iterations=2)#开运算
    sure_bg = cv.dilate(mb, kernel, iterations=3)#对开运算结果膨胀
    #cv.imshow("mor-opt", sure_bg)

    # 对开运算结果距离变换
    dist = cv.distanceTransform(mb, cv.DIST_L2, 3)
    dist_output = cv.normalize(dist, 0, 1.0, cv.NORM_MINMAX)
    #cv.imshow("distance-t", dist_output * 50)


    ret, surface = cv.threshold(dist, dist.max()*0.6, 255, cv.THRESH_BINARY)

    surface_fg = np.uint8(surface)
    cv.imshow("surface-bin", surface_fg)#种子

print("--------- Python OpenCV Tutorial ---------")
src = cv.imread("coins.jpg")
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE)
cv.imshow("input image", src)
watershed_demo()
cv.waitKey(0)
cv.destroyAllWindows()

5生成marker和分水岭变换

import cv2 as cv
import numpy as np

def watershed_demo():
    # remove noise if any
    print(src.shape)#图像维度(348, 500, 3)
    blurred = cv.pyrMeanShiftFiltering(src, 10, 100)#均值偏移滤波去噪
    # gray\binary image
    gray = cv.cvtColor(blurred, cv.COLOR_BGR2GRAY)#转换为灰度图
    ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)#二值化
    #cv.imshow("binary-image", binary)

    # m形态学操作
    kernel = cv.getStructuringElement(cv.MORPH_RECT, (3, 3))#卷积核
    mb = cv.morphologyEx(binary, cv.MORPH_OPEN, kernel, iterations=2)#开运算
    sure_bg = cv.dilate(mb, kernel, iterations=3)#对开运算结果膨胀
    #cv.imshow("mor-opt", sure_bg)

    # 对开运算结果距离变换
    dist = cv.distanceTransform(mb, cv.DIST_L2, 3)
    dist_output = cv.normalize(dist, 0, 1.0, cv.NORM_MINMAX)
    #cv.imshow("distance-t", dist_output * 50)


    ret, surface = cv.threshold(dist, dist.max()*0.6, 255, cv.THRESH_BINARY)

    surface_fg = np.uint8(surface)
    #cv.imshow("surface-bin", surface_fg)#种子

    unknown = cv.subtract(sure_bg, surface_fg)#种子区域除外的区域=膨胀结果-种子
    ret, markers = cv.connectedComponents(surface_fg)#联通区域

    # 分水岭变换
    markers = markers + 1
    markers[unknown == 255] = 0
    markers = cv.watershed(src, markers=markers)
    src[markers == -1] = [0, 0, 255]
    cv.imshow("result", src)
print("--------- Python OpenCV Tutorial ---------")
src = cv.imread("coins.jpg")
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE)
cv.imshow("input image", src)
watershed_demo()
cv.waitKey(0)
cv.destroyAllWindows()

最后结果

电气专业的计算机萌新,写博文不容易。如果你觉得本文对你有用,请点个赞支持下,谢谢。

  • 10
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
基于分水岭算法图像分割是一种常用的图像处理技术,可以将图像分割成多个区域,每个区域内的像素具有相似的特征。在 OpenCV 中,可以使用 cv2.watershed() 函数实现基于分水岭算法图像分割。 下面是一个简单的 Python 示例,演示如何使用基于分水岭算法图像分割: ```python import cv2 import numpy as np # 读取图像 img = cv2.imread('image.jpg') # 转换为灰度图像 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 阈值分割 ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU) # 形态学操作 kernel = np.ones((3,3),np.uint8) opening = cv2.morphologyEx(thresh,cv2.MORPH_OPEN,kernel,iterations=2) # 距离变换 dist_transform = cv2.distanceTransform(opening,cv2.DIST_L2,5) ret, sure_fg = cv2.threshold(dist_transform,0.1*dist_transform.max(),255,0) # 背景区域 sure_bg = cv2.dilate(opening,kernel,iterations=3) # 不确定区域 sure_fg = np.uint8(sure_fg) unknown = cv2.subtract(sure_bg,sure_fg) # 标记连通区域 ret, markers = cv2.connectedComponents(sure_fg) markers = markers + 1 markers[unknown==255] = 0 # 应用分水岭算法 markers = cv2.watershed(img,markers) img[markers == -1] = [255,0,0] # 显示结果 cv2.imshow('image', img) cv2.waitKey(0) cv2.destroyAllWindows() ``` 在上面的示例中,首先读取一张图像,并将其转换为灰度图像。然后使用阈值分割算法图像二值化。接下来,行形态学操作,以去除图像中的噪声。然后使用距离变换算法计算前景区域,并将其阈值化。接着,使用形态学操作计算背景区域。最后,使用 cv2.connectedComponents() 函数计算不确定区域,并使用标记连通区域的方法生成分水岭算法的输入标记图像。最后,应用 cv2.watershed() 函数图像分割,并在窗口中显示结果。 需要注意的是,分水岭算法的结果依赖于输入标记图像的质量,因此需要根据具体情况行调整,比如阈值分割的参数、形态学操作的参数、距离变换的参数等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

总裁余(余登武)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值