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

来源:互联网 发布:百度seo 价格 编辑:程序博客网 时间:2024/05/20 09:48

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

先补充点基础知识:

数字图像的质量取决于层次(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 的一律复制为255markers.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);}





原创粉丝点击