Opencv研读笔记:haartraining程序之cvCreateMTStumpClassifier函数详解(弱分类器创建)~

本文详细解析了OpenCV中cvCreateMTStumpClassifier函数的实现原理及使用方法,该函数主要用于寻找最优弱分类器,即最优Haar特征。通过穷举法对每个特征的训练样本特征值进行排序,确定最优阈值与特征。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

cvCreateMTStumpClassifier函数出自OpenCV中的haartraining程序,在Haartraining中强分类器创建函数icvCreateCARTStageClassifier中被两次调用,该函数用于寻找最优弱分类器,或者说成计算最优Haar特征。功能很明确,但是大家都知道的,opencv的代码绝大部分写的让人真心看不懂,这个函数算是haartraining中比较难以看懂的函数,局部变量达到20个之多,童鞋我也是不甘心,不甘心被这小小的函数所击溃,于是擦干泪水,仔细研读,终于恍然大悟,大彻大悟的同时,不忘回报优快云博客,与朋友们分享。

1. 最优弱分类器的计算过程,网上到处都有介绍,其实就是个穷举的过程,先对每个特征所对应的训练样本的特征值进行排序,然后遍历每个特征值作为阈值,根据特定的方法(1.misclass 2.gini 3.entropy 4.least sum of squares)确定最优阈值,进一步确定最优特征,也就是最优弱分类器了。

2. opencv写的比较通用,所以有点让人摸不清头脑,它是这么干的:先预计算“Haar特征-训练样本”矩阵(trainData),一般Haar特征有600个,然后先寻找这600个特征中的最优特征,但是总共的Haar特征可能有1万多个,对于新特征那就只能在重新计算训练样本升序矩阵(mat),继续寻找最优特征。

3. 由于程序一直跃跃欲试,想用并行的方法处理,导致了程序的局部变量增多(例如portion的引用),这是值得大家注意的地方。

4. 另外,上面说到cvCreateMTStumpClassifier函数被两次调用,一次是在cvCreateCARTClassifier中,一次是在icvCreateCARTStageClassifier中,其中,前者中trainData对应的是一个矩阵,而后者trainData对应的是一个行向量。

注意上面几处,再看源码,应该就不会被弄晕了,我直接上代码,并且做了比较详细的注释,这样子更加实在一些,希望能够对童鞋们有所帮助!

