Grabcut图像分割(背景替换)__opencv_day-119

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实现图像对象提取,通过背景图像替换,实现图像合成,通过对背景图像高斯模糊实现背景虚化效果,完整的步骤如下:

  1. ROI区域选择
  2. Grabcut对象分割
  3. Mask生成
  4. 使用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;
}
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值