cvbgfg_acmmm2003 源代码注释(一)

来源:互联网 发布:淘宝店logo设计 编辑:程序博客网 时间:2024/05/21 10:41

前面的模型定义还有参数的变量定义可以参考源文件background_segm.hpp 里面英文注释已经说得很清楚了 我就不再写了 这里只写文件cvbgfg_acmmm2003
论文是Foreground Object Detection from Videos Containing Complex Background,其实如果已经打算看这个源代码了,应该不会不知道这篇论文。
没有看过论文的不建议看代码,不知道作者理论来源的也不会有很大收获
为了易看,以插入代码的方式书写
#include "_cvaux.h"#include <math.h>#include <stdio.h>#include <stdlib.h>//#include <algorithm>/*选出最大元素*/static double* _cv_max_element( double* start, double* end ){    double* p = start++;    for( ; start != end;  ++start) {        if (*p < *start)   p = start;    }     return p;}static void CV_CDECL icvReleaseFGDStatModel( CvFGDStatModel** model );static int CV_CDECL icvUpdateFGDStatModel( IplImage* curr_frame,                                           CvFGDStatModel*  model );// Function cvCreateFGDStatModel initializes foreground detection process// parameters://      first_frame - frame from video sequence//      parameters  - (optional) if NULL default parameters of the algorithm will be used//      p_model     - pointer to CvFGDStatModel structureCV_IMPL CvBGStatModel*cvCreateFGDStatModel( IplImage* first_frame, CvFGDStatModelParams* parameters ){    CvFGDStatModel* p_model = 0;        CV_FUNCNAME( "cvCreateFGDStatModel" );    __BEGIN__;        int i, j, k, pixel_count, buf_size;    CvFGDStatModelParams params;    if( !CV_IS_IMAGE(first_frame) )        CV_ERROR( CV_StsBadArg, "Invalid or NULL first_frame parameter" );    if (first_frame->nChannels != 3)        CV_ERROR( CV_StsBadArg, "first_frame must have 3 color channels" );    // Initialize parameters:    if( parameters == NULL )    {        params.Lc      = CV_BGFG_FGD_LC;        params.N1c     = CV_BGFG_FGD_N1C;        params.N2c     = CV_BGFG_FGD_N2C;        params.Lcc     = CV_BGFG_FGD_LCC;        params.N1cc    = CV_BGFG_FGD_N1CC;        params.N2cc    = CV_BGFG_FGD_N2CC;        params.delta   = CV_BGFG_FGD_DELTA;        params.alpha1  = CV_BGFG_FGD_ALPHA_1;        params.alpha2  = CV_BGFG_FGD_ALPHA_2;        params.alpha3  = CV_BGFG_FGD_ALPHA_3;        params.T       = CV_BGFG_FGD_T;        params.minArea = CV_BGFG_FGD_MINAREA;        params.is_obj_without_holes = 1;        params.perform_morphing     = 1;    }    else    {        params = *parameters;    }    CV_CALL( p_model = (CvFGDStatModel*)cvAlloc( sizeof(*p_model) ));    memset( p_model, 0, sizeof(*p_model) );    p_model->type = CV_BG_MODEL_FGD;    p_model->release = (CvReleaseBGStatModel)icvReleaseFGDStatModel;    p_model->update = (CvUpdateBGStatModel)icvUpdateFGDStatModel;;    p_model->params = params;    // Initialize storage pools:    /*下面为申请内存空间 此处方法与GMM的方法一样 即申请一个整块空间 然后给不同的点分配相应的入口地址    并非是各个点分别申请空间 因此后面访问的时候一定要注意相应点的边界问题不要越界 否则大部分访问是不会出错的 但是实际访问的是其他点的数据     */             pixel_count = first_frame->width * first_frame->height;        buf_size = pixel_count*sizeof(p_model->pixel_stat[0]);    CV_CALL( p_model->pixel_stat = (CvBGPixelStat*)cvAlloc(buf_size) );    memset( p_model->pixel_stat, 0, buf_size );       /* 还要注意的是每个像素点均维护两种类型的表 即c和cc 表的个数由参数N2c和N2cc指定 */    buf_size = pixel_count*params.N2c*sizeof(p_model->pixel_stat[0].ctable[0]);    CV_CALL( p_model->pixel_stat[0].ctable = (CvBGPixelCStatTable*)cvAlloc(buf_size) );    memset( p_model->pixel_stat[0].ctable, 0, buf_size );    buf_size = pixel_count*params.N2cc*sizeof(p_model->pixel_stat[0].cctable[0]);    CV_CALL( p_model->pixel_stat[0].cctable = (CvBGPixelCCStatTable*)cvAlloc(buf_size) );    memset( p_model->pixel_stat[0].cctable, 0, buf_size );    for(     i = 0, k = 0; i < first_frame->height; i++ ) {        for( j = 0;        j < first_frame->width;  j++, k++ )        {            p_model->pixel_stat[k].ctable = p_model->pixel_stat[0].ctable + k*params.N2c;            p_model->pixel_stat[k].cctable = p_model->pixel_stat[0].cctable + k*params.N2cc;        }    }    // Init temporary images:    /*下面的前两个空间用来分别存储两种差分的结果 第三个是为了画出前景 三个均为单通道*/    CV_CALL( p_model->Ftd = cvCreateImage(cvSize(first_frame->width, first_frame->height), IPL_DEPTH_8U, 1));    CV_CALL( p_model->Fbd = cvCreateImage(cvSize(first_frame->width, first_frame->height), IPL_DEPTH_8U, 1));    CV_CALL( p_model->foreground = cvCreateImage(cvSize(first_frame->width, first_frame->height), IPL_DEPTH_8U, 1));    CV_CALL( p_model->background = cvCloneImage(first_frame));    CV_CALL( p_model->prev_frame = cvCloneImage(first_frame));    CV_CALL( p_model->storage = cvCreateMemStorage());    __END__;    if( cvGetErrStatus() < 0 )    {        CvBGStatModel* base_ptr = (CvBGStatModel*)p_model;        if( p_model && p_model->release )            p_model->release( &base_ptr );        else            cvFree( &p_model );        p_model = 0;    }    return (CvBGStatModel*)p_model;}/*释放内存空间*/static void CV_CDECLicvReleaseFGDStatModel( CvFGDStatModel** _model ){    CV_FUNCNAME( "icvReleaseFGDStatModel" );    __BEGIN__;        if( !_model )        CV_ERROR( CV_StsNullPtr, "" );    if( *_model )    {        CvFGDStatModel* model = *_model;        if( model->pixel_stat )        {            cvFree( &model->pixel_stat[0].ctable );            cvFree( &model->pixel_stat[0].cctable );            cvFree( &model->pixel_stat );        }        cvReleaseImage( &model->Ftd );        cvReleaseImage( &model->Fbd );        cvReleaseImage( &model->foreground );        cvReleaseImage( &model->background );        cvReleaseImage( &model->prev_frame );        cvReleaseMemStorage(&model->storage);        cvFree( _model );    }    __END__;}//  Function cvChangeDetection performs change detection for Foreground detection algorithm// parameters://      prev_frame -//      curr_frame -//      change_mask -/*用两幅三通道图像做差分 change_mask用来存储差分结果*/CV_IMPL intcvChangeDetection( IplImage*  prev_frame,                   IplImage*  curr_frame,                   IplImage*  change_mask ){    int i, j, b, x, y, thres;    const int PIXELRANGE=256;    if( !prev_frame    ||  !curr_frame    ||  !change_mask    ||   prev_frame->nChannels  != 3    ||   curr_frame->nChannels  != 3    ||   change_mask->nChannels != 1    ||   prev_frame->depth  != IPL_DEPTH_8U    ||   curr_frame->depth  != IPL_DEPTH_8U    ||   change_mask->depth != IPL_DEPTH_8U    ||   prev_frame->width  != curr_frame->width    ||   prev_frame->height != curr_frame->height    ||   prev_frame->width  != change_mask->width    ||   prev_frame->height != change_mask->height    ){        return 0;    }    cvZero ( change_mask );    // All operations per colour    /*分别对每个通道处理 相当于对向量的各个分量分别处理 这也是理所当然的*/    for (b=0 ; b<prev_frame->nChannels ; b++) {        // Create histogram:        long HISTOGRAM[PIXELRANGE];     //对0-255每个灰度差值进行统计        for (i=0 ; i<PIXELRANGE; i++) HISTOGRAM[i]=0; //差值统计的初始化                /*对应像素进行求差 然后统计*/        for (y=0 ; y<curr_frame->height ; y++)        {            uchar* rowStart1 = (uchar*)curr_frame->imageData + y * curr_frame->widthStep + b;            uchar* rowStart2 = (uchar*)prev_frame->imageData + y * prev_frame->widthStep + b;            for (x=0 ; x<curr_frame->width ; x++, rowStart1+=curr_frame->nChannels, rowStart2+=prev_frame->nChannels) {                int diff = abs( int(*rowStart1) - int(*rowStart2) );                HISTOGRAM[diff]++;                                  }        }        double  c[PIXELRANGE];        for (i=0 ; i<PIXELRANGE; i++) relativeVariance[i]=0;    //方差初始化        /*后面所写的x均值随机变量 不特指程序中的任何一个变量        以下每个差值的概率分布均是指累计概率分布 不过此处的随机变量是从255-0进行累计,并非通常的0-255         即为  p(X)=1-sum(p(x<X)) = sum(p(x>=X))        所以此处是对每一个差值均构建了概率分布  也就是并非一条概率曲线的存在 而是254-0 共有255条概率曲线存在 每条曲线确定一个差值的方差          */         for (thres=PIXELRANGE-2; thres>=0 ; thres--)        {            //            fprintf(stderr, "Iter %d\n", thres);            double sum=0;            double sqsum=0;            int count=0;            //            fprintf(stderr, "Iter %d entering loop\n", thres);            for (j=thres ; j<PIXELRANGE ; j++) {                sum   += double(j)*double(HISTOGRAM[j]);        //因为后面会除总的统计数count 因而此处可以看做求E(x)                sqsum += double(j*j)*double(HISTOGRAM[j]);      //E(x*x)                count += HISTOGRAM[j];                        //统计总量 为求概率              }            count = count == 0 ? 1 : count;            //            fprintf(stderr, "Iter %d finishing loop\n", thres);            double my = sum / count;                //均值            double sigma = sqrt( sqsum/count - my*my);  //方差 D(x) = E(x*x) - E(x)*E(x)            //            fprintf(stderr, "Iter %d sum=%g sqsum=%g count=%d sigma = %g\n", thres, sum, sqsum, count, sigma);            //            fprintf(stderr, "Writing to %x\n", &(relativeVariance[thres]));            relativeVariance[thres] = sigma;            //            fprintf(stderr, "Iter %d finished\n", thres);        }        // Find maximum:        uchar bestThres = 0;        //求出方差最大值  也就是变化值得期望 如果大于这个期望 可以认为这个点发生了较大变化 进行标注*/        double* pBestThres = _cv_max_element(relativeVariance, relativeVariance+PIXELRANGE);        bestThres = (uchar)(*pBestThres); if (bestThres <10) bestThres=10;      //因为uchar表示0-255,这里可以认为对最大方差进行规格化.同时设定方差的下界        for (y=0 ; y<prev_frame->height ; y++)        {            uchar* rowStart1 = (uchar*)(curr_frame->imageData) + y * curr_frame->widthStep + b;            uchar* rowStart2 = (uchar*)(prev_frame->imageData) + y * prev_frame->widthStep + b;            uchar* rowStart3 = (uchar*)(change_mask->imageData) + y * change_mask->widthStep;            for (x = 0; x < curr_frame->width; x++, rowStart1+=curr_frame->nChannels,                rowStart2+=prev_frame->nChannels, rowStart3+=change_mask->nChannels) {                // OR between different color channels                int diff = abs( int(*rowStart1) - int(*rowStart2) );                if ( diff > bestThres)                              //只要有一个分量发生了较大变化就可以标注                                    *rowStart3 |=255;                               //为什么不直接赋值? 与直接赋值的结果应当没有区别            }        }    }    return 1;}