5.5用分水岭算法实现图像分割

时间:2023-02-07 10:22:29
<img src="http://img.blog.csdn.net/20160409220852681?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />直接上代码吧,还不是太理解
//watershedSegmentation.h#if !defined WATERSHS#define WATERSHS#include <opencv2/core/core.hpp>#include <opencv2/imgproc/imgproc.hpp>class WatershedSegmenter {<img src="http://img.blog.csdn.net/20160409220658944?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" /><img src="http://img.blog.csdn.net/20160409220658944?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />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;		markers.convertTo(tmp,CV_8U,255,255);		return tmp;	}};#endif//
//main
#include <opencv2/core/core.hpp>#include <opencv2/imgproc/imgproc.hpp>#include <opencv2/highgui/highgui.hpp>#include "watershedSegmentation.h"int main(){#if 1	// Read input image	cv::Mat image= cv::imread("C:\\Users\\Administrator\\Desktop\\工作\\testp\\group.jpg");	if (!image.data)		return 0; 	// Display the image	cv::namedWindow("Original Image");	cv::imshow("Original Image",image);	// Get the binary map	cv::Mat binary;	binary= cv::imread("C:\\Users\\Administrator\\Desktop\\工作\\testp\\binary.bmp",0);	// Display the binary image	cv::namedWindow("Binary Image");	cv::imshow("Binary Image",binary);	// Eliminate noise and smaller objects	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);	cv::imwrite("ForegroundImage.jpg",fg);	// Identify image pixels without objects	cv::Mat bg;	cv::dilate(binary,bg,cv::Mat(),cv::Point(-1,-1),6);	cv::threshold(bg,bg,1,128,cv::THRESH_BINARY_INV);	// Display the background image	cv::namedWindow("Background Image");	cv::imshow("Background Image",bg);	//cv::imwrite("BackgroundImage.jpg",bg);	// Show markers image	cv::Mat markers(binary.size(),CV_8U,cv::Scalar(0));	markers= fg+bg;	cv::namedWindow("Markers");	cv::imshow("Markers",markers);	//cv::imwrite("Markers.jpg",markers);	// Create watershed segmentation object	WatershedSegmenter segmenter;	// Set markers and process	segmenter.setMarkers(markers);	segmenter.process(image);//	imshow("11",markers);	// Display segmentation result	cv::namedWindow("Segmentation");	cv::imshow("Segmentation",segmenter.getSegmentation());	//cv::imwrite("Segmentation.jpg",segmenter.getSegmentation());	// Display watersheds	cv::namedWindow("Watersheds");	cv::imshow("Watersheds",segmenter.getWatersheds());//	cv::imwrite("Watersheds.jpg",segmenter.getWatersheds());	#endif	#if 1	// Open another image	 image= cv::imread("C:\\Users\\Administrator\\Desktop\\工作\\testp\\tower.jpg");	// Identify background pixels	cv::Mat imageMask(image.size(),CV_8U,cv::Scalar(0));	cv::rectangle(imageMask,cv::Point(5,5),cv::Point(image.cols-5,image.rows-5),cv::Scalar(255),3);	// Identify foreground pixels (in the middle of the image)	cv::rectangle(imageMask,cv::Point(image.cols/2-10,image.rows/2-10),		cv::Point(image.cols/2+10,image.rows/2+10),cv::Scalar(1),10);	// Set markers and process	segmenter.setMarkers(imageMask);//	imshow("mask+rectangle",imageMask);	segmenter.process(image);	//imshow("seg_prosswater",segmenter.process(image));	// Display the image with markers	cv::rectangle(image,cv::Point(5,5),cv::Point(image.cols-5,image.rows-5),cv::Scalar(255,255,255),3);	cv::rectangle(image,cv::Point(image.cols/2-10,image.rows/2-10),		cv::Point(image.cols/2+10,image.rows/2+10),cv::Scalar(1,1,1),10);	cv::namedWindow("Image with marker");	cv::imshow("Image with marker",image);	//cv::imwrite("Image with marker.jpg",image);	// Display watersheds	cv::namedWindow("Watersheds of foreground object");	cv::imshow("Watersheds of foreground object",segmenter.getWatersheds());	//cv::imwrite("Watersheds of foreground object.jpg",segmenter.getWatersheds());#endif	cv::waitKey();	return 0;} <pre code_snippet_id="1640334" snippet_file_name="blog_20160409_7_2417268" name="code" class="cpp"></pre><pre code_snippet_id="1640334" snippet_file_name="blog_20160409_8_847105" name="code" class="cpp">不是太理解,标记图像第一副图像是前景和背景,但是后面一副图像直接是2个矩形。。反正经过处理之后图像的边缘像素值为-1
 


