1.前言
混合高斯分布(GMM)是背景建模中的经典算法,自提出至今已经有了很多围绕它改进和应用的论文。opencv中(2.4.13版本)也引入了该算法及其改进版本。
首先是基本版本的GMM,opencv将其封装为BackgroundSubtractorMOG,有关该版本算法源码解读及相关论文翻译参考点击打开链接
之后是改进版GMM,opencv把它封装为BackgroundSubtractorMOG2算法类,源代码位于opencv\sources\modules\video\src\bgfg_gaussmix2.cpp中。算法如何改进?改进的效果如何?下面将给出详细分析。
2.opencv中的改进版GMM——BackgroundSubtractorMOG2
首先通过例程观察BackgroundSubtractorMOG2与BackgroundSubtractorMOG的区别,有关该算法的opencv应用可以参考http://blog.csdn.net/sinat_31337047/article/details/52586160
测试代码如下:
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/opencv.hpp>
#include "VideoProcessor.h"
#include "FeatureTracker.h"
#include "BGFSSegmentor.h"
using namespace std;
using namespace cv;
int main(int argc, char* argv[])
{
VideoCapture capture("../768X576.avi");
if(!capture.isOpened())
return 0;
Mat frame;
Mat foreground, foreground2;
BackgroundSubtractorMOG mog;
BackgroundSubtractorMOG2 mog2;
bool stop(false);
namedWindow("Extracted Foreground");
while(!stop)
{
if(!capture.read(frame))
break;
cvtColor(frame, frame, CV_BGR2GRAY);
long long t = getTickCount();
mog(frame, foreground, 0.01);
long long t1 = getTickCount();
mog2(frame, foreground2, -1);
long long t2 = getTickCount();
cout<<"t1 = "<<(t1-t)/getTickFrequency()<<" t2 = "<<(t2-t1)/getTickFrequency()<<endl;
imshow("Extracted Foreground", foreground);
imshow("Extracted Foreground2", foreground2);
imshow("video", frame);
if(waitKey(10) >= 0)
stop = true;
}
waitKey();
return 0;
}
背景提取效果如下图所示,左左边为BackgroundSubtractorMOG2算法效果,右边为BackgroundSubtractorMOG效果。先忽略左边图像中的一些噪点,我们可以看到两者的最大不同在于左边图像中存在灰色填充的一些区域,这些正是BackgroundSubtractorMOG2算法的一个改进点-阴影检测,那些灰色区域就是算法计算得到的“阴影”区域。另外一处不同在于算法的运行时间,根据控制台输出结果,BackgroundSubtractorMOG2每帧检测大概0.03s,BackgroundSubtractorMOG每帧检测大概0.06s,BackgroundSubtractorMOG2算法在运行时间上有较大提升(不全是算法本身原因,实际上BackgroundSubtractorMOG2在执行时通过多线程并行执行)。
所以目前看来改进后的GMM算法,即BackgroundSubtractorMOG2算法主要有两点改进点:(1)增加阴影检测功能(2)算法效率有较大提升。后者意义不言而喻,前者的意义在于如果不使用一些方法检测得到阴影,那么它有可能被识别为前景物体,导致前景物体得到了错误的形状,从而对后续处理(譬如跟踪)产生不好的影响。
3.BackgroundSubtractorMOG2的支撑论文
那么BackgroundSubtractorMOG2如何做到这两点呢?还是要看源文件bgfg_gaussmix2.cpp了,文件中有关该算法的来源是这样说的(个人总结)
(1)该算法实现了混合高斯模型中模型参数的自适应,从而减少了运算量,这部分的论文支撑是《Improved adaptive Gausian mixture model for background subtraction》、《Efficient Adaptive Density Estimapion per Image Pixel for the Task of Background Subtraction》、《Recursive unsupervised learning of finite mixture models》
(2)该算法实现的阴影检测,参考了论文《Detecting Moving Shadows-Algorithms and Evaluation》
好吧,一共4篇外文,没办法只能下载下来看了。当然既然这里是在总结,就肯定不会让你们再走弯路跳坑。。。首先关于(1),自己仔细看了第一篇并且完成了翻译,见点击打开链接。这篇文章很好,不仅把改进步骤和具体实现讲的很清楚,还把基本的GMM算法中更新方程的数学推导明确的给了出来。所以推荐大家去读一读点击打开链接。第二篇文章实际上就是第一篇的全部内容+作者提出的另一种背景建模方法,所以如果只是为了理解BackgroundSubtractorMOG2的话就没必要读它了,第三篇呢个人没看,不过觉得并不影响算法原理的理解(好牵强。。。)。一句话总结,看《Improved adaptive Gausian mixture model for background subtraction》并且博主已经给你们翻译好啦
接着关于(2),也是挺坑,我大致看了《Detecting Moving Shadows-Algorithms and Evaluation》,发现这篇文章内容不是提出阴影检测算法,而是对之前阴影检测算法效果的评估比较。BackgroundSubtractorMOG2中用到的阴影检测原理应该来自于《The Sakbot System for Moving Object Detection and Tracking》,这篇文章我瞄了一眼,这里直接把阴影检测的原理大致总结一下:作者在HSV空间中检测阴影(原因在于该颜色空间与人眼感知的更为接近,且对阴影产生的亮度变化更为敏感),原理是作者通过实验发现,阴影覆盖的区域像素点的亮度会降低(V减小),且H和S也会衰减,这算是一个经验性的结论,不过貌似还比较有效果。不过另外一点坑是,opencv在实现该部分内容时,还是在RGB颜色空间中,代码看上去应该还是借鉴了上面的思想。。。
4.BackgroundSubtractorMOG2源码解读
接下来分析bgfg_gaussmix2.cpp文件,作者已经给出了比较详细地描述,这里我把一些重要的地方使用中文再标注了下。
#include "precomp.hpp"
namespace cv
{
/*
Interface of Gaussian mixture algorithm from:
"Improved adaptive Gausian mixture model for background subtraction"
Z.Zivkovic
International Conference Pattern Recognition, UK, August, 2004
http://www.zoranz.net/Publications/zivkovic2004ICPR.pdf
Advantages:
-fa