BackgroundSubtractorMOG部分代码

来源:互联网 发布:烈火交友软件 编辑:程序博客网 时间:2024/05/07 17:07

1、Opencv的帮助文档地址:http://docs.opencv.org/2.4/modules/video/doc/motion_analysis_and_object_tracking.html?highlight=backgroundsubtractormog#backgroundsubtractormog

2、关键函数
2.1、BackgroundSubtractorMOG::BackgroundSubtractorMOG(int _history, int _nmixtures,
double _backgroundRatio,
double _noiseSigma)
2.2、void BackgroundSubtractorMOG::operator()(InputArray _image, OutputArray _fgmask, double learningRate)

3、几点说明:
3.1、这个参数int _history 的用途。仅仅用于第一帧学习率,或者在学习率为负值时的学习率计算,其他地方没有使用
learningRate = learningRate >= 0 && nframes > 1 ? learningRate : 1./min( nframes, history );

3.2、 _backgroundRatio的用途,是个阈值,用于判断前多少个model作为背景模型。是前n个模型权重的和的比较阈值。具体可以参考下面代码注释部分

**代码摘自opencv

//backgroundRatio : 通过代码可知,就是k个模型的权重累加值>= backgroundRatio ,此时前k个model就是背景的model,大于k的model就是前景的model//nmixtures : model数量static void process8uC1( const Mat& image, Mat& fgmask, double learningRate,                         Mat& bgmodel, int nmixtures, double backgroundRatio,                         double varThreshold, double noiseSigma ){    int x, y, k, k1, rows = image.rows, cols = image.cols;    float alpha = (float)learningRate, T = (float)backgroundRatio, vT = (float)varThreshold;    int K = nmixtures;    MixData<float>* mptr = (MixData<float>*)bgmodel.data;    const float w0 = (float)defaultInitialWeight;    const float sk0 = (float)(w0/(defaultNoiseSigma*2));    const float var0 = (float)(defaultNoiseSigma*defaultNoiseSigma*4);    const float minVar = (float)(noiseSigma*noiseSigma);    for( y = 0; y < rows; y++ )    {        const uchar* src = image.ptr<uchar>(y);        uchar* dst = fgmask.ptr<uchar>(y);        if( alpha > 0 )         {            // 考虑更新模型的情况。            for( x = 0; x < cols; x++, mptr += K )            {                float wsum = 0;                float pix = src[x];                int kHit = -1, kForeground = -1;                // K:是高斯分布数量                for( k = 0; k < K; k++ )                {                    float w = mptr[k].weight;                    wsum += w;                    if( w < FLT_EPSILON ) // 由于mptr是按权重降序排列的,因此权重太小的情况就结束循环                        break;                    float mu = mptr[k].mean;                    float var = mptr[k].var;                    float diff = pix - mu;                    float d2 = diff*diff;                    if( d2 < vT*var ) //同样判断是否是匹配的分布                    {                        wsum -= w; // 这里得到的wsum是前面k-1个不匹配的分布的权重的累加和                        float dw = alpha*(1.f - w); //                        mptr[k].weight = w + dw; //更新权重                        mptr[k].mean = mu + alpha*diff; // 更新均值                        var = max(var + alpha*(d2 - var), minVar); // 更新方差                        mptr[k].var = var;                        mptr[k].sortKey = w/sqrt(var); // 排序的关键字,为什么?                        for( k1 = k-1; k1 >= 0; k1-- ) // 重新排序,通过交换的方式,将该高斯分布适当前移                        {                            if( mptr[k1].sortKey >= mptr[k1+1].sortKey )                                break;                            std::swap( mptr[k1], mptr[k1+1] );                        }                        kHit = k1+1;                        break;                    }                }                if( kHit < 0 ) // no appropriate gaussian mixture found at all, remove the weakest mixture and create a new one                {                    kHit = k = min(k, K-1);                    wsum += w0 - mptr[k].weight;                    mptr[k].weight = w0;                    mptr[k].mean = pix;                    mptr[k].var = var0;                    mptr[k].sortKey = sk0;                }                else                    for( ; k < K; k++ )                        wsum += mptr[k].weight;                float wscale = 1.f/wsum;                wsum = 0;                for( k = 0; k < K; k++ )                {                    wsum += mptr[k].weight *= wscale;                    mptr[k].sortKey *= wscale; // 前面权重或者分布有变化,这里做更新                    if( wsum > T && kForeground < 0 )                        kForeground = k+1;                }                dst[x] = (uchar)(-(kHit >= kForeground));            }        }        else        {            //不考虑更新模型的情况。这里更好理解些,看完这个在看考虑学习率的场景            for( x = 0; x < cols; x++, mptr += K )            {                float pix = src[x];                int kHit = -1, kForeground = -1;                //kForeground:前多少个分布是背景的分布。大于kForeground的就是前景分布                //kHit: 表示给定的像素最符合哪个分布 ;                 //kHit <0 ,表示没有匹配的分布,自然是前景;                //kHit<kForeground 自然是背景;否则是前景                //这里判断给定的像素值与哪个高斯分布最匹配,匹配的依据就是小于vT倍的方差                for( k = 0; k < K; k++ )                {                    if( mptr[k].weight < FLT_EPSILON )                        break;                    float mu = mptr[k].mean;                    float var = mptr[k].var;                    float diff = pix - mu;                    float d2 = diff*diff;                    if( d2 < vT*var )                    {                        kHit = k;                         break;                    }                }                if( kHit >= 0 ) //若是没有找到匹配的分布,就被判定为为前景,不需要下面的计算                {                    float wsum = 0;                    for( k = 0; k < K; k++ )                    {                        wsum += mptr[k].weight;                        if( wsum > T )                        {                            kForeground = k+1; // 前k个作为背景模型,这里计算的到k值。                            break;                        }                    }                }                dst[x] = (uchar)(kHit < 0 || kHit >= kForeground ? 255 : 0);// kForeground表示前kForeground个作为背景模型,若是kHit>=kForeground说明匹配的高斯分布已经不在前kForeground中,因此该像素点就是前景了。否则就判定为背景点            }        }    }}

[1]: 《An Improved Adaptive Background Mixture Model for Realtime Tracking with Shadow Detection》

0 0
原创粉丝点击