OpenCV2编程手册笔记之 5.5分水岭算法对图像进行分割

分水岭算法可以用来快速分割图像成为同类区域

原理概述:将图像视为拓扑结构的地图,均质区域就是被陡峭边缘包围的平坦盆地,因而,可以选出较为平坦的区域。

分水岭分割的结果通过cv::watershed函数获取,在这里,我们创建一个WatershedSegmenter类,进行分水岭算法的封装工作。

整体算法概述:

在选取的图像中,我们先进行二值化操作,操作争取将前景物体最大可能性提出。

之后,多次采用腐蚀的方法得到目标的前景图片,这个前景图片就只有0和255两个灰度值;

再多次使用膨胀的方法得到目标的背景图片,在之后使灰度图中高于128灰度的像素变为0,低于的部分为128(采用threshold);

之后,将前景背景相加,得到一张标记图,这张标记图就只有0,128,255三个灰度值。

之后,就可以得到图片了。

啥也不说,上代码。

分水岭算法概述:

1.一张灰度图,我们先将灰度值想象成柱状图,那么我们就能得到一张三维的灰度柱状图分布表。

2.如上所述,二值化后的图片只有0,128,255的几个值。

3.也就是说,腐蚀过后的图片是我们的前景图片,只有0和255这两个值,在三维图上,255的选定区域是最高的山峰,也就是标记区域,代表着目标图像。

   膨胀+二值化选取之后的图像拥有128和0两个值,0对应的是目标图像的区域,128对应着无关背景。

4.现在,将二者相加:

   我们可以得到中心有着高亮“山峰”的目标图像区域,以及无关的背景(腐蚀图像中255部分和膨胀图像中0相加;膨胀图像中128部分和腐蚀图像中0相加)

5.现在想象一下这张三维灰度直方图,255部分和0连接;0部分和128部分连接;128部分和255部分不相连接

   分水岭算法,现在就从255部分开始“注水”,也就是说,255部分用来确定从哪里开始“注水”。当注水到128部分和0部分边界时,注水停止。

   这时,前景就全被选出来了。

WatershedSegmenter类

#pragma once
#include "stdafx.h"
#include
class WatershedSegmenter
{
public:
    WatershedSegmenter();
    ~WatershedSegmenter();
private:
    cv::Mat markers;
public:
    void setMarkets(const cv::Mat &marketImage)
    {
        marketImage.convertTo(markers, CV_32S);
    }
    cv::Mat process(const cv::Mat &image);
    cv::Mat getSegmentation();
    cv::Mat getWatersheds();
};


#include "stdafx.h"
#include "WatershedSegmenter.h"


WatershedSegmenter::WatershedSegmenter()
{
}


WatershedSegmenter::~WatershedSegmenter()
{
}

cv::Mat WatershedSegmenter::process(const cv::Mat &image)
{
    cv::watershed(image, markers);
    return markers;
}

cv::Mat WatershedSegmenter::getSegmentation()
{
    cv::Mat tmp;
    markers.convertTo(tmp, CV_8U);
    return tmp;
}

cv::Mat WatershedSegmenter::getWatersheds()
{
    cv::Mat tmp;
    markers.convertTo(tmp, CV_8U, 255, 255);
    return tmp;
}


main函数


#include "stdafx.h"
#include
#include "WatershedSegmenter.h"
#include "MorphoFeatures.h"

int main()
{
    cv::Mat image = cv::imread("F:\\group.jpg");
    cv::Mat binary = cv::imread("F:\\Image\\binary.bmp", 0);
    cv::Mat fg, bg;
    cv::Mat markers(binary.size(), CV_8U, cv::Scalar(0));
    WatershedSegmenter segmenter;
    cv::erode(binary, fg, cv::Mat(), cv::Point(-1, -1), 6);
    cv::dilate(binary, bg, cv::Mat(), cv::Point(-1, -1), 6);
    cv::threshold(bg, bg, 1, 128, cv::THRESH_BINARY_INV);
    markers = fg + bg;
    segmenter.setMarkets(markers);
    segmenter.process(image);
    cv::imshow("Foreground Image", fg);
    cv::imshow("Background Image", bg);
    cv::imshow("Segmentation", segmenter.getSegmentation());
    cv::imshow("Watersheds", segmenter.getWatersheds());
    cv::waitKey(0);
    return 0;
}

你可能感兴趣的:(OpenCV2,计算机视觉编程手册,学习笔记)