【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中的一个。
Rect rect:包含待分割目标的ROI区域。在该区域之外的像素被标记为"obvious background"。这个参数仅在mode==GC_INIT_WITH_RECT的时候使用。
InputOutputArray bgdModel:背景model的临时数组。
InputOutputArray fgdModel:前景model的临时数组。
int iterCount:算法迭代次数。
int mode = GC_EVAL:必须是枚举类型GrabCutModes中的一种。
下面的代码实现一个简单的由鼠标交互式选取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;
}
原图:
红色框的区域选取的ROI区域:
抠图结果:
效果还是不错。