背景建模跟踪目标
学习opencv3(P393)
分析背景不怎么变化的视频的时候可以用BSM
基本原理:利用前几帧(或一帧)的图像作为背景模型,后续的帧图像与背景模型比较,得到的差异就是前景对象了。
两个常用的算法:图像分割(GMM – 高斯混合模型), 机器学习(KNN –K个最近邻)
一、帧间差分
主要是前一帧(或之后的几帧)减去另一帧,将足够不同的地方标位前景;
缺点:对于移动的物体,无法区分移动后的空洞
二、平均背景法
主要是学习得到背景像素的均值和方差,作为背景的模型,在均值里设置一个阈值,当差值大于或小于一定的距离度量就可以认为是前景了;
综合起来就是在main()函数中读入一段视频并构建背景模型,在给出的例子中,我们在训练模式下读取视频直到用户按下空格键,然后程序继续读入视频将检测前景物体。
缺点:依然是在场景中没有移动的背景物体的时候,它才工作良好,在场景中存在飘动的窗帘或是树枝等具有双或是多模态的特征时,该方法会失效,该方法也假设光线几乎是不同的,可以通过连通域腐蚀膨胀来清理小变化。
三、Gaussian模型
主要用到以增量的方式计算平均值,方差和协方差来设计背景模型,然后在新图像中,计算像素点的值属于该模型的概率来判断,协方差可以用马氏距离来计算。
很多场景中的背景,包括复杂的移动的物体(挥舞的树叶,转动的风扇,),场景中也经常包括变换的光线(关门窗带来的光线变化),一个处理这些场景的方法是对每个像素或每组像素使用一个时间序列模型,这个模型可以很好的处理时间上的波动,但缺点是需要大量的内存,不切实际;
四、复杂背景提取方法
1、YUV
将新像素值和先前观察到的值,进行对比,如果新值和先前的某个值很接近,我们认为它就是先前的那个值加上的扰动,如果不是我们就认为是该新值不同背景的新颜色,对这样的新的进行Gaussian建模,合成背景模型
2、码书codebook
码书可以处理像素变化剧烈的情况,通过这样的更加精确的建模方法,可以检测出颜色在这些背景之间的前景物体,
基本的背景提取算法,都有相同的基础想法,opencv对其提供了封装,这些封装算法,没有通过累加背景图片进行训练的函数,因为学术界的一致观点是任何背景提取算法有应该能够连续进行训练,而不是区分训练模式和运行模式,原因:不能找到一段没有前景物体的时间段来训练算法;很多时候背景中的物体最终是会移动的,那么这些物体就会在之后的检查中永久的留下一个空洞;连续的训练可以连续的构建背景模型,不断从背景中删除很少出现的物体(在出现会被视为前景),保留大多数时候都出现的物体(这些被视为背景)
五、背景建模,前景提取
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int argc, char**) {
VideoCapture capture;
capture.open(0);
if (!capture.isOpened()) {
printf("could not find the video file...\n");
return -1;
}
// create windows
Mat frame;
Mat bsmaskMOG2, bsmaskKNN;
namedWindow("input video", CV_WINDOW_AUTOSIZE);
namedWindow("MOG2", WINDOW_AUTOSIZE);
namedWindow("KNN Model", WINDOW_AUTOSIZE);
Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
// intialization BS
Ptr<BackgroundSubtractor> pMOG2 = createBackgroundSubtractorMOG2();
/*
Ptr<backgroundsubtractormog2>
cv::createBackgroundSubtractorMOG2 (
int history = 500, //用于训练背景的帧数,默认为500帧,如果不手动设置learningRate
,history就被用于计算当前的learningRate,此时history越大,learningRate越小,背景更新越慢;
double varThreshold = 16, //方差阈值,用于判断当前像素是前景还是背景。一般默认16
,如果光照变化明显,如阳光下的水面,建议设为25,36,具体去试一下也不是很麻烦,值越大,灵敏度越低;
bool detectShadows = true //是否检测影子,设为true为检测,false为不检测,
检测影子会增加程序时间复杂度,如无特殊要求,建议设为false;
)
*/
Ptr<BackgroundSubtractor> pKNN = createBackgroundSubtractorKNN();
while (capture.read(frame)) {
imshow("input video", frame);
// MOG BS
pMOG2->apply(frame, bsmaskMOG2);
/*
virtual void cv::BackgroundSubtractor::apply (
InputArray image, //image 源图
OutputArray fgmask, //fmask 前景(二值图像)
double learningRate = -1 //learningRate 学习速率,
,值为0-1,为0时背景不更新,为1时逐帧更新,默认为-1,即算法自动更新
)
*/
morphologyEx(bsmaskMOG2, bsmaskMOG2, MORPH_OPEN, kernel, Point(-1, -1));
imshow("MOG2", bsmaskMOG2);
// KNN BS mask
// 最后一个参数 (0-1之间表示学习背景模型时长,-1表示opencv自动设置学习时长
//,0表示不更改背景模型,1表示背景模型按照最后一帧重新初始化)
pKNN->apply(frame, bsmaskKNN,-1);
imshow("KNN Model", bsmaskKNN);
char c = waitKey(100);
if (c == 27) {
break;
}
}
capture.release();
waitKey(0);
return 0;
}
apply函数介绍:
最后一个参数 (0-1之间表示学习背景模型时长,-1表示opencv自动设置学习时长,0表示不更改背景模型,1表示背景模型按照最后一帧重新初始化)
virtual void cv::BackgroundSubtractor::apply
(
InputArray image, //image 源图
OutputArray fgmask, //fmask 前景(二值图像)
double learningRate = -1 //learningRate 学习速率,值为0-1,为0时背景不更新,为1时逐帧更新,默认为-1,即算法自动更新
)
1、Zivkovic方法
createBackgroundSubtractorMOG2函数介绍:
Ptr<backgroundsubtractormog2> cv::createBackgroundSubtractorMOG2
(
int history = 500, //用于训练背景的帧数,默认为500帧,一次量测被遗忘的时间,一次衰减影响按照(1-learningRate)**t;如果不手动设置learningRate,history就被用于计算当前的learningRate,此时history越大,learningRate越小,背景更新越慢;
double varThreshold = 16, //方差阈值,用于判断当前像素是前景还是背景。一般默认16,如果光照变化明显,如阳光下的水面,建议设为25,36,具体去试一下也不是很麻烦,值越大,灵敏度越低;
bool detectShadows = true //是否检测影子,设为true为检测,false为不检测,检测影子会增加程序时间复杂度,如无特殊要求,建议设为false;
)
2、KB方法
createBackgroundSubtractorMOG()函数
它提供了具有挑战背景建模问题的新能力:一个多模态模型,连续在线训练,两个用来提高初始化性能的训练模式和显示的阴影检测和去除。算法中的一些微调的参数:
1、history(历史参数):
用来设定合适算法从初始化模式切换为正常运行模式,默认值是200帧;
2、nmixture(高斯混合模数):用来对每个像素进行背景建模的时候,混合高斯模型中高斯分量的数量,默认是5;对于模型中每个高斯分量,每个分量都配有一个权重,该权重表示像素以多大比例使用当前分量解释
3、backgroundRatio(背景比率):默认0.7
4、noiseSigma(噪声强度):
3、还很很多方法需要扩展模块的安装
https://blog.csdn.net/Anderson_Y/article/details/82082095