OpenCV2 使用分水岭算法对图像分割的个人理解 cv::watershed()
来源:互联网 发布:centos 查看硬盘分区 编辑:程序博客网 时间:2024/05/20 11:34
本文是基于《opecv2 计算机视觉编程手册》中的案例对分水岭算法进行解读。
先介绍一下分水岭分割方法。它是一种基于拓扑理论的数学形态学的分割方法,其基本思想是把图像看作是测地学上的拓扑地貌,图像中每一点像素的灰度值表示该点的海拔高度,每一个局部极小值及其影响区域称为集水盆,而集水盆的边界则形成分水岭。分水岭的概念和形成可以通过模拟浸入过程来说明。在每一个局部极小值表面,刺穿一个小孔,然后把整个模型慢慢浸入水中,随着浸入的加深,每一个局部极小值的影响域慢慢向外扩展,在两个集水盆汇合处构筑大坝,即形成分水岭。
一般的分水岭算法会对微弱边缘,图像中的噪声,物体表面细微的灰度变化造成过度的分割。opencv中的分水岭算法对此进行了改进,它使用预定义的一组标记来引导对图像的分割。理解这一节,关键是理解这个标记。书上这一节的内容对这个标记讲得很模糊,网上也搜了很多cv::watershed(),大部分内容是opencv1.0案例使用鼠标响应事件的,有个别是opencv2.0的案例,但都只是复制代码,并未做一些解读。这里我谈谈自己的一些看法,希望对大家有所帮助,如有理解不正确的地方还请高手多多指教。
watershedSegmenter.h
#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) { //watershed()的输入参数必须为一个32位有符号的标记,所以要先进行转换 markerImage.convertTo(markers,CV_32S); } //执行watershed() cv::Mat process(const cv::Mat &image) { // Apply watershed cv::watershed(image,markers); return markers; } // 以图像形式返回结果 cv::Mat getSegmentation() { cv::Mat tmp; // 从32S到8U(0-255)会进行饱和运算,所以像素高于255的一律复制为255 markers.convertTo(tmp,CV_8U);// return tmp; } // 以图像形式返回分水岭(我理解的是分割线) cv::Mat getWatersheds() { cv::Mat tmp; //在设置标记图像,即执行setMarkers()后,边缘的像素会被赋值为-1,其他的用正整数表示 //下面的这个转换可以让边缘像素变为-1*255+255=0,即黑色,其余的溢出,赋值为255,即白色。 markers.convertTo(tmp,CV_8U,255,255); return tmp; }};#endif
segment.cpp
#include <iostream>#include <opencv2/core/core.hpp>#include <opencv2/imgproc/imgproc.hpp>#include <opencv2/highgui/highgui.hpp>#include "watershedSegmentation.h"int main(){ // Read input image 原图 cv::Mat image= cv::imread("../group.jpg"); if (!image.data) return 0; // Display the image cv::namedWindow("Original Image"); cv::imshow("Original Image",image);
group.jpg
// 二值图 这里进行了像素反转,因为一般我们用255白色表示前景(物体),用0黑色表示背景 cv::Mat binary; binary= cv::imread("../binary.bmp",0); // Display the binary image cv::namedWindow("Binary Image"); cv::imshow("Binary Image",binary);
binary.bmp
// 由二值图像获得前景。腐蚀。移除噪点与微小物体 cv::Mat fg; cv::erode(binary,fg,cv::Mat(),cv::Point(-1,-1),6); // Display the foreground image cv::namedWindow("Foreground Image"); cv::imshow("Foreground Image",fg);
fg前景
//膨胀二值图来获取背景(只有草地,没有树林) cv::Mat bg; cv::dilate(binary,bg,cv::Mat(),cv::Point(-1,-1),6); cv::threshold(bg,bg,1,128,cv::THRESH_BINARY_INV); //最后一个参数的表示 ifsrc>1,dst=0,else dst=128。这样就使背景全为灰色(128) // Display the background image cv::namedWindow("Background Image"); cv::imshow("Background Image",bg);
bg背景
// Show markers image cv::Mat markers(binary.size(),CV_8U,cv::Scalar(0)); markers= fg+bg;//使用重载操作符+ cv::namedWindow("Markers"); cv::imshow("Markers",markers);
markers标记图像 (最初的markers) 我觉得难点就是对这个标记图像的理解。下面谈谈我的个人看法。这个图像中,随便找一头牛。前景(物体:牛)是白色255,中间是黑色0,再然后才是背景灰128。可以把这3数看成海拔图,两个山岭相连,小的山岭128m,低处山谷0m,高的山岭255m。然后分水岭算法开始扩大白色255区域,往(黑色)注水,一直注到灰色的齐平,注水到黑色与白色部分全是白色。
设置markers,执行,显示结果
// Create watershed segmentation object WatershedSegmenter segmenter; // Set markers and process segmenter.setMarkers(markers); segmenter.process(image); // Display segmentation result cv::namedWindow("Segmentation"); cv::imshow("Segmentation",segmenter.getSegmentation());
注水后就成下图,上面的只是我的理解,可能不太正确,但我觉得这样便于理解怎么从上图白色那么一点变成下图。
结果图
// Display watersheds cv::namedWindow("Watersheds"); cv::imshow("Watersheds",segmenter.getWatersheds());
分水岭(分割线)
(完)
还请大家批评指教~
- OpenCV2 使用分水岭算法对图像分割的个人理解 cv::watershed()
- 0penCV_(Watershed Segmenter)使用 分水岭算法 对图像进行分割
- 使用分水岭算法对图像进行分割
- Opencv分水岭算法——watershed自动图像分割用法
- Opencv分水岭算法——watershed自动图像分割用法
- 计算机视觉之图像分割——分水岭算法WaterShed
- Opencv分水岭算法——watershed自动图像分割用法
- 基于边缘的图像分割——分水岭算法(watershed)算法分析(附opencv源码分析)
- matlab之watershed分水岭分割算法
- OpenCV2编程手册笔记之 5.5分水岭算法对图像进行分割
- opencv分水岭算法对图像进行分割
- 使用OpenCV和C++实现的分水岭算法(Watershed)
- 使用OpenCV和C++实现的分水岭算法(Watershed)
- watershed算法和图像分割
- 分水岭图像分割算法
- opencv2实现分水岭分割算法
- watershed分水岭算法的matlab例子详解
- waterShed-分水岭算法的原理及实现
- 阿里暑期实习c\c++研发工程师一面经历
- 第29题
- leetcode: Happy Number
- 水印文字
- 第三章 第4题
- OpenCV2 使用分水岭算法对图像分割的个人理解 cv::watershed()
- 第3章 第3题
- Windows窗口消息大全
- CodeForces 501D – Misha and Permutations Summation(康托/逆康托展开+树状数组+二分)
- [Spark]Django项目中使用Spark(pyspark)
- 31题
- [转] Node.js 框架比较: Express vs. Koa vs. Hapi
- 2015-04-22记录--一些JS疑惑
- [POJ] 1002 -> 487-3279