allow minObjectSize==maxObjectSize for single scale detection capability

pull/7468/head
StevenPuttemans 8 years ago
parent 8e701a948b
commit ca762a6ba7
  1. 4
      modules/objdetect/include/opencv2/objdetect.hpp
  2. 93
      modules/objdetect/src/cascadedetect.cpp

@ -255,7 +255,7 @@ public:
@param flags Parameter with the same meaning for an old cascade as in the function
cvHaarDetectObjects. It is not used for a new cascade.
@param minSize Minimum possible object size. Objects smaller than that are ignored.
@param maxSize Maximum possible object size. Objects larger than that are ignored.
@param maxSize Maximum possible object size. Objects larger than that are ignored. If `maxSize == minSize` model is evaluated on single scale.
The function is parallelized with the TBB library.
@ -283,7 +283,7 @@ public:
@param flags Parameter with the same meaning for an old cascade as in the function
cvHaarDetectObjects. It is not used for a new cascade.
@param minSize Minimum possible object size. Objects smaller than that are ignored.
@param maxSize Maximum possible object size. Objects larger than that are ignored.
@param maxSize Maximum possible object size. Objects larger than that are ignored. If `maxSize == minSize` model is evaluated on single scale.
*/
CV_WRAP_AS(detectMultiScale2) void detectMultiScale( InputArray image,
CV_OUT std::vector<Rect>& objects,

@ -41,6 +41,7 @@
#include "precomp.hpp"
#include <cstdio>
#include <iostream>
#include "cascadedetect.hpp"
#include "opencv2/objdetect/objdetect_c.h"
@ -1221,7 +1222,6 @@ static void detectMultiScaleOldFormat( const Mat& image, Ptr<CvHaarClassifierCas
std::transform(vecAvgComp.begin(), vecAvgComp.end(), objects.begin(), getRect());
}
void CascadeClassifierImpl::detectMultiScaleNoGrouping( InputArray _image, std::vector<Rect>& candidates,
std::vector<int>& rejectLevels, std::vector<double>& levelWeights,
double scaleFactor, Size minObjectSize, Size maxObjectSize,
@ -1230,17 +1230,64 @@ void CascadeClassifierImpl::detectMultiScaleNoGrouping( InputArray _image, std::
CV_INSTRUMENT_REGION()
Size imgsz = _image.size();
Size originalWindowSize = getOriginalWindowSize();
Mat grayImage;
_InputArray gray;
if( maxObjectSize.height == 0 || maxObjectSize.width == 0 )
maxObjectSize = imgsz;
// If a too small image patch is entering the function, break early before any processing
if( (imgsz.height < originalWindowSize.height) || (imgsz.width < originalWindowSize.width) )
return;
std::vector<float> all_scales, scales;
all_scales.reserve(1024);
scales.reserve(1024);
// First calculate all possible scales for the given image and model, then remove undesired scales
// This allows us to cope with single scale detections (minSize == maxSize) that do not fall on precalculated scale
for( double factor = 1; ; factor *= scaleFactor )
{
Size windowSize( cvRound(originalWindowSize.width*factor), cvRound(originalWindowSize.height*factor) );
if( windowSize.width > imgsz.width || windowSize.height > imgsz.height )
break;
all_scales.push_back((float)factor);
}
// This will capture allowed scales and a minSize==maxSize scale, if it is in the precalculated scales
for( size_t index = 0; index < all_scales.size(); index++){
Size windowSize( cvRound(originalWindowSize.width*all_scales[index]), cvRound(originalWindowSize.height*all_scales[index]) );
if( windowSize.width > maxObjectSize.width || windowSize.height > maxObjectSize.height)
break;
if( windowSize.width < minObjectSize.width || windowSize.height < minObjectSize.height )
continue;
scales.push_back(all_scales[index]);
}
// If minSize and maxSize parameter are equal and scales is not filled yet, then the scale was not available in the precalculated scales
// In that case we want to return the most fitting scale (closest corresponding scale using L2 distance)
if( scales.empty() && !all_scales.empty() ){
std::vector<double> distances;
// Calculate distances
for(size_t v = 0; v < all_scales.size(); v++){
Size windowSize( cvRound(originalWindowSize.width*all_scales[v]), cvRound(originalWindowSize.height*all_scales[v]) );
double d = (minObjectSize.width - windowSize.width) * (minObjectSize.width - windowSize.width)
+ (minObjectSize.height - windowSize.height) * (minObjectSize.height - windowSize.height);
distances.push_back(d);
}
// Take the index of lowest value
// Use that index to push the correct scale parameter
size_t iMin=0;
for(size_t i = 0; i < distances.size(); ++i){
if(distances[iMin] > distances[i])
iMin=i;
}
scales.push_back(all_scales[iMin]);
}
candidates.clear();
rejectLevels.clear();
levelWeights.clear();
if( maxObjectSize.height == 0 || maxObjectSize.width == 0 )
maxObjectSize = imgsz;
#ifdef HAVE_OPENCL
bool use_ocl = tryOpenCL && ocl::useOpenCL() &&
featureEvaluator->getLocalSize().area() > 0 &&
@ -1251,18 +1298,9 @@ void CascadeClassifierImpl::detectMultiScaleNoGrouping( InputArray _image, std::
!outputRejectLevels;
#endif
/*if( use_ocl )
{
if (_image.channels() > 1)
cvtColor(_image, ugrayImage, COLOR_BGR2GRAY);
else if (_image.isUMat())
ugrayImage = _image.getUMat();
else
_image.copyTo(ugrayImage);
gray = ugrayImage;
}
else*/
{
Mat grayImage;
_InputArray gray;
if (_image.channels() > 1)
cvtColor(_image, grayImage, COLOR_BGR2GRAY);
else if (_image.isMat())
@ -1270,25 +1308,8 @@ void CascadeClassifierImpl::detectMultiScaleNoGrouping( InputArray _image, std::
else
_image.copyTo(grayImage);
gray = grayImage;
}
std::vector<float> scales;
scales.reserve(1024);
for( double factor = 1; ; factor *= scaleFactor )
{
Size originalWindowSize = getOriginalWindowSize();
Size windowSize( cvRound(originalWindowSize.width*factor), cvRound(originalWindowSize.height*factor) );
if( windowSize.width > maxObjectSize.width || windowSize.height > maxObjectSize.height ||
windowSize.width > imgsz.width || windowSize.height > imgsz.height )
break;
if( windowSize.width < minObjectSize.width || windowSize.height < minObjectSize.height )
continue;
scales.push_back((float)factor);
}
if( scales.size() == 0 || !featureEvaluator->setImage(gray, scales) )
if( !featureEvaluator->setImage(gray, scales) )
return;
#ifdef HAVE_OPENCL

Loading…
Cancel
Save