纯净、安全、绿色的下载网站

首页|软件分类|下载排行|最新软件|IT学院

当前位置:首页IT学院IT技术

OpenCV图像分割中的分水岭算法 OpenCV图像分割中的分水岭算法原理与应用详解

iracer   2021-03-28 我要评论
想了解OpenCV图像分割中的分水岭算法原理与应用详解的相关内容吗iracer在本文为您仔细讲解OpenCV图像分割中的分水岭算法的相关知识和一些Code实例欢迎阅读和指正我们先划重点:OpenCV,图像分割,分水岭算法下面大家一起来学习吧

图像分割是按照一定的原则将一幅图像分为若干个互不相交的小局域的过程它是图像处理中最为基础的研究领域之一目前有很多图像分割方法其中分水岭算法是一种基于区域的图像分割算法分水岭算法因实现方便已经在医疗图像模式识别等领域得到了广泛的应用

1.传统分水岭算法基本原理

分水岭比较经典的计算方法是L.Vincent于1991年在PAMI上提出的[1]传统的分水岭分割方法是一种基于拓扑理论的数学形态学的分割方法其基本思想是把图像看作是测地学上的拓扑地貌图像中每一像素的灰度值表示该点的海拔高度每一个局部极小值及其影响区域称为集水盆地而集水盆地的边界则形成分水岭分水岭的概念和形成可以通过模拟浸入过程来说明在每一个局部极小值表面刺穿一个小孔然后把整个模型慢慢浸人水中随着浸入的加深每一个局部极小值的影响域慢慢向外扩展在两个集水盆汇合处构筑大坝如下图所示即形成分水岭

传统分水岭算法示意图

然而基于梯度图像的直接分水岭算法容易导致图像的过分割产生这一现象的原因主要是由于输入的图像存在过多的极小区域而产生许多小的集水盆地从而导致分割后的图像不能将图像中有意义的区域表示出来所以必须对分割结果的相似区域进行合并
[1]L.Vincent, P Soille. Watersheds in digital space: An efficientalgorithms based on immersion simulation[J]. IEEE Trans. on Pattern Analysisand Machine Intelligence, 1991, 13(6): 583-598.

2.改进的分水岭算法基本原理

因为传统分水岭算法存在过分割的不足OpenCV提供了一种改进的分水岭算法使用一系列预定义标记来引导图像分割的定义方式使用OpenCV的分水岭算法cv::wathershed需要输入一个标记图像图像的像素值为32位有符号正数(CV_32S类型)每个非零像素代表一个标签它的原理是对图像中部分像素做标记表明它的所属区域是已知的分水岭算法可以根据这个初始标签确定其他像素所属的区域传统的基于梯度的分水岭算法和改进后基于标记的分水岭算法示意图如下图所示


传统基于梯度的分水岭算法和基于标记的分水岭算法原理图

从上图可以看出传统基于梯度的分水岭算法由于局部最小值过多造成分割后的分水岭较多而基于标记的分水岭算法水淹过程从预先定义好的标记图像(像素)开始较好的克服了过度分割的不足本质上讲基于标记点的改进算法是利用先验知识来帮助分割的一种方法因此改进算法的关键在于如何获得准确的标记图像即如何将前景物体与背景准确的标记出来

3.基于标记点的分水岭算法应用

基于标记点的分水岭算法应用步骤

● 封装分水岭算法类

● 获取标记图像

获取前景像素并用255标记前景

获取背景像素并用128标记背景未知像素使用0标记

合成标记图像

● 将原图和标记图像输入分水岭算法

● 显示结果

(1)封装分水岭算法类

将分水岭算法cv::watershed(image,markers)封装进类WatershedSegmenter并保存为头文件以便于操作(本段封装代码参考《OpenCV计算机视觉编程攻略(第二版)》)

#if !defined WATERSHS 
#define WATERSHS 
 
#include <opencv2/core/core.hpp> 
#include <opencv2/imgproc/imgproc.hpp> 
 
class WatershedSegmenter { 
 
 private: 
 
   cv::Mat markers; 
 
 public: 
 
   void setMarkers(const cv::Mat& markerImage) { 
 
    // Convert to image of ints 
    markerImage.convertTo(markers,CV_32S); 
   } 
 
   cv::Mat process(const cv::Mat &image) { 
 
    // Apply watershed 
    cv::watershed(image,markers); 
 
    return markers; 
   } 
 
   // Return result in the form of an image 
   cv::Mat getSegmentation() { 
      
    cv::Mat tmp; 
    // all segment with label higher than 255 
    // will be assigned value 255 
    markers.convertTo(tmp,CV_8U); 
 
    return tmp; 
   } 
 
   // Return watershed in the form of an image以图像的形式返回分水岭 
   cv::Mat getWatersheds() { 
   
    cv::Mat tmp; 
    //在变换前把每个像素p转换为255p+255(在conertTo中实现) 
    markers.convertTo(tmp,CV_8U,255,255); 
 
    return tmp; 
   } 
}; 
#endif 

(2)获取标记图像

标记前景

读取原图

// Read input image 
  cv::Mat image1= cv::imread("image.jpg"); 
  if (!image1.data) 
    return 0;  
// Display the color image 
  cv::resize(image1, image1, cv::Size(), 0.7, 0.7); 
  cv::namedWindow("Original Image1"); 
  cv::imshow("Original Image1",image1); 

原图

以下代码目的是获取前景物体的像素并用255标记这里使用阈值分割初步分割前景和背景接着使用形态学闭运算连接二值图像中前景的各个部分并平滑边缘如何更好的获取前景像素需要根据实际图像的情况灵活处理

