OpenCV学习(二十) :分水岭算法:watershed()

本文详细介绍了OpenCV中的分水岭算法,包括watershed()函数的使用、手动和自动添加markers的示例,以及基于距离的分水岭算法。通过图像处理步骤,如灰度化、边缘检测和形态学操作,实现图像区域的精确分割。

OpenCV学习(二十) :分水岭算法:watershed()

参考博客:
OpenCV—分水岭算法
图像处理——分水岭算法
OpenCV学习(7) 分水岭算法(1)
Opencv分水岭算法——watershed自动图像分割用法 -牧野-

分水岭算法是一种图像区域分割法,在分割的过程中,它会把跟临近像素间的相似性作为重要的参考依据,从而将在空间位置上相近并且灰度值相近(求梯度)的像素点互相连接起来构成一个封闭的轮廓。分水岭算法常用的操作步骤:彩色图像灰度化,然后再求梯度图,最后在梯度图的基础上进行分水岭算法,求得分段图像的边缘线。

1、watershed()函数

void watershed( 
InputArray image, 	          // 必须是一个8bit 3通道彩色图像矩阵序列
InputOutputArray markers      // markers必须包含了种子点信息:算法会根据markers传入的轮廓作为种子(也就是所谓的注水点),
//对图像上其他的像素点根据分水岭算法规则进行判断,并对每个像素点的区域归属进行划定,
//直到处理完图像上所有像素点。而区域与区域之间的分界处的值被置为“-1”,以做区分。

==markers==
在将图像传递给函数之前,您必须粗略地勾勒出索引为正(>0)的图像标记中的所需区域。
因此,每个区域都表示为一个或多个具有像素值1,2,3的连接组件,以此类推。
可以使用findcontours()drawcontours()从二进制掩码中检索这些标记。这些标记是未来图像区域的“种子”。
标记中的所有其他像素,如果它们与轮廓区域的关系未知,应该由算法定义,则应该设置为0。
在函数输出中,标记中的每个像素被设置为“seed”组件的值,或者在区域之间的边界处设置为-1); 

2、示例一:手动添加 markers

watershed图像自动分割的实现步骤:
1)图像灰度化、滤波、Canny边缘检测
2)查找轮廓,并且把轮廓信息按照不同的编号绘制到watershed的第二个入参merkers上,相当于标记注水点。
3)watershed分水岭运算
4)绘制分割出来的区域,视觉控还可以使用随机颜色填充,或者跟原始图像融合以下,以得到更好的显示效果。

#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

#define WINDOW_NAME1 "【程序窗口1】"        //为窗口标题定义的宏
#define WINDOW_NAME2 "【分水岭算法效果图】"        //为窗口标题定义的宏

Mat g_maskImage, g_srcImage;
Point prevPt(-1, -1);

int main()
{
   
   
    //输出一些帮助信息
    printf(  "\n\n\n\t欢迎来到【分水岭算法】示例程序~\n\n");
    printf(  "\t请先用鼠标在图片窗口中标记出大致的区域,\n\n\t然后再按键【1】或者【SPACE】启动算法。"
        "\n\n\t按键操作说明: \n\n"
        "\t\t键盘按键【1】或者【SPACE】- 运行的分水岭分割算法\n"
        "\t\t键盘按键【2】- 恢复原始图片\n"
        "\t\t键盘按键【ESC】- 退出程序\n\n\n");


    //【1】载入原图并显示,初始化掩膜和灰度图
    g_srcImage = imread("F:/C++/2. OPENCV 3.1.0/TEST/1.jpg", 1);
    imshow( WINDOW_NAME1, g_srcImage );

    Mat srcImage,grayImage;
    g_srcImage.copyTo(srcImage);
    cvtColor(g_srcImage, g_maskImage, COLOR_BGR2GRAY);  // 彩色图转灰度图
    cvtColor(g_maskImage, grayImage, COLOR_GRAY2BGR);   // 转回三通道图
     g_maskImage = Scalar::all(0);

    //【2】设置鼠标回调函数
    setMouseCallback( WINDOW_NAME1, on_Mouse, 0 );

    //【3】轮询按键,进行处理
    while(1)
    {
   
   
        //获取键值
        int c = waitKey(0);

        //若按键键值为ESC时,退出
        if( (char)c == 27 )
            break;

        //按键键值为2时,恢复源图
        if( (char)c == '2' )
        {
   
   
            g_maskImage = Scalar::all(0);
            srcImage.copyTo(g_srcImage);
            imshow( "image", g_srcImage );
        }

        //若检测到按键值为1或者空格,则进行处理
        if( (char)c == '1' || (char)c == ' ' )
  
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值