背景建模之:贝叶斯背景建模——cvbgfg_acmmm2003 源代码注释(一)

前面的模型定义还有参数的变量定义可以参考源文件background_segm.hpp 里面英文注释已经说得很清楚了 我就不再写了 这里只写文件cvbgfg_acmmm2003
论文是Foreground Object Detection from Videos Containing Complex Background,其实如果已经打算看这个源代码了,应该不会不知道这篇论文。
没有看过论文的不建议看代码,不知道作者理论来源的也不会有很大收获
为了易看,以插入代码的方式书写
[cpp]  view plain copy
  1. #include "_cvaux.h"  
  2.   
  3. #include <math.h>  
  4. #include <stdio.h>  
  5. #include <stdlib.h>  
  6. //#include <algorithm>  
  7.   
  8. /*选出最大元素*/  
  9. static double* _cv_max_element( double* start, double* end )  
  10. {  
  11.     double* p = start++;  
  12.   
  13.     for( ; start != end;  ++start) {  
  14.   
  15.         if (*p < *start)   p = start;  
  16.     }   
  17.   
  18.     return p;  
  19. }  
  20.   
  21. static void CV_CDECL icvReleaseFGDStatModel( CvFGDStatModel** model );  
  22. static int CV_CDECL icvUpdateFGDStatModel( IplImage* curr_frame,  
  23.                                            CvFGDStatModel*  model );  
  24.   
  25. // Function cvCreateFGDStatModel initializes foreground detection process  
  26. // parameters:  
  27. //      first_frame - frame from video sequence  
  28. //      parameters  - (optional) if NULL default parameters of the algorithm will be used  
  29. //      p_model     - pointer to CvFGDStatModel structure  
  30. CV_IMPL CvBGStatModel*  
  31. cvCreateFGDStatModel( IplImage* first_frame, CvFGDStatModelParams* parameters )  
  32. {  
  33.     CvFGDStatModel* p_model = 0;  
  34.       
  35.     CV_FUNCNAME( "cvCreateFGDStatModel" );  
  36.   
  37.     __BEGIN__;  
  38.       
  39.     int i, j, k, pixel_count, buf_size;  
  40.     CvFGDStatModelParams params;  
  41.   
  42.     if( !CV_IS_IMAGE(first_frame) )  
  43.         CV_ERROR( CV_StsBadArg, "Invalid or NULL first_frame parameter" );  
  44.   
  45.     if (first_frame->nChannels != 3)  
  46.         CV_ERROR( CV_StsBadArg, "first_frame must have 3 color channels" );  
  47.   
  48.     // Initialize parameters:  
  49.     if( parameters == NULL )  
  50.     {  
  51.         params.Lc      = CV_BGFG_FGD_LC;  
  52.         params.N1c     = CV_BGFG_FGD_N1C;  
  53.         params.N2c     = CV_BGFG_FGD_N2C;  
  54.   
  55.         params.Lcc     = CV_BGFG_FGD_LCC;  
  56.         params.N1cc    = CV_BGFG_FGD_N1CC;  
  57.         params.N2cc    = CV_BGFG_FGD_N2CC;  
  58.   
  59.         params.delta   = CV_BGFG_FGD_DELTA;  
  60.   
  61.         params.alpha1  = CV_BGFG_FGD_ALPHA_1;  
  62.         params.alpha2  = CV_BGFG_FGD_ALPHA_2;  
  63.         params.alpha3  = CV_BGFG_FGD_ALPHA_3;  
  64.   
  65.         params.T       = CV_BGFG_FGD_T;  
  66.         params.minArea = CV_BGFG_FGD_MINAREA;  
  67.   
  68.         params.is_obj_without_holes = 1;  
  69.         params.perform_morphing     = 1;  
  70.     }  
  71.     else  
  72.     {  
  73.         params = *parameters;  
  74.     }  
  75.   
  76.     CV_CALL( p_model = (CvFGDStatModel*)cvAlloc( sizeof(*p_model) ));  
  77.     memset( p_model, 0, sizeof(*p_model) );  
  78.     p_model->type = CV_BG_MODEL_FGD;  
  79.     p_model->release = (CvReleaseBGStatModel)icvReleaseFGDStatModel;  
  80.     p_model->update = (CvUpdateBGStatModel)icvUpdateFGDStatModel;;  
  81.     p_model->params = params;  
  82.   
  83.     // Initialize storage pools:  
  84.     /*下面为申请内存空间 此处方法与GMM的方法一样 即申请一个整块空间 然后给不同的点分配相应的入口地址 
  85.     并非是各个点分别申请空间 因此后面访问的时候一定要注意相应点的边界问题不要越界 否则大部分访问是不会出错的 但是实际访问的是其他点的数据  
  86.     */  
  87.       
  88.       
  89.      pixel_count = first_frame->width * first_frame->height;  
  90.       
  91.     buf_size = pixel_count*sizeof(p_model->pixel_stat[0]);  
  92.     CV_CALL( p_model->pixel_stat = (CvBGPixelStat*)cvAlloc(buf_size) );  
  93.     memset( p_model->pixel_stat, 0, buf_size );  
  94.       
  95.    /* 还要注意的是每个像素点均维护两种类型的表 即c和cc 表的个数由参数N2c和N2cc指定 */  
  96.     buf_size = pixel_count*params.N2c*sizeof(p_model->pixel_stat[0].ctable[0]);  
  97.     CV_CALL( p_model->pixel_stat[0].ctable = (CvBGPixelCStatTable*)cvAlloc(buf_size) );  
  98.     memset( p_model->pixel_stat[0].ctable, 0, buf_size );  
  99.   
  100.     buf_size = pixel_count*params.N2cc*sizeof(p_model->pixel_stat[0].cctable[0]);  
  101.     CV_CALL( p_model->pixel_stat[0].cctable = (CvBGPixelCCStatTable*)cvAlloc(buf_size) );  
  102.     memset( p_model->pixel_stat[0].cctable, 0, buf_size );  
  103.   
  104.     for(     i = 0, k = 0; i < first_frame->height; i++ ) {  
  105.         for( j = 0;        j < first_frame->width;  j++, k++ )  
  106.         {  
  107.             p_model->pixel_stat[k].ctable = p_model->pixel_stat[0].ctable + k*params.N2c;  
  108.             p_model->pixel_stat[k].cctable = p_model->pixel_stat[0].cctable + k*params.N2cc;  
  109.         }  
  110.     }  
  111.   
  112.     // Init temporary images:  
  113.     /*下面的前两个空间用来分别存储两种差分的结果 第三个是为了画出前景 三个均为单通道*/  
  114.     CV_CALL( p_model->Ftd = cvCreateImage(cvSize(first_frame->width, first_frame->height), IPL_DEPTH_8U, 1));  
  115.     CV_CALL( p_model->Fbd = cvCreateImage(cvSize(first_frame->width, first_frame->height), IPL_DEPTH_8U, 1));  
  116.     CV_CALL( p_model->foreground = cvCreateImage(cvSize(first_frame->width, first_frame->height), IPL_DEPTH_8U, 1));  
  117.   
  118.     CV_CALL( p_model->background = cvCloneImage(first_frame));  
  119.     CV_CALL( p_model->prev_frame = cvCloneImage(first_frame));  
  120.     CV_CALL( p_model->storage = cvCreateMemStorage());  
  121.   
  122.     __END__;  
  123.   
  124.     if( cvGetErrStatus() < 0 )  
  125.     {  
  126.         CvBGStatModel* base_ptr = (CvBGStatModel*)p_model;  
  127.   
  128.         if( p_model && p_model->release )  
  129.             p_model->release( &base_ptr );  
  130.         else  
  131.             cvFree( &p_model );  
  132.         p_model = 0;  
  133.     }  
  134.   
  135.     return (CvBGStatModel*)p_model;  
  136. }  
  137.   
  138. /*释放内存空间*/  
  139. static void CV_CDECL  
  140. icvReleaseFGDStatModel( CvFGDStatModel** _model )  
  141. {  
  142.     CV_FUNCNAME( "icvReleaseFGDStatModel" );  
  143.   
  144.     __BEGIN__;  
  145.       
  146.     if( !_model )  
  147.         CV_ERROR( CV_StsNullPtr, "" );  
  148.   
  149.     if( *_model )  
  150.     {  
  151.         CvFGDStatModel* model = *_model;  
  152.         if( model->pixel_stat )  
  153.         {  
  154.             cvFree( &model->pixel_stat[0].ctable );  
  155.             cvFree( &model->pixel_stat[0].cctable );  
  156.             cvFree( &model->pixel_stat );  
  157.         }  
  158.   
  159.         cvReleaseImage( &model->Ftd );  
  160.         cvReleaseImage( &model->Fbd );  
  161.         cvReleaseImage( &model->foreground );  
  162.         cvReleaseImage( &model->background );  
  163.         cvReleaseImage( &model->prev_frame );  
  164.         cvReleaseMemStorage(&model->storage);  
  165.   
  166.         cvFree( _model );  
  167.     }  
  168.   
  169.     __END__;  
  170. }  
  171.   
  172. //  Function cvChangeDetection performs change detection for Foreground detection algorithm  
  173. // parameters:  
  174. //      prev_frame -  
  175. //      curr_frame -  
  176. //      change_mask -  
  177. /*用两幅三通道图像做差分 change_mask用来存储差分结果*/  
  178. CV_IMPL int  
  179. cvChangeDetection( IplImage*  prev_frame,  
  180.                    IplImage*  curr_frame,  
  181.                    IplImage*  change_mask )  
  182. {  
  183.     int i, j, b, x, y, thres;  
  184.     const int PIXELRANGE=256;  
  185.   
  186.     if( !prev_frame  
  187.     ||  !curr_frame  
  188.     ||  !change_mask  
  189.     ||   prev_frame->nChannels  != 3  
  190.     ||   curr_frame->nChannels  != 3  
  191.     ||   change_mask->nChannels != 1  
  192.     ||   prev_frame->depth  != IPL_DEPTH_8U  
  193.     ||   curr_frame->depth  != IPL_DEPTH_8U  
  194.     ||   change_mask->depth != IPL_DEPTH_8U  
  195.     ||   prev_frame->width  != curr_frame->width  
  196.     ||   prev_frame->height != curr_frame->height  
  197.     ||   prev_frame->width  != change_mask->width  
  198.     ||   prev_frame->height != change_mask->height  
  199.     ){  
  200.         return 0;  
  201.     }  
  202.   
  203.     cvZero ( change_mask );  
  204.   
  205.     // All operations per colour  
  206.     /*分别对每个通道处理 相当于对向量的各个分量分别处理 这也是理所当然的*/  
  207.     for (b=0 ; b<prev_frame->nChannels ; b++) {  
  208.   
  209.         // Create histogram:  
  210.   
  211.         long HISTOGRAM[PIXELRANGE];     //对0-255每个灰度差值进行统计  
  212.         for (i=0 ; i<PIXELRANGE; i++) HISTOGRAM[i]=0; //差值统计的初始化  
  213.           
  214.         /*对应像素进行求差 然后统计*/  
  215.         for (y=0 ; y<curr_frame->height ; y++)  
  216.         {  
  217.             uchar* rowStart1 = (uchar*)curr_frame->imageData + y * curr_frame->widthStep + b;  
  218.             uchar* rowStart2 = (uchar*)prev_frame->imageData + y * prev_frame->widthStep + b;  
  219.             for (x=0 ; x<curr_frame->width ; x++, rowStart1+=curr_frame->nChannels, rowStart2+=prev_frame->nChannels) {  
  220.                 int diff = abs( int(*rowStart1) - int(*rowStart2) );  
  221.                 HISTOGRAM[diff]++;                        
  222.             }  
  223.         }  
  224.   
  225.         double  c[PIXELRANGE];  
  226.         for (i=0 ; i<PIXELRANGE; i++) relativeVariance[i]=0;    //方差初始化  
  227.   
  228.         /*后面所写的x均值随机变量 不特指程序中的任何一个变量 
  229.         以下每个差值的概率分布均是指累计概率分布 不过此处的随机变量是从255-0进行累计,并非通常的0-255  
  230.         即为  p(X)=1-sum(p(x<X)) = sum(p(x>=X)) 
  231.         所以此处是对每一个差值均构建了概率分布  也就是并非一条概率曲线的存在 而是254-0 共有255条概率曲线存在 每条曲线确定一个差值的方差   
  232.         */   
  233.         for (thres=PIXELRANGE-2; thres>=0 ; thres--)  
  234.         {  
  235.             //            fprintf(stderr, "Iter %d\n", thres);  
  236.             double sum=0;  
  237.             double sqsum=0;  
  238.             int count=0;  
  239.             //            fprintf(stderr, "Iter %d entering loop\n", thres);  
  240.             for (j=thres ; j<PIXELRANGE ; j++) {  
  241.                 sum   += double(j)*double(HISTOGRAM[j]);        //因为后面会除总的统计数count 因而此处可以看做求E(x)  
  242.                 sqsum += double(j*j)*double(HISTOGRAM[j]);      //E(x*x)  
  243.                 count += HISTOGRAM[j];                        //统计总量 为求概率    
  244.             }  
  245.             count = count == 0 ? 1 : count;  
  246.             //            fprintf(stderr, "Iter %d finishing loop\n", thres);  
  247.             double my = sum / count;                //均值  
  248.             double sigma = sqrt( sqsum/count - my*my);  //方差 D(x) = E(x*x) - E(x)*E(x)  
  249.             //            fprintf(stderr, "Iter %d sum=%g sqsum=%g count=%d sigma = %g\n", thres, sum, sqsum, count, sigma);  
  250.             //            fprintf(stderr, "Writing to %x\n", &(relativeVariance[thres]));  
  251.             relativeVariance[thres] = sigma;  
  252.             //            fprintf(stderr, "Iter %d finished\n", thres);  
  253.         }  
  254.   
  255.         // Find maximum:  
  256.         uchar bestThres = 0;  
  257.   
  258.         //求出方差最大值  也就是变化值得期望 如果大于这个期望 可以认为这个点发生了较大变化 进行标注*/  
  259.         double* pBestThres = _cv_max_element(relativeVariance, relativeVariance+PIXELRANGE);  
  260.         bestThres = (uchar)(*pBestThres); if (bestThres <10) bestThres=10;      //因为uchar表示0-255,这里可以认为对最大方差进行规格化.同时设定方差的下界  
  261.   
  262.         for (y=0 ; y<prev_frame->height ; y++)  
  263.         {  
  264.             uchar* rowStart1 = (uchar*)(curr_frame->imageData) + y * curr_frame->widthStep + b;  
  265.             uchar* rowStart2 = (uchar*)(prev_frame->imageData) + y * prev_frame->widthStep + b;  
  266.             uchar* rowStart3 = (uchar*)(change_mask->imageData) + y * change_mask->widthStep;  
  267.             for (x = 0; x < curr_frame->width; x++, rowStart1+=curr_frame->nChannels,  
  268.                 rowStart2+=prev_frame->nChannels, rowStart3+=change_mask->nChannels) {  
  269.                 // OR between different color channels  
  270.                 int diff = abs( int(*rowStart1) - int(*rowStart2) );  
  271.                 if ( diff > bestThres)                              //只要有一个分量发生了较大变化就可以标注                  
  272.                     *rowStart3 |=255;                               //为什么不直接赋值? 与直接赋值的结果应当没有区别  
  273.             }  
  274.         }  
  275.     }  
  276.   
  277.     return 1;  
  278. }  

猜你喜欢

转载自blog.csdn.net/LYYLYQLJD/article/details/9343971