下面是opencv3的代码 来自毛星云

//--------------------------------------【程序说明】-------------------------------------------
// 程序说明:《OpenCV3编程入门》OpenCV2版书本配套示例程序77
// 程序描述:分水岭算法综合示例
// 开发测试所用操作系统: Windows 7 64bit
// 开发测试所用IDE版本:Visual Studio 2010
// 开发测试所用OpenCV版本: 2.4.9
// 2014年06月 Created by @浅墨_毛星云
// 2014年11月 Revised by @浅墨_毛星云
//------------------------------------------------------------------------------------------------



//---------------------------------【头文件、命名空间包含部分】----------------------------
// 描述:包含程序所使用的头文件和命名空间
//------------------------------------------------------------------------------------------------
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
using namespace cv;
using namespace std;

//-----------------------------------【宏定义部分】--------------------------------------------
// 描述:定义一些辅助宏
//------------------------------------------------------------------------------------------------
#define WINDOW_NAME1 "【程序窗口1】" //为窗口标题定义的宏
#define WINDOW_NAME2 "【分水岭算法效果图】" //为窗口标题定义的宏

//-----------------------------------【全局函变量声明部分】--------------------------------------
// 描述:全局变量的声明
//-----------------------------------------------------------------------------------------------
Mat g_maskImage, g_srcImage;
Point prevPt(-1, -1);

//-----------------------------------【全局函数声明部分】--------------------------------------
// 描述:全局函数的声明
//-----------------------------------------------------------------------------------------------
static void ShowHelpText();
static void on_Mouse( int event, int x, int y, int flags, void* );


//-----------------------------------【main( )函数】--------------------------------------------
// 描述:控制台应用程序的入口函数,我们的程序从这里开始执行
//-----------------------------------------------------------------------------------------------
int main( int argc, char** argv )
{
//【0】改变console字体颜色
system("color 6F");

//【0】显示帮助文字
ShowHelpText( );

//【1】载入原图并显示,初始化掩膜和灰度图
g_srcImage = imread("1.jpg", 1);
imshow( WINDOW_NAME1, g_srcImage );
Mat srcImage,grayImage;
g_srcImage.copyTo(srcImage);
cvtColor(g_srcImage, g_maskImage, COLOR_BGR2GRAY);
cvtColor(g_maskImage, grayImage, COLOR_GRAY2BGR);
g_maskImage = Scalar::all(0);

//【2】设置鼠标回调函数
setMouseCallback( WINDOW_NAME1, on_Mouse, 0 );

//【3】轮询按键,进行处理
while(1)
{
//获取键值
int c = waitKey(0);

//若按键键值为ESC时,退出
if( (char)c == 27 )
break;

//按键键值为2时,恢复源图
if( (char)c == '2' )
{
g_maskImage = Scalar::all(0);
srcImage.copyTo(g_srcImage);
imshow( "image", g_srcImage );
}

//若检测到按键值为1或者空格,则进行处理
if( (char)c == '1' || (char)c == ' ' )
{
//定义一些参数
int i, j, compCount = 0;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;

//寻找轮廓
findContours(g_maskImage, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);

//轮廓为空时的处理
if( contours.empty() )
continue;

//拷贝掩膜
Mat maskImage(g_maskImage.size(), CV_32S);
maskImage = Scalar::all(0);

//循环绘制出轮廓 //感觉这里绘制轮廓不重要,重要的是几个 因为后面又覆盖了maskImage watershed( srcImage, maskImage );
for( int index = 0; index >= 0; index = hierarchy[index][0], compCount++ )
drawContours(maskImage, contours, index, Scalar::all(compCount+1), -1, 8, hierarchy, INT_MAX);

//compCount为零时的处理
if( compCount == 0 )
continue;

//生成随机颜色
vector<Vec3b> colorTab;
for( i = 0; i < compCount; i++ )
{
int b = theRNG().uniform(0, 255);
int g = theRNG().uniform(0, 255);
int r = theRNG().uniform(0, 255);

colorTab.push_back(Vec3b((uchar)b, (uchar)g, (uchar)r));
}

//计算处理时间并输出到窗口中
double dTime = (double)getTickCount();
watershed( srcImage, maskImage );
dTime = (double)getTickCount() - dTime;
printf( "\t处理时间 = %gms\n", dTime*1000./getTickFrequency() );

//双层循环,将分水岭图像遍历存入watershedImage中
Mat watershedImage(maskImage.size(), CV_8UC3);
for( i = 0; i < maskImage.rows; i++ )
for( j = 0; j < maskImage.cols; j++ )
{
int index = maskImage.at<int>(i,j); //不同的index用不同的index颜色
if( index == -1 )
watershedImage.at<Vec3b>(i,j) = Vec3b(255,255,255);
else if( index <= 0 || index > compCount )
watershedImage.at<Vec3b>(i,j) = Vec3b(0,0,0);
else
watershedImage.at<Vec3b>(i,j) = colorTab[index - 1];
}

//混合灰度图和分水岭效果图并显示最终的窗口
watershedImage = watershedImage*0.5 + grayImage*0.5;
imshow( WINDOW_NAME2, watershedImage );
}
}

return 0;
}


