下面片段是生成用于在积分图中的矩形块的坐标,Feature类中存的是在积分图矩阵中的初始偏移量,矩形的左上角坐标和宽高,以及是否旋转。不同类型的Haar特征已经在代码中体现的很明确了,故不赘述。
接着,在 CvHaarEvaluator::Feature构造函数中,对刚刚求得的坐标做了偏移量上的转换。
CV_SUM_OFFSET和CV_TILTED_OFFSET是计算偏移量的宏,它们将左上角点和宽高转换成在单行sum或者tilted矩阵中的位置。sum矩阵的求法和LBP中是一样的,也是利用了OpenCV自带的cv::integral函数,而斜45度的矩阵也没有用到旋转图像之类的操作,而是…嗯,还是integral函数,自带重载功能,实现了45度倾斜操作。
归一化因子计算如下:
SqSum是平方积分图。
最后,不同小块乘上权重系数,作为Haar特征值。
- <span style="font-size:14px;">void CvHaarEvaluator::generateFeatures()
- {
- int mode = ((const CvHaarFeatureParams*)((CvFeatureParams*)featureParams))->mode;
- int offset = winSize.width + 1;
- for( int x = 0; x < winSize.width; x++ )
- {
- for( int y = 0; y < winSize.height; y++ )
- {
- for( int dx = 1; dx <= winSize.width; dx++ )
- {
- for( int dy = 1; dy <= winSize.height; dy++ )
- {
- // haar_x2
- if ( (x+dx*2 <= winSize.width) && (y+dy <= winSize.height) )
- {
- features.push_back( Feature( offset, false,
- x, y, dx*2, dy, -1,
- x+dx, y, dx , dy, +2 ) );
- }
- // haar_y2
- if ( (x+dx <= winSize.width) && (y+dy*2 <= winSize.height) )
- {
- features.push_back( Feature( offset, false,
- x, y, dx, dy*2, -1,
- x, y+dy, dx, dy, +2 ) );
- }
- // haar_x3
- if ( (x+dx*3 <= winSize.width) && (y+dy <= winSize.height) )
- {
- features.push_back( Feature( offset, false,
- x, y, dx*3, dy, -1,
- x+dx, y, dx , dy, +3 ) );
- }
- // haar_y3
- if ( (x+dx <= winSize.width) && (y+dy*3 <= winSize.height) )
- {
- features.push_back( Feature( offset, false,
- x, y, dx, dy*3, -1,
- x, y+dy, dx, dy, +3 ) );
- }
- if( mode != CvHaarFeatureParams::BASIC )
- {
- // haar_x4
- if ( (x+dx*4 <= winSize.width) && (y+dy <= winSize.height) )
- {
- features.push_back( Feature( offset, false,
- x, y, dx*4, dy, -1,
- x+dx, y, dx*2, dy, +2 ) );
- }
- // haar_y4
- if ( (x+dx <= winSize.width ) && (y+dy*4 <= winSize.height) )
- {
- features.push_back( Feature( offset, false,
- x, y, dx, dy*4, -1,
- x, y+dy, dx, dy*2, +2 ) );
- }
- }
- // x2_y2
- if ( (x+dx*2 <= winSize.width) && (y+dy*2 <= winSize.height) )
- {
- features.push_back( Feature( offset, false,
- x, y, dx*2, dy*2, -1,
- x, y, dx, dy, +2,
- x+dx, y+dy, dx, dy, +2 ) );
- }
- if (mode != CvHaarFeatureParams::BASIC)
- {
- if ( (x+dx*3 <= winSize.width) && (y+dy*3 <= winSize.height) )
- {
- features.push_back( Feature( offset, false,
- x , y , dx*3, dy*3, -1,
- x+dx, y+dy, dx , dy , +9) );
- }
- }
- if (mode == CvHaarFeatureParams::ALL)
- {
- // tilted haar_x2
- if ( (x+2*dx <= winSize.width) && (y+2*dx+dy <= winSize.height) && (x-dy>= 0) )
- {
- features.push_back( Feature( offset, true,
- x, y, dx*2, dy, -1,
- x, y, dx, dy, +2 ) );
- }
- // tilted haar_y2
- if ( (x+dx <= winSize.width) && (y+dx+2*dy <= winSize.height) && (x-2*dy>= 0) )
- {
- features.push_back( Feature( offset, true,
- x, y, dx, 2*dy, -1,
- x, y, dx, dy, +2 ) );
- }
- // tilted haar_x3
- if ( (x+3*dx <= winSize.width) && (y+3*dx+dy <= winSize.height) && (x-dy>= 0) )
- {
- features.push_back( Feature( offset, true,
- x, y, dx*3, dy, -1,
- x+dx, y+dx, dx, dy, +3 ) );
- }
- // tilted haar_y3
- if ( (x+dx <= winSize.width) && (y+dx+3*dy <= winSize.height) && (x-3*dy>= 0) )
- {
- features.push_back( Feature( offset, true,
- x, y, dx, 3*dy, -1,
- x-dy, y+dy, dx, dy, +3 ) );
- }
- // tilted haar_x4
- if ( (x+4*dx <= winSize.width) && (y+4*dx+dy <= winSize.height) && (x-dy>= 0) )
- {
- features.push_back( Feature( offset, true,
- x, y, dx*4, dy, -1,
- x+dx, y+dx, dx*2, dy, +2 ) );
- }
- // tilted haar_y4
- if ( (x+dx <= winSize.width) && (y+dx+4*dy <= winSize.height) && (x-4*dy>= 0) )
- {
- features.push_back( Feature( offset, true,
- x, y, dx, 4*dy, -1,
- x-dy, y+dy, dx, 2*dy, +2 ) );
- }
- }
- }
- }
- }
- }
- numFeatures = (int)features.size();
- }</span>
- <span style="font-size:14px;">CvHaarEvaluator::Feature::Feature( int offset, bool _tilted,
- int x0, int y0, int w0, int h0, float wt0,
- int x1, int y1, int w1, int h1, float wt1,
- int x2, int y2, int w2, int h2, float wt2 )
- {
- tilted = _tilted;
- rect[0].r.x = x0;
- rect[0].r.y = y0;
- rect[0].r.width = w0;
- rect[0].r.height = h0;
- rect[0].weight = wt0;
- rect[1].r.x = x1;
- rect[1].r.y = y1;
- rect[1].r.width = w1;
- rect[1].r.height = h1;
- rect[1].weight = wt1;
- rect[2].r.x = x2;
- rect[2].r.y = y2;
- rect[2].r.width = w2;
- rect[2].r.height = h2;
- rect[2].weight = wt2;
- if( !tilted )
- {
- for( int j = 0; j < CV_HAAR_FEATURE_MAX; j++ )
- {
- if( rect[j].weight == 0.0F )
- break;
- CV_SUM_OFFSETS( fastRect[j].p0, fastRect[j].p1,
- fastRect[j].p2, fastRect[j].p3, rect[j].r, offset )
- }
- }
- else
- {
- for( int j = 0; j < CV_HAAR_FEATURE_MAX; j++ )
- {
- if( rect[j].weight == 0.0F )
- break;
- CV_TILTED_OFFSETS( fastRect[j].p0, fastRect[j].p1,
- fastRect[j].p2, fastRect[j].p3, rect[j].r, offset )
- }
- }
- }
- </span>
- <span style="font-size:14px;">void CvHaarEvaluator::setImage(const Mat& img, uchar clsLabel, int idx)
- {
- CV_DbgAssert( !sum.empty() && !tilted.empty() && !normfactor.empty() );
- CvFeatureEvaluator::setImage( img, clsLabel, idx);
- Mat innSum(winSize.height + 1, winSize.width + 1, sum.type(), sum.ptr<int>((int)idx));
- Mat innTilted(winSize.height + 1, winSize.width + 1, tilted.type(), tilted.ptr<int>((int)idx));
- Mat innSqSum;
- integral(img, innSum, innSqSum, innTilted);
- normfactor.ptr<float>(0)[idx] = calcNormFactor( innSum, innSqSum );
- }</span>
- <span style="font-size:14px;">float calcNormFactor( const Mat& sum, const Mat& sqSum )
- {
- CV_DbgAssert( sum.cols > 3 && sqSum.rows > 3 );
- Rect normrect( 1, 1, sum.cols - 3, sum.rows - 3 );
- size_t p0, p1, p2, p3;
- CV_SUM_OFFSETS( p0, p1, p2, p3, normrect, sum.step1() )
- double area = normrect.width * normrect.height;
- const int *sp = (const int*)sum.data;
- int valSum = sp[p0] - sp[p1] - sp[p2] + sp[p3];
- const double *sqp = (const double *)sqSum.data;
- double valSqSum = sqp[p0] - sqp[p1] - sqp[p2] + sqp[p3];
- return (float) sqrt( (double) (area * valSqSum - (double)valSum * valSum) );
- }</span>
SqSum是平方积分图。
最后,不同小块乘上权重系数,作为Haar特征值。
- <span style="font-size:14px;">inline float CvHaarEvaluator::Feature::calc(
- const cv::Mat &_sum,
- const cv::Mat &_tilted,
- size_t y) const
- {
- const int* img = tilted ?
- _tilted.ptr<int>((int)y) : _sum.ptr<int>((int)y);
- float ret = rect[0].weight * (
- img[fastRect[0].p0]
- - img[fastRect[0].p1]
- - img[fastRect[0].p2]
- + img[fastRect[0].p3] ) +
- rect[1].weight * (
- img[fastRect[1].p0]
- - img[fastRect[1].p1]
- - img[fastRect[1].p2]
- + img[fastRect[1].p3] );
- if( rect[2].weight != 0.0f )
- ret += rect[2].weight * (
- img[fastRect[2].p0]
- - img[fastRect[2].p1]
- - img[fastRect[2].p2]
- + img[fastRect[2].p3] );
- return ret;
- }</span>