cvHaarDetectObjects代码

  1. CV_IMPL CvSeq*  
  2. cvHaarDetectObjects( const CvArr* _img,   
  3.                      CvHaarClassifierCascade* cascade,  
  4.                      CvMemStorage* storage, double scale_factor,  
  5.                      int min_neighbors, int flags, CvSize min_size )  
  6. {  
  7.     int split_stage = 2;  
  8.    
  9.     CvMat stub, *img = (CvMat*)_img;                                                           //CvMat多通道矩阵  *img=_img指针代换传入图  
  10.     CvMat *temp = 0, *sum = 0, *tilted = 0, *sqsum = 0, *norm_img = 0, *sumcanny = 0, *img_small = 0;  
  11.     CvSeq* seq = 0;  
  12.     CvSeq* seq2 = 0;                                                                           //CvSeq可动态增长元素序列  
  13.     CvSeq* idx_seq = 0;  
  14.     CvSeq* result_seq = 0;  
  15.     CvMemStorage* temp_storage = 0;  
  16.     CvAvgComp* comps = 0;  
  17.     int i;  
  18.      
  19. #ifdef _OPENMP  
  20.     CvSeq* seq_thread[CV_MAX_THREADS] = {0};  
  21.     int max_threads = 0;  
  22. #endif  
  23.      
  24.     CV_FUNCNAME( “cvHaarDetectObjects” );  
  25.    
  26.     __BEGIN__;  
  27.    
  28.     double factor;  
  29.     int npass = 2, coi;                                                                                                                 //npass=2  
  30.     int do_canny_pruning = flags & CV_HAAR_DO_CANNY_PRUNING;                 //true做canny边缘处理  
  31.    
  32.     if( !CV_IS_HAAR_CLASSIFIER(cascade) )  
  33.         CV_ERROR( !cascade ? CV_StsNullPtr : CV_StsBadArg, “Invalid classifier cascade” );  
  34.    
  35.     if( !storage )  
  36.         CV_ERROR( CV_StsNullPtr, “Null storage pointer” );  
  37.    
  38.     CV_CALL( img = cvGetMat( img, &stub, &coi ));  
  39.     if( coi )  
  40.         CV_ERROR( CV_BadCOI, “COI is not supported” );                                    //一些出错代码  
  41.    
  42.     if( CV_MAT_DEPTH(img->type) != CV_8U )  
  43.         CV_ERROR( CV_StsUnsupportedFormat, “Only 8-bit images are supported” );  
  44.    
  45.     CV_CALL( temp = cvCreateMat( img->rows, img->cols, CV_8UC1 ));  
  46.     CV_CALL( sum = cvCreateMat( img->rows + 1, img->cols + 1, CV_32SC1 ));  
  47.     CV_CALL( sqsum = cvCreateMat( img->rows + 1, img->cols + 1, CV_64FC1 ));  
  48.     CV_CALL( temp_storage = cvCreateChildMemStorage( storage ));  
  49.    
  50. #ifdef _OPENMP  
  51.     max_threads = cvGetNumThreads();  
  52.     for( i = 0; i < max_threads; i++ )  
  53.     {  
  54.         CvMemStorage* temp_storage_thread;  
  55.         CV_CALL( temp_storage_thread = cvCreateMemStorage(0));                 //CV_CALL就是运行,假如出错就报错。  
  56.         CV_CALL( seq_thread[i] = cvCreateSeq( 0, sizeof(CvSeq),                //CvSeq可动态增长元素序列  
  57.    
  58.                         sizeof(CvRect), temp_storage_thread ));  
  59.     }  
  60. #endif  
  61.    
  62.     if( !cascade->hid_cascade )  
  63.         CV_CALL( icvCreateHidHaarClassifierCascade(cascade) );  
  64.    
  65.     if( cascade->hid_cascade->has_tilted_features )  
  66.         tilted = cvCreateMat( img->rows + 1, img->cols + 1, CV_32SC1 );         //多通道矩阵 图像长宽+1 4通道  
  67.    
  68.     seq = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvRect), temp_storage );        //创建序列seq  矩形  
  69.     seq2 = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvAvgComp), temp_storage );    //创建序列seq2  矩形和邻近  
  70.     result_seq = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvAvgComp), storage );   //创建序列result_seq  矩形和邻近  
  71.    
  72.     if( min_neighbors == 0 )  
  73.         seq = result_seq;  
  74.    
  75.     if( CV_MAT_CN(img->type) > 1 )  
  76.     {  
  77.         cvCvtColor( img, temp, CV_BGR2GRAY );                                  //img转为灰度  
  78.         img = temp;                                                                                                                                  
  79.     }  
  80.      
  81.     if( flags & CV_HAAR_SCALE_IMAGE )                                                                                        //flag && 匹配图  
  82.     {  
  83.         CvSize win_size0 = cascade->orig_window_size;                         //CvSize win_size0为分类器的原始大小  
  84.         int use_ipp = cascade->hid_cascade->ipp_stages != 0 &&                
  85.                     icvApplyHaarClassifier_32s32f_C1R_p != 0;                 //IPP相关函数  
  86.    
  87.         if( use_ipp )  
  88.             CV_CALL( norm_img = cvCreateMat( img->rows, img->cols, CV_32FC1 ));           //图像的矩阵化 4通道.  
  89.         CV_CALL( img_small = cvCreateMat( img->rows + 1, img->cols + 1, CV_8UC1 ));       //小图矩阵化 单通道 长宽+1  
  90.    
  91.         for( factor = 1; ; factor *= scale_factor )                                       //成scale_factor倍数匹配  
  92.         {  
  93.             int positive = 0;  
  94.             int x, y;  
  95.             CvSize win_size = { cvRound(win_size0.width*factor),  
  96.                                 cvRound(win_size0.height*factor) };                      //winsize         分类器行列(扩大factor倍)          
  97.             CvSize sz = { cvRound( img->cols/factor ), cvRound( img->rows/factor ) };     //sz 图像行列(缩小factor倍)               三个Cvsize  
  98.             CvSize sz1 = { sz.width – win_size0.width, sz.height – win_size0.height };    //sz1 图像 减分类器行列  
  99.             CvRect rect1 = { icv_object_win_border, icv_object_win_border,  
  100.                 win_size0.width – icv_object_win_border*2,                                //icv_object_win_border (int) 初始值=1  
  101.                 win_size0.height – icv_object_win_border*2 };                                  //矩形框rect1  
  102.             CvMat img1, sum1, sqsum1, norm1, tilted1, mask1;                              //多通道矩阵  
  103.             CvMat* _tilted = 0;  
  104.    
  105.             if( sz1.width <= 0 || sz1.height <= 0 )                                       //图片宽或高小于分类器–>跳出  
  106.                 break;  
  107.             if( win_size.width < min_size.width || win_size.height < min_size.height )    //分类器高或宽小于给定的mini_size的高或宽–>继续  
  108.                 continue;  
  109. //CV_8UC1见定义.  
  110. //#define CV_MAKETYPE(depth,cn) ((depth) + (((cn)-1) << CV_CN_SHIFT))     
  111. //深度+(cn-1)左移3位   depth,depth+8,depth+16,depth+24.  
  112.             img1 = cvMat( sz.height, sz.width, CV_8UC1, img_small->data.ptr );            //小图的矩阵化 img1 单通道      
  113.             sum1 = cvMat( sz.height+1, sz.width+1, CV_32SC1, sum->data.ptr );             //长宽+1 4通道8位            多通道矩阵  
  114.             sqsum1 = cvMat( sz.height+1, sz.width+1, CV_64FC1, sqsum->data.ptr );         //长宽+1 4通道16位  
  115.             if( tilted )  
  116.             {  
  117.                 tilted1 = cvMat( sz.height+1, sz.width+1, CV_32SC1, tilted->data.ptr );   //长宽+1 4通道8位  
  118.                 _tilted = &tilted1;                                                                  //长宽+1 4通道8位  
  119.             }  
  120.             norm1 = cvMat( sz1.height, sz1.width, CV_32FC1, norm_img ? norm_img->data.ptr : 0 ); //norm1 图像 减 分类器行列 4通道  
  121.             mask1 = cvMat( sz1.height, sz1.width, CV_8UC1, temp->data.ptr );                     //mask1 灰度图  
  122.    
  123.             cvResize( img, &img1, CV_INTER_LINEAR );                                      //img双线性插值 输出到img1  
  124.             cvIntegral( &img1, &sum1, &sqsum1, _tilted );                                                                  //计算积分图像  
  125.    
  126.             if( use_ipp && icvRectStdDev_32s32f_C1R_p( sum1.data.i, sum1.step,  
  127.                 sqsum1.data.db, sqsum1.step, norm1.data.fl, norm1.step, sz1, rect1 ) < 0 )  
  128.                 use_ipp = 0;  
  129.    
  130.             if( use_ipp )                                                                                 //如果ipp=true   (intel视频处理加速等的函数库)  
  131.             {  
  132.                 positive = mask1.cols*mask1.rows;                                                                                  //mask1长乘宽–>positive  
  133.                 cvSet( &mask1, cvScalarAll(255) );                                                                                  //mask1赋值为255  
  134.                 for( i = 0; i < cascade->count; i++ )  
  135.                 {  
  136.                     if( icvApplyHaarClassifier_32s32f_C1R_p(sum1.data.i, sum1.step,  
  137.                         norm1.data.fl, norm1.step, mask1.data.ptr, mask1.step,  
  138.                         sz1, &positive, cascade->hid_cascade->stage_classifier[i].threshold,  
  139.                         cascade->hid_cascade->ipp_stages[i]) < 0 )  
  140.                     {  
  141.                         use_ipp = 0;                                                                         //ipp=false;  
  142.                         break;  
  143.                     }  
  144.                     if( positive <= 0 )  
  145.                         break;  
  146.                 }  
  147.             }  
  148.              
  149.             if( !use_ipp )                                                                                         //如果ipp=false  
  150.             {  
  151.                 cvSetImagesForHaarClassifierCascade( cascade, &sum1, &sqsum1, 0, 1. );  
  152.                 for( y = 0, positive = 0; y < sz1.height; y++ )  
  153.                     for( x = 0; x < sz1.width; x++ )  
  154.                     {  
  155.                         mask1.data.ptr[mask1.step*y + x] =  
  156.                             cvRunHaarClassifierCascade( cascade, cvPoint(x,y), 0 ) > 0;   //匹配图像.  
  157.                         positive += mask1.data.ptr[mask1.step*y + x];  
  158.                     }  
  159.             }  
  160.    
  161.             if( positive > 0 )  
  162.             {  
  163.                 for( y = 0; y < sz1.height; y++ )  
  164.                     for( x = 0; x < sz1.width; x++ )  
  165.                         if( mask1.data.ptr[mask1.step*y + x] != 0 )  
  166.                         {  
  167.                             CvRect obj_rect = { cvRound(y*factor), cvRound(x*factor),      
  168.                                                 win_size.width, win_size.height };  
  169.                             cvSeqPush( seq, &obj_rect );                                        //将匹配块放到seq中  
  170.                         }  
  171.             }  
  172.         }  
  173.     }  
  174.     else                                                                                                        //!(flag && 匹配图)  
  175.     {  
  176.         cvIntegral( img, sum, sqsum, tilted );  
  177.      
  178.         if( do_canny_pruning )  
  179.         {  
  180.             sumcanny = cvCreateMat( img->rows + 1, img->cols + 1, CV_32SC1 );                  //如果 做canny边缘检测  
  181.             cvCanny( img, temp, 0, 50, 3 );  
  182.             cvIntegral( temp, sumcanny );  
  183.         }  
  184.      
  185.         if( (unsigned)split_stage >= (unsigned)cascade->count ||  
  186.             cascade->hid_cascade->is_tree )                                                                                                                  
  187.         {  
  188.             split_stage = cascade->count;  
  189.             npass = 1;  
  190.         }  
  191.    
  192.         for( factor = 1; factor*cascade->orig_window_size.width < img->cols – 10 &&                                //匹配  
  193.                          factor*cascade->orig_window_size.height < img->rows – 10;  
  194.              factor *= scale_factor )  
  195.         {  
  196.             const double ystep = MAX( 2, factor );  
  197.             CvSize win_size = { cvRound( cascade->orig_window_size.width * factor ),  
  198.                                 cvRound( cascade->orig_window_size.height * factor )};  
  199.             CvRect equ_rect = { 0, 0, 0, 0 };  
  200.             int *p0 = 0, *p1 = 0, *p2 = 0, *p3 = 0;  
  201.             int *pq0 = 0, *pq1 = 0, *pq2 = 0, *pq3 = 0;  
  202.             int pass, stage_offset = 0;  
  203.             int stop_height = cvRound((img->rows – win_size.height) / ystep);  
  204.    
  205.             if( win_size.width < min_size.width || win_size.height < min_size.height )                        //超边跳出  
  206.                 continue;  
  207.    
  208.             cvSetImagesForHaarClassifierCascade( cascade, sum, sqsum, tilted, factor );                        //匹配  
  209.             cvZero( temp );                                                                                                //清空temp数组  
  210.    
  211.             if( do_canny_pruning )                                                                                        //canny边缘检测  
  212.             {  
  213.                 equ_rect.x = cvRound(win_size.width*0.15);  
  214.                 equ_rect.y = cvRound(win_size.height*0.15);  
  215.                 equ_rect.width = cvRound(win_size.width*0.7);  
  216.                 equ_rect.height = cvRound(win_size.height*0.7);  
  217.    
  218.                 p0 = (int*)(sumcanny->data.ptr + equ_rect.y*sumcanny->step) + equ_rect.x;  
  219.                 p1 = (int*)(sumcanny->data.ptr + equ_rect.y*sumcanny->step)  
  220.                             + equ_rect.x + equ_rect.width;  
  221.                 p2 = (int*)(sumcanny->data.ptr + (equ_rect.y + equ_rect.height)*sumcanny->step) + equ_rect.x;  
  222.                 p3 = (int*)(sumcanny->data.ptr + (equ_rect.y + equ_rect.height)*sumcanny->step)  
  223.                             + equ_rect.x + equ_rect.width;  
  224.    
  225.                 pq0 = (int*)(sum->data.ptr + equ_rect.y*sum->step) + equ_rect.x;  
  226.                 pq1 = (int*)(sum->data.ptr + equ_rect.y*sum->step)  
  227.                             + equ_rect.x + equ_rect.width;  
  228.                 pq2 = (int*)(sum->data.ptr + (equ_rect.y + equ_rect.height)*sum->step) + equ_rect.x;  
  229.                 pq3 = (int*)(sum->data.ptr + (equ_rect.y + equ_rect.height)*sum->step)  
  230.                             + equ_rect.x + equ_rect.width;  
  231.             }  
  232.    
  233.             cascade->hid_cascade->count = split_stage;                                                //分裂级  
  234.    
  235.             for( pass = 0; pass < npass; pass++ )  
  236.             {  
  237. #ifdef _OPENMP  
  238.     #pragma omp parallel for num_threads(max_threads), schedule(dynamic)  
  239. #endif  
  240.                 forint _iy = 0; _iy < stop_height; _iy++ )  
  241.                 {  
  242.                     int iy = cvRound(_iy*ystep);  
  243.                     int _ix, _xstep = 1;  
  244.                     int stop_width = cvRound((img->cols – win_size.width) / ystep);  
  245.                     uchar* mask_row = temp->data.ptr + temp->step * iy;  
  246.    
  247.                     for( _ix = 0; _ix < stop_width; _ix += _xstep )  
  248.                     {  
  249.                         int ix = cvRound(_ix*ystep); // it really should be ystep  
  250.                      
  251.                         if( pass == 0 )                                                   //第一次循环 做  
  252.                         {  
  253.                             int result;  
  254.                             _xstep = 2;  
  255.    
  256.                             if( do_canny_pruning )                                                        //canny边缘检测  
  257.                             {  
  258.                                 int offset;  
  259.                                 int s, sq;  
  260.                          
  261.                                 offset = iy*(sum->step/sizeof(p0[0])) + ix;  
  262.                                 s = p0[offset] – p1[offset] – p2[offset] + p3[offset];  
  263.                                 sq = pq0[offset] – pq1[offset] – pq2[offset] + pq3[offset];  
  264.                                 if( s < 100 || sq < 20 )  
  265.                                     continue;  
  266.                             }  
  267.    
  268.                             result = cvRunHaarClassifierCascade( cascade, cvPoint(ix,iy), 0 );                //匹配结果存到result里  
  269.                             if( result > 0 )  
  270.                             {  
  271.                                 if( pass < npass – 1 )  
  272.                                     mask_row[ix] = 1;  
  273.                                 else  
  274.                                 {  
  275.                                     CvRect rect = cvRect(ix,iy,win_size.width,win_size.height);  
  276. #ifndef _OPENMP                                                                                                        //如果用OpenMP  
  277.                                     cvSeqPush( seq, &rect );                                                        //result 放到seq中  
  278. #else                                                                                                                        //如果不用OpenMP  
  279.                                     cvSeqPush( seq_thread[omp_get_thread_num()], &rect );                        //result放到seq_thread里  
  280. #endif  
  281.                                 }  
  282.                             }  
  283.                             if( result < 0 )  
  284.                                 _xstep = 1;  
  285.                         }  
  286.                         else if( mask_row[ix] )                     //不是第一次  
  287.                         {  
  288.                             int result = cvRunHaarClassifierCascade( cascade, cvPoint(ix,iy),  
  289.                                                                      stage_offset );  
  290.                             if( result > 0 )  
  291.                             {  
  292.                                 if( pass == npass – 1 )          //如果是最后一次  
  293.                                 {  
  294.                                     CvRect rect = cvRect(ix,iy,win_size.width,win_size.height);  
  295. #ifndef _OPENMP  
  296.                                     cvSeqPush( seq, &rect );  
  297. #else  
  298.                                     cvSeqPush( seq_thread[omp_get_thread_num()], &rect );  
  299. #endif  
  300.                                 }  
  301.                             }  
  302.                             else  
  303.                                 mask_row[ix] = 0;  
  304.                         }  
  305.                     }  
  306.                 }  
  307.                 stage_offset = cascade->hid_cascade->count;  
  308.                 cascade->hid_cascade->count = cascade->count;  
  309.             }  
  310.         }  
  311.     }  
  312.    
  313. #ifdef _OPENMP  
  314. // gather the results                                               //收集结果  
  315. for( i = 0; i < max_threads; i++ )  
  316. {  
  317. CvSeq* s = seq_thread[i];  
  318.         int j, total = s->total;  
  319.         CvSeqBlock* b = s->first;  
  320.         for( j = 0; j < total; j += b->count, b = b->next )  
  321.             cvSeqPushMulti( seq, b->data, b->count );                  //结果输出到seq  
  322. }  
  323. #endif  
  324.    
  325.     if( min_neighbors != 0 )  
  326.     {  
  327.         // group retrieved rectangles in order to filter out noise         收集找出的匹配块,过滤噪声  
  328.         int ncomp = cvSeqPartition( seq, 0, &idx_seq, is_equal, 0 );  
  329.         CV_CALL( comps = (CvAvgComp*)cvAlloc( (ncomp+1)*sizeof(comps[0])));  
  330.         memset( comps, 0, (ncomp+1)*sizeof(comps[0]));  
  331.    
  332.         // count number of neighbors                                   计算相邻个数  
  333.         for( i = 0; i < seq->total; i++ )  
  334.         {  
  335.             CvRect r1 = *(CvRect*)cvGetSeqElem( seq, i );  
  336.             int idx = *(int*)cvGetSeqElem( idx_seq, i );  
  337.             assert( (unsigned)idx < (unsigned)ncomp );  
  338.    
  339.             comps[idx].neighbors++;  
  340.               
  341.             comps[idx].rect.x += r1.x;  
  342.             comps[idx].rect.y += r1.y;  
  343.             comps[idx].rect.width += r1.width;  
  344.             comps[idx].rect.height += r1.height;  
  345.         }  
  346.    
  347.         // calculate average bounding box                                    计算重心  
  348.         for( i = 0; i < ncomp; i++ )  
  349.         {  
  350.             int n = comps[i].neighbors;  
  351.             if( n >= min_neighbors )  
  352.             {  
  353.                 CvAvgComp comp;  
  354.                 comp.rect.x = (comps[i].rect.x*2 + n)/(2*n);  
  355.                 comp.rect.y = (comps[i].rect.y*2 + n)/(2*n);  
  356.                 comp.rect.width = (comps[i].rect.width*2 + n)/(2*n);  
  357.                 comp.rect.height = (comps[i].rect.height*2 + n)/(2*n);  
  358.                 comp.neighbors = comps[i].neighbors;  
  359.    
  360.                 cvSeqPush( seq2, &comp );                                   //结果输入到seq2  
  361.             }  
  362.         }  
  363.    
  364.         // filter out small face rectangles inside large face rectangles                在大的面块中找出小的面块  
  365.         for( i = 0; i < seq2->total; i++ )                                                                                //在seq2中寻找  
  366.         {  
  367.             CvAvgComp r1 = *(CvAvgComp*)cvGetSeqElem( seq2, i );                //r1指向结果  
  368.             int j, flag = 1;  
  369.    
  370.             for( j = 0; j < seq2->total; j++ )  
  371.             {  
  372.                 CvAvgComp r2 = *(CvAvgComp*)cvGetSeqElem( seq2, j );  
  373.                 int distance = cvRound( r2.rect.width * 0.2 );  
  374.              
  375.                 if( i != j &&  
  376.                     r1.rect.x >= r2.rect.x – distance &&  
  377.                     r1.rect.y >= r2.rect.y – distance &&  
  378.                     r1.rect.x + r1.rect.width <= r2.rect.x + r2.rect.width + distance &&  
  379.                     r1.rect.y + r1.rect.height <= r2.rect.y + r2.rect.height + distance &&  
  380.                     (r2.neighbors > MAX( 3, r1.neighbors ) || r1.neighbors < 3) )  
  381.                 {  
  382.                     flag = 0;  
  383.                     break;  
  384.                 }  
  385.             }  
  386.    
  387.             if( flag )  
  388.             {  
  389.                 cvSeqPush( result_seq, &r1 );      //添加r1到返回结果.  
  390.                  
  391.             }  
  392.         }  
  393.     }  
  394.    
  395.     __END__; 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值