(五)OpenCV图像分割_07_Grabcut图像分割方法

  1. grabCut图像中对象交互抠图
    setMouseCallback
    onMouse(int event, int x, int y, int flags, void*param)
  2. 输入图像、矩形输入、初始分类、GMM描述
  3. GMM训练分类、Graph Cut分类、最终分类、继续迭代/停止
  4. 图像中对象抠图
#include <opencv2/opencv.hpp>
#include <iostream>

using namespace std;
using namespace cv;

Mat src;
const char* Window_Title = "Grabcuts";
bool init = false;
Rect rect;
Mat mask, fgModel, bgModel;//mask,前景,背景
void showImage();
void MouseEvent(int event, int x, int y, int flags, void* param);//鼠标回调函数
void maskROI();//为Grabcut创建mask区域
void GrabCuts();

int main(int argc, char** argv)
{
	src = imread("../path.jpg");
	if (src.empty())
	{
		cout << "could not load image..." << endl;
		return -1;
	}

	mask.create(src.size(), CV_8UC1);//mask初始化
	mask.setTo(Scalar::all(GC_BGD));//全部设置为背景GC_BGD

	namedWindow(Window_Title, WINDOW_AUTOSIZE);
	setMouseCallback(Window_Title, MouseEvent, 0);//设置鼠标事件
	imshow(Window_Title, src);

	while (true)
	{
		char c = (char)waitKey(0);
		if (c == ' ')//按空格调用Grabcut
		{
			GrabCuts();
			showImage();
		}
		if ((int)c == 27)
		{
			break;
		}
	}

	waitKey(0);
	return 0;
}

void showImage()//显示选择的前景区域
{
	Mat dst,Mask;
	Mask.create(mask.size(), CV_8UC1);
	/
	Mask = mask & 1;//&=操作符重载//进一步掩膜
	if (init) //进一步抠出无效区域,鼠标按下,init变为false
	{
		src.copyTo(dst, Mask); //在位置(x, y)时,如果mask的像素值不等于0,则dst(x, y) = src(x, y);
	}
	else 
	{
		src.copyTo(dst);
	}
	/

	rectangle(dst, rect, Scalar(0, 0, 255), 2, 8);//在dst上绘制rect大小的矩形框
	imshow(Window_Title, dst);//把dst绘制在窗口上
}

void MouseEvent(int event, int x, int y, int flags, void* param)
{
	switch (event)
	{
	case EVENT_LBUTTONDOWN://鼠标左键按下
		rect.x = x;
		rect.y = y;
		rect.width = 1;
		rect.height = 1;
		init = false;
		break;
	case EVENT_MOUSEMOVE://鼠标移动
		if (flags & EVENT_FLAG_LBUTTON)
		{
			rect = Rect(Point(rect.x, rect.y), Point(x, y));//矩形的对角点
			showImage();//鼠标边移动,边绘制
		}
		break;

	case EVENT_LBUTTONUP://鼠标右键弹起
		if (rect.width > 1 && rect.height > 1)//从左到右,从上到下
		{
			maskROI();//鼠标弹起的时候,调用mask函数
			showImage();//鼠标弹起的时候,绘制
		}
		break;
	default:
		break;
	}
	return;
}

void maskROI()
{
	mask.setTo(GC_BGD);//设置为Grabcut的背景色
	//max min都是防止rect未初始化导致的差错
	rect.x = max(0, rect.x);
	rect.y = max(0, rect.y);
	rect.width = min(rect.width, src.cols - rect.x);
	rect.height = min(rect.height, src.rows - rect.y);
	mask(rect).setTo(Scalar(GC_PR_FGD));//rect区域设置为Grabcut的前景
	// GC_FGD =1;//前景
	// GC_BGD =0;//背景
	// GC_PR_FGD = 3//可能的前景
	// GC_PR_BGD = 2//可能的背景
	return;
}

void GrabCuts()
{
	if (rect.width < 2 || rect.height < 2) //rect太小则返回
	{
		return;
	}

	if (init)
	{
		//grabCut
		grabCut(src, // 待分割图像,8bit,3通道
			mask, // 如果没有手动标记 GC_BGD或GC_FGD ,那么结果只会有 GC_PR_BGD或GC_PR_FGD
			rect, // 当 mode=GC_INIT_WITH_RECT时使用,rect外部的为GC_BGD,rect内部的为GC_FGD
			bgModel, // 背景模型(内部使用)
			fgModel, //前景模型(内部使用)
			1);// 迭代次数,必须大于0
	}
	else
	{
		grabCut(src, mask, rect, bgModel, fgModel, 1, GC_INIT_WITH_RECT/*// GC_INIT_WITH_RECT表示用矩形框初始化Grabcut,GC_INIT_WITH_MASK表示用掩码图像初始化Grabcut, GC_EVAL表示执行分割*/);
		init = true;
	}
	return;
}

src为:
在这里插入图片描述
按下鼠标左键,拉出如图的矩形框:
在这里插入图片描述
按下键盘空格,输出结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值