本文是基于《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;
}
// 以图像