OpenCV混合高斯模型函数注释说明
OpenCV混合高斯模型函数注释说明
一、cvaux.h
#define CV_BGFG_MOG_MAX_NGAUSSIANS 500
//高斯背景检测算法的默认参数设置
#define CV_BGFG_MOG_BACKGROUND_THRESHOLD 0.7 //高斯分布权重之和阈值
#define CV_BGFG_MOG_STD_THRESHOLD 2.5 //λ=2.5(99%)
#define CV_BGFG_MOG_WINDOW_SIZE 200 //学习率α=1/win_size
#define CV_BGFG_MOG_NGAUSSIANS 5 //k=5个混合高斯模型
#define CV_BGFG_MOG_WEIGHT_INIT 0.05 //初始权重
#define CV_BGFG_MOG_SIGMA_INIT 30 //初始标准差
#define CV_BGFG_MOG_MINAREA 15.f //??? #define CV_BGFG_MOG_NCOLORS 3 //颜色通道数
/************* CV_BG_STAT_MODEL_FIELDS()的宏定义**********************/
#define CV_BG_STAT_MODEL_FIELDS()
int type; //type of BG model
CvReleaseBGStatModel release; // \
CvUpdateBGStatModel update; \
IplImage* background; /*8UC3 reference background image*/ \
IplImage* foreground; /*8UC1 foreground image*/ \
IplImage** layers; /*8UC3 reference background image, can be null */ \
int layer_count; /* can be zero */ \
CvMemStorage* storage; /*storage for foreground_regions?/ \
CvSeq* foreground_regions /*foreground object contours*/
/*************************高斯背景模型参数结构体*************************/
typedef struct CvGaussBGStatModelParams
{
int win_size; //等于 1/alpha
int n_gauss; //高斯模型的个数
double bg_threshold, std_threshold, minArea; // bg_threshold:高斯分布权重之和阈值、std_threshold:2.5、minArea:???
double weight_init, variance_init; //权重和方差
}CvGaussBGStatModelParams;
/**************************高斯分布模型结构体***************************/
typedef struct CvGaussBGValues
{
int match_sum;
double weight;
double variance[CV_BGFG_MOG_NCOLORS];
double mean[CV_BGFG_MOG_NCOLORS];
}
CvGaussBGValues;
typedef struct CvGaussBGPoint
{
CvGaussBGValues* g_values;
}
CvGaussBGPoint;
/*************************高斯背景模型结构体*************************/
typedef struct CvGaussBGModel
{
CV_BG_STAT_MODEL_FIELDS();
CvGaussBGStatModelParams params;
CvGaussBGPoint* g_point;
int countFrames;
}
CvGaussBGModel;
二、cvbgfg_gaussmix.cpp
//////////////////////////////////////////////////////////// cvCreateGaussianBGModel////////////////////////////////////////////////////////////////
功能:高斯背景模型变量bg_model初始化赋值
CV_IMPL CvBGStatModel* cvCreateGaussianBGModel( IplImage* first_frame, CvGaussBGStatModelParams* parameters)
{
CvGaussBGModel* bg_model = 0; //高斯背景状态模型变量 CV_FUNCNAME( "cvCreateGaussianBGModel" ); __BEGIN__; double var_init;
CvGaussBGStatModelParams params; //高斯背景状态模型参数变量
int i, j, k, n, m, p;
//初始化参数,如果参数为空,则进行初始化赋值
if( parameters == NULL )
{
params.win_size = CV_BGFG_MOG_WINDOW_SIZE; //学习率α=1/200=0.005
params.bg_threshold = CV_BGFG_MOG_BACKGROUND_THRESHOLD; //判断是否为背景点的阈值0.7
params.std_threshold = CV_BGFG_MOG_STD_THRESHOLD;//标准阈值2.5
params.weight_init = CV_BGFG_MOG_WEIGHT_INIT; //权重值0.05
params.variance_init = CV_BGFG_MOG_SIGMA_INIT*CV_BGFG_MOG_SIGMA_INIT; //方差30*30
params.minArea = CV_BGFG_MOG_MINAREA; //???
params.n_gauss = CV_BGFG_MOG_NGAUSSIANS; //高斯模型个数
}
else
{
params = *parameters;
} if( !CV_IS_IMAGE(first_frame) ) //如果第一帧不是图像,则报错
CV_ERROR( CV_StsBadArg, "Invalid or NULL first_frame parameter" ); CV_CALL( bg_model = (CvGaussBGModel*)cvAlloc( sizeof(*bg_model) )); //申请内存空间
memset( bg_model, 0, sizeof(*bg_model) );
bg_model->type = CV_BG_MODEL_MOG; // CV_BG_MODEL_MOG高斯背景模型
bg_model->release = (CvReleaseBGStatModel)icvReleaseGaussianBGModel; //释放内存的函数指针
bg_model->update = (CvUpdateBGStatModel)icvUpdateGaussianBGModel; //更新高斯模型的函数指针
bg_model->params = params; //申请内存空间
CV_CALL( bg_model->g_point = (CvGaussBGPoint*)cvAlloc(sizeof(CvGaussBGPoint)*
((first_frame->width*first_frame->height) + 256))); //256? CV_CALL( bg_model->background = cvCreateImage(cvSize(first_frame->width,
first_frame->height), IPL_DEPTH_8U, first_frame->nChannels));
CV_CALL( bg_model->foreground = cvCreateImage(cvSize(first_frame->width,
first_frame->height), IPL_DEPTH_8U, 1)); CV_CALL( bg_model->storage = cvCreateMemStorage()); //初始化
var_init = 2 * params.std_threshold * params.std_threshold; //初始化方差
CV_CALL( bg_model->g_point[0].g_values =
(CvGaussBGValues*)cvAlloc( sizeof(CvGaussBGValues)*params.n_gauss*
(first_frame->width*first_frame->height + 128))); //128?
//n:表示像素点的索引值
//p:表示当前像素对应颜色通道的首地址
// g_point[]:对应像素点、g_values[]:对应高斯模型、variance[]和 mean[]:对应颜色通道
for( i = 0, p = 0, n = 0; i < first_frame->height; i++ ) //行
{
for( j = 0; j < first_frame->width; j++, n++ ) //列
{
bg_model->g_point[n].g_values = bg_model->g_point[0].g_values + n*params.n_gauss;//每个像素点的第一个高斯模型的地址(每个像素对应n_gauss个高斯分布模型) //初始化第一个高斯分布模型的参数
bg_model->g_point[n].g_values[0].weight = 1; //取较大权重,此处设置为1
bg_model->g_point[n].g_values[0].match_sum = 1;//高斯函数被匹配的次数(???)
for( m = 0; m < first_frame->nChannels; m++) //对各颜色通道的方差和均值赋值
{
bg_model->g_point[n].g_values[0].variance[m] = var_init; //初始化较大的方差
bg_model->g_point[n].g_values[0].mean[m] = (unsigned char)first_frame->imageData[p + m]; //赋值为当前像素值
} //初始化剩下的高斯分布模型的参数
for( k = 1; k < params.n_gauss; k++)
{
bg_model->g_point[n].g_values[k].weight = 0;//各高斯分布取相等且较小权重值,此处取0
bg_model->g_point[n].g_values[k].match_sum = 0;
for( m = 0; m < first_frame->nChannels; m++)
{
bg_model->g_point[n].g_values[k].variance[m] = var_init; //初始化较大的方差
bg_model->g_point[n].g_values[k].mean[m] = 0; //赋值0
}
}
p += first_frame->nChannels;
}
} bg_model->countFrames = 0; __END__; if( cvGetErrStatus() < 0 )
{
CvBGStatModel* base_ptr = (CvBGStatModel*)bg_model; if( bg_model && bg_model->release )
bg_model->release( &base_ptr );
else
cvFree( &bg_model );
bg_model = 0;
} return (CvBGStatModel*)bg_model;
}
////////////////////////////////////////////////////////// icvUpdateGaussianBGModel ///////////////////////////////////////////////////////////////
功能:对高斯背景模型变量bg_model进行更新
static int CV_CDECL icvUpdateGaussianBGModel( IplImage* curr_frame, CvGaussBGModel* bg_model )
{
int i, j, k;
int region_count = 0;
CvSeq *first_seq = NULL, *prev_seq = NULL, *seq = NULL; bg_model->countFrames++; for( i = 0; i < curr_frame->height; i++ ) //行
{
for( j = 0; j < curr_frame->width; j++ ) //列
{
int match[CV_BGFG_MOG_MAX_NGAUSSIANS];
double sort_key[CV_BGFG_MOG_MAX_NGAUSSIANS];
const int nChannels = curr_frame->nChannels; //通道数目
const int n = i*curr_frame->width+j; //像素索引值
const int p = n*curr_frame->nChannels; //像素点颜色通道的首地址 // A few short cuts
CvGaussBGPoint* g_point = &bg_model->g_point[n];
const CvGaussBGStatModelParams bg_model_params = bg_model->params;
double pixel[4];
int no_match; for( k = 0; k < nChannels; k++ ) //拷贝各通道颜色分量值
pixel[k] = (uchar)curr_frame->imageData[p+k]; no_match = icvMatchTest( pixel, nChannels, match, g_point, &bg_model_params );
//判断高斯背景模型更新帧数是否达到设置值win_size(???)
(初始更新阶段和一般更新阶段在更新处理过程中是不同的,其中定义初始更新阶段为帧数小于win_size)
if( bg_model->countFrames == bg_model->params.win_size ) //一般更新阶段
{
icvUpdateFullWindow( pixel, nChannels, match, g_point, &bg_model->params );
if( no_match == -1)
icvUpdateFullNoMatch( curr_frame, p, match, g_point, &bg_model_params );
}
else
{
icvUpdatePartialWindow( pixel, nChannels, match, g_point, &bg_model_params );
if( no_match == -1)
icvUpdatePartialNoMatch( pixel, nChannels, match, g_point, &bg_model_params );
}
icvGetSortKey( nChannels, sort_key, g_point, &bg_model_params );
icvInsertionSortGaussians( g_point, sort_key, (CvGaussBGStatModelParams *)&bg_model_params );
icvBackgroundTest( nChannels, n, p, match, bg_model );
}
} //foreground filtering //filter small regions
cvClearMemStorage(bg_model->storage); //cvMorphologyEx( bg_model->foreground, bg_model->foreground, 0, 0, CV_MOP_OPEN, 1 );
//cvMorphologyEx( bg_model->foreground, bg_model->foreground, 0, 0, CV_MOP_CLOSE, 1 ); cvFindContours( bg_model->foreground, bg_model->storage, &first_seq, sizeof(CvContour), CV_RETR_LIST );
for( seq = first_seq; seq; seq = seq->h_next )
{
CvContour* cnt = (CvContour*)seq;
if( cnt->rect.width * cnt->rect.height < bg_model->params.minArea )
{
//delete small contour
prev_seq = seq->h_prev;
if( prev_seq )
{
prev_seq->h_next = seq->h_next;
if( seq->h_next ) seq->h_next->h_prev = prev_seq;
}
else
{
first_seq = seq->h_next;
if( seq->h_next ) seq->h_next->h_prev = NULL;
}
}
else
{
region_count++;
}
}
bg_model->foreground_regions = first_seq;
cvZero(bg_model->foreground);
cvDrawContours(bg_model->foreground, first_seq, CV_RGB(0, 0, 255), CV_RGB(0, 0, 255), 10, -1); return region_count;
}
//////////////////////////////////////////////////////////// icvMatchTest ////////////////////////////////////////////////////////////////
功能:将当前像素与个高斯分布进行匹配判断,如果匹配成功,则返回相应高斯分布的索引值
static int icvMatchTest( double* src_pixel, int nChannels, int* match,
const CvGaussBGPoint* g_point,
const CvGaussBGStatModelParams *bg_model_params )
{
int k;
int matchPosition=-1;
for ( k = 0; k < bg_model_params->n_gauss; k++) match[k]=0; //高斯分布匹配标识数组初始化置0 for ( k = 0; k < bg_model_params->n_gauss; k++)
{
double sum_d2 = 0.0;
double var_threshold = 0.0;
for(int m = 0; m < nChannels; m++) //计算当前高斯分布各通道均值与像素点各通道值相减
{
double d = g_point->g_values[k].mean[m]- src_pixel[m];
sum_d2 += (d*d);
var_threshold += g_point->g_values[k].variance[m];
} //difference < STD_LIMIT*STD_LIMIT or difference**2 < STD_LIMIT*STD_LIMIT*VAR
var_threshold = _model_params->std_threshold*bg_model_params->std_threshold*var_threshold;
//匹配方程为:或者
if(sum_d2 < var_threshold)
{
match[k] = 1; //匹配时标识置1
matchPosition = k; //存储匹配的高斯分布索引值
break; //一旦匹配,就终止与后续高斯分布的匹配
}
} return matchPosition; //返回匹配上的高斯分布索引值
}
//////////////////////////////////////////////////// icvUpdateFullWindow ////////////////////////////////////////////////////////////
功能:更新各高斯分布的权重值(对于匹配上的高斯分布要增大权值,其余的减小权值),如果存在匹配上的高斯分布,还要更新其均值和方差。
static void icvUpdateFullWindow( double* src_pixel, int nChannels, int* match,
CvGaussBGPoint* g_point,
const CvGaussBGStatModelParams *bg_model_params )
{
const double learning_rate_weight = (1.0/(double)bg_model_params->win_size); //学习率α
for(int k = 0; k < bg_model_params->n_gauss; k++)
{
//若match[k]=0,则权重ω的更新公式:
//若match[k]=0,则权重ω的更新公式:
g_point->g_values[k].weight =
g_point->g_values[k].weight + (learning_rate_weight*((double)match[k] -g_point->g_values[k].weight));
if(match[k]) //更新匹配的高斯分布的参数
{
//参数学习率
double learning_rate_gaussian = (double)match[k]/(g_point->g_values[k].weight*(double)bg_model_params->win_size);
for(int m = 0; m < nChannels; m++)
{
const double tmpDiff = src_pixel[m] - g_point->g_values[k].mean[m];
//均值μ更新公式为:
g_point->g_values[k].mean[m] =
g_point->g_values[k].mean[m] +(learning_rate_gaussian * tmpDiff);
//方差更新公式为:
g_point->g_values[k].variance[m] = g_point->g_values[k].variance[m]+
(learning_rate_gaussian*((tmpDiff*tmpDiff) - g_point->g_values[k].variance[m]));
}
}
}
}
//////////////////////////////////////////////////// icvUpdateFullNoMatch ////////////////////////////////////////////////////////////
功能:当前像素点与所有高斯分布都不匹配时,需要将比值最小的高斯分布替换为新的高斯分布(权值小、方差大),其余的高斯分布保持原来的均值和方差,但权值需要减小。
static void icvUpdateFullNoMatch( IplImage* gm_image, int p, int* match,
CvGaussBGPoint* g_point,
const CvGaussBGStatModelParams *bg_model_params)
{
int k, m;
double alpha;
int match_sum_total = 0; //new value of last one
g_point->g_values[bg_model_params->n_gauss - 1].match_sum = 1; //将新的高斯分布的match_sum置为1 //get sum of all but last value of match_sum
for( k = 0; k < bg_model_params->n_gauss ; k++ )
match_sum_total += g_point->g_values[k].match_sum; //设置新的高斯分布的参数
g_point->g_values[bg_model_params->n_gauss - 1].weight = 1./(double)match_sum_total; //给新的高斯分布设置一个较小的权值,即1.0/ match_sum_total
for( m = 0; m < gm_image->nChannels ; m++ )
{
// first pass mean is image value
g_point->g_values[bg_model_params->n_gauss - 1].variance[m] = bg_model_params->variance_init; //初始化一个较大的方差
g_point->g_values[bg_model_params->n_gauss - 1].mean[m] = (unsigned char)gm_image->imageData[p + m]; //将当前像素值作为均值
} //更新其余高斯分布的参数
alpha = 1.0 - (1.0/bg_model_params->win_size);
for( k = 0; k < bg_model_params->n_gauss - 1; k++ )
{
//更新权值的公式为:
g_point->g_values[k].weight *= alpha;
if( match[k] ) //对于匹配的高斯分布,权值更新公式为
g_point->g_values[k].weight += alpha;
}
}
//////////////////////////////////////////////////// icvUpdatePartialWindow ////////////////////////////////////////////////////////////
功能:更新各高斯分布的权重值(对于匹配上的高斯分布要增大权值,其余的减小权值),如果存在匹配上的高斯分布,还要更新其均值和方差。
static void icvUpdatePartialWindow( double* src_pixel, int nChannels, int* match, CvGaussBGPoint* g_point, const CvGaussBGStatModelParams *bg_model_params )
{
int k, m;
int window_current = 0; for( k = 0; k < bg_model_params->n_gauss; k++ )
window_current += g_point->g_values[k].match_sum; for( k = 0; k < bg_model_params->n_gauss; k++ )
{
g_point->g_values[k].match_sum += match[k];
double learning_rate_weight = (1.0/((double)window_current + 1.0)); //increased by one since sum
g_point->g_values[k].weight = g_point->g_values[k].weight +
(learning_rate_weight*((double)match[k] - g_point->g_values[k].weight)); if( g_point->g_values[k].match_sum > 0 && match[k] )
{
double learning_rate_gaussian = (double)match[k]/((double)g_point->g_values[k].match_sum);
for( m = 0; m < nChannels; m++ )
{
const double tmpDiff = src_pixel[m] - g_point->g_values[k].mean[m];
g_point->g_values[k].mean[m] = g_point->g_values[k].mean[m] +
(learning_rate_gaussian*tmpDiff);
g_point->g_values[k].variance[m] = g_point->g_values[k].variance[m]+
(learning_rate_gaussian*((tmpDiff*tmpDiff) - g_point->g_values[k].variance[m]));
}
}
}
}
OpenCV混合高斯模型函数注释说明的更多相关文章
- Opencv混合高斯模型前景分离
#include "stdio.h" #include "string.h" #include "iostream" #include &q ...
- 混合高斯模型:opencv中MOG2的代码结构梳理
/* 头文件:OurGaussmix2.h */ #include "opencv2/core/core.hpp" #include <list> #include&q ...
- 运动检测(前景检测)之(二)混合高斯模型GMM
运动检测(前景检测)之(二)混合高斯模型GMM zouxy09@qq.com http://blog.csdn.net/zouxy09 因为监控发展的需求,目前前景检测的研究还是很多的,也出现了很多新 ...
- [zz] 混合高斯模型 Gaussian Mixture Model
聚类(1)——混合高斯模型 Gaussian Mixture Model http://blog.csdn.net/jwh_bupt/article/details/7663885 聚类系列: 聚类( ...
- PRML读书会第九章 Mixture Models and EM(Kmeans,混合高斯模型,Expectation Maximization)
主讲人 网络上的尼采 (新浪微博: @Nietzsche_复杂网络机器学习) 网络上的尼采(813394698) 9:10:56 今天的主要内容有k-means.混合高斯模型. EM算法.对于k-me ...
- 混合高斯模型(GMM)推导及实现
作者:桂. 时间:2017-03-20 06:20:54 链接:http://www.cnblogs.com/xingshansi/p/6584555.html 声明:欢迎被转载,不过记得注明出处哦 ...
- <转>与EM相关的两个算法-K-mean算法以及混合高斯模型
转自http://www.cnblogs.com/jerrylead/archive/2011/04/06/2006924.html http://www.cnblogs.com/jerrylead/ ...
- 混合高斯模型的EM求解(Mixtures of Gaussians)及Python实现源代码
今天为大家带来混合高斯模型的EM推导求解过程. watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveHVhbnl1YW5zZW4=/font/5a6L5L2T/ ...
- EM相关两个算法 k-mean算法和混合高斯模型
转自http://www.cnblogs.com/jerrylead/archive/2011/04/06/2006924.html http://www.cnblogs.com/jerrylead/ ...
随机推荐
- SQL基本函数
字符型函数 函数名称 描述 LOWER 将特定的字符串转化为小写,只影响字母字符串. UPPER 将整个字符串转换成大写,只影响字母字符串. INITCAP 将字符串中每一个单词的第一个字母转换为大写 ...
- 关于Lt分发系统的时序图分析
我们已经知道,系统共分为两个模块,mather与son 同时系统允许的操作也有三种,向mather提交war包,我某个服务器更新代码,为所有服务器更新代码 我们一个一个来看 先说,向mather提交w ...
- ScheduledExecutorService和timer的异同
先来个传统的Timer的例子: package com.jerry.concurrency; import java.text.ParseException; import java.text.Sim ...
- 【移动开发】一张图搞定Activity和Fragment的生命周期
- linux shell bash使用管道|和read结合时问题解决
最近在将ksh转成bash运行的时候出现了问题.代码如下: echo $1 | sed 's/\..*$/''/' | read FILE_NAME 当使用ksh执行的时候没有问题,FILE_NAME ...
- Android触摸屏幕时间-android学习之旅(三)
android的多点触摸是经常遇到的编程技巧,这一篇可以将详细的介绍这个问题. 简单实例 android的触摸需要实现OnTouchListener接口,继承里面方法. 布局代码: <?xml ...
- Cocos2D中的纹理(textures)的解释
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 免责申明:本博客提供的所有翻译文章原稿均来自互联网,仅供学习交流 ...
- 取KindEditor中的textarea的值区不到的解决方案,固定kindEditor的高度
可以通过下面的方式取到textarea的值 var content = $(document.getElementsByTagName('iframe')[0].contentWindow.do ...
- 08_Android中的SimpleAdapter的使用
1 目的界面 2.编写Android清单文件 <?xml version="1.0" encoding="utf-8"?> <manif ...
- 用 boost::multi_index 管理玩家
用 boost::multi_index 管理玩家(金庆的专栏)网游服务器上的玩家集合需要多种索引:如用ID查找,角色名查找, 用登录时分配的会话ID查找.用boost::multi_index进行玩 ...