<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");
}