OpenCV视频篇—背景消除与前景ROI提取

一、背景消除概述

📌 背景减除(Background Subtraction)是许多基于计算机视觉的任务中的主要预处理步骤。

📌背景减除(BS)是通过使用静态摄像机来生成前景掩码(即,包含属于场景中的移动对象的像素的二进制图像)的常用和广泛使用的技术。

📌BS计算当前帧和背景模型之间的减法的前景掩码,该背景模型包含场景的静态部分,或者更一般地,在给定观察到的场景的特征的情况下,可以将其视为背景的所有内容。

如果有完整的静止的背景帧,可以通过帧差法来计算像素差从而获取到前景对象。但是在大多数情况下,没有这样的图像,所以需要从拥有的任何图像中提取背景。当运动物体有阴影时,由于阴影也在移动,情况会变的变得更加复杂。为此引入了背景减除算法通过这一方法我们能够从视频中分离出运动的物体前景,从而达到目标检测的目的。

在这里插入图片描述

二、OpenCV中提供的背景消除法

1、背景建模包括两个主要步骤

①后台初始化
计算背景的初始模型。
②背景更新
更新模型以适应场景中的可能变化。

2、基于高斯混合模型GMM实现背景提取
3、基于最近邻KNN实现背景提取

三、实例

引用Opencv官方Example里的视频 vtest.mp4 来实现背景消除和ROI行人提取。

步骤:

  1. 初始化背景建模对象GMM
  2. 读取视频一帧
  3. 使用背景建模消除生成mask
  4. 对mask进行轮廓分析提取ROI
  5. 绘制ROI对象

