OpenCVハイブリッドガウスモデル関数コメント説明

18529 ワード

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]));
            }
        }
    }
}