BackgroundSubtractorMOG2基于自适应混合高斯背景建模,具有一定的抗光照干扰的能力,参数配置如下
Ptr<BackgroundSubtractorMOG2> bgsubtractor = createBackgroundSubtractorMOG2();
// 用于训练背景的帧数,如果不手动设置learning rate,history就被用于计算当前的learning rate,
// history越大,learning rate越低,背景更新越慢
bgsubtractor->setHistory(500);
// 方差阈值,主要用于判断前景还是背景,值越大,灵敏度越低
// 如果光照变化明显,如阳光下的水面,建议设为25,36
bgsubtractor->setVarThreshold(16);
// 是否检测有影子,开启后会增加算法复杂度
bgsubtractor->setDetectShadows(true);
// 高斯模型个数,默认5个,最多8个
bgsubtractor->setBackgroundRatio(4);
// 高斯背景模型权重和阈值,nmixtures个模型按权重重排序后,
// 只取模型权重累加值大于backgroundRatio的前几个作为背景模型
bgsubtractor->setNMixtures(5);
// 新建高斯模型的方差初始值,默认15
bgsubtractor->setVarInit(15);
// 背景更新时,用于限制高斯模型方差的最大值,默认20
bgsubtractor->setVarMax(20);
// 背景更新时,用于限制高斯模型方差的最小值,默认4
bgsubtractor->setVarMin(4);
// 方差阈值,用于已经存在的匹配的模型,如果不存在则新建一个
bgsubtractor->setVarThresholdGen(100);
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/xfeatures2d.hpp>
using namespace std;
using namespace cv;
//图像分割
int labelTargets(Mat& src, Mat& mask, int thresh = 100);
int main()
{
const char* fn = "D:\\vs-projects\\moving\\vtest.avi";
VideoCapture cap;
Mat source, image, foreGround, backGround, fgMask;
Ptr<BackgroundSubtractorMOG2> pBgModel = createBackgroundSubtractorMOG2();
pBgModel->setHistory(20);
pBgModel->setVarThreshold(100);
pBgModel->setDetectShadows(false);
//打开视频
cap.open(fn);
if (!cap.isOpened())
{
cout << "无法打开视频文件:" << fn << endl;
return;
}
for (;;)
{
//获取视频帧
cap >> source;
if (source.empty())
break;
resize(source, image, Size(source.cols / 2, source.rows / 2), INTER_LINEAR);
//转为灰度图
//cvtColor(image, image, COLOR_BGR2GRAY);
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);
foreGround = Scalar::all(0);
//image和fgMask重叠以后把fgMask像素值为0对应image中的点变为透明,而保留其他点
image.copyTo(foreGround, fgMask);
//imshow("src", foreGround);
//waitKey(20);
//标记找到的运动目标
int nTargets = labelTargets(image, fgMask);
//cout << "共检测到" << nTargets << "个目标" << endl;
}
}
int labelTargets(Mat& src, Mat& mask, int thresh)
{
//以下是图像分割
Mat seg = mask.clone();
vector<vector<Point>> cnts;
findContours(seg, cnts, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
//以下进行筛选
float area;
Rect rect;
int count = 0;
string strCount;
for (int i = cnts.size() - 1; i >= 0; i--)
{
vector<Point> c = cnts[i];
area = contourArea(c);
if (area < thresh)
continue;
count++;
//包围特征点的矩形框的坐标和长宽信息
rect = boundingRect(c);
//输出矩形框的坐标和面积
cout << "位置:(" << rect.x << "," << rect.y << ")面积:" << rect.width * rect.height << endl;
//在原图上画出矩形框
rectangle(src, rect, Scalar(0, 0, 0xff), 1);
stringstream ss;
ss << count;
ss >> strCount;
putText(src, strCount, Point(rect.x, rect.y), CV_FONT_HERSHEY_PLAIN, 0.5, Scalar(0, 0xff, 0));
imshow("src", src);
waitKey(20);
}
return count;
}