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

最后结果

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

猜你喜欢

转载自blog.csdn.net/kobeyu652453/article/details/107406413