OpenCV4学习笔记(57)——基于GrabCut图像分割算法实现背景替换与背景虚化效果

在上一篇笔记《OpenCV4学习笔记(56)》中,整理了关于在OpenCV中使用GrabCut图像分割算法的相关内容,那么本次笔记就以GrabCut算法为基础来实现对图像的背景替换和背景虚化效果。

实现对图像的背景替换和背景虚化效果的整体流程如下:
(1)对图像进行USM锐化(可参阅《OpenCV4学习笔记(16)》
,用于增强图像细节,以便于提取前景区域。
(2)手动选择ROI区域并执行GrabCut算法进行图像分割。
(3)提取ROI区域的二值图像,并进行形态学滤波。
(4)读取要进行替换的新背景图像并进行高斯模糊。
(5)将新背景图像和前景图像相混合,并进一步进行模糊操作。

代码演示如下:

	//基于grabCut图像分割算法的背景替换和背景虚化
	//读取图像并进行USM锐化,增强目标细节,便于提取前景
	Mat image= imread("D:\\opencv_c++\\opencv_tutorial\\data\\images\\master.jpg");
	resize(image, image, Size(500, 700));
	imshow("image", image);
	Mat gaussian_image, USM_image;
	GaussianBlur(image, gaussian_image, Size(), 20, 20);
	addWeighted(image, 1.5, gaussian_image, -0.5, 0, USM_image, CV_16S);
	convertScaleAbs(USM_image, USM_image);
	imshow("USM_image", USM_image);

	//选择目标前景区域
	Rect roi_rect = selectROI("USM_image", USM_image, false);

	//进行grabCut图像分割
	Mat mask = Mat::zeros(image.size(), CV_8UC1);
	Mat bgdModel, fgdModel;
	grabCut(USM_image, mask, roi_rect, bgdModel, fgdModel, 10, GC_INIT_WITH_RECT);

	//提取前景ROI区域二值图像
	Mat foreground = Mat::zeros(image.size(), image.type());
	Mat foreground_roi = Mat::zeros(image.size(), CV_8UC3);
	for (int row = 0; row < image.rows; row++)
	{
		for (int col = 0; col < image.cols; col++)
		{
			if (mask.at<uchar>(row, col) == 1 || mask.at<uchar>(row, col) == 3)
			{
				foreground_roi.at<Vec3b>(row, col) = Vec3b(255,255,255);
			}
		}
	}

	//将得到的前景ROI区域二值图像进行开运算消除细微干扰后,和锐化图像进行与(and)操作,得到锐化后的前景区域
	Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
	morphologyEx(foreground_roi, foreground_roi, MORPH_OPEN, kernel);
	bitwise_and(foreground_roi, USM_image, foreground);
	imshow("foreground", foreground);

	//读取要进行替换的背景图像
	Mat background = imread("D:\\opencv_c++\\opencv_tutorial\\data\\images\\background.jpg");
	resize(background, background, image.size());
	Mat new_background = background.clone();
	for (int row = 0; row < background.rows; row++)
	{
		for (int col = 0; col < background.cols; col++)
		{
			if (foreground.at<Vec3b>(row, col) != Vec3b(0, 0, 0))
			{
				new_background.at<Vec3b>(row, col) = image.at<Vec3b>(row, col);
			}
		}
	}
	imshow("new_background", new_background);

	//背景虚化
	//对背景图像进行高斯模糊
	Mat gaus_background = Mat::zeros(background.size(),background.type());
	GaussianBlur(background, gaus_background, Size(), 2, 2);
	for (int row = 0; row < gaus_background.rows; row++)
	{
		for (int col = 0; col < gaus_background.cols; col++)
		{
			if (foreground.at<Vec3b>(row, col) != Vec3b(0, 0, 0))
			{
				//将锐化图像前景和虚化背景图像混合
				gaus_background.at<Vec3b>(row, col) = foreground.at<Vec3b>(row, col);
			}
		}
	}
	//对虚化图像再进行高斯模糊,抵消前景的边缘效应和锐化效果
	GaussianBlur(gaus_background, gaus_background, Size(3, 3), 1);
	imshow("gaus_background", gaus_background);

这里使用的演示图像是:
在这里插入图片描述
接着经过锐化后的效果图像:
在这里插入图片描述
随后进行GrabCut图像分割,得到掩膜mask,注意mask直接显示的话是全黑的,因为它只有从0~3这四个像素取值:
在这里插入图片描述
对掩膜mask放大来看像素值,下面分别是可能背景和可能前景、明显背景和可能背景的分割处,:
在这里插入图片描述
在这里插入图片描述
由掩膜得到的前景图像为:
在这里插入图片描述

最后得到的新背景图像和背景虚化图像如下:
在这里插入图片描述
在这里插入图片描述
到这里就实现了对于一幅图像的背景替换和背景虚化了,但是从细节效果上来看,这种直接替换的方式使得前景和背景的连接处过渡仍然不够自然,感觉有些许割裂感。如果能对图像的前景与背景之间进行过渡处理,那么能很好的提高视觉效果。

好了,本次笔记整理到此结束,谢谢阅读~

PS:本人的注释比较杂,既有自己的心得体会也有网上查阅资料时摘抄下的知识内容,所以如有雷同,纯属我向前辈学习的致敬,如果有前辈觉得我的笔记内容侵犯了您的知识产权,请和我联系,我会将涉及到的博文内容删除,谢谢!

原创文章 63 获赞 124 访问量 8391

猜你喜欢

转载自blog.csdn.net/weixin_45224869/article/details/105854025