Grabcut图像分割
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区域可以被初始化为:
- GC_BGD 定义为明显的背景像素 0
- GC_FGD 定义为明显的前景像素 1
- GC_PR_BGD 定义为可能的背景像素 2
- GC_PR_FGD 定义为可能的前景像素 3
- rect 表示roi区域
- bgdModel表示临时背景模型数组
- fgdModel表示临时前景模型数组
- iterCount表示图割算法迭代次数
- mode当使用用户提供的roi时候使用GC_INIT_WITH_RECT
Grabcut图像分割 – 背景替换
使用Grabcut实现图像对象提取,通过背景图像替换,实现图像合成,通过对背景图像高斯模糊实现背景虚化效果,完整的步骤如下:
- ROI区域选择
- Grabcut对象分割
- Mask生成
- 使用mask,实现背景与前景的高斯权重融合
例子;
#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>
#include <cmath>
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<uchar>(i, j) / 255.0;
int b = src.at<Vec3b>(i, j)[0];
int g = src.at<Vec3b>(i, j)[1];
int r = src.at<Vec3b>(i, j)[2];
int b1 = background.at<Vec3b>(i, j)[0];
int g1 = background.at<Vec3b>(i, j)[1];
int r1 = background.at<Vec3b>(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<Vec3b>(i, j)[0] = static_cast<int>(b3);
result.at<Vec3b>(i, j)[1] = static_cast<int>(g3);;
result.at<Vec3b>(i, j)[2] = static_cast<int>(r3);;
}
}
imshow("result", result);
waitKey(0);
return 0;
}