OpenCV Haar AdaBoost源码改进(比EMCV快6倍)

这几天研究了OpenCV源码 Haar AdaBoost算法,作了一下改进

1.去掉了所有动态分配内存的操作,对嵌入式系统有一定的速度提升

2.注释覆盖了大量关键代码

3.减少了代码一半的体积,并且减少了部分健壮性的代码,速度比OpenCV源码提升16%

4.修改了大量数据结构,不依赖CV源码直接编译

5.去掉了double型,改成Int

6.开方改成查表

7.除法改成乘法加位移


注:使用时请注意,现仅支持单分支的Stages和单结点的Classifier训练好的结果集

        在720MHZ的DSP板子上对一幅352*288的灰度图像进行人脸检测只需300ms,比EMCV快6倍

完整PC版工程链接 (VC6.0能直接编译,但没有5,6,7步的优化)点击打开链接

完整DSP版工程链接 (CCS3.0能直接编译,包含所有优化)点击打开链接

DSP优化的关键代码实例如下(这个版本在CCS下编译,若想用VC6.0直接编译,还要修改一定的数据结构)

Haar.cpp

[cpp]  view plain  copy
 
  1. <pre name="code" class="cpp">#include "Haar.h"  
  2. #include "loadCascade.h"  
  3. #include "Util.h"  
  4. #include "stdio.h"  
  5. #include "string.h"  
  6. #include <math.h>  
  7. #include <stdint.h>  
  8. #include <c6x.h>  
  9.   
  10. /*******************Global************************************/  
  11. HaarClassifierCascade *cascade ;  
  12. //HidHaarClassifierCascade hid_cascade;  
  13. //32bits cell Mat  
  14. int     MatPool32[MaxMatNum][MAXROWS][MAXCOLS];  
  15. //8bits cell   
  16. unsigned char  MatPool8[MaxMatNum][MAXROWS][MAXCOLS];  
  17.   
  18. //8bits*3 cell   
  19. unsigned char  ImgRGBPool8[MaxMatNum][RGBCHANNEL][MAXROWS][MAXCOLS];  
  20.   
  21. //64bits  cell   
  22. _int64   MatPool64[MaxMatNum][MAXROWS][MAXCOLS];  
  23.   
  24. //候选区域坐标节点并查集  
  25. PTreeNode PTreeNodes[MAXPTREENODES];  
  26.   
  27. char HidCascade[MAXHIDCASCADE];  
  28.   
  29. //分类器检测结果区域序列  
  30. Sequence result_seq;  
  31.   
  32.   
  33.   
  34.   
  35.   
  36. //==================================================================  
  37. //函数名:  IsEqual  
  38. //作者:    qiurenbo  
  39. //日期:    2014-10-1  
  40. //功能:    判断两个矩形是否邻接  
  41. //输入参数:_r1  _r2 候选区域矩形        
  42. //返回值:  返回相似性(是否是邻接的矩形)  
  43. //修改记录:  
  44. //==================================================================  
  45. int IsEqual( const void* _r1, const void* _r2)  
  46. {  
  47.     const Rect* r1 = (const Rect*)_r1;  
  48.     const Rect* r2 = (const Rect*)_r2;  
  49.     int distance5x = r1->width ;//int distance = cvRound(r1->width*0.2);  
  50.       
  51.     return r2->x*5 <= r1->x*5 + distance5x &&  
  52.         r2->x*5 >= r1->x*5 - distance5x &&  
  53.         r2->y*5 <= r1->y*5 + distance5x &&  
  54.         r2->y*5 >= r1->y*5 - distance5x &&  
  55.         r2->width*5 <= r1->width * 6 &&  
  56.         r2->width * 6 >= r1->width*5;  
  57. }  
  58.   
  59. //==================================================================  
  60. //函数名:  ReadFaceCascade  
  61. //作者:    qiurenbo  
  62. //日期:    2014-10-1  
  63. //功能:    根据候选区域的相似性(IsEqual函数)建立并查集  
  64. //输入参数:seq  候选目标区域序列        
  65. //返回值:  返回分类后的类别数   
  66. //修改记录:  
  67. //==================================================================  
  68. int SeqPartition( const Sequence* seq )  
  69. {  
  70.     Sequence* result = 0;  
  71.     //CvMemStorage* temp_storage = 0;  
  72.     int class_idx = 0;  
  73.       
  74.   
  75.     memset(PTreeNodes, 0, MAXPTREENODES*sizeof(PTreeNode));  
  76.       
  77.     int i, j;  
  78.      
  79.   
  80.   
  81.     //建立以seq中元素为根节点的森林  
  82.     for( i = 0; i < seq->total; i++ )  
  83.         PTreeNodes[i].element = (char*)&seq->rectQueue[i];  
  84.   
  85.     //遍历所有根节点  
  86.     for( i = 0; i < seq->total; i++ )  
  87.     {  
  88.         PTreeNode* node = &PTreeNodes[i];  
  89.         PTreeNode* root = node;  
  90.         //确保node中元素指针不为空  
  91.         if( !node->element )  
  92.             continue;  
  93.           
  94.         //找到元素在树中的根结点  
  95.         while( root->parent )  
  96.             root = root->parent;  
  97.           
  98.         for( j = 0; j < seq->total; j++ )  
  99.         {  
  100.             PTreeNode* node2 = &PTreeNodes[j];  
  101.               
  102.             //确保1.node中元素指针不为空  
  103.             //    2.且不是同一个node结点  
  104.             //    3.且是相似区域  
  105.             // 若是相似区域,则合并元素  
  106.             if( node2->element && node2 != node &&  
  107.                 IsEqual( node->element, node2->element))  
  108.             {  
  109.                 PTreeNode* root2 = node2;  
  110.                   
  111.                //找到元素在树中的根结点  
  112.                 while( root2->parent )  
  113.                     root2 = root2->parent;  
  114.                   
  115.                 //合并的前提是不在一颗树中  
  116.                 if( root2 != root )  
  117.                 {  
  118.                     //秩小的树归入秩大的树中  
  119.                     if( root->rank > root2->rank )  
  120.                         root2->parent = root;  
  121.                     //秩相等的时候才改变树的秩  
  122.                     else  
  123.                     {  
  124.                         root->parent = root2;  
  125.                         root2->rank += root->rank == root2->rank;  
  126.                         root = root2;  
  127.                     }  
  128.                     //assert( root->parent == 0 );  
  129.                       
  130.                     // 路径压缩,子节点node2直接指向根节点  
  131.                     while( node2->parent )  
  132.                     {  
  133.                         PTreeNode* temp = node2;  
  134.                         node2 = node2->parent;  
  135.                         temp->parent = root;  
  136.                     }  
  137.                       
  138.                     // 路径压缩,子节点node直接指向根节点  
  139.                     node2 = node;  
  140.                     while( node2->parent )  
  141.                     {  
  142.                         PTreeNode* temp = node2;  
  143.                         node2 = node2->parent;  
  144.                         temp->parent = root;  
  145.                     }  
  146.                 }  
  147.             }  
  148.           
  149.         }  
  150.     }  
  151.   
  152.   
  153.     for( i = 0; i < seq->total; i++ )  
  154.     {  
  155.         PTreeNode* node = &PTreeNodes[i];  
  156.         int idx = -1;  
  157.           
  158.         if( node->element )  
  159.         {  
  160.             while( node->parent )  
  161.                 node = node->parent;  
  162.               
  163.             //计算有几棵并查树,巧妙地利用取反避免重复计算  
  164.             if( node->rank >= 0 )  
  165.                 node->rank = ~class_idx++;  
  166.             idx = ~node->rank;  
  167.         }  
  168.           
  169.          
  170.     }  
  171.   
  172.     return class_idx;  
  173. }  
  174.   
  175.   
  176. //==================================================================  
  177. //函数名:  ReadFaceCascade  
  178. //作者:    qiurenbo  
  179. //日期:    2014-09-30  
  180. //功能:    读取Cascade文件  
  181. //输入参数:void        
  182. //返回值:  void    
  183. //修改记录:  
  184. //==================================================================  
  185. void ReadFaceCascade()  
  186. {  
  187.     int i;  
  188.     //load cascade  
  189.     cascade = (HaarClassifierCascade*)HaarClassifierCascade_face;  
  190.   
  191.     //load stages  
  192.     int stage_size = StageClassifier_face[0];  
  193.     HaarStageClassifier *stages ;  
  194.     stages = (HaarStageClassifier *)(StageClassifier_face+1);  
  195.       
  196.     //load classifier  
  197.     int classifier_size = Classifier_face[0];  
  198.     HaarClassifier *cls ;  
  199.     cls = (HaarClassifier*) (Classifier_face+1);  
  200.       
  201.     int class_info_size = class_info[0];  
  202.     int * cls_info ;  
  203.     cls_info = (int*)(class_info+1);  
  204.   
  205.       
  206.       
  207.     //link cascade with stages  
  208.     cascade->stage_classifier = stages;  
  209.     //link stages,classifiers  
  210.     int offset=0;  
  211.     int offset_t=(sizeof(HaarFeature)/sizeof(int));  
  212.     int offset_l=offset_t+1;  
  213.     int offset_r=offset_t+2;  
  214.     int offset_a=offset_t+3;  
  215.     int offset_total=0;  
  216.     for(i=0;i<stage_size;++i)  
  217.     {  
  218.         (stages+i)->classifier = (cls+offset);  
  219.         offset +=(stages+i)->count;  
  220.     }  
  221.       
  222.     offset_total = 5+ (sizeof(HaarFeature)/sizeof(int));  
  223.     //link classifiers and haar_featrue;  
  224.     for(i=0;i<classifier_size;++i)  
  225.     {  
  226.         HaarClassifier *cs= cls+i;  
  227.       
  228.         cs->haar_feature = (HaarFeature*)(cls_info+i*offset_total);  
  229.         cs->threshold = (int*)(cls_info+i*offset_total+offset_t);  
  230.         cs->left =(int*)(cls_info+i*offset_total+offset_l);  
  231.         cs->right=(int*)(cls_info+i*offset_total+offset_r);  
  232.         cs->alpha=(int*)(cls_info+i*offset_total+offset_a);  
  233.       
  234.     }  
  235. }  
  236. //==================================================================  
  237. //函数名:  IntegralImage  
  238. //作者:    qiurenbo  
  239. //日期:    2014-09-26  
  240. //功能:    从矩阵池中获取rows * cols的矩阵   
  241. //输入参数:mat      矩阵结构体地址  
  242. //          rows    待分配的行数  
  243. //          cols    待分配的列数  
  244. //          type    待分配的矩阵类型   
  245. //          matIndex 从矩阵池中分配的矩阵序列(手动指定..)        
  246. //返回值:  void    
  247. //修改记录:  
  248. //==================================================================  
  249.   
  250. void GetMat(void* mat, int rows, int cols, int type, int matIndex)  
  251. {  
  252.     switch(type)  
  253.     {  
  254.         case BITS8:   
  255.                 ((Mat8*)mat)->rows = rows;  
  256.                 ((Mat8*)mat)->cols = cols;  
  257.                 ((Mat8*)mat)->mat8Ptr =  (Mat8Ptr)&MatPool8[matIndex];  
  258.                 break;  
  259.               
  260.         case BITS32:   
  261.                 ((Mat32*)mat)->rows = rows;  
  262.                 ((Mat32*)mat)->cols = cols;  
  263.                 ((Mat32*)mat)->mat32Ptr =  (Mat32Ptr)&MatPool32[matIndex];  
  264.                 break;  
  265.   
  266.         case BITS64:  
  267.                 ((Mat64*)mat)->rows = rows;  
  268.                 ((Mat64*)mat)->cols = cols;  
  269.                 ((Mat64*)mat)->mat64Ptr =  (Mat64Ptr)&MatPool64[matIndex];  
  270.                 break;  
  271.     }  
  272. }  
  273.   
  274.   
  275. //==================================================================  
  276. //函数名:  IntegralImage  
  277. //作者:    qiurenbo  
  278. //日期:    2014-09-26  
  279. //功能:    计算目标检测区域的积分图  
  280. //输入参数:src      待检测目标所在矩阵起始  
  281. //          srcstep 待检测区域列数  
  282. //          sum     积分图矩阵   (W+1)*(H+1)   
  283. //          sumstep 积分图矩阵列数      
  284. //          sqsum   平方和图矩阵 (W+1)*(H+1)    
  285. //          sqsumstep 平方和图矩阵列数  
  286. //          size   待检测区域大小 W*H  
  287. //            
  288. //            
  289. //返回值:  void    
  290. //修改记录:  
  291. //==================================================================  
  292. void IntegralImage(ImgPtr src, int srcstep,  
  293.                    Mat32Ptr sum, int sumstep,       
  294.                    Mat64Ptr sqsum, int sqsumstep,  
  295.                    Size size)  
  296. {  
  297.     int s = 0;  
  298.     _int64 sq = 0;  
  299.     //移动指针到积分图的下一行,第一行全为0  
  300.     sum += sumstep + 1;       
  301.     sqsum += sqsumstep + 1;   
  302.       
  303.     //y代表相对于输入检测矩阵起始第几行  
  304.     for(int y = 0; y < size.height; y++, src += srcstep,         
  305.         sum += sumstep, sqsum += sqsumstep )      
  306.     {     
  307.         //sum和sqsum为(W+1)*(H+1)大小矩阵,故将第一列置为0  
  308.         sum[-1] = 0;                                          
  309.         sqsum[-1] = 0;                                        
  310.           
  311.         for(int x = 0 ; x < size.width; x++ )      
  312.         {                                                     
  313.             int it = src[x];                             
  314.             int t = (it);     
  315.               
  316.             //查表计算平方  
  317.             _int64  tq =  CV_8TO16U_SQR(it);    
  318.             //s代表行上的累加和  
  319.             s += t;    
  320.             //sq代表行上的累加和  
  321.             sq += tq;                                         
  322.             t = sum[x - sumstep] + s;                         
  323.             tq = sqsum[x - sqsumstep] + sq;                   
  324.             sum[x] = t;                                       
  325.             sqsum[x] = (_int64)tq;                                    
  326.         }                                                     
  327.     }                          
  328. }  
  329.   
  330. //==================================================================  
  331. //函数名:  Integral  
  332. //作者:    qiurenbo  
  333. //日期:    2014-09-26  
  334. //功能:    计算目标检测区域的积分图  
  335. //输入参数:image 图像  
  336. //          sumImage 积分图指针  
  337. //          sumSqImage 平方和图指针                   
  338. //返回值:  void    
  339. //修改记录:  
  340. //==================================================================  
  341. void Integral(Image* image, Mat32* sumImage, Mat64* sumSqImage)  
  342. {  
  343.   
  344.     //取保地址空间已经分配,从数组中  
  345.     if (image == NULL || sumImage == NULL || sumSqImage == NULL)  
  346.         return;  
  347.   
  348.     Image*src    =      (Image*)image;  
  349.     Mat32 *sum   =      (Mat32*)sumImage;  
  350.     Mat64 *sqsum =      (Mat64*)sumSqImage;  
  351.      
  352.     Size size;  
  353.     size.height = src->rows;  
  354.     size.width =  src->cols;  
  355.   
  356.     IntegralImage(src->imgPtr, src->cols,  
  357.         sum->mat32Ptr, sum->cols,       
  358.         sqsum->mat64Ptr, sqsum->cols,size);  
  359.       
  360.   
  361. }  
  362. //==================================================================  
  363. //函数名:  AlignPtr  
  364. //作者:    qiurenbo  
  365. //日期:    2014-10-03  
  366. //功能:   按algin字节对齐  
  367. //输入参数:ptr 要对齐的指针     
  368. //          align 对齐的字节数             
  369. //返回值:  void*     
  370. //修改记录:  
  371. //==================================================================  
  372. void* AlignPtr( const void* ptr, int align)  
  373. {  
  374.   
  375.     return (void*)( ((unsigned int)ptr + align - 1) & ~(align-1) );  
  376. }   
  377. //==================================================================  
  378. //函数名:  CreateHidHaarClassifierCascade  
  379. //作者:    qiurenbo  
  380. //日期:    2014-09-28  
  381. //功能:    创建隐式积分图加快计算速度  
  382. //输入参数:cascade 级联分类器指针                
  383. //返回值:  static HidHaarClassifierCascade*   返回一个隐式级联分类器指针  
  384. //修改记录:  
  385. //==================================================================  
  386. static HidHaarClassifierCascade*  
  387. CreateHidHaarClassifierCascade(HaarClassifierCascade* cascade)  
  388. {  
  389.   
  390.   
  391.   
  392.       
  393.     cascade->hid_cascade = (struct HidHaarClassifierCascade *)HidCascade;  
  394.     //分配栈空间  
  395.     HidHaarClassifierCascade* out = (struct HidHaarClassifierCascade *)HidCascade;  
  396.     const int icv_stage_threshold_bias = 419; //0.0001*(2^22)=419.4304  
  397.   
  398.     HidHaarClassifier* haar_classifier_ptr;  
  399.     HidHaarTreeNode* haar_node_ptr;  
  400.     int i, j, l;  
  401.      
  402.     int total_classifiers = 2135;  
  403.     int total_nodes = 0;  
  404.       
  405.     
  406.     int has_tilted_features = 0;  
  407.     int max_count = 0;  
  408.   
  409.   
  410.   
  411.   
  412.     /* 初始化HidCascade头 */  
  413.     out->count = cascade->count;  
  414.     out->stage_classifier = (HidHaarStageClassifier*)(out + 1);  
  415.     //out->stage_classifier = (HidHaarStageClassifier*)AlignPtr(out + 1, 4);  
  416.     //classifier起始地址  
  417.     haar_classifier_ptr = (HidHaarClassifier*)(out->stage_classifier + cascade->count);  
  418.     //haar_classifier_ptr = (HidHaarClassifier*)AlignPtr(out->stage_classifier + cascade->count, 4);  
  419.     //node起始地址  
  420.     //haar_node_ptr = (HidHaarTreeNode*)AlignPtr(haar_classifier_ptr + total_classifiers, 4);  
  421.     haar_node_ptr = (HidHaarTreeNode*)(haar_classifier_ptr + total_classifiers);  
  422.     out->is_stump_based = 1;  
  423.     out->is_tree = 0;  
  424.   
  425.     // 用cascade初始化HidCascade  
  426.     for( i = 0; i < cascade->count; i++ )  
  427.     {  
  428.   
  429.         //用cascades Stage初始化HidCascade的Stage  
  430.         HaarStageClassifier* stage_classifier = cascade->stage_classifier + i;  
  431.         HidHaarStageClassifier* hid_stage_classifier = out->stage_classifier + i;  
  432.   
  433.         hid_stage_classifier->count = stage_classifier->count;  
  434.         hid_stage_classifier->threshold = stage_classifier->threshold - icv_stage_threshold_bias;  
  435.         //hid_stage_classifier->classifier = (struct HidHaarClassifier *)&HidClassifiers[i];  
  436.          hid_stage_classifier->classifier = haar_classifier_ptr;  
  437.         //初始化为二特征,下面会根据真实的特征数至1或0(三特征)  
  438.         hid_stage_classifier->two_rects = 1;  
  439.         haar_classifier_ptr += stage_classifier->count;  
  440.   
  441.   
  442.         //Stage构成一颗退化的二叉树(单分支),每个结点最多只有一个孩子  
  443.         hid_stage_classifier->parent = (stage_classifier->parent == -1)  
  444.             ? NULL : out->stage_classifier + stage_classifier->parent;  
  445.         hid_stage_classifier->next = (stage_classifier->next == -1)  
  446.             ? NULL :  out->stage_classifier + stage_classifier->next;  
  447.         hid_stage_classifier->child = (stage_classifier->child == -1)  
  448.             ? NULL : out->stage_classifier + stage_classifier->child ;  
  449.           
  450.         //判断该stage是否为树状结构(多分枝)  
  451.         out->is_tree |= hid_stage_classifier->next != NULL;  
  452.   
  453.   
  454.         //赋值classifer属性  
  455.         for( j = 0; j < stage_classifier->count; j++ )  
  456.         {  
  457.             HaarClassifier* classifier = stage_classifier->classifier + j;  
  458.             HidHaarClassifier* hid_classifier = hid_stage_classifier->classifier + j;  
  459.             int node_count = classifier->count;  
  460.               
  461.             int* alpha_ptr = (int*)(haar_node_ptr + node_count);  
  462.   
  463.             hid_classifier->count = node_count;  
  464.             hid_classifier->node = haar_node_ptr;  
  465.             hid_classifier->alpha = alpha_ptr;  
  466.              
  467.             //赋值node属性  
  468.             for( l = 0; l < node_count; l++ )  
  469.             {  
  470.                 HidHaarTreeNode* node =  hid_classifier->node + l;  
  471.                 HaarFeature* feature = classifier->haar_feature + l;  
  472.                 memset( node, -1, sizeof(*node) );  
  473.                 node->threshold = classifier->threshold[l];  
  474.                 node->left = classifier->left[l];  
  475.                 node->right = classifier->right[l];  
  476.                   
  477.                 //对特征数目进行判断,若是三特征,则至two_rects为0  
  478.                 if( (feature->rect[2].weight) == 0 ||  
  479.                     feature->rect[2].r.width == 0 ||  
  480.                     feature->rect[2].r.height == 0 )  
  481.                     memset( &(node->feature.rect[2]), 0, sizeof(node->feature.rect[2]) );  
  482.                 else  
  483.                     hid_stage_classifier->two_rects = 0;  
  484.             }  
  485.   
  486.             //赋值alpha  
  487.             memcpy( hid_classifier->alpha, classifier->alpha, (node_count+1)*sizeof(hid_classifier->alpha[0]));  
  488.             haar_node_ptr = (HidHaarTreeNode*)(alpha_ptr+node_count + 1);  
  489.                   
  490.   
  491.             //判断cascade中的分类器是否是树桩分类器,只有根结点的决策树  
  492.             out->is_stump_based &= node_count == 1;  
  493.         }  
  494.     }  
  495.   
  496.   
  497.     //cascade->hid_cascade = out;  
  498.     //assert( (char*)haar_node_ptr - (char*)out <= datasize );  
  499.   
  500.      
  501.   
  502.   
  503.   
  504.     return out;  
  505. }  
  506.   
  507. //==================================================================  
  508. //函数名:  SetImagesForHaarClassifierCascade  
  509. //作者:    qiurenbo  
  510. //日期:    2014-09-29  
  511. //功能:    根据尺度调整Haar特征的大小和权重  
  512. //输入参数:cascade 级联分类器指针   
  513. //          sum     积分图  
  514. //          sqsum   平方和积分图  
  515. //          scale32x 尺度               
  516. //返回值:  无  
  517. //修改记录:  
  518. //==================================================================  
  519. void SetImagesForHaarClassifierCascade(HaarClassifierCascade* _cascade, Mat32* sum, Mat64* sqsum, int scale32x)  
  520. {  
  521.   
  522.   
  523.   
  524.     
  525.     HidHaarClassifierCascade* hidCascade;  
  526.     int coi0 = 0, coi1 = 0;  
  527.     int i;  
  528.     Rect equ_rect;  
  529.     int weight_scale;  
  530.     HaarFeature* feature;  
  531.     HidHaarFeature* hidfeature;  
  532.     int sum0 = 0, area0 = 0;  
  533.     Rect r[3];  
  534.     Rect tr;  
  535.     int correction_ratio;  
  536.   
  537.   
  538.     //根据尺度获取窗口大小  
  539.     _cascade->scale32x = scale32x;  
  540.     _cascade->real_window_size.width = (_cascade->orig_window_size.width * scale32x + 16)>>5 ;  
  541.     _cascade->real_window_size.height = (_cascade->orig_window_size.height * scale32x +16) >> 5;  
  542.   
  543.   
  544.     //设置隐式级联分类器的积分图  
  545.     hidCascade = _cascade->hid_cascade;  
  546.     hidCascade->sum = sum;  
  547.     hidCascade->sqsum = sqsum;  
  548.   
  549.     //根据尺度设置积分图起始矩阵的位置  
  550.     equ_rect.x = equ_rect.y = (scale32x+16)>>5;      
  551.     equ_rect.width = ((_cascade->orig_window_size.width-2)*scale32x + 16 ) >> 5;   //+0.5是为了四舍五入  
  552.     equ_rect.height = ((_cascade->orig_window_size.height-2)*scale32x + 16 ) >> 5;  
  553.     weight_scale = equ_rect.width*equ_rect.height;  
  554.     hidCascade->window_area = weight_scale; //矩形面积  
  555.       
  556.     //获取积分图上起始矩阵四个像素的坐标  
  557.     hidCascade->p0 = sum->mat32Ptr + (equ_rect.y) * sum->cols+ equ_rect.x;  
  558.     hidCascade->p1 = sum->mat32Ptr + (equ_rect.y) * sum->cols + equ_rect.x + equ_rect.width;  
  559.     hidCascade->p2 = sum->mat32Ptr + (equ_rect.y + equ_rect.height) * sum->cols + equ_rect.x;  
  560.     hidCascade->p3 = sum->mat32Ptr + (equ_rect.y + equ_rect.height) * sum->cols + equ_rect.x + equ_rect.width;  
  561.   
  562.     //获取平方和积分图上起始矩阵四个像素的坐标  
  563.     hidCascade->pq0 = sqsum->mat64Ptr + (equ_rect.y) * sqsum->cols+ equ_rect.x;  
  564.     hidCascade->pq1 = sqsum->mat64Ptr + (equ_rect.y) * sqsum->cols+ equ_rect.x + equ_rect.width;  
  565.     hidCascade->pq2 = sqsum->mat64Ptr + (equ_rect.y + equ_rect.height) * sqsum->cols+ equ_rect.x;  
  566.     hidCascade->pq3 = sqsum->mat64Ptr + (equ_rect.y + equ_rect.height) * sqsum->cols+ equ_rect.x + equ_rect.width;  
  567.   
  568.     //遍历每个Classifer所使用的特征,对它们进行尺度放大,并将改变的值赋给HidCascade,隐式级联分类器  
  569.     for( i = 0; i < hidCascade->count; i++ )  
  570.     {  
  571.         int j, k, l;  
  572.         for( j = 0; j < hidCascade->stage_classifier[i].count; j++ )  
  573.         {  
  574.             for( l = 0; l < hidCascade->stage_classifier[i].classifier[j].count; l++ )  
  575.             {  
  576.                 feature = &_cascade->stage_classifier[i].classifier[j].haar_feature[l];  
  577.   
  578.                 hidfeature = &hidCascade->stage_classifier[i].classifier[j].node[l].feature;  
  579.                 sum0 = 0;  
  580.                 area0 = 0;  
  581.                   
  582.                   
  583.            
  584.                 for( k = 0; k < CV_HAAR_FEATURE_MAX; k++ )  
  585.                 {  
  586.                     if( !hidfeature->rect[k].p0 )  
  587.                         break;  
  588.                       
  589.                     r[k] = feature->rect[k].r;  
  590.                   
  591.                       
  592.                       
  593.                     //左上角坐标和矩阵长宽都按尺度放大  
  594.                     tr.x = (r[k].x * scale32x + 16) >> 5;  
  595.                     tr.width = (r[k].width * scale32x + 16) >> 5;  
  596.                     tr.y = ( r[k].y * scale32x + 16 ) >> 5;  
  597.                     tr.height = ( r[k].height * scale32x +16 ) >> 5;  
  598.                       
  599.                       
  600.                     correction_ratio = weight_scale;  
  601.                       
  602.                     //设置矩阵四个顶点在积分图中的位置(为了计算特征方便)  
  603.                     hidfeature->rect[k].p0 = sum->mat32Ptr + tr.y * sum->cols +  tr.x;  
  604.                     hidfeature->rect[k].p1 = sum->mat32Ptr + tr.y * sum->cols +  tr.x + tr.width;   
  605.                     hidfeature->rect[k].p2 = sum->mat32Ptr + (tr.y + tr.height) *sum->cols +  tr.x;   
  606.                     hidfeature->rect[k].p3 = sum->mat32Ptr + (tr.y + tr.height) *sum->cols +  tr.x + tr.width;  
  607.                       
  608.                     //rect[1] = weight/area, 左移22位是为了避免浮点计算,将权值/检测窗口面积(不断扩大),降低权值  
  609.                     hidfeature->rect[k].weight = ((feature->rect[k].weight)<< NODE_THRESHOLD_SHIFT)/(correction_ratio);  
  610.                       
  611.                     if( k == 0 )  
  612.                         area0 = tr.width * tr.height;  
  613.                    else  
  614.                         sum0 += hidfeature->rect[k].weight * tr.width * tr.height;  
  615.               
  616.                 }  
  617.                  //rect[0].weight ,权重和特征矩形面积成反比  
  618.                  hidfeature->rect[0].weight = (int)(-sum0/area0);  
  619.                       
  620.             } /* l */  
  621.         } /* j */  
  622.     }  
  623.       
  624. };  
  625.   
  626. uint64_t block1 = 0;  
  627. //uint64_t block2 = 0;  
  628. //==================================================================  
  629. //函数名:  RunHaarClassifierCascade  
  630. //作者:    qiurenbo  
  631. //日期:    2014-09-30  
  632. //功能:    在指定窗口范围计算特征  
  633. //输入参数:_cascade 级联分类器指针   
  634. //          pt          检测窗口左上角坐标  
  635. //          start_stage 起始stage下标     
  636. //返回值:  <=0          未检测到目标或参数有问题  
  637. //          1           成功检测到目标  
  638. //修改记录:  
  639. //====================================================================  
  640. int RunHaarClassifierCascade( HaarClassifierCascade* _cascade, Point& pt, int start_stage )  
  641. {  
  642.                              
  643.     int result = -1;  
  644.   
  645.   
  646.     int p_offset, pq_offset;  
  647.     int i, j;  
  648.     _int64 rectsum, variance_factor;  
  649.     int variance_norm_factor;  
  650.     HidHaarClassifier* classifier;  
  651.     HidHaarTreeNode* node;  
  652.     int sum, t, a, b;  
  653.     int stage_sum;  
  654.   
  655. /*  uint64_t start_time, end_time, overhead, cyclecountSet=0, cyclecountRun=0; 
  656.     //In the initialization portion of the code: 
  657.     TSCL = 0; //enable TSC 
  658.     start_time = _itoll(TSCH, TSCL); 
  659.     end_time = _itoll(TSCH, TSCL); 
  660.     overhead = end_time-start_time; //Calculating the overhead of the method.*/  
  661.     HidHaarClassifierCascade* hidCascade;  
  662.   
  663.     if (_cascade == NULL)  
  664.         return -1;  
  665.     
  666.   
  667.     hidCascade = _cascade->hid_cascade;  
  668.     if( !hidCascade )  
  669.         return -1;  
  670.       
  671.   
  672.     //确保矩形的有效性,并防止计算窗口出边界  
  673.     if( pt.x < 0 || pt.y < 0 ||  
  674.         pt.x + _cascade->real_window_size.width >= hidCascade->sum->cols-2 ||  
  675.         pt.y + _cascade->real_window_size.height >= hidCascade->sum->rows-2 )  
  676.         return -1;  
  677.   
  678.   
  679.     //计算特征点在积分图中的偏移,相当于移动窗口  
  680.     p_offset = pt.y * (hidCascade->sum->cols) + pt.x;  
  681.     pq_offset = pt.y * (hidCascade->sqsum->cols) + pt.x;  
  682.   
  683.   
  684.     //计算移动后整个窗口的特征值  
  685.     rectsum = calc_sum(*hidCascade,p_offset);//*cascade->inv_window_area;  
  686.     variance_factor = hidCascade->pq0[pq_offset] - hidCascade->pq1[pq_offset] -  
  687.                            hidCascade->pq2[pq_offset] + hidCascade->pq3[pq_offset];  
  688.      variance_factor = (variance_factor - ((rectsum*rectsum*windowArea[hidCascade->window_area-324])>>16))*windowArea[hidCascade->window_area-324]>>16;  
  689.     //variance_norm_factor = int(sqrt(float(variance_factor))+0.5f);//qmath  
  690.     variance_norm_factor = shortSqrtTable[variance_factor];  
  691.   
  692.     if( variance_norm_factor < 0 )  
  693.         variance_norm_factor = 1;  
  694.   
  695.     //计算每个classifier的用到的特征区域的特征值  
  696.   
  697.     for( i = start_stage; i < hidCascade->count; i++ )  
  698.     //for( i = start_stage; i < hidCascade->count; i++ )  
  699.     {  
  700.         stage_sum = 0;  
  701.           
  702.       
  703.         node = hidCascade->stage_classifier[i].classifier->node;  
  704.         classifier = hidCascade->stage_classifier[i].classifier;  
  705.         //if( hidCascade->stage_classifier[i].two_rects )  
  706.         //{  
  707.         for( j = 0; j < hidCascade->stage_classifier[i].count; j++ )  
  708.         {  
  709.             //start_time = _itoll(TSCH, TSCL);  
  710.             //classifier = hidCascade->stage_classifier[i].classifier + j;  
  711.               
  712.             //start_time = _itoll(TSCH, TSCL);  
  713.             t = node->threshold*variance_norm_factor >> 10;  
  714.             //end_time = _itoll(TSCH, TSCL);  
  715.         //  block1 += end_time - start_time - overhead;  
  716.               
  717.             //start_time = _itoll(TSCH, TSCL);  
  718.             //计算Haar特征    
  719.             sum = calc_sum(node->feature.rect[0],p_offset) * node->feature.rect[0].weight >> 10;  
  720.             sum += calc_sum(node->feature.rect[1],p_offset) * node->feature.rect[1].weight >> 10;  
  721.           
  722.           
  723.             //两特征和三特征分开处理  
  724.             if( node->feature.rect[2].p0 )  
  725.                 sum += calc_sum(node->feature.rect[2],p_offset) * node->feature.rect[2].weight >> 10;  
  726.   
  727.             //end_time = _itoll(TSCH, TSCL);  
  728.             //block1 += end_time - start_time - overhead;  
  729.         //  
  730.             //a = classifier->alpha[0];  
  731.             //b = classifier->alpha[1];  
  732.             //start_time = _itoll(TSCH, TSCL);  
  733.             stage_sum += sum < t ? classifier->alpha[0] : classifier->alpha[1];  
  734.             //  end_time = _itoll(TSCH, TSCL);  
  735.             //  block2 += end_time - start_time - overhead  
  736.             node = (HidHaarTreeNode*)((char*)(node) + 80);  
  737.             classifier++;  
  738.         }  
  739.           
  740.         if( stage_sum < hidCascade->stage_classifier[i].threshold )  
  741.         {  
  742.               
  743.             return -i;  
  744.               
  745.         }  
  746.     }  
  747.       
  748.    //QueryPerformanceCounter(&t2);  
  749.    //printf("FeatureDetectTime:%fms\n",(t2.QuadPart - t1.QuadPart)*1000.0/tc.QuadPart);  
  750.   
  751.     
  752.   
  753.     return 1;  
  754. }  
  755.   
  756. //==================================================================  
  757. //函数名:  HaarDetectObjects  
  758. //作者:    qiurenbo  
  759. //日期:    2014-09-30  
  760. //功能:    在指定图片中查找目标  
  761. //输入参数: _img                图片指针          
  762. //          cascade             级联分类器指针   
  763. //          start_stage         起始stage下标   
  764. //          scale_factor32x     窗口变化尺度倍数 /32  
  765. //          min_neighbors       最小临界目标(min_neighbors个以上的候选目标的区域才是最后的目标区域)  
  766. //          minSize             目标最小的大小  
  767. //返回值:  <=0                  未检测到目标或参数有问题  
  768. //          1                   成功检测到目标  
  769. //修改记录:  
  770. //====================================================================  
  771. void HaarDetectObjects(Image* _img,  
  772.                     HaarClassifierCascade* cascade,   //训练好的级联分类器  
  773.                     char* storage, int scale_factor32x,  
  774.                     int min_neighbors, int flags, Size minSize)  
  775. {  
  776.       
  777.       
  778.     //第一次分类用到的最大stage  
  779.     //第二次分类用到的起始stage  
  780.     int split_stage = 2;  
  781.   
  782.    // ImgPtr stub, *img =  _img;  
  783.     Mat32       sum ;  
  784.     Mat64       sqsum;  
  785.     Image       tmp;  
  786.   
  787.     //检测区域候选队列  
  788.     Sequence    seq;  
  789.       
  790.     //结果候选恿?  
  791.     Sequence    seq2;  
  792.       
  793.     //并查集合并序列  
  794.     Sequence comps;  
  795.   
  796.     Rect r1;  
  797.     PTreeNode* node;  
  798.     int r1_neighbor;  
  799.     int j, flag = 1;  
  800.     Rect r2 ;  
  801.     int r2_neighbor;  
  802.     int distance;//cvRound( r2.rect.width * 0.2 );  
  803.     memset(&seq, 0, sizeof(Sequence));  
  804.     memset(&comps, 0, sizeof(Sequence));  
  805.     memset(&seq2, 0, sizeof(Sequence));  
  806.     memset(&result_seq, 0, sizeof(result_seq));  
  807.   
  808.     int i;  
  809.       
  810.   
  811.     int factor32x;  
  812.     int npass = 2;  
  813.   
  814.     if( !cascade )  
  815.        return ;  
  816.   
  817.   
  818.     //获取积分图和平方和积分图的矩阵  
  819.     GetMat(&sum , _img->rows + 1, _img->cols + 1, BITS32, 0);  
  820.     GetMat(&sqsum, _img->rows + 1, _img->cols + 1, BITS64, 0);  
  821.     GetMat(&tmp, _img->rows, _img->cols, BITS8, 1);  
  822.   
  823.     //若不存在隐式积分图(用于加速计算),则创建一个  
  824.      if( !cascade->hid_cascade )  
  825.         CreateHidHaarClassifierCascade(cascade);  
  826.   
  827.   
  828.     //计算积分图  
  829.     Integral(_img, &sum, &sqsum);  
  830.   
  831.     int count = 0;  
  832.     int count2 = 0;  
  833.     // In the variable declaration portion of the code:  
  834.     /*uint64_t start_time, end_time, overhead, cyclecountSet=0, cyclecountRun=0;  
  835.     // In the initialization portion of the code:  
  836.     TSCL = 0; //enable TSC  
  837.     start_time = _itoll(TSCH, TSCL);  
  838.     end_time = _itoll(TSCH, TSCL);  
  839.     overhead = end_time-start_time; //Calculating the overhead of the method.*/  
  840.   
  841.   
  842.     //不断调整窗口尺度,直到到达图像边缘(_img->cols-10) ||(_img->rows - 10)  
  843.     //并且确保尺度小于3倍(96)  
  844.     for( factor32x = 32; factor32x*cascade->orig_window_size.width < (_img->cols - 10)<<5 &&  
  845.         factor32x*cascade->orig_window_size.height < (_img->rows - 10)<<5  
  846.         &&factor32x<96;  
  847.     factor32x = (factor32x*scale_factor32x+16)>>5 )  
  848.     {  
  849.           
  850.         const int ystep32x = MAX(64, factor32x);  
  851.   
  852.         //调整搜索窗口尺度  
  853.         Size win_size;  
  854.         win_size.height = (cascade->orig_window_size.height * factor32x + 16)>>5;  
  855.         win_size.width = (cascade->orig_window_size.width * factor32x + 16 )>>5;  
  856.           
  857.        //pass指扫描次数,stage_offset指第二次扫描时从第几个stage开始  
  858.         int pass, stage_offset = 0;  
  859.           
  860.         //确保搜索窗口在尺度放大后仍然在图像中  
  861.         int stop_height =  ( ((_img->rows - win_size.height)<<5)+ (ystep32x>>1) ) / ystep32x;  
  862.           
  863.         //确保搜索窗口大于目标的最小尺寸  
  864.         if( win_size.width < minSize.width || win_size.height < minSize.height )  
  865.             continue;  
  866.         //QueryPerformanceFrequency(&tc);  
  867.         //QueryPerformanceCounter(&t1);  
  868.         //根据尺度设置隐式级联分类器中的特征和权重,并设置这些特征在积分图中的位置,以加速运算  
  869.           
  870.         // Code to be profiled  
  871.         //start_time = _itoll(TSCH, TSCL);  
  872.         SetImagesForHaarClassifierCascade(cascade, &sum, &sqsum, factor32x );  
  873.         //end_time = _itoll(TSCH, TSCL);  
  874.         //cyclecountSet = end_time-start_time-overhead;  
  875.         //QueryPerformanceCounter(&t2);  
  876.         //printf("SetImageFeatureRunTime:%fms\n",(t2.QuadPart - t1.QuadPart)*1000.0/tc.QuadPart);  
  877.   
  878.   
  879.         //设置粗检测所使用的起始分类器  
  880.         cascade->hid_cascade->count = split_stage;  
  881.       
  882.           
  883.         //用检测窗口扫描两遍图像:  
  884.         //第一遍通过级联两个stage粗略定位目标大致区域,对候选区域进行标定(利用tmp矩阵)  
  885.         //第二遍对标定的候选区域进行完整筛选,将候选区域放置到队列中  
  886.         for( pass = 0; pass < npass; pass++ )  
  887.         {  
  888.   
  889.             forint _iy = 0; _iy < stop_height; _iy++ )  
  890.             {     
  891.                 //检测窗口纵坐标步长为2,保持不变  
  892.                 int iy = (_iy*ystep32x+16)>>5;  
  893.                 int _ix, _xstep = 1;  
  894.                   
  895.                 //stop_width是指_ix迭代的上限,_ix还要*ystep32x才是真正的窗口坐标  
  896.                 int stop_width =( ((_img->cols - win_size.width)<<5) +ystep32x/2) / ystep32x;  
  897.                 unsigned char* mask_row = tmp.imgPtr + tmp.cols* iy;  
  898.                   
  899.                   
  900.                 for( _ix = 0; _ix < stop_width; _ix += _xstep )  
  901.                 {  
  902.                       
  903.                     //检测窗口横坐标按步长为4开始移动,若没有检测到目标,则改变下一次步长为2  
  904.                     int ix = (_ix*ystep32x+16)>>5; // it really should be ystep  
  905.                   
  906.                     //当前检测窗口左上角坐标  
  907.                     Point pt;  
  908.                     pt.x = ix;  
  909.                     pt.y = iy;  
  910.   
  911.                     //粗略检测  
  912.                     if( pass == 0 )  
  913.                     {  
  914.                           
  915.                         int result = 0;  
  916.                         _xstep = 2;  
  917.                       
  918.                         //start_time = _itoll(TSCH, TSCL);  
  919.                         result = RunHaarClassifierCascade( cascade, pt, 0 );  
  920.                         //end_time = _itoll(TSCH, TSCL);  
  921.                         //cyclecountRun += end_time-start_time-overhead;  
  922.                         if( result > 0 )  
  923.                         {  
  924.                             if( pass < npass - 1 )  
  925.                                 mask_row[ix] = 1;  
  926.                           
  927.                         }  
  928.                         //没有检测到改变步长为2(看ix的值)  
  929.                         if( result < 0 )  
  930.                             _xstep = 1;  
  931.                     }  
  932.                     //第二次检测先前粗定位的坐标  
  933.                     else if( mask_row[ix] )  
  934.                     {  
  935.                         //start_time = _itoll(TSCH, TSCL);  
  936.                         int result = RunHaarClassifierCascade(cascade, pt, stage_offset);  
  937.                     //  end_time = _itoll(TSCH, TSCL);  
  938.                     //  cyclecountRun += end_time-start_time-overhead;  
  939.                           
  940.                         //count2++;  
  941.                         //int result = 0;  
  942.                         if( result > 0 )  
  943.                         {  
  944.                             seq.rectQueue[seq.tail].height = win_size.height;  
  945.                             seq.rectQueue[seq.tail].width = win_size.width;  
  946.                             seq.rectQueue[seq.tail].x = ix;  
  947.                             seq.rectQueue[seq.tail].y = iy;  
  948.                             seq.total++;  
  949.                             seq.tail++;  
  950.                         }  
  951.                         else  
  952.                             mask_row[ix] = 0;  
  953.                           
  954.                 }  
  955.             }  
  956.   
  957.           
  958.         }  
  959.   
  960.         //因为前两个stage在第一次检测的时候已经用过;  
  961.         //第二次检测的时候,从第3个stage开始进行完整的检测  
  962.         stage_offset = cascade->hid_cascade->count;  
  963.         cascade->hid_cascade->count = cascade->count;  
  964.         //cascade->hid_cascade->count = 15;  
  965.     }  
  966.  }  
  967.   
  968.     //printf("The SetImage section took: %lld CPU cycles\n", cyclecountSet);  
  969. //  printf("The RunImage section took: %lld CPU cycles\n", cyclecountRun);  
  970. //  printf("The Block1 section took: %lld CPU cycles\n", block1);  
  971. //  printf("The Block2 section took: %lld CPU cycles\n", block2);  
  972.   
  973.     if( min_neighbors != 0 )  
  974.     {  
  975.       
  976.         //将候选目标按相似度构成并查集  
  977.         //返回值代表并查集树的个数  
  978.         int ncomp = SeqPartition(&seq);  
  979.       
  980.           
  981.           
  982.         //对相邻候选区域进行累加,为计算平均边界做准备  
  983.         for( i = 0; i < seq.total; i++ )  
  984.         {  
  985.             r1 = seq.rectQueue[i];  
  986.             node = &PTreeNodes[i];  
  987.             while(node->parent)  
  988.                 node = node->parent;  
  989.             int idx = (node - PTreeNodes);  
  990.              
  991.               
  992.             comps.neighbors[idx]++;  
  993.               
  994.             comps.rectQueue[idx].x += r1.x;  
  995.             comps.rectQueue[idx].y += r1.y;  
  996.             comps.rectQueue[idx].width += r1.width;  
  997.             comps.rectQueue[idx].height += r1.height;  
  998.         }  
  999.   
  1000.         // 计算平均目标边界  
  1001.         for( i = 0; i < seq.total; i++ )  
  1002.         {  
  1003.             int n = comps.neighbors[i];  
  1004.   
  1005.             //只有满足最小临接的结果才是最终结果  
  1006.             if( n >= min_neighbors )  
  1007.             {  
  1008.                 Rect* rect = &seq2.rectQueue[seq2.tail];  
  1009.                 rect->x = (comps.rectQueue[i].x*2 + n)/(2*n);  
  1010.                 rect->y = (comps.rectQueue[i].y*2 + n)/(2*n);  
  1011.                 rect->width = (comps.rectQueue[i].width*2 + n)/(2*n);  
  1012.                 rect->height = (comps.rectQueue[i].height*2 + n)/(2*n);  
  1013.                 seq2.neighbors[seq2.tail] = comps.neighbors[i];  
  1014.                 seq2.tail++;  
  1015.                 seq2.total++;  
  1016.             }  
  1017.         }  
  1018.   
  1019.   
  1020.         //从候选矩形中得到最大的矩形  
  1021.         for( i = 0; i < seq2.total; i++ )  
  1022.         {  
  1023.             r1 = seq2.rectQueue[i];  
  1024.             r1_neighbor = seq2.neighbors[i];  
  1025.             flag = 1;  
  1026.           
  1027.             for( j = 0; j < seq2.total; j++ )  
  1028.             {  
  1029.                 r2 = seq2.rectQueue[j];  
  1030.                 r2_neighbor = seq2.neighbors[j];  
  1031.                 distance = (r2.width *2+5)/10;//cvRound( r2.rect.width * 0.2 );  
  1032.                   
  1033.                 if( i != j &&  
  1034.                     r1.x >= r2.x - distance &&  
  1035.                     r1.y >= r2.y - distance &&  
  1036.                     r1.x + r1.width <= r2.x + r2.width + distance &&  
  1037.                     r1.y + r1.height <= r2.y + r2.height + distance &&  
  1038.                     (r2_neighbor > MAX( 3, r1_neighbor ) || r1_neighbor < 3) )  
  1039.                 {  
  1040.                     flag = 0;  
  1041.                     break;  
  1042.                 }  
  1043.             }  
  1044.               
  1045.             if( flag )  
  1046.             {  
  1047.                 result_seq.rectQueue[result_seq.tail] = r1;  
  1048.                 result_seq.tail++;  
  1049.                 result_seq.total++;  
  1050.                   
  1051.             }  
  1052.         }  
  1053.           
  1054.     }  
  1055.       
  1056. }  
  1057.   
  1058.   
  1059.   
  1060.   
  1061.   
  1062.   
  1063.   
  1064.   
  1065.   
  1066.   
  1067. void DownSample(Image* pImage, int factor)  
  1068. {  
  1069.     int i = 0;  
  1070.     int j = 0;  
  1071.     int counti = 0;  
  1072.     int countj = 0;  
  1073.   
  1074.     int step = pImage->cols / factor;  
  1075.     for (i =0; i < pImage->rows; i+= factor)  
  1076.     {  
  1077.         countj++;  
  1078.         for (j =0; j < pImage->cols; j += factor)  
  1079.         {  
  1080.             *(pImage->imgPtr + i*step/factor + j/factor) = *(pImage->imgPtr + i*pImage->cols + j);  
  1081.             counti++;  
  1082.         }  
  1083.         counti = 0;  
  1084.     }  
  1085.       
  1086.     pImage->cols /= factor;  
  1087.     pImage->rows /= factor;  
  1088. }  


 
 

