【OpenCV】GrabCut图像分割

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/iefenghao/article/details/88870852

在OpenCV中,实现了grabcut分割算法,该算法可以方便的分割出前景图像,操作简单,而且分割的效果很好。

grabCut( InputArray img, InputOutputArray mask, Rect rect,
                           InputOutputArray bgdModel, InputOutputArray fgdModel,
                           int iterCount, int mode = GC_EVAL );

 img:输入原图像;

mask:输出掩码;

rect:用户选择的前景矩形区域;

bgModel:输出背景图像;

fgModel:输出前景图像;

iterCount:迭代次数;

grabCut函数的第一个参数为我们要处理的图像,图像的类型必须为:CV_8UC3

第二个参数是mask图像,它的大小和image一样,但是它的格式为CV_8UC1,只能是单通道的,grabcut算法的结果就保存在该图像中。

前面的代码中,我们并没有对mask图像(result)进行初始化设置,因为第6个参数为cv::GC_INIT_WITH_RECT,它表示算法会根据rectangle的范围,来生成一个初始化的mask图像。

mask图像的值只能为下面下面4个值(PR,probably表示可能的):

GC_BGD    = 0,  //背景

GC_FGD    = 1,  //前景 
GC_PR_BGD = 2,  //可能背景

GC_PR_FGD = 3   //可能前景 

根据rectangle生成的mask图像规则为:四边形外面的部分一定是背景,所以在mask图中对应的像素值为GC_BGD,而四边形内部的的值可能为前景,所以对应的像素值为GC_PR_FGD。

效果图:

原图

 

分割图

步骤:

(1) 读入并显示图像

(2) 设置鼠标事件,获得画出的矩形框

(3) 初始化mask矩阵

(4) 等待输入字母,运行GrabCut函数

代码:

//GrabCut程序
#include <iostream>
#include<opencv2\opencv.hpp>

using namespace cv;
using namespace std;

void onMouse(int event, int x, int y, int flags, void* userdata);
Rect rect;
Mat src_img, roi_img, dst_img;
void showImg();
int main(int arc, char** argv) 
{
	src_img = imread("3.jpg");
	namedWindow("src 1210", CV_WINDOW_AUTOSIZE);
	imshow("src 1210", src_img);
	setMouseCallback("src 1210", onMouse);	
	Mat dst_img = Mat::zeros(src_img.size(), CV_8UC1);
	// GrabCut 抠图
	//两个临时矩阵变量,作为算法的中间变量使用
	Mat bgModel, fgModel;
	char c = waitKey(0);
	if (c == 'o') {
		grabCut(src_img, dst_img, rect, bgModel, fgModel, 1, GC_INIT_WITH_RECT);
		//比较dst_img的值为可能的前景像素才输出到dst_img中
		compare(dst_img, GC_PR_FGD, dst_img, CMP_EQ);
		// 产生输出图像
		Mat foreground(src_img.size(), CV_8UC3, Scalar(255, 255, 255));
		//将原图像src_img中的dst_img区域拷贝到foreground中
		src_img.copyTo(foreground, dst_img);

		imshow("dst 1210", foreground);
	}
	waitKey(0);
	return 0;
}

void showImg() {
	src_img.copyTo(roi_img);
	rectangle(roi_img, rect, Scalar(0, 0, 255), 2);
	imshow("src 1210", roi_img);
}
//鼠标选择矩形框
void onMouse(int event, int x, int y, int flags, void* userdata) {
	switch (event)
	{
	case CV_EVENT_LBUTTONDOWN://鼠标左键按下事件
		rect.x = x;
		rect.y = y;
		rect.width = 1;
		rect.height = 1;
		break;
	case CV_EVENT_MOUSEMOVE://鼠标移动事件
		if (flags && CV_EVENT_FLAG_LBUTTON) {
			rect = Rect(Point(rect.x, rect.y), Point(x, y));
			showImg();
		}
		break;
	case EVENT_LBUTTONUP://鼠标弹起事件
		if (rect.width > 1 && rect.height > 1) {
			showImg();
		}
		break;
	default:
		break;
	}
}

欢迎大家批评指正!

猜你喜欢

转载自blog.csdn.net/iefenghao/article/details/88870852