通过OpenCV对视频进行绿幕抠图

效果

在这里插入图片描述

今天跟大家分享的是最近比较受大家喜欢的视频或图片的部分场景抠图替换,先不多说,先看效果:
这是原视频,在场景中有个电视机被制成了绿幕。

胆小的猫


这是另一个需要添加的视频,我们的目的是将下边的“美女”视频添加到上边视频的绿幕电视机上。

跳舞


这是最终合成之后的视频,可以看到,Tom打开电视后看到了鞠婧祎跳舞。

合成后的视频

代码

1、打开视频素材

	VideoCapture capture, capture_TV;
	capture.open("./胆小的猫.flv");
	capture_TV.open("./跳舞.mp4");
	if ((!capture.isOpened()) || (!capture_TV.isOpened()))
	{
		return -1;
	}

2、保存视频路径及格式设置

	VideoWriter writer;
	writer.open("./my1.flv", writer.fourcc('F', 'L', 'V', '1'), 30, Size(1366, 768), true);//CAP_OPENCV_MJPEG

3、读取一帧视频

读的是一帧“胆小的猫”,并以此作为while循环的条件,后面的程序也都是在while循环中执行。

	while (capture.read(frame))
	{   
	}

4、寻找绿幕背景

在每一帧图像中搜寻绿幕背景并筛选,如果当前帧图像不含有绿幕,则显示原图,如果含有绿幕,则读取一帧“跳舞”视频,并将其显示在绿幕上。
筛选的目的主要是避免一些绿色背景的干扰。
通过观察,在当前视频下去掉一些形态学操作并不影响效果,同时为了提高程序执行速度,所以就注销了部分代码。

		//寻找绿幕
		cvtColor(frame, hsv, COLOR_BGR2HSV);
		inRange(hsv, Scalar(35, 43, 46), Scalar(77, 255, 255), green_mask);
		//inRange(hsv, Scalar(50, 200, 200), Scalar(70, 255, 255), green_mask);
		//imshow("green_mask", green_mask);
		//k0 = getStructuringElement(MORPH_RECT, Size(5, 5), Point(-1, -1));
		//morphologyEx(green_mask, green_mask, MORPH_OPEN, k0);
		//k = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
		//morphologyEx(green_mask, green_mask, MORPH_CLOSE, k);
		threshold(green_mask, green_mask_bin, 200, 255, THRESH_BINARY);
		findContours(green_mask_bin, contours, hierarchy, RETR_TREE, CHAIN_APPROX_NONE, Point(0, 0));

		vector <vector<Point>>::iterator iter = contours.begin();
		for (; iter != contours.end();)
		{
			double g_dConArea = contourArea(*iter);
			if (g_dConArea < 290000 || g_dConArea > 320000)
			{
				iter = contours.erase(iter);
			}
			else
			{
				++iter;
			}
		}
		if (contours.size() == 0)
		{
			frame.copyTo(result);

			imshow("ImageShow2", frame);
			imshow("ImageShow", result);
			writer.write(result);
		}

5、融合

			capture_TV.read(background);
			drawContours(mask, contours, -1, Scalar(255), CV_FILLED);  

			for (int i = 0; i < (int)contours.size(); i++)
			{
				Rect rect1 = boundingRect(Mat(contours[i]));
				resize(background, background, rect1.size());
				h = frame.rows;
				w = frame.cols;
				//int bg_row = 0;
				//dims = frame.channels();
				for (int row = 0; row < h; row++)
				{
					uchar* current = frame.ptr<uchar>(row);
					//uchar* bgrow = background.ptr<uchar>(bg_row);
					uchar* maskrow = mask.ptr<uchar>(row);
					uchar* targetrow = result.ptr<uchar>(row);
					for (int col = 0; col < w; col++)
					{
						m = *maskrow++;
						if (m == 255)
						{ 
							*targetrow++ = background.at<Vec3b>(row - rect1.y, col - rect1.x)[0];
							*targetrow++ = background.at<Vec3b>(row - rect1.y, col - rect1.x)[1];
							*targetrow++ = background.at<Vec3b>(row - rect1.y, col - rect1.x)[2];
							current += 3;

						}
						else if (m == 0)
						{
							*targetrow++ = *current++;
							*targetrow++ = *current++;
							*targetrow++ = *current++;
						}
					}
				}
			}

			imshow("ImageShow2", frame);
			imshow("ImageShow1", background);
			imshow("ImageShow", result);
			writer.write(result);

6、代码执行效果

在MFC中通过窗口进行了显示对比,最后保存的视频在文件目录中。

程序执行

源代码下载链接:视频绿幕抠图程序源码https://download.csdn.net/download/weixin_46405486/14022257
或在此下载https://www.syjshare.com/res/EA0Z34CU

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老中医@

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值