Haar.h

[cpp]  view plain  copy
 
  1. #ifndef _HAAR_H_  
  2. #define _HAAR_H_  
  3. #include "Tables.h"  
  4.   
  5.   
  6. #define NODE_THRESHOLD_SHIFT 22  
  7.   
  8.   
  9. #define MAXHIDCASCADE 200000  //隐式级联分类器所占空间(字节)  
  10. #define MAXROWS   400     
  11. #define MAXCOLS   400     
  12. #define MAXSTAGES  22     
  13. #define MAXCLASSIFER  213  
  14. #define MAXTREENODE 2  
  15. #define MAXALPHA   2  
  16. #define MAXSEQS    25  
  17. #define MaxMatNum  2  
  18. #define RGBCHANNEL 3  
  19. #define BITS8         0x00000001  
  20. #define BITS32        0x00000010  
  21. #define BITS64        0x00000100  
  22.   
  23.   
  24.   
  25.   
  26. #define CV_8TO16U_SQR(x)  my8x16uSqrTab[(x)+128]  
  27. #define CLR_RESULT_QUEUE()  result_seq.tail = 0;\  
  28.                             result_seq.total = 0;   
  29.   
  30.   
  31.   
  32.   
  33. typedef unsigned char BYTE;  
  34.   
  35.   
  36. typedef long long _int64;  
  37. typedef unsigned char   (*ImgPtr);  
  38. typedef unsigned char   (*Mat8Ptr);  
  39. typedef int             (*Mat32Ptr);  
  40. typedef _int64          (*Mat64Ptr);  
  41.   
  42.   
  43. /*****************并查集数据结构*******************************/  
  44. #define MAXPTREENODES 100  
  45. typedef struct PTreeNode  
  46. {  
  47.     struct PTreeNode* parent;  
  48.     char* element;  
  49.     int rank;  
  50. }PTreeNode;  
  51.   
  52.   
  53. /************************积分图变量***************************/  
  54. typedef int sumtype;  
  55. typedef _int64 sqsumtype;  
  56.   
  57.   
  58. /************************************************************/  
  59. typedef struct Rect  
  60. {  
  61.        int x;  
  62.        int y;  
  63.        int width;  
  64.        int height;  
  65. }Rect;  
  66.   
  67.   
  68. typedef struct  
  69. {  
  70.     int width;  
  71.     int height;  
  72.   
  73.   
  74.   
  75.   
  76. }Size;  
  77.   
  78.   
  79. typedef struct Image  
  80. {  
  81.     ImgPtr  imgPtr;  
  82.     int rows;  
  83.     int cols;  
  84. }Image;  
  85.   
  86.   
  87. typedef struct Mat8  
  88. {  
  89.     Mat8Ptr  mat8Ptr;  
  90.     int rows;  
  91.     int cols;  
  92. }Mat8;  
  93. typedef struct Mat32  
  94. {  
  95.     Mat32Ptr  mat32Ptr;  
  96.     int rows;  
  97.     int cols;  
  98. }Mat32;  
  99.   
  100.   
  101. typedef struct Mat64  
  102. {  
  103.     Mat64Ptr  mat64Ptr;  
  104.     int rows;  
  105.     int cols;  
  106. }Mat64;  
  107.   
  108.   
  109.   
  110.   
  111.   
  112.   
  113. typedef struct Sequence  
  114. {  
  115.     int       total;   
  116.     Rect      rectQueue[MAXSEQS];  
  117.     int       neighbors[MAXSEQS];  
  118.     int       tail;  
  119. }Sequence;  
  120.   
  121.   
  122.   
  123.   
  124. //Haar特征的数量  
  125. #define CV_HAAR_FEATURE_MAX  3      
  126.   
  127.   
  128. /*************HidHaar to Caculation Feature***********************************/  
  129. typedef struct HidHaarFeature  
  130. {  
  131.     struct  
  132.     {  
  133.         sumtype *p0, *p1, *p2, *p3;  
  134.         int weight;  
  135.     }  
  136.     rect[CV_HAAR_FEATURE_MAX];  
  137. }HidHaarFeature;  
  138.   
  139.   
  140.   
  141.   
  142. typedef struct HidHaarTreeNode  
  143. {  
  144.     HidHaarFeature feature;  
  145.     int threshold;  
  146.     int left;  
  147.     int right;  
  148. }HidHaarTreeNode;  
  149.   
  150.   
  151.   
  152.   
  153. typedef struct HidHaarClassifier  
  154. {  
  155.     int count;  
  156.     //CvHaarFeature* orig_feature;  
  157.   
  158.   
  159.     HidHaarTreeNode* node;  
  160.     int* alpha;  
  161.     //HidHaarTreeNode node[MAXTREENODE];  
  162.     //int alpha[MAXALPHA];  
  163. }HidHaarClassifier;  
  164.   
  165.   
  166. typedef struct HidHaarStageClassifier  
  167. {  
  168.     int  count;  
  169.     int threshold;  
  170.     HidHaarClassifier* classifier;  
  171.     //HidHaarClassifier classifier[MAXCLASSIFER];  
  172.     int two_rects;  
  173.       
  174.     struct HidHaarStageClassifier* next;  
  175.     struct HidHaarStageClassifier* child;  
  176.     struct HidHaarStageClassifier* parent;  
  177. }HidHaarStageClassifier;  
  178.   
  179.   
  180.   
  181.   
  182. typedef struct HidHaarClassifierCascade  
  183. {  
  184.     int  count;  
  185.     int  is_stump_based;  
  186.     int  has_tilted_features;  
  187.     int  is_tree;  
  188.     int window_area;  
  189.     Mat32* sum;  
  190.     Mat64* sqsum;  
  191.     HidHaarStageClassifier* stage_classifier;  
  192.     //HidHaarStageClassifier stage_classifier[MAXSTAGES];  
  193.     sqsumtype *pq0, *pq1, *pq2, *pq3;  
  194.     sumtype *p0, *p1, *p2, *p3;  
  195.       
  196.     void** ipp_stages;  
  197. }HidHaarClassifierCascade;  
  198.   
  199.   
  200.   
  201.   
  202.   
  203.   
  204. /******************Haar Cascade*****************************************/  
  205. typedef struct HaarFeature  
  206. {  
  207.     int  tilted;  
  208.     struct  
  209.     {  
  210.         Rect r;  
  211.         int weight;  
  212.     } rect[CV_HAAR_FEATURE_MAX];  
  213. }HaarFeature;  
  214.   
  215.   
  216. typedef struct HaarClassifier  
  217. {  
  218.     int count;  
  219.     HaarFeature* haar_feature;  
  220.     int* threshold;  
  221.     int* left;  
  222.     int* right;  
  223.     int* alpha;  
  224. }HaarClassifier;  
  225.   
  226.   
  227. typedef struct HaarStageClassifier  
  228. {  
  229.     int  count;  
  230.     int threshold;  
  231.     HaarClassifier* classifier;  
  232.       
  233.     int next;  
  234.     int child;  
  235.     int parent;  
  236. }HaarStageClassifier;  
  237.   
  238.   
  239.   
  240.   
  241. typedef struct HaarClassifierCascade  
  242. {  
  243.     int  flags;  
  244.     int  count;  
  245.     Size orig_window_size;  
  246.     Size real_window_size;  
  247.     int scale32x;  
  248.     HaarStageClassifier* stage_classifier;  
  249.     HidHaarClassifierCascade* hid_cascade;  
  250. }HaarClassifierCascade;  
  251.   
  252.   
  253.   
  254.   
  255.   
  256.   
  257. typedef struct CvAvgComp  
  258. {  
  259.     Rect rect;  
  260.     int neighbors;  
  261. }  
  262. CvAvgComp;  
  263.   
  264.   
  265.   
  266.   
  267. typedef struct Point  
  268. {  
  269.     int x;  
  270.     int y;  
  271. }Point;  
  272.   
  273.   
  274.   
  275.   
  276.   
  277.   
  278. /******************全局变量****************************************/  
  279. //cascade  
  280. extern HaarClassifierCascade *cascade ;  
  281. //extern HidHaarClassifierCascade hid_cascade;  
  282.   
  283.   
  284. //32bits cell Mat  
  285. extern int            MatPool32[MaxMatNum][MAXROWS][MAXCOLS];  
  286. //8bits cell   
  287. extern unsigned char  MatPool8[MaxMatNum][MAXROWS][MAXCOLS];  
  288.   
  289.   
  290. //8bits*3 cell   
  291. extern unsigned char  ImgRGBPool8[MaxMatNum][RGBCHANNEL][MAXROWS][MAXCOLS];  
  292. //64bits float cell   
  293. extern _int64    MatPool64[MaxMatNum][MAXROWS][MAXCOLS];  
  294.   
  295.   
  296.   
  297.   
  298.   
  299.   
  300. //分类器检测结果区域序列  
  301. extern Sequence result_seq;  
  302.   
  303.   
  304. /********************全局函数******************************************/  
  305. extern void ReadFaceCascade();  
  306. extern void HaarDetectObjects(Image* _img,HaarClassifierCascade* cascade,     
  307.                               char* storage, int scale_factor32x,  
  308.                               int min_neighbors, int flags, Size minSize);  
  309. #endif  

你可能感兴趣的:(源码,adaboost,haar)