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