您的位置:首页 > 编程语言

BackgroundSubtractorMOG部分代码

2016-03-05 09:52 465 查看
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》
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  opencv