opencv8-图像分割-分水岭算法

因为现在在做的项目里牵涉到图像分割,这两天一直在找各种资料。终于可以更新了!

先补充点基础知识:

数字图像的质量取决于层次(Hierarchy)、对比度、清晰度。

层次越多视觉效果就越好。

对比度=最大亮度/最小亮度。

在对图像的研究和应用中,人们往往仅对图像中的某些部分感兴趣,这些部分一般称为目标或前景。这就是图像分割的意义啦!

概念:

图像分割就是指根据图像的灰度、颜色、纹理和形状等特征把图像划分成若干互不交叠的区域,并使这些特征在同一区域内呈现出相似性。

换句话说图像分割是基于亮度值的不连续性和相似性。

-不连续性是基于亮度的不连续变化分割图像,如边缘

-根据制定的准则将图像分割为相似的区域,如阈值处理、区域生长、区域分离和合并。

目的:

为了辨识和分析目标,图像分割就是要要把图像分成各有特性的区域并提取出感兴趣目标。

四大类方法:

1、基于阈值的分割方法

以像素性质的分布进行阈值处理。

要有一个可以比较的阈值,可以提前选取好,或者算法自动选取。这个方法主要是基于图像的灰度特征,把图像中每个像素的灰度值都跟阈值比较,得到比较结果后进行分类,相似灰度的像素在一个类中。所以此方法最重要的就是如何选取一个好的阈值。

2、基于边缘的分割方法

边缘处有很多具有明显差异的灰度不连续处,常用间断检测、边缘连接和边界检测。

3、基于区域的分割方法

直接搜寻区域进行分割。主要有种子区域生长法、区域分裂合并法和分水岭法。

4、基于图论的分割方法

此类方法把图像分割问题与图的最小割(min cut)问题相关联。首先将图像映射为带权无向图G=<V,E>,图中每个节点N∈V对应于图像中的每个像素,每条边∈E连接着一对相邻的像素,边的权值表示了相邻像素之间在灰度、颜色或纹理方面的非负相似度。而对图像的一个分割s就是对图的一个剪切,被分割的每个区域C∈S对应着图中的一个子图。而分割的最优原则就是使划分后的子图在内部保持相似度最大,而子图之间的相似度保持最小。基于图论的分割方法的本质就是移除特定的边,将图划分为若干子图从而实现分割。目前所了解到的基于图论的方法有GraphCut,GrabCut和Random Walk等。

今天先给大家介绍经典的图像分割算法-分水岭

函数原型:

 void watershed( InputArray image, InputOutputArray markers );

输入的是一个32位的有符号整数标记图,每个非零的像素表示一个标记。我们将图像中已知属于某个区域的像素进行标记。基于这个初始标记,分水岭算法开始确定其他像素的归属区域。

原理:

将图像看做拓扑结构的地图,那么均匀区域对应的是被陡峭地区包围的平坦盆地。但这个算法存在过分割问题。

#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
//#include "watershedSegmenter.h"

class watershedSegmenter
{
private:
	//用来表示标记(图)
	cv::Mat  markers;
public:
	void setMarkers(const cv::Mat & markerImage){
	
		//watershed()的输入参数必须为一个32位有符号的标记,所以要先进行转换
		markerImage.convertTo(markers,CV_32S);
	}
	//执行watershed()
	cv::Mat process(const cv::Mat &image){
	
		cv::watershed(image,markers);
		return markers;
	}
	//以图像形式返回结果
	cv::Mat getSegmentation(){
	
		cv::Mat temp;
		//从32S到8u(0-255)会进行饱和运算,所以像素高于255 的一律复制为255
		markers.convertTo(temp,CV_8U);
		return temp;
	}
	//以图像形式返回分水岭
	cv::Mat getWatersheds(){
	
		cv::Mat temp;
		markers.convertTo(temp,CV_8U,255,255);
		return temp;
	}
};
int main()
{
    // Read input image 原图
    cv::Mat image= cv::imread("E://group.jpg",1);
    if (!image.data)
        return 0; 

    // Display the image
    cv::namedWindow("Original Image");
    cv::imshow("Original Image",image);

	//二值图-像素反转
	cv::Mat binary;
	binary=cv::imread("E://binary.jpg",0);
	cv::namedWindow("Binary Image");
    cv::imshow("Binary Image",binary);

	//二值图像获得前景。腐蚀,移除噪点与微小物体
	cv::Mat foreground;
	cv::erode(binary,foreground,cv::Mat(),cv::Point(-1,-1),6);
	cv::namedWindow("foreground Image");
    cv::imshow("foreground Image",foreground);
	//膨胀二值图获取背景
	cv::Mat background;
	cv::dilate(binary,background,cv::Mat(),cv::Point(-1,-1),6);
	cv::threshold(background,background,1,128,cv::THRESH_BINARY_INV);
	cv::namedWindow("background Image");
    cv::imshow("background Image",background);
	//形成标记图
	cv::Mat markers(binary.size(),CV_8U,cv::Scalar(0));
	markers=foreground+background;
	cv::namedWindow("Markers");
    cv::imshow("Markers",markers);

	//创建分水岭分割对象
	watershedSegmenter segmenters;
	//设置标记并处理
	segmenters.setMarkers(markers);
	segmenters.process(image);
	cv::namedWindow("Segmenters");
	cv::imshow("Segmenters",segmenters.getSegmentation());

	cv::namedWindow("watershed");
	cv::imshow("watershed",segmenters.getSegmentation());
	
	cv::waitKey(0);
}





  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值