(转载请注明:http://blog.csdn.NET/wsj998689aa/article/details/42294703,作者:迷雾forest)


[cpp]  view plain  copy
  1. // 函数功能:计算最优弱分类器  
  2. CV_BOOST_IMPL  
  3. CvClassifier* cvCreateMTStumpClassifier( CvMat* trainData,      // 训练样本HAAR特征值矩阵  
  4.                       int flags,                                // 1.按行排列,0.按列排列  
  5.                       CvMat* trainClasses,                      // 样本类别{-1,1}  
  6.                       CvMat* /*typeMask*/,                      // 为了便于回调函数统一格式  
  7.                       CvMat* missedMeasurementsMask,            // 未知,很少用到  
  8.                       CvMat* compIdx,                           // 特征序列(必须为NULL)(行向量)  
  9.                       CvMat* sampleIdx,                         // 实际训练样本序列(行向量)  
  10.                       CvMat* weights,                           // 实际训练样本样本权重(行向量)  
  11.                       CvClassifierTrainParams* trainParams )    // 其它数据&参数  
  12. {  
  13.     CvStumpClassifier* stump = NULL;        // 弱分类器(桩)  
  14.     int m = 0;                              // 样本总数  
  15.     int n = 0;                              // 所有特征个数     
  16.     uchar* data = NULL;                     // trainData数据指针  
  17.     size_t cstep   = 0;                     // trainData一行字节数  
  18.     size_t sstep   = 0;                     // trainData元素字节数  
  19.     int    datan   = 0;                     // 预计算特征个数  
  20.     uchar* ydata = NULL;                    // trainClasses数据指针  
  21.     size_t ystep = 0;                       // trainClasses元素字节数  
  22.     uchar* idxdata = NULL;                  // sampleIdx数据指针  
  23.     size_t idxstep = 0;                     // sampleIdx单个元素字节数  
  24.     int    l = 0;                           // 实际训练样本个数      
  25.     uchar* wdata = NULL;                    // weights数据指针  
  26.     size_t wstep = 0;                       // weights元素字节数  
  27.   
  28.     /* sortedIdx为事先计算好的特征值-样本矩阵,包含有预计算的所有HAAR特征对应于所有样本的特征值(按大小排列) */  
  29.     uchar* sorteddata = NULL;               // sortedIdx数据指针  
  30.     int    sortedtype    = 0;               // sortedIdx元素类型  
  31.     size_t sortedcstep   = 0;               // sortedIdx一行字节数  
  32.     size_t sortedsstep   = 0;               // sortedIdx元素字节数  
  33.     int    sortedn       = 0;               // sortedIdx行数(预计算特征个数)  
  34.     int    sortedm       = 0;               // sortedIdx列数(实际训练样本个数)  
  35.   
  36.     char* filter = NULL;                    // 样本存在标示(行向量),如果样本存在则为1,否则为0  
  37.     int i = 0;  
  38.       
  39.     int compidx = 0;                        // 每组特征的起始序号  
  40.     int stumperror;                         // 计算阈值方法:1.misclass 2.gini 3.entropy 4.least sum of squares  
  41.     int portion;                            // 每组特征个数,对所有特征n进行分组处理,每组portion个  
  42.   
  43.     /* private variables */  
  44.     CvMat mat;                              // 补充特征-样本矩阵  
  45.     CvValArray va;  
  46.     float lerror;                           // 阈值左侧误差  
  47.     float rerror;                           // 阈值右侧误差  
  48.     float left;<span style="white-space:pre">         </span>            // 置信度(左分支)  
  49.     float right;<span style="white-space:pre">            </span>    // 置信度(右分支)  
  50.     float threshold;                        // 阈值  
  51.     int optcompidx;                         // 最优特征  
  52.   
  53.     float sumw;                               
  54.     float sumwy;  
  55.     float sumwyy;  
  56.   
  57.     /*临时变量,循环用*/  
  58.     int t_compidx;  
  59.     int t_n;  
  60.       
  61.     int ti;  
  62.     int tj;  
  63.     int tk;  
  64.   
  65.     uchar* t_data;                          // 指向data  
  66.     size_t t_cstep;                         // cstep  
  67.     size_t t_sstep;                         // sstep  
  68.   
  69.     size_t matcstep;                        // mat一行字节数  
  70.     size_t matsstep;                        // mat元素字节数  
  71.   
  72.     int* t_idx;                             // 样本序列  
  73.     /* end private variables */  
  74.   
  75.     CV_Assert( trainParams != NULL );  
  76.     CV_Assert( trainClasses != NULL );  
  77.     CV_Assert( CV_MAT_TYPE( trainClasses->type ) == CV_32FC1 );  
  78.     CV_Assert( missedMeasurementsMask == NULL );  
  79.     CV_Assert( compIdx == NULL );  
  80.   
  81.     // 计算阈值方法:1.misclass 2.gini 3.entropy 4.least sum of squares  
  82.     stumperror = (int) ((CvMTStumpTrainParams*) trainParams)->error;  
  83.   
  84.     // 样本类别  
  85.     ydata = trainClasses->data.ptr;  
  86.     if( trainClasses->rows == 1 )  
  87.     {  
  88.         m = trainClasses->cols;  
  89.         ystep = CV_ELEM_SIZE( trainClasses->type );  
  90.     }  
  91.     else  
  92.     {  
  93.         m = trainClasses->rows;  
  94.         ystep = trainClasses->step;  
  95.     }  
  96.   
  97.     // 样本权重  
  98.     wdata = weights->data.ptr;  
  99.     if( weights->rows == 1 )  
  100.     {  
  101.         CV_Assert( weights->cols == m );  
  102.         wstep = CV_ELEM_SIZE( weights->type );  
  103.     }  
  104.     else  
  105.     {  
  106.         CV_Assert( weights->rows == m );  
  107.         wstep = weights->step;  
  108.     }  
  109.   
  110.     // sortedIdx为空,trainData为行向量(1*m);sortedIdx不为空,trainData为矩阵(m*datan);  
  111.     if( ((CvMTStumpTrainParams*) trainParams)->sortedIdx != NULL )  
  112.     {  
  113.         sortedtype =  
  114.             CV_MAT_TYPE( ((CvMTStumpTrainParams*) trainParams)->sortedIdx->type );  
  115.         assert( sortedtype == CV_16SC1 || sortedtype == CV_32SC1  
  116.                 || sortedtype == CV_32FC1 );  
  117.         sorteddata = ((CvMTStumpTrainParams*) trainParams)->sortedIdx->data.ptr;  
  118.         sortedsstep = CV_ELEM_SIZE( sortedtype );  
  119.         sortedcstep = ((CvMTStumpTrainParams*) trainParams)->sortedIdx->step;  
  120.         sortedn = ((CvMTStumpTrainParams*) trainParams)->sortedIdx->rows;  
  121.         sortedm = ((CvMTStumpTrainParams*) trainParams)->sortedIdx->cols;  
  122.     }  
  123.   
  124.     if( trainData == NULL )                         // 为空的情况没有遇到  
  125.     {  
  126.         assert( ((CvMTStumpTrainParams*) trainParams)->getTrainData != NULL );  
  127.         n = ((CvMTStumpTrainParams*) trainParams)->numcomp;  
  128.         assert( n > 0 );  
  129.     }  
  130.     else  
  131.     {  
  132.         assert( CV_MAT_TYPE( trainData->type ) == CV_32FC1 );  
  133.         data = trainData->data.ptr;  
  134.         if( CV_IS_ROW_SAMPLE( flags ) )             // trainData为矩阵  
  135.         {  
  136.             cstep = CV_ELEM_SIZE( trainData->type );  
  137.             sstep = trainData->step;  
  138.             assert( m == trainData->rows );  
  139.             datan = n = trainData->cols;  
  140.         }  
  141.         else                                        // trainData为向量  
  142.         {  
  143.             sstep = CV_ELEM_SIZE( trainData->type );  
  144.             cstep = trainData->step;  
  145.             assert( m == trainData->cols );  
  146.             datan = n = trainData->rows;  
  147.         }  
  148.   
  149.         // trainData为矩阵,当trainData为向量时,datan = n = 1  
  150.         if( ((CvMTStumpTrainParams*) trainParams)->getTrainData != NULL )  
  151.         {  
  152.             n = ((CvMTStumpTrainParams*) trainParams)->numcomp;     // 总特征个数    
  153.         }          
  154.     }  
  155.   
  156.     // 预计算特征个数一定要小于特征总数  
  157.     assert( datan <= n );  
  158.   
  159.     if( sampleIdx != NULL )     // 已经剔除小权值样本  
  160.     {  
  161.         assert( CV_MAT_TYPE( sampleIdx->type ) == CV_32FC1 );  
  162.         idxdata = sampleIdx->data.ptr;  
  163.         idxstep = ( sampleIdx->rows == 1 )  
  164.             ? CV_ELEM_SIZE( sampleIdx->type ) : sampleIdx->step;  
  165.         l = ( sampleIdx->rows == 1 ) ? sampleIdx->cols : sampleIdx->rows;  
  166.   
  167.         // sorteddata中存放的是所有训练样本,需要筛选出实际训练样本  
  168.         if( sorteddata != NULL )  
  169.         {  
  170.             filter = (char*) cvAlloc( sizeofchar ) * m );  
  171.             memset( (void*) filter, 0, sizeofchar ) * m );  
  172.             for( i = 0; i < l; i++ )  
  173.             {  
  174.                 filter[(int) *((float*) (idxdata + i * idxstep))] = (char) 1;   // 存在则为1,不存在则为0  
  175.             }  
  176.         }  
  177.     }  
  178.     else                        // 未剔除小权值样本  
  179.     {  
  180.         l = m;  
  181.     }  
  182.   
  183.     // 桩  
  184.     stump = (CvStumpClassifier*) cvAlloc( sizeof( CvStumpClassifier) );  
  185.     memset( (void*) stump, 0, sizeof( CvStumpClassifier ) );  
  186.   
  187.     // 每组特征个数  
  188.     portion = ((CvMTStumpTrainParams*)trainParams)->portion;  
  189.       
  190.     if( portion < 1 )  
  191.     {  
  192.         /* auto portion */  
  193.         portion = n;  
  194.         #ifdef _OPENMP  
  195.         portion /= omp_get_max_threads();          
  196.         #endif /* _OPENMP */          
  197.     }  
  198.   
  199.     stump->eval = cvEvalStumpClassifier;  
  200.     stump->tune = NULL;  
  201.     stump->save = NULL;  
  202.     stump->release = cvReleaseStumpClassifier;  
  203.   
  204.     stump->lerror = FLT_MAX;  
  205.     stump->rerror = FLT_MAX;  
  206.     stump->left  = 0.0F;  
  207.     stump->right = 0.0F;  
  208.   
  209.     compidx = 0;  
  210.   
  211.     // 并行计算,默认为关闭的  
  212.     #ifdef _OPENMP  
  213.     #pragma omp parallel private(mat, va, lerror, rerror, left, right, threshold, \  
  214.                                  optcompidx, sumw, sumwy, sumwyy, t_compidx, t_n, \  
  215.                                  ti, tj, tk, t_data, t_cstep, t_sstep, matcstep,  \  
  216.                                  matsstep, t_idx)  
  217.     #endif /* _OPENMP */  
  218.     {  
  219.         lerror = FLT_MAX;  
  220.         rerror = FLT_MAX;  
  221.         left  = 0.0F;  
  222.         right = 0.0F;  
  223.         threshold = 0.0F;  
  224.         optcompidx = 0;  
  225.   
  226.         sumw   = FLT_MAX;  
  227.         sumwy  = FLT_MAX;  
  228.         sumwyy = FLT_MAX;  
  229.   
  230.         t_compidx = 0;  
  231.         t_n = 0;  
  232.           
  233.         ti = 0;  
  234.         tj = 0;  
  235.         tk = 0;  
  236.   
  237.         t_data = NULL;  
  238.         t_cstep = 0;  
  239.         t_sstep = 0;  
  240.   
  241.         matcstep = 0;  
  242.         matsstep = 0;  
  243.   
  244.         t_idx = NULL;  
  245.   
  246.         mat.data.ptr = NULL;  
  247.           
  248.         // 预计算特征个数小于特征总数,则说明存在新特征,用于计算样本的新特征,存放在mat中  
  249.         if( datan < n )  
  250.         {  
  251.             if( CV_IS_ROW_SAMPLE( flags ) )  
  252.             {  
  253.                 mat = cvMat( m, portion, CV_32FC1, 0 );  
  254.                 matcstep = CV_ELEM_SIZE( mat.type );  
  255.                 matsstep = mat.step;  
  256.             }  
  257.             else  
  258.             {  
  259.                 mat = cvMat( portion, m, CV_32FC1, 0 );  
  260.                 matcstep = mat.step;  
  261.                 matsstep = CV_ELEM_SIZE( mat.type );  
  262.             }  
  263.             mat.data.ptr = (uchar*) cvAlloc( sizeoffloat ) * mat.rows * mat.cols );  
  264.         }  
  265.   
  266.         // 将实际训练样本序列存放进t_idx  
  267.         if( filter != NULL || sortedn < n )  
  268.         {  
  269.             t_idx = (int*) cvAlloc( sizeofint ) * m );  
  270.             if( sortedn == 0 || filter == NULL )  
  271.             {  
  272.                 if( idxdata != NULL )  
  273.                 {  
  274.                     for( ti = 0; ti < l; ti++ )  
  275.                     {  
  276.                         t_idx[ti] = (int) *((float*) (idxdata + ti * idxstep));  
  277.                     }  
  278.                 }  
  279.                 else  
  280.                 {  
  281.                     for( ti = 0; ti < l; ti++ )  
  282.                     {  
  283.                         t_idx[ti] = ti;  
  284.                     }  
  285.                 }                  
  286.             }  
  287.         }  
  288.   
  289.         #ifdef _OPENMP  
  290.         #pragma omp critical(c_compidx)  
  291.         #endif /* _OPENMP */  
  292.   
  293.         // 初始化计算特征范围  
  294.         {  
  295.             t_compidx = compidx;  
  296.             compidx += portion;  
  297.         }  
  298.   
  299.         // 寻找最优弱分类器  
  300.         while( t_compidx < n )  
  301.         {  
  302.             t_n = portion;                      // 每组特征个数  
  303.             if( t_compidx < datan )             // 已经计算过的特征  
  304.             {  
  305.                 t_n = ( t_n < (datan - t_compidx) ) ? t_n : (datan - t_compidx);  
  306.                 t_data = data;  
  307.                 t_cstep = cstep;  
  308.                 t_sstep = sstep;  
  309.             }  
  310.             else                                // 新特征  
  311.             {  
  312.                 t_n = ( t_n < (n - t_compidx) ) ? t_n : (n - t_compidx);  
  313.                 t_cstep = matcstep;  
  314.                 t_sstep = matsstep;  
  315.                 t_data = mat.data.ptr - t_compidx * ((size_t) t_cstep );  
  316.   
  317.                 // 计算每个新特征对应于每个训练样本的特征值  
  318.                 ((CvMTStumpTrainParams*)trainParams)->getTrainData( &mat,  
  319.                         sampleIdx, compIdx, t_compidx, t_n,  
  320.                         ((CvMTStumpTrainParams*)trainParams)->userdata );  
  321.             }  
  322.   
  323.             /* 预计算特征部分,直接寻找最优特征,也就是传说中的最优弱分类器 */  
  324.             if( sorteddata != NULL )  
  325.             {  
  326.                 if( filter != NULL )    // 需要提取实际训练样本  
  327.                 {  
  328.                     switch( sortedtype )  
  329.                     {  
  330.                         case CV_16SC1:  // 这里重复度很高,只注释一个分支,剩下的都一个道理  
  331.   
  332.                             // 从一组特征(datan个预计算特征)中寻找最优特征  
  333.                             for( ti = t_compidx; ti < MIN( sortedn, t_compidx + t_n ); ti++ )  
  334.                             {  
  335.                                 tk = 0;  
  336.   
  337.                                 // 提取实际训练样本  
  338.                                 for( tj = 0; tj < sortedm; tj++ )  
  339.                                 {  
  340.                                     int curidx = (int) ( *((short*) (sorteddata  
  341.                                             + ti * sortedcstep + tj * sortedsstep)) );  
  342.                                     if( filter[curidx] != 0 )  
  343.                                     {  
  344.                                         t_idx[tk++] = curidx;  
  345.                                     }  
  346.                                 }  
  347.   
  348.                                 // 如果findStumpThreshold_32s返回值为1, 则更新最优特征  
  349.                                 if( findStumpThreshold_32s[stumperror](   
  350.                                         t_data + ti * t_cstep, t_sstep,  
  351.                                         wdata, wstep, ydata, ystep,  
  352.                                         (uchar*) t_idx, sizeofint ), tk,  
  353.                                         &lerror, &rerror,  
  354.                                         &threshold, &left, &right,   
  355.                                         &sumw, &sumwy, &sumwyy ) )  
  356.                                 {  
  357.                                     optcompidx = ti;  
  358.                                 }  
  359.                             }  
  360.                             break;  
  361.                         case CV_32SC1:  
  362.                             for( ti = t_compidx; ti < MIN( sortedn, t_compidx + t_n ); ti++ )  
  363.                             {  
  364.                                 tk = 0;  
  365.                                 for( tj = 0; tj < sortedm; tj++ )  
  366.                                 {  
  367.                                     int curidx = (int) ( *((int*) (sorteddata  
  368.                                             + ti * sortedcstep + tj * sortedsstep)) );  
  369.                                     if( filter[curidx] != 0 )  
  370.                                     {  
  371.                                         t_idx[tk++] = curidx;  
  372.                                     }  
  373.                                 }  
  374.                                 if( findStumpThreshold_32s[stumperror](   
  375.                                         t_data + ti * t_cstep, t_sstep,  
  376.                                         wdata, wstep, ydata, ystep,  
  377.                                         (uchar*) t_idx, sizeofint ), tk,  
  378.                                         &lerror, &rerror,  
  379.                                         &threshold, &left, &right,   
  380.                                         &sumw, &sumwy, &sumwyy ) )  
  381.                                 {  
  382.                                     optcompidx = ti;  
  383.                                 }  
  384.                             }  
  385.                             break;  
  386.                         case CV_32FC1:  
  387.                             for( ti = t_compidx; ti < MIN( sortedn, t_compidx + t_n ); ti++ )  
  388.                             {  
  389.                                 tk = 0;  
  390.                                 for( tj = 0; tj < sortedm; tj++ )  
  391.                                 {  
  392.                                     int curidx = (int) ( *((float*) (sorteddata  
  393.                                             + ti * sortedcstep + tj * sortedsstep)) );  
  394.                                     if( filter[curidx] != 0 )  
  395.                                     {  
  396.                                         t_idx[tk++] = curidx;  
  397.                                     }  
  398.                                 }  
  399.                                 if( findStumpThreshold_32s[stumperror](   
  400.                                         t_data + ti * t_cstep, t_sstep,  
  401.                                         wdata, wstep, ydata, ystep,  
  402.                                         (uchar*) t_idx, sizeofint ), tk,  
  403.                                         &lerror, &rerror,  
  404.                                         &threshold, &left, &right,   
  405.                                         &sumw, &sumwy, &sumwyy ) )  
  406.                                 {  
  407.                                     optcompidx = ti;  
  408.                                 }  
  409.                             }  
  410.                             break;  
  411.                         default:  
  412.                             assert( 0 );  
  413.                             break;  
  414.                     }  
  415.                 }  
  416.                 else            // 所有训练样本均参与计算  
  417.                 {  
  418.                     switch( sortedtype )  
  419.                     {  
  420.                         case CV_16SC1:  
  421.                             for( ti = t_compidx; ti < MIN( sortedn, t_compidx + t_n ); ti++ )  
  422.                             {  
  423.                                 if( findStumpThreshold_16s[stumperror](   
  424.                                         t_data + ti * t_cstep, t_sstep,  
  425.                                         wdata, wstep, ydata, ystep,  
  426.                                         sorteddata + ti * sortedcstep, sortedsstep, sortedm,  
  427.                                         &lerror, &rerror,  
  428.                                         &threshold, &left, &right,   
  429.                                         &sumw, &sumwy, &sumwyy ) )  
  430.                                 {  
  431.                                     optcompidx = ti;  
  432.                                 }  
  433.                             }  
  434.                             break;  
  435.                         case CV_32SC1:  
  436.                             for( ti = t_compidx; ti < MIN( sortedn, t_compidx + t_n ); ti++ )  
  437.                             {  
  438.                                 if( findStumpThreshold_32s[stumperror](   
  439.                                         t_data + ti * t_cstep, t_sstep,  
  440.                                         wdata, wstep, ydata, ystep,  
  441.                                         sorteddata + ti * sortedcstep, sortedsstep, sortedm,  
  442.                                         &lerror, &rerror,  
  443.                                         &threshold, &left, &right,   
  444.                                         &sumw, &sumwy, &sumwyy ) )  
  445.                                 {  
  446.                                     optcompidx = ti;  
  447.                                 }  
  448.                             }  
  449.                             break;  
  450.                         case CV_32FC1:  
  451.                             for( ti = t_compidx; ti < MIN( sortedn, t_compidx + t_n ); ti++ )  
  452.                             {  
  453.                                 if( findStumpThreshold_32f[stumperror](   
  454.                                         t_data + ti * t_cstep, t_sstep,  
  455.                                         wdata, wstep, ydata, ystep,  
  456.                                         sorteddata + ti * sortedcstep, sortedsstep, sortedm,  
  457.                                         &lerror, &rerror,  
  458.                                         &threshold, &left, &right,   
  459.                                         &sumw, &sumwy, &sumwyy ) )  
  460.                                 {  
  461.                                     optcompidx = ti;  
  462.                                 }  
  463.                             }  
  464.                             break;  
  465.                         default:  
  466.                             assert( 0 );  
  467.                             break;  
  468.                     }  
  469.                 }  
  470.             }  
  471.   
  472.             /* 新特征部分,要对样本特征值进行排序,然后再寻找最优特征 */  
  473.             ti = MAX( t_compidx, MIN( sortedn, t_compidx + t_n ) );  
  474.             for( ; ti < t_compidx + t_n; ti++ )  
  475.             {  
  476.                 va.data = t_data + ti * t_cstep;  
  477.                 va.step = t_sstep;  
  478.   
  479.                 // 对样本特征值进行排序  
  480.                 icvSortIndexedValArray_32s( t_idx, l, &va );  
  481.   
  482.                 // 继续寻找最优特征  
  483.                 if( findStumpThreshold_32s[stumperror](   
  484.                         t_data + ti * t_cstep, t_sstep,  
  485.                         wdata, wstep, ydata, ystep,  
  486.                         (uchar*)t_idx, sizeofint ), l,  
  487.                         &lerror, &rerror,  
  488.                         &threshold, &left, &right,   
  489.                         &sumw, &sumwy, &sumwyy ) )  
  490.                 {  
  491.                     optcompidx = ti;  
  492.                 }  
  493.             }  
  494.             #ifdef _OPENMP  
  495.             #pragma omp critical(c_compidx)  
  496.             #endif /* _OPENMP */  
  497.   
  498.             // 更新特征计算范围  
  499.             {  
  500.                 t_compidx = compidx;  
  501.                 compidx += portion;  
  502.             }  
  503.         }  
  504.   
  505.         #ifdef _OPENMP  
  506.         #pragma omp critical(c_beststump)  
  507.         #endif /* _OPENMP */  
  508.   
  509.         // 设置最优弱分类器  
  510.         {  
  511.             if( lerror + rerror < stump->lerror + stump->rerror )  
  512.             {  
  513.                 stump->lerror    = lerror;  
  514.                 stump->rerror    = rerror;  
  515.                 stump->compidx   = optcompidx;  
  516.                 stump->threshold = threshold;  
  517.                 stump->left      = left;  
  518.                 stump->right     = right;  
  519.             }  
  520.         }  
  521.   
  522.         /* free allocated memory */  
  523.         if( mat.data.ptr != NULL )  
  524.         {  
  525.             cvFree( &(mat.data.ptr) );  
  526.         }  
  527.         if( t_idx != NULL )  
  528.         {  
  529.             cvFree( &t_idx );  
  530.         }  
  531.     } /* end of parallel region */  
  532.   
  533.     /* END */  
  534.   
  535.     /* free allocated memory */  
  536.     if( filter != NULL )  
  537.     {  
  538.         cvFree( &filter );  
  539.     }  
  540.     // 如果设置为离散型,置信度应为1或者-1  
  541.     if( ((CvMTStumpTrainParams*) trainParams)->type == CV_CLASSIFICATION_CLASS )  
  542.     {  
  543.         stump->left = 2.0F * (stump->left >= 0.5F) - 1.0F;  
  544.         stump->right = 2.0F * (stump->right >= 0.5F) - 1.0F;  
  545.     }  
  546.   
  547.     return (CvClassifier*) stump;  
  548. }  


其实,我现在一直认为,寻找弱分类器是一个很easy的过程,根本不需要这么多行代码,这么多局部变量,但是仔细阅读之后发现,opencv还是很牛的,这段代码的通用性比较强大,兼顾了并行操作可能性。可以应对多特征弱分类器,代码结构也是比较爽快的,尤其是其在条件宏、函数指针方面的应用,令人羡慕异常。今后还要继续研读opencv代码,对编程素养的提高,绝对有很大帮助。

如果有啥问题,还请不吝赐教哦!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值