opencv-背景建模

转载于:http://blog.csdn.net/angl129/article/details/29887783


背景建模

     在摄像机静止的情况下,背景减法是一种较常见的运动目标检测方法。它利用当前帧和参考帧(背景模型)之差进行运动物体的检测,如下图所示;这些运动的物体一般就是我们感兴趣的目标,即前景检测。详细的描述可参考:http://docs.opencv.org/trunk/doc/tutorials/video/background_subtraction/background_subtraction.html

 

 

一、 背景建模的一般方法

     背景建模的一般方法可分为:帧差、中值滤波、高斯平均、混合高斯、Vibe和以纹理为特征的背景建模等。 http://www.cnblogs.com/xrwang/archive/2010/02/21/ForegroundDetection.html

vibe具体描述可参考: http://blog.sciencenet.cn/blog-722391-571072.html ;http://blog.csdn.net/stellar0/article/details/8777283

     其存在的主要问题有:光照的缓慢变化及突变两种情况、动态背景、相似、阴影和噪声等。不同的方法在某些方面表现的较优的性能,很少有某一方法能在各个方面都呈现出最优的情况,所以需针对不同的应用场景选择最合适的方法。在这里主要是结合Opencv的实现对混合高斯背景模型进行介绍和分析。背景混合模型中,每个像素的强度值由一个高斯混合模型来表示,通过一定的方法判断那些强度值更倾向于背景。

 

二、Opencv实现过程

    OpenCV中用于实现混合高斯前景分割的方法,主要有BackgroundSubtractorMOG和BackgroundSubtractorMOG2两个类。这2个类都继承BackgroundSubtractor类,其定义如下:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. class BackgroundSubtractor : public Algorithm  
  2. {  
  3. public:  
  4.      virtual ~ BackgroundSubtractor();  
  5.      virtual void operator()(InputArray image, OutputArray fgmask,double learningRate=0);  
  6.      virtual void getBackgroundImage( OutputArray backgroundImage) const;  
  7. }   

其成员函数的功能如下:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. 1)void BackgroundSubtractor::operator()(InputArray image, OutputArray fgmask,double learningRate=0)  

功能:计算前景掩膜(foreground mask)

参数:image-视频帧

           fgmask-输出前景掩膜,为8-bit的二进制图像

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. 2)void BackgroundSubtractor::getBackgroundImage( OutputArray backgroundImage) const  

功能:获得背景图像

参数:backgroundImage-输出的背景图像

 

  

下面主要总结OpenCV中实现高斯混合背景建模的二个类:

1、BackgroundSubtractorMOG

1)构造函数

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. BackgroundSubtractorMOG::BackgroundSubtractorMOG()  
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. BackgroundSubtractorMOG::BackgroundSubtractorMOG(int history,int nmixtures,double backgroundRatio,double noiseSigma=0)  

       其构造函数有2个,若采取默认的构造函数,则对应的参数将取默认值;第二个构造函数中参数对应为:

      history—历史视频帧的长度   

      nmixtures---混合高斯的数目

      backgroundRatio---背景比例

      noiseSigma-----噪声强度

2)operator() 函数

      功能:更新背景模型并返回前景掩膜

      具体实现:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void BackgroundSubtractorMOG::operator()(InputArray _image, OutputArray _fgmask, double learningRate)  
  2. {  
  3.     Mat image = _image.getMat();  
  4.     bool needToInitialize = nframes == 0 || learningRate >= 1 || image.size() != frameSize || image.type() != frameType;  
  5.   
  6.     if( needToInitialize )  
  7.         initialize(image.size(), image.type());  
  8.   
  9.     CV_Assert( image.depth() == CV_8U );  
  10.     _fgmask.create( image.size(), CV_8U );  
  11.     Mat fgmask = _fgmask.getMat();  
  12.   
  13.     ++nframes;  
  14.     learningRate = learningRate >= 0 && nframes > 1 ? learningRate : 1./min( nframes, history ); //根据学习率和帧数确定当前学习率大小  
  15.     CV_Assert(learningRate >= 0);  
  16.   
  17.     if( image.type() == CV_8UC1 )   //根据图像的通道数确定处理的函数  
  18.         process8uC1( image, fgmask, learningRate, bgmodel, nmixtures, backgroundRatio, varThreshold, noiseSigma );  
  19.     else if( image.type() == CV_8UC3 )  
  20.         process8uC3( image, fgmask, learningRate, bgmodel, nmixtures, backgroundRatio, varThreshold, noiseSigma );  
  21.     else  
  22.         CV_Error( CV_StsUnsupportedFormat, "Only 1- and 3-channel 8-bit images are supported in BackgroundSubtractorMOG" );  
  23. }  

      可看出,高斯混合背景建模具体功能主要由process8uc1()和process8uc3()两个函数实现,这两个函数的具体实现可参考OpenCV源代码目录下\sources\modules\video\src\bgfg_gaussmix.cpp文件。

 

2、BackgroundSubtractorMOG2

1)构造函数

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. BackgroundSubtractorMOG2::BackgroundSubtractorMOG2()  
  2. BackgroundSubtractorMOG2::BackgroundSubtractorMOG2(int history,float varThreshold,bool bShadowDetection=true)  

其中第二个构造函数的参数定义如下:

   history-历史帧的长度

   varThreshold-变量的阈值

   bShadowDetection-是否进行阴影的检测

