C++ opencv动态行人检测(传统方法)

简述:在一些工业现场及其他环境,使用深度学习的方法进行图像处理是不可行的(原因有成本问题等)。也正因如此尽管笔者偏向于python编程,但这次主要做的是C++环境下的行人检测。这里主要采用的是背景板减法,即opencv中自带的BackgroundSubtractorMOG2函数。该函数基于自适应混合高斯背景建模,具有一定的抗光照干扰的能力。基本配置是VS2013+opencv3.0.0 。

背景板法基本原理:利用当前帧和参考帧之间差进行运动物体的检测,如果加以约束条件,这些运动的物体就是我们感兴趣的目标。对于背景而言,opencv的MOG2函数主要是利用Adaptive GMM模型,即自适应混合高斯模型来模拟背景。GMM的模型详解可以参考博文:点击打开链接 。简单来说就是利用EM算法来估计GMM的参数,再用这些参数来求最大似然函数。根据Zoran的说法,其算法要比opencv中另一种方法GMG快大约40%。

MOG2基本使用方法

	Ptr<BackgroundSubtractorMOG2> bgsubtractor = createBackgroundSubtractorMOG2();
	bgsubtractor->setHistory(20);
	bgsubtractor->setVarThreshold(100);
	bgsubtractor->setDetectShadows(true);
	bgsubtractor->setBackgroundRatio(4);
	bgsubtractor->setNMixtures(5);
	bgsubtractor->setShadowThreshold(40);
	bgsubtractor->setVarInit(15);
	bgsubtractor->setVarMax(20);
	bgsubtractor->setVarMin(4);
	bgsubtractor->setVarThresholdGen(100);

History:用于训练背景的帧数,history可以用于计算当前的learning rate ,history越大,learning rate越低,背景更新越缓慢;

VarThreshold:方差阈值,主要用于判断前景还是背景,值越大,灵敏度越低;

DetectShadows:是否检测有影子,开启后会增加算法复杂度。

NMixtures:高斯模型个数,默认5个,最多8个,模型数越多,耗时越长;

BackgroundRatio:高斯背景模型权重和阈值,nmixtures个模型按权重排序后,只取模型权重累加值大于backgroundRatio的前几个作为背景模型;

VarInit:新建高斯模型的方差初始值,默认15;

VarMax:背景更新时,用于限制高斯模型方差的最大值,默认20;

VarMin:背景更新时,用于限制高斯模型方差的最小值,默认4;

VarThresholdGen:方差阈值,用于已经存在的匹配的模型,如果不存在则新建一个。

行人检测思路:主要是采用人体特定的长宽比进行计算,筛选近似于人体长宽比的物体进行画框标注,针对误判情况,添加必须大于一定帧数阈值的方式予以消除。

算法实例

#include "stdafx.h"
#include <opencv2\imgproc\imgproc.hpp>
#include <windows.h>
#include <opencv2/opencv.hpp>
#include <cmath>
#include <iostream>
//#include "DetectPackage.h"
#include <cmath>
using namespace std;
using namespace cv;
int main() {
	VideoCapture cap("G://folder/test.mp4");
	if (!cap.isOpened()) {
		cout << "video not exist!" << endl;
		return -1;
	}
	long FRAMECNT = cap.get(CV_CAP_PROP_FRAME_COUNT);
	Mat frame, mask, maskCp;
	vector<vector<Point>> cnts;
	Rect maxRect;
	const double RECT_HW_RATIO = 1.5;	// 人体长宽比阈值
	const double RECT_AREA_RATIO = 0.008;	// 人体占整个图像最小比例阈值
	const double RECT_AREA_RATIO2 = 0.2;	// 人体占整体图像最大比例阈值
	Ptr<BackgroundSubtractorMOG2> bgsubtractor = createBackgroundSubtractorMOG2();
	bgsubtractor->setHistory(20);
	bgsubtractor->setVarThreshold(100);
	bgsubtractor->setDetectShadows(true);
	bool hasPeople = false;		// 是否有人
	int count = 0;	// 帧数
	int hasPeopleFrameCnt = 0; // 每K帧统计到的有人帧数
	int spaceFrames = 0;		// 每隔125帧统计一次
	const int SPACE_FRAME = 125;

	while (++count < FRAMECNT - 10) {
		cap >> frame;
		resize(frame, frame, Size(frame.cols / 4, frame.rows / 4));
		// 背景更新
		bgsubtractor->apply(frame, mask, 0.002);
		// 中值滤波
		medianBlur(mask, mask, 3);
		// 阈值分割,去阴影
		threshold(mask, mask, 200, 255, CV_THRESH_BINARY);
		// 找轮廓
		maskCp = mask.clone();
		findContours(maskCp, cnts, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
		vector<Point> maxCnt;
		for (int i = 0; i < cnts.size(); ++i) {
			maxCnt = maxCnt.size() > cnts[i].size() ? maxCnt : cnts[i];
		}
		// 画最大外接矩形
		if (maxCnt.size() > 0) {
			maxRect = boundingRect(maxCnt);
			double rectAreaRatio = (double)maxRect.area() / (frame.cols * frame.rows);
			if ((double)maxRect.height / maxRect.width > RECT_HW_RATIO && rectAreaRatio > RECT_AREA_RATIO &&
				rectAreaRatio < RECT_AREA_RATIO2) {
				rectangle(frame, maxRect.tl(), maxRect.br(), Scalar(0, 255, 0), 2);
					++hasPeopleFrameCnt;	
			}
		}
		++spaceFrames;
		if (spaceFrames >= SPACE_FRAME) {
			if (hasPeopleFrameCnt > SPACE_FRAME / 8) {
				hasPeople = true;
				cout << count << ":有人" << endl;
			}
			else {
				hasPeople = false;
				cout << count << ":无人" << endl;
			}
			hasPeopleFrameCnt = 0;
			spaceFrames = 0;
		}

		imshow("frame", frame);
		imshow("mask", mask);
		if (waitKey(10) == 27) {
			break;
		}
	}
	return 0;
};



  • 4
    点赞
  • 54
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值