Opencv图割Grabcut

Grabcut的算法实现的流程:


**********参数说明****************


GrabCut函数使用

      在OpenCV的源码目录的samples的文件夹下,有grabCut的使用例程,请参考:

opencv\samples\cpp\grabcut.cpp

grabCut函数的API说明如下:

void cv::grabCut( InputArray _img, InputOutputArray _mask, Rect rect,

                  InputOutputArray _bgdModel, InputOutputArray _fgdModel,

                  int iterCount, int mode )

/*

****参数说明:

         img——待分割的源图像,必须是83通道(CV_8UC3)图像,在处理的过程中不会被修改;

         mask——掩码图像,如果使用掩码进行初始化,那么mask保存初始化掩码信息;在执行分割的时候,也可以将用户交互所设定的前景与背景保存到mask中,然后再传入grabCut函数;在处理结束之后,mask中会保存结果。mask只能取以下四种值:

                   GCD_BGD=0),背景;

                   GCD_FGD=1),前景;

                   GCD_PR_BGD=2),可能的背景;

                   GCD_PR_FGD=3),可能的前景。

                   如果没有手工标记GCD_BGD或者GCD_FGD,那么结果只会有GCD_PR_BGDGCD_PR_FGD

         rect——用于限定需要进行分割的图像范围,只有该矩形窗口内的图像部分才被处理;

         bgdModel——背景模型,如果为null,函数内部会自动创建一个bgdModelbgdModel必须是单通道浮点型(CV_32FC1)图像,且行数只能为1,列数只能为13x5

         fgdModel——前景模型,如果为null,函数内部会自动创建一个fgdModelfgdModel必须是单通道浮点型(CV_32FC1)图像,且行数只能为1,列数只能为13x5

         iterCount——迭代次数,必须大于0

         mode——用于指示grabCut函数进行什么操作,可选的值有:

                   GC_INIT_WITH_RECT=0),用矩形窗初始化GrabCut

                   GC_INIT_WITH_MASK=1),用掩码图像初始化GrabCut

                   GC_EVAL=2),执行分割。

*/

下面放上程序:
#include<opencv2\highgui\highgui.hpp>
#include<opencv2\imgproc\imgproc.hpp>
#include<iostream>
using namespace cv;

Point Point1, Point2;
Rect rect;
Mat srcImage, roiImage;

void on_MouseHandle(int event, int x, int y, int flags, void* param);//event鼠标事件代号,x,y鼠标坐标,flags拖拽和键盘操作的代号 
int main()
{
	srcImage = imread("flower.jpg");
	if (!srcImage.data)
	{
		printf("could not load image...\n");
		return -1;
	}
	namedWindow("srcImage", CV_WINDOW_AUTOSIZE);
	imshow("srcImage", srcImage);
	//定义前景与输出图像
	Mat foreground(srcImage.size(), CV_8UC3, Scalar(255, 255, 255));//定义一张三通道的前景图
	Mat result(srcImage.size(), CV_8UC1);//定义输出图像
	//鼠标响应函数、
	setMouseCallback("srcImage", on_MouseHandle, 0);
	//Grabcut分割前景与背景
	Mat fgMat, bgMat;//定义前景与背景
	//定义迭代次数
	int i = 3;
	//选择区域有效,按下Esc键退出
	while (true) 
	{
		char c = (char)waitKey(0);
		if (c == 'n')
		{
			//实现图割操作
			grabCut(srcImage, result, rect, bgMat, fgMat, i, GC_INIT_WITH_RECT);

			//图像匹配
			compare(result, GC_PR_FGD, result, CMP_EQ);//比较result的值可能是前景才输出到result中

			//生成前景图像
			srcImage.copyTo(foreground, result);//将reuslt的结果覆盖到foreground中
			imshow("foreground", foreground);
		}
		if ((int)c == 27)
		{
			break;
		}
	}

	waitKey(0);
	return 0;
}

void on_MouseHandle(int event, int x, int y, int flags, void* param)
{
	if (event == CV_EVENT_LBUTTONDOWN)//如果鼠标的左键按下的话,读取初始坐标
	{
		Point1 = Point(x, y);//鼠标的初始坐标
	}
	else if (event == EVENT_MOUSEMOVE && (flags & CV_EVENT_FLAG_LBUTTON))//左键按下的时候,鼠标移动,则在图像上画矩形
	{
		Mat img1 = srcImage.clone();//克隆一张新的图
		Point2 = Point(x, y);//鼠标的当前的坐标
							 //在图形上绘制矩形区域
		rectangle(img1, Point1, Point2, Scalar(0, 0, 255), 2, 8, 0);
		imshow("image", img1);
	}
	else if (event == CV_EVENT_LBUTTONUP)//鼠标的左键松开的时候
	{
		Point2 = Point(x, y);
		rect = Rect(Point1.x, Point1.y, Point2.x - Point1.x, Point2.y - Point1.y);
		//roiImage = srcImage(rect);
		//imshow("roiImage", roiImage);
	}
}

原图:


鼠标选择的矩形图:

效果图:



猜你喜欢

转载自blog.csdn.net/linqianbi/article/details/79123306