欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【OpenCV】grabcut抠图

程序员文章站 2024-02-19 22:29:28
...

 OpenCV中的grabcut函数实现的是论文《"GrabCut": interactive foreground extraction using iterated graph cuts》的算法。

OpenCV的函数原型如下:


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

参数:

InputArray img:输入8位3通道图像。

InputOutputArray mask:输入\输出8位单通道掩码。如果函数设置mode= GC_INIT_WITH_RECT,则该掩码由函数来初始化。它的元素值是GrabCutClasses中的一个。

【OpenCV】grabcut抠图

Rect rect:包含待分割目标的ROI区域。在该区域之外的像素被标记为"obvious background"。这个参数仅在mode==GC_INIT_WITH_RECT的时候使用。

InputOutputArray bgdModel:背景model的临时数组。

InputOutputArray fgdModel:前景model的临时数组。

int iterCount:算法迭代次数。

int mode = GC_EVAL:必须是枚举类型GrabCutModes中的一种。

【OpenCV】grabcut抠图

下面的代码实现一个简单的由鼠标交互式选取ROI区域进行抠图的代码。

#include <iostream>  
#include <opencv2/opencv.hpp>   

using namespace std;

cv::Rect rect;
cv::Point2i cursor;

void onMouse(int event, int x, int y, int flags, void *param)
{
	cv::Mat* src = (cv::Mat*)param;
	cv::Mat roiImg;
	src->copyTo(roiImg);
	switch (event)
	{
	case CV_EVENT_LBUTTONDOWN:
		cursor = cv::Point2i(x, y);
		rect = cv::Rect(x, y, 1, 1);
		std::cout << "CV_EVENT_LBUTTONDOWN==" << rect << std::endl;
		break;
    
	case CV_EVENT_LBUTTONUP:
		rect.width = abs(x - rect.x);
		rect.height = abs(y - rect.y);
		std::cout << "CV_EVENT_LBUTTONUP==" << rect << std::endl;
		cv::rectangle(roiImg, rect, cv::Scalar(0, 0, 255), 2);
		cv::imshow("input", roiImg);
		break;

	case CV_EVENT_MOUSEMOVE:
		if (flags && CV_EVENT_FLAG_LBUTTON) {
			rect.x = MIN(x, cursor.x);
			rect.y = MIN(y, cursor.y);
			rect.width = abs(cursor.x - x);
			rect.height = abs(cursor.y - y);
		}
		break;
	}
}

int main()
{
	cv::Mat img = cv::imread("boldt.jpg");
	if (img.empty())
	{
		cout << "error";
		return -1;
	}

	cv::namedWindow("SrcImage");
	cv::setMouseCallback("SrcImage", onMouse, &img);
	cv::imshow("SrcImage", img);
	cv::waitKey();


	cv::Mat result;
	cv::Mat bgModel, fgModel;
	cv::grabCut(img, result, rect, bgModel, fgModel, 5, cv::GC_INIT_WITH_RECT);
	cv::compare(result, cv::GC_PR_FGD, result, cv::CMP_EQ);

	cv::Mat foreground(img.size(), CV_8UC3, cv::Scalar(255, 255, 255));
	img.copyTo(foreground, result);

	cv::namedWindow("Foreground");
	cv::imshow("Foreground", foreground);
	cv::waitKey();
	return 0;
}

原图:

【OpenCV】grabcut抠图

红色框的区域选取的ROI区域:

【OpenCV】grabcut抠图

抠图结果:

【OpenCV】grabcut抠图

效果还是不错。