train_cascade 源码阅读之Haar特征

下面片段是生成用于在积分图中的矩形块的坐标,Feature类中存的是在积分图矩阵中的初始偏移量,矩形的左上角坐标和宽高,以及是否旋转。不同类型的Haar特征已经在代码中体现的很明确了,故不赘述。
[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:14px;">void CvHaarEvaluator::generateFeatures()  
  2. {  
  3.     int mode = ((const CvHaarFeatureParams*)((CvFeatureParams*)featureParams))->mode;  
  4.     int offset = winSize.width + 1;  
  5.     forint x = 0; x < winSize.width; x++ )  
  6.     {  
  7.         forint y = 0; y < winSize.height; y++ )  
  8.         {  
  9.             forint dx = 1; dx <= winSize.width; dx++ )  
  10.             {  
  11.                 forint dy = 1; dy <= winSize.height; dy++ )  
  12.                 {  
  13.                     // haar_x2  
  14.                     if ( (x+dx*2 <= winSize.width) && (y+dy <= winSize.height) )  
  15.                     {  
  16.                         features.push_back( Feature( offset, false,  
  17.                             x,    y, dx*2, dy, -1,  
  18.                             x+dx, y, dx  , dy, +2 ) );  
  19.                     }  
  20.                     // haar_y2  
  21.                     if ( (x+dx <= winSize.width) && (y+dy*2 <= winSize.height) )  
  22.                     {  
  23.                         features.push_back( Feature( offset, false,  
  24.                             x,    y, dx, dy*2, -1,  
  25.                             x, y+dy, dx, dy,   +2 ) );  
  26.                     }  
  27.                     // haar_x3  
  28.                     if ( (x+dx*3 <= winSize.width) && (y+dy <= winSize.height) )  
  29.                     {  
  30.                         features.push_back( Feature( offset, false,  
  31.                             x,    y, dx*3, dy, -1,  
  32.                             x+dx, y, dx  , dy, +3 ) );  
  33.                     }  
  34.                     // haar_y3  
  35.                     if ( (x+dx <= winSize.width) && (y+dy*3 <= winSize.height) )  
  36.                     {  
  37.                         features.push_back( Feature( offset, false,  
  38.                             x, y,    dx, dy*3, -1,  
  39.                             x, y+dy, dx, dy,   +3 ) );  
  40.                     }  
  41.                     if( mode != CvHaarFeatureParams::BASIC )  
  42.                     {  
  43.                         // haar_x4  
  44.                         if ( (x+dx*4 <= winSize.width) && (y+dy <= winSize.height) )  
  45.                         {  
  46.                             features.push_back( Feature( offset, false,  
  47.                                 x,    y, dx*4, dy, -1,  
  48.                                 x+dx, y, dx*2, dy, +2 ) );  
  49.                         }  
  50.                         // haar_y4  
  51.                         if ( (x+dx <= winSize.width ) && (y+dy*4 <= winSize.height) )  
  52.                         {  
  53.                             features.push_back( Feature( offset, false,  
  54.                                 x, y,    dx, dy*4, -1,  
  55.                                 x, y+dy, dx, dy*2, +2 ) );  
  56.                         }  
  57.                     }  
  58.                     // x2_y2  
  59.                     if ( (x+dx*2 <= winSize.width) && (y+dy*2 <= winSize.height) )  
  60.                     {  
  61.                         features.push_back( Feature( offset, false,  
  62.                             x,    y,    dx*2, dy*2, -1,  
  63.                             x,    y,    dx,   dy,   +2,  
  64.                             x+dx, y+dy, dx,   dy,   +2 ) );  
  65.                     }  
  66.                     if (mode != CvHaarFeatureParams::BASIC)  
  67.                     {  
  68.                         if ( (x+dx*3 <= winSize.width) && (y+dy*3 <= winSize.height) )  
  69.                         {  
  70.                             features.push_back( Feature( offset, false,  
  71.                                 x   , y   , dx*3, dy*3, -1,  
  72.                                 x+dx, y+dy, dx  , dy  , +9) );  
  73.                         }  
  74.                     }  
  75.                     if (mode == CvHaarFeatureParams::ALL)  
  76.                     {  
  77.                         // tilted haar_x2  
  78.                         if ( (x+2*dx <= winSize.width) && (y+2*dx+dy <= winSize.height) && (x-dy>= 0) )  
  79.                         {  
  80.                             features.push_back( Feature( offset, true,  
  81.                                 x, y, dx*2, dy, -1,  
  82.                                 x, y, dx,   dy, +2 ) );  
  83.                         }  
  84.                         // tilted haar_y2  
  85.                         if ( (x+dx <= winSize.width) && (y+dx+2*dy <= winSize.height) && (x-2*dy>= 0) )  
  86.                         {  
  87.                             features.push_back( Feature( offset, true,  
  88.                                 x, y, dx, 2*dy, -1,  
  89.                                 x, y, dx, dy,   +2 ) );  
  90.                         }  
  91.                         // tilted haar_x3  
  92.                         if ( (x+3*dx <= winSize.width) && (y+3*dx+dy <= winSize.height) && (x-dy>= 0) )  
  93.                         {  
  94.                             features.push_back( Feature( offset, true,  
  95.                                 x,    y,    dx*3, dy, -1,  
  96.                                 x+dx, y+dx, dx,   dy, +3 ) );  
  97.                         }  
  98.                         // tilted haar_y3  
  99.                         if ( (x+dx <= winSize.width) && (y+dx+3*dy <= winSize.height) && (x-3*dy>= 0) )  
  100.                         {  
  101.                             features.push_back( Feature( offset, true,  
  102.                                 x,    y,    dx, 3*dy, -1,  
  103.                                 x-dy, y+dy, dx, dy,   +3 ) );  
  104.                         }  
  105.                         // tilted haar_x4  
  106.                         if ( (x+4*dx <= winSize.width) && (y+4*dx+dy <= winSize.height) && (x-dy>= 0) )  
  107.                         {  
  108.                             features.push_back( Feature( offset, true,  
  109.                                 x,    y,    dx*4, dy, -1,  
  110.                                 x+dx, y+dx, dx*2, dy, +2 ) );  
  111.                         }  
  112.                         // tilted haar_y4  
  113.                         if ( (x+dx <= winSize.width) && (y+dx+4*dy <= winSize.height) && (x-4*dy>= 0) )  
  114.                         {  
  115.                             features.push_back( Feature( offset, true,  
  116.                                 x,    y,    dx, 4*dy, -1,  
  117.                                 x-dy, y+dy, dx, 2*dy, +2 ) );  
  118.                         }  
  119.                     }  
  120.                 }  
  121.             }  
  122.         }  
  123.     }  
  124.     numFeatures = (int)features.size();  
  125. }</span>  
