opencv背景处理pmog方式(效果较差值差掉,个人感觉降噪不是很到位)

至于环境自己想去搭建,搭建完直接拷贝运行即可。
这个是实时的视频提取前景物

#include "opencv2/opencv.hpp"
using namespace cv;
using namespace std;

int main()
{
	
	VideoCapture cap;  // 定义VideoCapture类用以打开指定视频
	Mat source, image, foreGround, backGround, fgMask;
	Ptr<BackgroundSubtractor> pBgModel =
		createBackgroundSubtractorMOG2().dynamicCast<BackgroundSubtractor>();
	cap.open(1);//这里我的摄像头编号是1,需要根据自己的实际情况做修改,一般一个摄像头默认编号开始为0
	if (!cap.isOpened())  // 查看摄像头是否成功打开
		cout << "Cannot open the file: "<< endl;

	for (;;)  // 循环读取视频流
	{
		cap >> source;  // 将cap提取到的当前帧传给source(原始图像)
		if (source.empty())  // 如果原始图像为空,即视频已结束
		{
			break;  // 直接跳出循环
		}

		resize(source, image, Size(source.cols / 2, source.rows / 2), INTER_LINEAR);
		// 如果原始图像不为空,调用resize函数改变原始图像尺寸,方式为"线性差值法"

		if (foreGround.empty())
		{   // 通过前景是否为空,判断当前帧是否为视频开始
			foreGround.create(image.size(), image.type());
		}   // 如果是视频开始,则为"前景图像"创建矩阵空间,此处是按照原始图像的缩放图像的尺寸和类型进行初始化

		pBgModel->apply(image, fgMask);
		//降噪处理。不降噪误差很大,参数可改
		GaussianBlur(fgMask, fgMask, Size(5, 5), 0);  // 利用高斯滤波器对前景的掩膜做平滑降噪
		threshold(fgMask, fgMask, 30, 255, THRESH_BINARY);  // 通过阈值化去除掩膜中灰度小于30的像素

		foreGround = Scalar::all(0);  // 利用"Scalar"函数将所创建的前景矩阵空间中所有元素赋初值0
		image.copyTo(foreGround, fgMask);  // 标记运动目标
		pBgModel->getBackgroundImage(backGround);

		imshow("Sized Image", image);  // 显示原始图像的缩放图像。
		imshow("Background", backGround);  // 显示背景图像。
		imshow("Foreground", foreGround);  // 显示前景图像。
		imshow("Foreground Mask", fgMask);  // 显示前景图像的掩膜。

		char key = waitKey(100);  // 每一帧等待100毫秒
		if (key == 27)  // 如果想中途终止程序,按"Esc"退出
		{
			break;
		}
	}

	waitKey(0);  // 程序执行结束后防止闪退
}


运行效果:


目标标记函数:

int labelTargets(Mat &src, Mat &mask, int thresh)  // 自定义的目标标记函数
{
	Mat seg = mask.clone();  // 将掩膜复制到seg当中
	vector<vector<Point> > cnts;  // 定义了二维点类型变量cuts
	findContours(seg, cnts, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
	// 调用findContours()函数对掩膜复制图像seg中的Blob进行检测,检测方式是忽略内部边缘仅识别外部边缘

	// 以下进行筛选
	float area;  // 定义浮点型area变量用以存放单一Blob外围边缘所围面积
	Rect rect;
	int count = 0;  // 定义整型变量用以计数
	string strCount;  // 定义字符串型变量
	for (int i = cnts.size() - 1; i >= 0; i--)
	{  // 调用vector的size()函数以检测cnts第一维的个数,即Blob个体数,并对其进行循环处理
		vector<Point> c = cnts[i];  // 定义一维点类型变量c用以存放Blob个体,即一维cnts集合
		area = contourArea(c);  // 调用contourArea()函数计算该单一Blob外围边缘所围面积
		if (area < thresh) // 滤除面积小于10的分割结果:可能是噪声
		{
			continue;
		}

		count++; // 统计米粒数量
		cout << "blob " << i << " : " << area << endl;
		rect = boundingRect(c);  // 创建包围矩形数据
		// 在原始图像上画出包围矩形,并给每个矩形标号
		rectangle(src, rect, Scalar(0, 0, 0xff), 1);
		// 调用rectangle()函数在src图像中,把rect包围矩形用红色,1个像素粗细的线框包围起来

		stringstream ss;  // 定义字符流变量"ss",作用是将指定字符串生成输入或输出流
		ss << count;  // 将计数数据传递给字符流
		ss >> strCount;  // 将字符流中的数据传送给字符串变量
		putText(src, strCount, Point(rect.x, rect.y), CV_FONT_HERSHEY_PLAIN, 0.5, Scalar(0, 0xff, 0));
		// 调用putText函数,在src图像上将strCount字符串输出在矩形框左上角,并定义了字体和字号和颜色
	}

	return count;
}

在主函数中加上:

int nTargets = labelTargets(image, fgMask);
cout << "There are " << nTargets << " targets." << endl;

运行效果:

可以看到会标记实时的运动效果。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值