2)operator()函数

      更新背景模型并返回前景掩膜,与BackgroundSubtractorMOG类中operator()函数实现相同的功能。

     具体实现:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1.   void BackgroundSubtractorMOG2::operator()(InputArray _image, OutputArray _fgmask, double learningRate)  
  2. {  
  3.     Mat image = _image.getMat();  
  4.     bool needToInitialize = nframes == 0 || learningRate >= 1 || image.size() != frameSize || image.type() != frameType;  
  5.   
  6.     if( needToInitialize )  
  7.         initialize(image.size(), image.type());  
  8.   
  9.     _fgmask.create( image.size(), CV_8U );  
  10.     Mat fgmask = _fgmask.getMat();  
  11.   
  12.     ++nframes;  
  13.     learningRate = learningRate >= 0 && nframes > 1 ? learningRate : 1./min( 2*nframes, history );  
  14.     CV_Assert(learningRate >= 0);  
  15.   
  16.     parallel_for_(Range(0, image.rows),  
  17.                   MOG2Invoker(image, fgmask,  
  18.                               (GMM*)bgmodel.data,  
  19.                               (float*)(bgmodel.data + sizeof(GMM)*nmixtures*image.rows*image.cols),  
  20.                               bgmodelUsedModes.data, nmixtures, (float)learningRate,  
  21.                               (float)varThreshold,  
  22.                               backgroundRatio, varThresholdGen,  
  23.                               fVarInit, fVarMin, fVarMax, float(-learningRate*fCT), fTau,  
  24.                               bShadowDetection, nShadowDetection));  
  25. }  

      该函数实现中主要是parallel_for_()函数,其中背景建模的功能的实现主要是struct MOG2Invoker : ParallelLoopBody{}这一结构体,其具体的定义参考sources\modules\video\src\bgfg_gaussmix2.cpp。

3)getBackgroundImage()函数

      获取背景图像,是该类新实现的具体功能。具体实现:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void BackgroundSubtractorMOG2::getBackgroundImage(OutputArray backgroundImage) const  
  2. {  
  3.     int nchannels = CV_MAT_CN(frameType);  
  4.     CV_Assert( nchannels == 3 );  
  5.     Mat meanBackground(frameSize, CV_8UC3, Scalar::all(0));  
  6.   
  7.     int firstGaussianIdx = 0;  
  8.     const GMM* gmm = (GMM*)bgmodel.data;  
  9.     const Vec3f* mean = reinterpret_cast<const Vec3f*>(gmm + frameSize.width*frameSize.height*nmixtures);  
  10.     for(int row=0; row<meanBackground.rows; row++)  
  11.     {  
  12.         for(int col=0; col<meanBackground.cols; col++)  
  13.         {  
  14.             int nmodes = bgmodelUsedModes.at<uchar>(row, col);  
  15.             Vec3f meanVal;  
  16.             float totalWeight = 0.f;  
  17.             for(int gaussianIdx = firstGaussianIdx; gaussianIdx < firstGaussianIdx + nmodes; gaussianIdx++)  
  18.             {  
  19.                 GMM gaussian = gmm[gaussianIdx];  
  20.                 meanVal += gaussian.weight * mean[gaussianIdx];  
  21.                 totalWeight += gaussian.weight;  
  22.   
  23.                 if(totalWeight > backgroundRatio)  
  24.                     break;  
  25.             }  
  26.   
  27.             meanVal *= (1.f / totalWeight);  
  28.             meanBackground.at<Vec3b>(row, col) = Vec3b(meanVal);  
  29.             firstGaussianIdx += nmixtures;  
  30.         }  
  31.     }  
  32.   
  33.     switch(CV_MAT_CN(frameType)) //根据视频帧的类型返回相应的背景图像  
  34.     {  
  35.     case 1:  
  36.     {  
  37.         vector<Mat> channels;  
  38.         split(meanBackground, channels);  
  39.         channels[0].copyTo(backgroundImage);  
  40.         break;  
  41.     }  
  42.   
  43.     case 3:  
  44.     {  
  45.         meanBackground.copyTo(backgroundImage);  
  46.         break;  
  47.     }  
  48.   
  49.     default:  
  50.         CV_Error(CV_StsUnsupportedFormat, "");  
  51.     }  
  52. }  

 

三、实例分析

以BackgroundSubtractorMOG2类为例:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. #include<iostream>  
  2. #include<opencv2\core\core.hpp>  
  3. #include<opencv2\highgui\highgui.hpp>  
  4. #include<opencv2\imgproc\imgproc.hpp>  
  5. #include<opencv2\video\background_segm.hpp>  
  6.   
  7. using namespace cv;  
  8. using namespace std;  
  9.   
  10. void helpProcess()  
  11. {  
  12.     cout<<"Opencv中背景减法的实例程序!\n";  
  13. }  
  14.   
  15. int main()  
  16. {  
  17.     helpProcess();  
  18.     VideoCapture video("Car.avi");  
  19.     Mat Frame,fgMask,bg;  
  20.     int FrameNum=0;  
  21.   
  22.     if(!video.isOpened()) {printf("读取视频失败,请确认视频目录是否正确!\n");return false;}  
  23.   
  24.     BackgroundSubtractorMOG2 bgSub;     //定义背景减法的对象,以默认构造函数进行初始化  
  25.   
  26.     while(video.read(Frame))  
  27.     {  
  28.         FrameNum++;  
  29.         cout<<FrameNum<<endl;  
  30.         bgSub(Frame,fgMask,0.001);     //背景减法获取前景掩膜  
  31.         bgSub.getBackgroundImage(bg);  //获取背景图像  
  32.           
  33.         //显示  
  34.         imshow("Foreground mask",fgMask);  
  35.         imshow("Background Image",bg);  
  36.         waitKey(10);  
  37.       
  38.     }  
  39.   
  40.     return 0;  
  41.   
  42. }  

对应运行结果:

       背景建模受光照的缓慢变化及突变、阴影、图像噪声、动态背景,如晃动的树叶等等因素的影响,在不同的应用场景下,还需进行不同的处理。


  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值