Grabcut是基于图像切割(graph cut)实现的图像切割算法,它需要用户输入一个bounding box作为分割目标位置,实现对目标与背景的分割或分离,这个跟Kmeans与MeanShift等图像分割方法有很大的不同,但是Gradcut分割速度快,效果很好,支持交互操作,因此在很多app图像分割、背景虚化的软件中可以看到它的身影。
void cv::grabCut(
InputArray img,
InputOutputArray mask,
Rect rect,
InputOutputArray bgdModel,
InputOutputArray fgdModel,
int iterCount,
int mode = GC_EVAL
)
img 输入的三通道图像
mask 输入的单通道图像,初始化方式为GC_INIT_WITH_RECT表示ROI区域可以被初始化为:
使用Grabcut实现图像对象提取,通过背景图像替换,实现图像合成,通过对背景图像高斯模糊实现背景虚化效果,完整的步骤如下:
#include
#include
#include
#include
using namespace cv;
using namespace std;
int main(int argc, char** argv) {
//读取图像
Mat src = imread("E:/opencv/master.jpg");
Mat background = imread("E:/opencv/beijing1.jpg");
if (src.empty() || background.empty()) {
cout << "没有找到图片" << endl;
return -1;
}
imshow("src", src);
imshow("background", background);
//创建单通道的mask
Mat mask;
Rect rect(53, 12, src.cols - 100, src.rows - 12);
Mat bgdModel, fgdModel;
grabCut(src, mask, rect, bgdModel, fgdModel, 5, GC_INIT_WITH_RECT);
//比较
compare(mask, GC_PR_FGD, mask, CMP_EQ);
Mat element = getStructuringElement(MORPH_RECT, Size(3, 3));
//膨胀
dilate(mask, mask, element);
//高斯模糊
GaussianBlur(mask, mask, Size(5, 5), 0);
imshow("background-mask", mask);
//虚化背景
GaussianBlur(background, background, Size(0, 0), 15);
//混合图像
Mat result = Mat::zeros(src.size(), src.type());
for (int i = 0; i < src.rows; i++) {
for (int j = 0; j < src.cols; j++) {
float w1 = mask.at(i, j) / 255.0;
int b = src.at(i, j)[0];
int g = src.at(i, j)[1];
int r = src.at(i, j)[2];
int b1 = background.at(i, j)[0];
int g1 = background.at(i, j)[1];
int r1 = background.at(i, j)[2];
int b3 = (1.0 - w1) * b1 + b * w1;
int g3 = (1.0 - w1) * g1 + g * w1;
int r3 = (1.0 - w1) * r1 + r * w1;
result.at(i, j)[0] = static_cast(b3);
result.at(i, j)[1] = static_cast(g3);;
result.at(i, j)[2] = static_cast(r3);;
}
}
imshow("result", result);
waitKey(0);
return 0;
}