接着,在 CvHaarEvaluator::Feature构造函数中,对刚刚求得的坐标做了偏移量上的转换。
[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:14px;">CvHaarEvaluator::Feature::Feature( int offset, bool _tilted,  
  2.                                           int x0, int y0, int w0, int h0, float wt0,  
  3.                                           int x1, int y1, int w1, int h1, float wt1,  
  4.                                           int x2, int y2, int w2, int h2, float wt2 )  
  5. {  
  6.     tilted = _tilted;  
  7.   
  8.     rect[0].r.x = x0;  
  9.     rect[0].r.y = y0;  
  10.     rect[0].r.width  = w0;  
  11.     rect[0].r.height = h0;  
  12.     rect[0].weight   = wt0;  
  13.   
  14.     rect[1].r.x = x1;  
  15.     rect[1].r.y = y1;  
  16.     rect[1].r.width  = w1;  
  17.     rect[1].r.height = h1;  
  18.     rect[1].weight   = wt1;  
  19.   
  20.     rect[2].r.x = x2;  
  21.     rect[2].r.y = y2;  
  22.     rect[2].r.width  = w2;  
  23.     rect[2].r.height = h2;  
  24.     rect[2].weight   = wt2;  
  25.   
  26.     if( !tilted )  
  27.     {  
  28.         forint j = 0; j < CV_HAAR_FEATURE_MAX; j++ )  
  29.         {  
  30.             if( rect[j].weight == 0.0F )  
  31.                 break;  
  32.             CV_SUM_OFFSETS( fastRect[j].p0, fastRect[j].p1,   
  33.                             fastRect[j].p2, fastRect[j].p3, rect[j].r, offset )  
  34.         }  
  35.     }  
  36.     else  
  37.     {  
  38.         forint j = 0; j < CV_HAAR_FEATURE_MAX; j++ )  
  39.         {  
  40.             if( rect[j].weight == 0.0F )  
  41.                 break;  
  42.             CV_TILTED_OFFSETS( fastRect[j].p0, fastRect[j].p1,   
  43.                                fastRect[j].p2, fastRect[j].p3, rect[j].r, offset )  
  44.         }  
  45.     }  
  46. }  
  47. </span>  
