86.基于分水岭算法的分割

目录

        1 概念讲解

        2 分水岭算法详解

        3  API函数详解

        4. 使用C++编写代码进行实现

        1 概念讲解

        分水岭算法(Watershed Algorithm)是一种图像分割算法,用于将图像分割成具有平滑边界的不同区域。它模拟了水流在山谷和边界上的流动过程,将图像看作地形,将亮度梯度视为高度差,将分割结果看作是水流填充山谷后形成的湖泊。将灰度值较大的像素连成的线可以看做一条山脊,也就是分水岭。

        分水岭间的水就是用于二值化的灰度阈值,二值化阈值可以理解为水平面,比水平面低的区域会被淹没,刚开始用水填充每个孤立的山谷(局部最小值)。

        当水平面上升到一定高度时,水就会溢出当前山谷,可以通过在分水岭上修大坝,避免两个山谷的水汇集,因此图像就可以分为两个像素集合,一个是被水淹没的山谷像素集,另一个是分水岭线像素集。最终这些大坝形成的线就对整个图像进行了分区,实现对图像的分割。

        2 分水岭算法详解

        空间相邻且灰度值相近的像素级被划分为一个区域。

分水岭算法的流程:

        1.把图像的所有像素按照灰度值来分类,并设定一个测地距离阈值。

        2.找到灰度值最小的像素点,让Threshold从最小值开始增长,并标记局部区域首先被淹没的点为起始点。

        3.水平面在增长的过程中,会碰到周围的像素点,测量这些像素到起始点的测地距离,如果小于测地距离阈值,则将这些像素掩膜,否则在这些像素上设置大坝。

        4.随着水平面越来越高,会设置更多更高的大坝,直到灰度最大值,所有区域都在分水岭线上相遇,这些大坝就完成了图像像素分区。

        3  API函数详解

        在OpenCV中,分水岭算法相关的函数主要包括以下几个:

Void watershed(InputArray image, InputOutputArray markers);


image  --  输入图像,8位3通道彩色图像
markers  --  与输入图像大小相同,包含不同区域的轮廓,每个轮廓要有自己唯一的编号,
算法使用markers传入的轮廓作为注水点,对图像上其他像素点根据分水岭算法进行判断,
并对每个像素点的归属区域进行划定。

        用于执行连通组件分析的函数connectedComponents。它可以对标记图像进行连通区域的分析和标记。函数原型如下:

int connectedComponents(InputArray image, OutputArray labels, 
int connectivity, int ltype);

参数说明:

image:输入图像,要求是二值图像(黑白图像)。
labels:输出图像,用于存储标记结果,每个连通区域被赋予不同的标签。
connectivity:连接性设置,指定像素的连接方式,常用取值为4或8,表示4邻域或8邻域连接。
ltype:标签图像的数据类型,常用取值为 CV_32S 或 CV_16U。
返回值:

函数返回连通区域的数量(包括背景区域)。

使用 connectedComponents() 函数进行连通组件分析的流程通常如下:

        (1)读入并预处理待分析的二值图像。

        (2)定义一个与输入图像大小相同的标签图像,用于存储连通区域的标签。

        (3)调用 connectedComponents() 函数执行连通组件分析,将结果保存在标签图像中。

        (4)根据需要对标签图像进行后续处理,如去除小区域、提取感兴趣区域等。

        连通组件分析常用于目标检测、形状分析、图像分割等应用中。它可以将图像中的连通区域分离出来,并为每个连通区域赋予一个唯一的标签,便于后续的处理和分析。

        4. 使用C++编写代码进行实现

        下面是使用C++编写的示例代码,演示了如何在OpenCV中实现分水岭算法:

#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

int main() {
    // 加载图像
    Mat image = imread("ccla_dst.png", IMREAD_COLOR);

    // 预处理:灰度化、滤波等
    Mat grayImage;
    cvtColor(image, grayImage, COLOR_BGR2GRAY);
    medianBlur(grayImage, grayImage, 3);

    // 计算梯度图像
    Mat gradient;
    Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
    morphologyEx(grayImage, gradient, MORPH_GRADIENT, kernel);
    imshow("gradient Image", gradient);
    // 提取种子点
    Mat markers;
    threshold(gradient, markers, 10, 255, THRESH_BINARY );
   
    Mat markers8u;
    markers.convertTo(markers8u, CV_32S);

    // 执行分水岭算法
    watershed(image, markers8u);
    imshow("markers", markers);
    // 绘制分割边界
    Mat result = Mat::zeros(markers.size(), CV_8UC3);
    for (int i = 0; i < markers.rows; ++i) {
        for (int j = 0; j < markers.cols; ++j) {
            int index = markers.at<uchar>(i, j);
            if (index == 255)
                result.at<Vec3b>(i, j) = Vec3b(0, 255, 0);  // 边界处为绿色
            else
                result.at<Vec3b>(i, j) = image.at<Vec3b>(i, j);  // 其他区域保留原始颜色
        }
    }

    // 显示结果
    imshow("Original Image", image);
    imshow("Segmentation Result", result);
    waitKey(0);

    return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

别叭叭儿—好好学

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

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

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

打赏作者

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

抵扣说明:

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

余额充值