void bg() {
	//1 读取视频
	VideoCapture cap = VideoCapture("D:/test/vtest.avi");
	//1.1 获取视频的总帧数
	double framesNum=cap.get(CAP_PROP_FRAME_COUNT);
	cout << " frameNum=" << framesNum << endl;

	//2. 背景消除
	//采用高斯混合模型分离算法MOG2和KNN算法进行前景分离
	Ptr<BackgroundSubtractor> bgMOG2;
	Ptr<BackgroundSubtractor> bgKNN;
	//2.1 高斯混合模型分离算法MOG2
	bgMOG2=createBackgroundSubtractorMOG2(500, 100,false);
	//2.2 KNN算法
	bgKNN = createBackgroundSubtractorKNN(500, 400, false);

	//3. 进行帧读取和处理
	Mat maskMOG2,maskKNN,ret,frame;
	//3.1 k指从键盘输出的值
	int k = 0;
	//3.2 flag计算当前读取的帧数
	double flag = 0;
	//3.3 循环处理每一帧图片,直到按下ESC或者当前视频读取完停止循环
	while (char(k) != 'q' && (char)k!= 27)
	{
		//3.4 读取每一帧
		cap.read(frame);
		    //克隆读取到的图片
		Mat frameKNN = frame.clone();
		    //显示读取的视频
		imshow("frame", frame);

		//4 采用基于混合高斯的算法计算前景蒙版
		bgMOG2->apply(frame, maskMOG2);
		    //采用基于KNN的算法计算前景蒙版
		bgKNN->apply(frame, maskKNN);
		
		//4.1 进行形态学的开操作
		Mat kernel=getStructuringElement(MORPH_RECT, Size(3, 3));
		morphologyEx(maskMOG2, maskMOG2, MORPH_OPEN, kernel);
		morphologyEx(maskKNN, maskKNN, MORPH_OPEN, kernel);
		
		//4.2 显示混合高斯算法的前景蒙版并保存每一帧
		imshow("maskMOG2", maskMOG2);
		String name11= "D:/test/maskMOG2/" + std::to_string((int)flag) + ".png";
		cout << "name11: " << name11 << "    ";
		imwrite(name11, maskMOG2);
		name11 = "";
	
		//4.3 显示KNN算法的前景蒙版并保存每一帧
		imshow("maskKNN", maskKNN);
		String name22 = "D:/test/maskKNN/" + std::to_string((int)flag) + ".jpg";
		cout << "name22: " << name22 << "    ";
		imwrite(name22, maskKNN);
		name22 = "";
	

		//5. 分离出前景
		Mat img1, img2, img3,qjKNN, bg;//==mask
		//5.1 反转二值图像
		bitwise_not(maskKNN, img1);
		//5.2 按位与操作
		bitwise_and(frame, frame, img2, maskKNN);
		//5.3 设置背景为全白色
        bg=Mat::zeros(frame.size(), frame.type());
		bg.setTo(Scalar(255, 255, 255));
		//5.4 按位或操作
		bitwise_or(img2, bg, img3, img1);
		//5.5 加法操作
		add(img3, img2,qjKNN);
		//5.6 显示前景图像并保存每一帧
		imshow("img3", qjKNN);
		String name33 = "D:/test/people/" + std::to_string((int)flag) + ".png";
		cout << "name33: " << name33 << "    ";
		imwrite(name33, img3);
		name33 = "";

		//6. MOG2的轮廓提取
		// 保存每一帧轮廓
		vector<vector<Point>> contoursMOG2,contoursKNN;
		//6.1 对MOG2的前景蒙版进行轮廓提取
		findContours(maskMOG2, contoursMOG2, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
		//6.2 对KNN的前景蒙版进行轮廓提取
		findContours(maskKNN, contoursKNN, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
		
		//7. 循环遍历MOG2的前景蒙版轮廓
		for (int i = 0; i < contoursMOG2.size(); i++)
		{
			//7.1 计算每一个轮廓面积
			double area=contourArea(contoursMOG2[i]);
			//7.2 轮廓面积过小的直接略过
			if (area<150)
			{
				continue;
			}
			//7.3 计算轮廓最小的外接矩形
	        RotatedRect rect=minAreaRect(contoursMOG2[i]);
			//7.4 每一轮廓拟合成椭圆并画到读取的帧上
			ellipse(frame, rect, Scalar(0, 255, 0), 2);
			//7.5 画出轮廓中椭圆的圆心并画到读取的帧上
			circle(frame, rect.center,2,Scalar(0,0,255),2);
		}
		//7.6 保存每一帧轮廓处理后的帧
		String name = "D:/test/MOG2/" +std::to_string((int)flag)+".png" ;
		cout << "name: " << name << "    ";
		imwrite(name, frame);
		name = "";
		imshow("ResultMOG2", frame);
		
		//7. KNN的轮廓提取,同上
		for (int i = 0; i < contoursKNN.size(); i++)
		{
			double area = contourArea(contoursKNN[i]);
			if (area < 150)
			{
				continue;
			}
			RotatedRect rect = minAreaRect(contoursKNN[i]);
			ellipse(frameKNN, rect, Scalar(0, 255, 0), 2);
			circle(frameKNN, rect.center, 2, Scalar(0, 0, 255), 2);

		}
		String name2 = "D:/test/KNN/" + std::to_string((int)flag) + ".png";
		cout << "name2: " << name2 << "    ";
		imwrite(name2, frameKNN);
		name2 = "";
		imshow("ResultKNN", frameKNN);
		
		
		//8. 处理完一帧后读取下一帧
		flag+=1;
		//9. 若读取到视频最后一帧,停止循环
		if (flag==framesNum)
		{
			break;
		}
		k = waitKey(30);
	}
	
}

📌采用createBackgroundSubtractorMOG2生成的前15帧gif动画:

中间15帧:

134帧前景的gif图:

📌采用 createBackgroundSubtractorKNN生成的前15帧gif动画:

中间15帧:

134帧前景图片:

📌提取knn下的210张前景图片组成的gif:

学习:
OpenCV–0016:图像ROI与ROI操作
OpenCV视频篇——背景/前景分割类
OpenCV图像处理- 视频背景消除与前景ROI提取
高斯混合模型(GMM)算法理解及代码实现

  • 2
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值