From ca762a6ba7d0482b542234436de7b8447a9f860a Mon Sep 17 00:00:00 2001 From: StevenPuttemans Date: Wed, 12 Oct 2016 13:59:45 +0200 Subject: [PATCH] allow minObjectSize==maxObjectSize for single scale detection capability --- modules/objdetect/include/opencv2/objdetect.hpp | 4 +- modules/objdetect/src/cascadedetect.cpp | 105 ++++++++++++++---------- 2 files changed, 65 insertions(+), 44 deletions(-) diff --git a/modules/objdetect/include/opencv2/objdetect.hpp b/modules/objdetect/include/opencv2/objdetect.hpp index c57bcde..cd444d2 100644 --- a/modules/objdetect/include/opencv2/objdetect.hpp +++ b/modules/objdetect/include/opencv2/objdetect.hpp @@ -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& objects, diff --git a/modules/objdetect/src/cascadedetect.cpp b/modules/objdetect/src/cascadedetect.cpp index 9eef693..1b99a7c 100644 --- a/modules/objdetect/src/cascadedetect.cpp +++ b/modules/objdetect/src/cascadedetect.cpp @@ -41,6 +41,7 @@ #include "precomp.hpp" #include +#include #include "cascadedetect.hpp" #include "opencv2/objdetect/objdetect_c.h" @@ -1221,7 +1222,6 @@ static void detectMultiScaleOldFormat( const Mat& image, Ptr& candidates, std::vector& rejectLevels, std::vector& 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 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 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,44 +1298,18 @@ 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*/ - { - if (_image.channels() > 1) - cvtColor(_image, grayImage, COLOR_BGR2GRAY); - else if (_image.isMat()) - grayImage = _image.getMat(); - else - _image.copyTo(grayImage); - gray = grayImage; - } - - std::vector scales; - scales.reserve(1024); - - for( double factor = 1; ; factor *= scaleFactor ) - { - Size originalWindowSize = getOriginalWindowSize(); + Mat grayImage; + _InputArray gray; - 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 (_image.channels() > 1) + cvtColor(_image, grayImage, COLOR_BGR2GRAY); + else if (_image.isMat()) + grayImage = _image.getMat(); + else + _image.copyTo(grayImage); + gray = grayImage; - if( scales.size() == 0 || !featureEvaluator->setImage(gray, scales) ) + if( !featureEvaluator->setImage(gray, scales) ) return; #ifdef HAVE_OPENCL -- 2.7.4