CV_SUM_OFFSET和CV_TILTED_OFFSET是计算偏移量的宏,它们将左上角点和宽高转换成在单行sum或者tilted矩阵中的位置。sum矩阵的求法和LBP中是一样的,也是利用了OpenCV自带的cv::integral函数,而斜45度的矩阵也没有用到旋转图像之类的操作,而是…嗯,还是integral函数,自带重载功能,实现了45度倾斜操作。
[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:14px;">void CvHaarEvaluator::setImage(const Mat& img, uchar clsLabel, int idx)  
  2. {  
  3.     CV_DbgAssert( !sum.empty() && !tilted.empty() && !normfactor.empty() );  
  4.     CvFeatureEvaluator::setImage( img, clsLabel, idx);  
  5.     Mat innSum(winSize.height + 1, winSize.width + 1, sum.type(), sum.ptr<int>((int)idx));  
  6.     Mat innTilted(winSize.height + 1, winSize.width + 1, tilted.type(), tilted.ptr<int>((int)idx));  
  7.     Mat innSqSum;  
  8.     integral(img, innSum, innSqSum, innTilted);  
  9.     normfactor.ptr<float>(0)[idx] = calcNormFactor( innSum, innSqSum );  
  10. }</span>  
归一化因子计算如下:
[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:14px;">float calcNormFactor( const Mat& sum, const Mat& sqSum )  
  2. {  
  3.     CV_DbgAssert( sum.cols > 3 && sqSum.rows > 3 );  
  4.     Rect normrect( 1, 1, sum.cols - 3, sum.rows - 3 );  
  5.     size_t p0, p1, p2, p3;  
  6.     CV_SUM_OFFSETS( p0, p1, p2, p3, normrect, sum.step1() )  
  7.     double area = normrect.width * normrect.height;  
  8.     const int *sp = (const int*)sum.data;  
  9.     int valSum = sp[p0] - sp[p1] - sp[p2] + sp[p3];  
  10.     const double *sqp = (const double *)sqSum.data;  
  11.     double valSqSum = sqp[p0] - sqp[p1] - sqp[p2] + sqp[p3];  
  12.     return (float) sqrt( (double) (area * valSqSum - (double)valSum * valSum) );  
  13. }</span>  

SqSum是平方积分图。
最后,不同小块乘上权重系数,作为Haar特征值。
[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:14px;">inline float CvHaarEvaluator::Feature::calc(  
  2.         const cv::Mat &_sum,  
  3.         const cv::Mat &_tilted,  
  4.         size_t y) const  
  5. {  
  6.     const int* img = tilted ?  
  7.                 _tilted.ptr<int>((int)y) : _sum.ptr<int>((int)y);  
  8.     float ret = rect[0].weight * (  
  9.                 img[fastRect[0].p0]  
  10.             - img[fastRect[0].p1]  
  11.             - img[fastRect[0].p2]  
  12.             + img[fastRect[0].p3] ) +  
  13.             rect[1].weight * (  
  14.                 img[fastRect[1].p0]  
  15.             - img[fastRect[1].p1]  
  16.             - img[fastRect[1].p2]  
  17.             + img[fastRect[1].p3] );  
  18.     if( rect[2].weight != 0.0f )  
  19.         ret += rect[2].weight * (  
  20.                     img[fastRect[2].p0]  
  21.                 - img[fastRect[2].p1]  
  22.                 - img[fastRect[2].p2]  
  23.                 + img[fastRect[2].p3] );  
  24.     return ret;  
  25. }</span>  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值