//-----------------------------------【onMouse( )函数】---------------------------------------
// 描述:鼠标消息回调函数
//-----------------------------------------------------------------------------------------------
static void on_Mouse( int event, int x, int y, int flags, void* )
{
//处理鼠标不在窗口中的情况
if( x < 0 || x >= g_srcImage.cols || y < 0 || y >= g_srcImage.rows )
return;

//处理鼠标左键相关消息
if( event == CV_EVENT_LBUTTONUP || !(flags & CV_EVENT_FLAG_LBUTTON) )
prevPt = Point(-1,-1);
else if( event == CV_EVENT_LBUTTONDOWN )
prevPt = Point(x,y);

//鼠标左键按下并移动,绘制出白色线条
else if( event == CV_EVENT_MOUSEMOVE && (flags & CV_EVENT_FLAG_LBUTTON) )
{
Point pt(x, y);
if( prevPt.x < 0 )
prevPt = pt;
line( g_maskImage, prevPt, pt, Scalar::all(255), 5, 8, 0 );
line( g_srcImage, prevPt, pt, Scalar::all(0), 5, 8, 0 );
prevPt = pt;
imshow(WINDOW_NAME1, g_srcImage);
}
}


//-----------------------------------【ShowHelpText( )函数】----------------------------------
// 描述:输出一些帮助信息
//----------------------------------------------------------------------------------------------
static void ShowHelpText()
{
//输出欢迎信息和OpenCV版本
printf("\n\n\t\t\t非常感谢购买《OpenCV3编程入门》一书!\n");
printf("\n\n\t\t\t此为本书OpenCV2版的第77个配套示例程序\n");
printf("\n\n\t\t\t 当前使用的OpenCV版本为:" CV_VERSION );
printf("\n\n ----------------------------------------------------------------------------\n");

//输出一些帮助信息
printf( "\n\n\n\t欢迎来到【分水岭算法】示例程序~\n\n");
printf( "\t请先用鼠标在图片窗口中标记出大致的区域,\n\n\t然后再按键【1】或者【SPACE】启动算法。"
"\n\n\t按键操作说明: \n\n"
"\t\t键盘按键【1】或者【SPACE】- 运行的分水岭分割算法\n"
"\t\t键盘按键【2】- 恢复原始图片\n"
"\t\t键盘按键【ESC】- 退出程序\n\n\n");
}