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

xiaoxiao2021-02-28  70

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

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

分水岭分割的结果通过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 <opencv2\opencv.hpp> 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 <opencv2\opencv.hpp> #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; }

转载请注明原文地址: https://www.6miu.com/read-64194.html

最新回复(0)