// Identify image pixels with object 
   
  Mat binary; 
  cv::cvtColor(image1,binary,COLOR_BGRA2GRAY); 
  cv::threshold(binary,binary,30,255,THRESH_BINARY_INV);//阈值分割原图的灰度图获得二值图像 
  // Display the binary image 
  cv::namedWindow("binary Image1"); 
  cv::imshow("binary Image1",binary); 
  waitKey(); 
   
  // CLOSE operation 
  cv::Mat element5(5,5,CV_8U,cv::Scalar(1));//5*5正方形8位uchar型全1结构元素 
  cv::Mat fg1; 
  cv::morphologyEx(binary, fg1,cv::MORPH_CLOSE,element5,Point(-1,-1),1);// 闭运算填充物体内细小空洞、连接邻近物体 
 
  // Display the foreground image 
  cv::namedWindow("Foreground Image"); 
  cv::imshow("Foreground Image",fg1); 
  waitKey(); 

阈值分割原图像的灰度图


闭运算获取前景

标记背景和未知区域

在上面阈值分割得到的二值图像binary的基础上通过对白色前景的深度膨胀运算获得一个超过前景实际大小的物体紧接着用反向阈值将深度膨胀后的图像中的黑色部分转换成128即完成了对背景像素的标记实际上在0~255范围内任意不为0或255的值均可作为背景的标记当然如果有其他类型的物体可以使用另外一个数值作为其标记也就是说多个目标可以有多个标记来帮助分水岭算法正确分割图像

// Identify image pixels without objects 
   
  cv::Mat bg1; 
  cv::dilate(binary,bg1,cv::Mat(),cv::Point(-1,-1),4);//膨胀4次锚点为结构元素中心点 
  cv::threshold(bg1,bg1,1,128,cv::THRESH_BINARY_INV);//>=1的像素设置为128(即背景) 
  // Display the background image 
  cv::namedWindow("Background Image"); 
  cv::imshow("Background Image",bg1); 
  waitKey(); 

将背景设置为128未知区域设置为0

合成标记图像

将前景、背景及未知区域合成为一个标记图像则标记图像中通过255标记前景物体通过128标记背景通过0标记未知区域

//Get markers image 
 
  Mat markers1 = fg1 + bg1; //使用Mat类的重载运算符+来合并图像 
  cv::namedWindow("markers Image"); 
  cv::imshow("markers Image",markers1); 
  waitKey(); 

标记图像

(3)分水岭算法分割图像

将标记图像和原图输入分水岭算法封装的类WatershedSegmenter执行分水岭算法并显示算法运行的结果

// Apply watershed segmentation 
 
  WatershedSegmenter segmenter1; //实例化一个分水岭分割方法的对象 
  segmenter1.setMarkers(markers1);//设置算法的标记图像使得水淹过程从这组预先定义好的标记像素开始 
  segmenter1.process(image1);   //传入待分割原图 
    
  // Display segmentation result 
  cv::namedWindow("Segmentation1"); 
  cv::imshow("Segmentation1",segmenter1.getSegmentation());//将修改后的标记图markers转换为可显示的8位灰度图并返回分割结果(白色为前景灰色为背景0为边缘) 
  waitKey(); 
    // Display watersheds 
  cv::namedWindow("Watersheds1"); 
  cv::imshow("Watersheds1",segmenter1.getWatersheds());//以图像的形式返回分水岭(分割线条) 
  waitKey(); 

代码segmenter1.process(image)将修改标记图像markers每个值为0的像素都会被赋予一个输入标签而边缘处的像素赋值为-1得到的标签图像如下图所示


显示分水岭分割图像


分水岭分割线显示

(4)显示结果图像

本步骤的目的是将前景物体的分割结果在黑/白底色中显示出来背景颜色由黑转白时使用了Mat矩阵扫描的.ptr方法与指针运算

// Get the masked image 
  Mat maskimage = segmenter1.getSegmentation(); 
  cv::threshold(maskimage,maskimage,250,1,THRESH_BINARY); 
  cv::cvtColor(maskimage,maskimage,COLOR_GRAY2BGR); 
 
  maskimage = image1.mul(maskimage); 
  cv::namedWindow("maskimage"); 
  cv::imshow("maskimage",maskimage); 
  waitKey(); 
 
  // Turn background (0) to white (255) 
  int nl= maskimage.rows; // number of lines 
  int nc= maskimage.cols * maskimage.channels(); // total number of elements per line 
 
  for (int j=0; j<nl; j++) { 
     uchar* data= maskimage.ptr<uchar>(j); 
    for (int i=0; i<nc; i++)  
    { 
      // process each pixel --------------------- 
      if (*data==0) //将背景由黑色改为白色显示 
        *data=255; 
      data++;//指针操作:如为uchar型指针则移动1个字节即移动到下1列 
    } 
   } 
  cv::namedWindow("result"); 
  cv::imshow("result",maskimage); 
  waitKey(); 

原图的前景分割图(黑色背景)


原图的前景分割图(白色背景)

从上图的分割结果可以看出基于标记图像的分水岭算法较好的实现了复杂背景下前景目标分割算法应用的关键步骤为标记图像的获取目前很多文献提出了各类获取标记图像的方法如何使用还需要根据所处理的图像来量身确定

贴出实验原始图像:)


相关文章

猜您喜欢

网友评论

Copyright 2020 www.fresh-weather.com 【世纪下载站】 版权所有 软件发布

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 点此查看联系方式