From 88c71d1b7dff788847a4973ef8c185d3021c99aa Mon Sep 17 00:00:00 2001 From: "marina.kolpakova" Date: Sat, 24 Nov 2012 01:58:44 +0400 Subject: [PATCH 1/2] add NMS according to Dollar's paper. --- .../include/opencv2/objdetect/objdetect.hpp | 6 +- modules/objdetect/src/objdetect_init.cpp | 8 +-- modules/objdetect/src/softcascade.cpp | 70 ++++++++++++++++++- 3 files changed, 77 insertions(+), 7 deletions(-) diff --git a/modules/objdetect/include/opencv2/objdetect/objdetect.hpp b/modules/objdetect/include/opencv2/objdetect/objdetect.hpp index a78bef56f..f0bb58e5f 100644 --- a/modules/objdetect/include/opencv2/objdetect/objdetect.hpp +++ b/modules/objdetect/include/opencv2/objdetect/objdetect.hpp @@ -534,12 +534,14 @@ public: int shrinkage; }; + enum { NO_REJECT = 1, DOLLAR = 2, /*PASCAL = 4,*/ DEFAULT = NO_REJECT}; + // An empty cascade will be created. // Param minScale is a minimum scale relative to the original size of the image on which cascade will be applyed. // Param minScale is a maximum scale relative to the original size of the image on which cascade will be applyed. // Param scales is a number of scales from minScale to maxScale. // Param rejfactor is used for NMS. - CV_WRAP SCascade(const double minScale = 0.4, const double maxScale = 5., const int scales = 55, const int rejfactor = 1); + CV_WRAP SCascade(const double minScale = 0.4, const double maxScale = 5., const int scales = 55, const int rejCriteria = 1); CV_WRAP virtual ~SCascade(); @@ -571,7 +573,7 @@ private: double maxScale; int scales; - int rejfactor; + int rejCriteria; }; CV_EXPORTS bool initModule_objdetect(void); diff --git a/modules/objdetect/src/objdetect_init.cpp b/modules/objdetect/src/objdetect_init.cpp index d53c9480d..77afeaa6e 100644 --- a/modules/objdetect/src/objdetect_init.cpp +++ b/modules/objdetect/src/objdetect_init.cpp @@ -46,10 +46,10 @@ namespace cv { CV_INIT_ALGORITHM(SCascade, "CascadeDetector.SCascade", - obj.info()->addParam(obj, "minScale", obj.minScale); - obj.info()->addParam(obj, "maxScale", obj.maxScale); - obj.info()->addParam(obj, "scales", obj.scales); - obj.info()->addParam(obj, "rejfactor", obj.rejfactor)); + obj.info()->addParam(obj, "minScale", obj.minScale); + obj.info()->addParam(obj, "maxScale", obj.maxScale); + obj.info()->addParam(obj, "scales", obj.scales); + obj.info()->addParam(obj, "rejCriteria", obj.rejCriteria)); bool initModule_objdetect(void) { diff --git a/modules/objdetect/src/softcascade.cpp b/modules/objdetect/src/softcascade.cpp index 0ee7c0fd4..384a989fe 100644 --- a/modules/objdetect/src/softcascade.cpp +++ b/modules/objdetect/src/softcascade.cpp @@ -422,7 +422,7 @@ struct cv::SCascade::Fields }; cv::SCascade::SCascade(const double mins, const double maxs, const int nsc, const int rej) -: fields(0), minScale(mins), maxScale(maxs), scales(nsc), rejfactor(rej) {} +: fields(0), minScale(mins), maxScale(maxs), scales(nsc), rejCriteria(rej) {} cv::SCascade::~SCascade() { delete fields;} @@ -439,6 +439,68 @@ bool cv::SCascade::load(const FileNode& fn) return fields->fill(fn); } +namespace { +typedef cv::SCascade::Detection Detection; +typedef std::vector dvector; + +struct NMS +{ + + virtual ~NMS(){} + virtual void apply(dvector& objects) const = 0; +}; + + +struct ConfidenceLess +{ + bool operator()(const Detection& a, const Detection& b) const + { + return a.confidence > b.confidence; + } +}; + +struct DollarNMS: public NMS +{ + virtual ~DollarNMS(){} + + static float overlap(const cv::Rect &a, const cv::Rect &b) + { + int w = std::min(a.x + a.width, b.x + b.width) - std::max(a.x, b.x); + int h = std::min(a.y + a.height, b.y + b.height) - std::max(a.y, b.y); + + return (w < 0 || h < 0)? 0.f : (float)(w * h); + } + + virtual void apply(dvector& objects) const + { + std::sort(objects.begin(), objects.end(), ConfidenceLess()); + + for (dvector::iterator dIt = objects.begin(); dIt != objects.end(); ++dIt) + { + const Detection &a = *dIt; + for (dvector::iterator next = dIt + 1; next != objects.end(); ) + { + const Detection &b = *next; + + const float ovl = overlap(a.bb, b.bb) / std::min(a.bb.area(), b.bb.area()); + + if (ovl > 0.65f) + next = objects.erase(next); + else + ++next; + } + } + } +}; + +cv::Ptr createNMS(int type) +{ + CV_Assert(type == cv::SCascade::DOLLAR); + return cv::Ptr(new DollarNMS); +} + +} + void cv::SCascade::detectNoRoi(const cv::Mat& image, std::vector& objects) const { Fields& fld = *fields; @@ -459,6 +521,9 @@ void cv::SCascade::detectNoRoi(const cv::Mat& image, std::vector& obj } } } + + if (rejCriteria != NO_REJECT) + createNMS(rejCriteria)->apply(objects); } void cv::SCascade::detect(cv::InputArray _image, cv::InputArray _rois, std::vector& objects) const @@ -506,6 +571,9 @@ void cv::SCascade::detect(cv::InputArray _image, cv::InputArray _rois, std::vect } } } + + if (rejCriteria != NO_REJECT) + createNMS(rejCriteria)->apply(objects); } void cv::SCascade::detect(InputArray _image, InputArray _rois, OutputArray _rects, OutputArray _confs) const From 2d45af790e6c1fd1a78c708436e6e3afdde338a0 Mon Sep 17 00:00:00 2001 From: "marina.kolpakova" Date: Wed, 12 Dec 2012 04:59:48 +0400 Subject: [PATCH 2/2] fix according to pull requests comments --- .../include/opencv2/objdetect/objdetect.hpp | 2 +- modules/objdetect/src/softcascade.cpp | 65 ++++++++----------- 2 files changed, 27 insertions(+), 40 deletions(-) diff --git a/modules/objdetect/include/opencv2/objdetect/objdetect.hpp b/modules/objdetect/include/opencv2/objdetect/objdetect.hpp index f0bb58e5f..79b9ea3f0 100644 --- a/modules/objdetect/include/opencv2/objdetect/objdetect.hpp +++ b/modules/objdetect/include/opencv2/objdetect/objdetect.hpp @@ -540,7 +540,7 @@ public: // Param minScale is a minimum scale relative to the original size of the image on which cascade will be applyed. // Param minScale is a maximum scale relative to the original size of the image on which cascade will be applyed. // Param scales is a number of scales from minScale to maxScale. - // Param rejfactor is used for NMS. + // Param rejCriteria is used for NMS. CV_WRAP SCascade(const double minScale = 0.4, const double maxScale = 5., const int scales = 55, const int rejCriteria = 1); CV_WRAP virtual ~SCascade(); diff --git a/modules/objdetect/src/softcascade.cpp b/modules/objdetect/src/softcascade.cpp index 384a989fe..b34deeb60 100644 --- a/modules/objdetect/src/softcascade.cpp +++ b/modules/objdetect/src/softcascade.cpp @@ -443,15 +443,8 @@ namespace { typedef cv::SCascade::Detection Detection; typedef std::vector dvector; -struct NMS -{ - virtual ~NMS(){} - virtual void apply(dvector& objects) const = 0; -}; - - -struct ConfidenceLess +struct ConfidenceGt { bool operator()(const Detection& a, const Detection& b) const { @@ -459,44 +452,40 @@ struct ConfidenceLess } }; -struct DollarNMS: public NMS +static float overlap(const cv::Rect &a, const cv::Rect &b) { - virtual ~DollarNMS(){} + int w = std::min(a.x + a.width, b.x + b.width) - std::max(a.x, b.x); + int h = std::min(a.y + a.height, b.y + b.height) - std::max(a.y, b.y); - static float overlap(const cv::Rect &a, const cv::Rect &b) + return (w < 0 || h < 0)? 0.f : (float)(w * h); +} + +void DollarNMS(dvector& objects) +{ + static const float DollarThreshold = 0.65f; + std::sort(objects.begin(), objects.end(), ConfidenceGt()); + + for (dvector::iterator dIt = objects.begin(); dIt != objects.end(); ++dIt) { - int w = std::min(a.x + a.width, b.x + b.width) - std::max(a.x, b.x); - int h = std::min(a.y + a.height, b.y + b.height) - std::max(a.y, b.y); - - return (w < 0 || h < 0)? 0.f : (float)(w * h); - } - - virtual void apply(dvector& objects) const - { - std::sort(objects.begin(), objects.end(), ConfidenceLess()); - - for (dvector::iterator dIt = objects.begin(); dIt != objects.end(); ++dIt) + const Detection &a = *dIt; + for (dvector::iterator next = dIt + 1; next != objects.end(); ) { - const Detection &a = *dIt; - for (dvector::iterator next = dIt + 1; next != objects.end(); ) - { - const Detection &b = *next; + const Detection &b = *next; - const float ovl = overlap(a.bb, b.bb) / std::min(a.bb.area(), b.bb.area()); + const float ovl = overlap(a.bb, b.bb) / std::min(a.bb.area(), b.bb.area()); - if (ovl > 0.65f) - next = objects.erase(next); - else - ++next; - } + if (ovl > DollarThreshold) + next = objects.erase(next); + else + ++next; } } -}; +} -cv::Ptr createNMS(int type) +static void suppress(int type, std::vector& objects) { CV_Assert(type == cv::SCascade::DOLLAR); - return cv::Ptr(new DollarNMS); + DollarNMS(objects); } } @@ -522,8 +511,7 @@ void cv::SCascade::detectNoRoi(const cv::Mat& image, std::vector& obj } } - if (rejCriteria != NO_REJECT) - createNMS(rejCriteria)->apply(objects); + if (rejCriteria != NO_REJECT) suppress(rejCriteria, objects); } void cv::SCascade::detect(cv::InputArray _image, cv::InputArray _rois, std::vector& objects) const @@ -572,8 +560,7 @@ void cv::SCascade::detect(cv::InputArray _image, cv::InputArray _rois, std::vect } } - if (rejCriteria != NO_REJECT) - createNMS(rejCriteria)->apply(objects); + if (rejCriteria != NO_REJECT) suppress(rejCriteria, objects); } void cv::SCascade::detect(InputArray _image, InputArray _rois, OutputArray _rects, OutputArray _confs) const