improvements in Haar CascadeClassifier: 1) use CV_32S instead of CV_32F for the integral of squares (which is more accurate and more efficient); 2) skip the window if its contrast is too low

This commit is contained in:
Vadim Pisarevsky 2015-05-28 19:33:21 +03:00
parent 036c438904
commit 5a94a95fbf
3 changed files with 23 additions and 15 deletions

View File

@ -318,6 +318,7 @@ static void integral_##suffix( T* src, size_t srcstep, ST* sum, size_t sumstep,
{ integral_(src, srcstep, sum, sumstep, sqsum, sqsumstep, tilted, tiltedstep, size, cn); } { integral_(src, srcstep, sum, sumstep, sqsum, sqsumstep, tilted, tiltedstep, size, cn); }
DEF_INTEGRAL_FUNC(8u32s, uchar, int, double) DEF_INTEGRAL_FUNC(8u32s, uchar, int, double)
DEF_INTEGRAL_FUNC(8u32s32s, uchar, int, int)
DEF_INTEGRAL_FUNC(8u32f64f, uchar, float, double) DEF_INTEGRAL_FUNC(8u32f64f, uchar, float, double)
DEF_INTEGRAL_FUNC(8u64f64f, uchar, double, double) DEF_INTEGRAL_FUNC(8u64f64f, uchar, double, double)
DEF_INTEGRAL_FUNC(16u64f64f, ushort, double, double) DEF_INTEGRAL_FUNC(16u64f64f, ushort, double, double)
@ -505,6 +506,8 @@ void cv::integral( InputArray _src, OutputArray _sum, OutputArray _sqsum, Output
func = (IntegralFunc)GET_OPTIMIZED(integral_8u32s); func = (IntegralFunc)GET_OPTIMIZED(integral_8u32s);
else if( depth == CV_8U && sdepth == CV_32S && sqdepth == CV_32F ) else if( depth == CV_8U && sdepth == CV_32S && sqdepth == CV_32F )
func = (IntegralFunc)integral_8u32s32f; func = (IntegralFunc)integral_8u32s32f;
else if( depth == CV_8U && sdepth == CV_32S && sqdepth == CV_32S )
func = (IntegralFunc)integral_8u32s32s;
else if( depth == CV_8U && sdepth == CV_32F && sqdepth == CV_64F ) else if( depth == CV_8U && sdepth == CV_32F && sqdepth == CV_64F )
func = (IntegralFunc)integral_8u32f64f; func = (IntegralFunc)integral_8u32f64f;
else if( depth == CV_8U && sdepth == CV_32F && sqdepth == CV_32F ) else if( depth == CV_8U && sdepth == CV_32F && sqdepth == CV_32F )

View File

@ -627,33 +627,33 @@ void HaarEvaluator::computeChannels(int scaleIdx, InputArray img)
int sqy = sy + (sqofs / sbufSize.width); int sqy = sy + (sqofs / sbufSize.width);
UMat sum(usbuf, Rect(sx, sy, s.szi.width, s.szi.height)); UMat sum(usbuf, Rect(sx, sy, s.szi.width, s.szi.height));
UMat sqsum(usbuf, Rect(sx, sqy, s.szi.width, s.szi.height)); UMat sqsum(usbuf, Rect(sx, sqy, s.szi.width, s.szi.height));
sqsum.flags = (sqsum.flags & ~UMat::DEPTH_MASK) | CV_32F; sqsum.flags = (sqsum.flags & ~UMat::DEPTH_MASK) | CV_32S;
if (hasTiltedFeatures) if (hasTiltedFeatures)
{ {
int sty = sy + (tofs / sbufSize.width); int sty = sy + (tofs / sbufSize.width);
UMat tilted(usbuf, Rect(sx, sty, s.szi.width, s.szi.height)); UMat tilted(usbuf, Rect(sx, sty, s.szi.width, s.szi.height));
integral(img, sum, sqsum, tilted, CV_32S, CV_32F); integral(img, sum, sqsum, tilted, CV_32S, CV_32S);
} }
else else
{ {
UMatData* u = sqsum.u; UMatData* u = sqsum.u;
integral(img, sum, sqsum, noArray(), CV_32S, CV_32F); integral(img, sum, sqsum, noArray(), CV_32S, CV_32S);
CV_Assert(sqsum.u == u && sqsum.size() == s.szi && sqsum.type()==CV_32F); CV_Assert(sqsum.u == u && sqsum.size() == s.szi && sqsum.type()==CV_32S);
} }
} }
else else
{ {
Mat sum(s.szi, CV_32S, sbuf.ptr<int>() + s.layer_ofs, sbuf.step); Mat sum(s.szi, CV_32S, sbuf.ptr<int>() + s.layer_ofs, sbuf.step);
Mat sqsum(s.szi, CV_32F, sum.ptr<int>() + sqofs, sbuf.step); Mat sqsum(s.szi, CV_32S, sum.ptr<int>() + sqofs, sbuf.step);
if (hasTiltedFeatures) if (hasTiltedFeatures)
{ {
Mat tilted(s.szi, CV_32S, sum.ptr<int>() + tofs, sbuf.step); Mat tilted(s.szi, CV_32S, sum.ptr<int>() + tofs, sbuf.step);
integral(img, sum, sqsum, tilted, CV_32S, CV_32F); integral(img, sum, sqsum, tilted, CV_32S, CV_32S);
} }
else else
integral(img, sum, sqsum, noArray(), CV_32S, CV_32F); integral(img, sum, sqsum, noArray(), CV_32S, CV_32S);
} }
} }
@ -689,18 +689,23 @@ bool HaarEvaluator::setWindow( Point pt, int scaleIdx )
return false; return false;
pwin = &sbuf.at<int>(pt) + s.layer_ofs; pwin = &sbuf.at<int>(pt) + s.layer_ofs;
const float* pq = (const float*)(pwin + sqofs); const int* pq = (const int*)(pwin + sqofs);
int valsum = CALC_SUM_OFS(nofs, pwin); int valsum = CALC_SUM_OFS(nofs, pwin);
float valsqsum = CALC_SUM_OFS(nofs, pq); unsigned valsqsum = (unsigned)(CALC_SUM_OFS(nofs, pq));
double nf = (double)normrect.area() * valsqsum - (double)valsum * valsum; double area = normrect.area();
double nf = area * valsqsum - (double)valsum * valsum;
if( nf > 0. ) if( nf > 0. )
{
nf = std::sqrt(nf); nf = std::sqrt(nf);
else
nf = 1.;
varianceNormFactor = (float)(1./nf); varianceNormFactor = (float)(1./nf);
return area*varianceNormFactor < 1e-1;
return true; }
else
{
varianceNormFactor = 1.f;
return false;
}
} }

View File

@ -160,7 +160,7 @@ void runHaarClassifier(
__global const int* psum = psum1; __global const int* psum = psum1;
#endif #endif
__global const float* psqsum = (__global const float*)(psum1 + sqofs); __global const int* psqsum = (__global const int*)(psum1 + sqofs);
float sval = (psum[nofs.x] - psum[nofs.y] - psum[nofs.z] + psum[nofs.w])*invarea; float sval = (psum[nofs.x] - psum[nofs.y] - psum[nofs.z] + psum[nofs.w])*invarea;
float sqval = (psqsum[nofs0.x] - psqsum[nofs0.y] - psqsum[nofs0.z] + psqsum[nofs0.w])*invarea; float sqval = (psqsum[nofs0.x] - psqsum[nofs0.y] - psqsum[nofs0.z] + psqsum[nofs0.w])*invarea;
float nf = (float)normarea * sqrt(max(sqval - sval * sval, 0.f)); float nf = (float)normarea * sqrt(max(sqval - sval * sval, 0.f));