diff --git a/modules/contrib/include/opencv2/contrib/detection_based_tracker.hpp b/modules/contrib/include/opencv2/contrib/detection_based_tracker.hpp index bef80bfe5..df482bab6 100644 --- a/modules/contrib/include/opencv2/contrib/detection_based_tracker.hpp +++ b/modules/contrib/include/opencv2/contrib/detection_based_tracker.hpp @@ -12,17 +12,66 @@ class DetectionBasedTracker public: struct Parameters { - int minObjectSize; - int maxObjectSize; - double scaleFactor; int maxTrackLifetime; - int minNeighbors; int minDetectionPeriod; //the minimal time between run of the big object detector (on the whole frame) in ms (1000 mean 1 sec), default=0 Parameters(); }; - DetectionBasedTracker(const std::string& cascadeFilename, const Parameters& params); + class IDetector + { + public: + IDetector(): + MinObjSize(96, 96), + MaxObjSize(INT_MAX, INT_MAX), + ScaleFactor(1.1f), + MinNeighbours(2) + {} + + virtual void detect(const cv::Mat& Image, std::vector& objects) = 0; + + void setMinObjectSize(const cv::Size& min) + { + MinObjSize = min; + } + void setMaxObjectSize(const cv::Size& max) + { + MaxObjSize = max; + } + cv::Size getMinObjectSize() const + { + return MinObjSize; + } + cv::Size getMaxObjectSize() const + { + return MaxObjSize; + } + float getScaleFactor() + { + return ScaleFactor; + } + void setScaleFactor(float value) + { + ScaleFactor = value; + } + int getMinNeighbours() + { + return ScaleFactor; + } + void setMinNeighbours(int value) + { + + } + virtual ~IDetector() {} + + protected: + cv::Size MinObjSize; + cv::Size MaxObjSize; + int MinNeighbours; + float ScaleFactor; + }; + + DetectionBasedTracker(cv::Ptr MainDetector, cv::Ptr TrackingDetector, const Parameters& params); virtual ~DetectionBasedTracker(); virtual bool run(); @@ -44,7 +93,6 @@ class DetectionBasedTracker cv::Ptr separateDetectionWork; friend void* workcycleObjectDetectorFunction(void* p); - struct InnerParameters { int numLastPositionsToTrack; @@ -90,8 +138,7 @@ class DetectionBasedTracker std::vector weightsPositionsSmoothing; std::vector weightsSizesSmoothing; - cv::CascadeClassifier cascadeForTracking; - + cv::Ptr cascadeForTracking; void updateTrackedObjects(const std::vector& detectedObjects); cv::Rect calcTrackedObjectPositionToShow(int i) const; diff --git a/modules/contrib/src/detection_based_tracker.cpp b/modules/contrib/src/detection_based_tracker.cpp index d65e9d9c3..0fcf4d83e 100644 --- a/modules/contrib/src/detection_based_tracker.cpp +++ b/modules/contrib/src/detection_based_tracker.cpp @@ -52,10 +52,11 @@ static inline cv::Rect scale_rect(const cv::Rect& r, float scale) }; void* workcycleObjectDetectorFunction(void* p); + class DetectionBasedTracker::SeparateDetectionWork { public: - SeparateDetectionWork(DetectionBasedTracker& _detectionBasedTracker, const std::string& cascadeFilename); + SeparateDetectionWork(DetectionBasedTracker& _detectionBasedTracker, cv::Ptr _detector); virtual ~SeparateDetectionWork(); bool communicateWithDetectingThread(const Mat& imageGray, vector& rectsWhereRegions); bool run(); @@ -77,7 +78,7 @@ class DetectionBasedTracker::SeparateDetectionWork protected: DetectionBasedTracker& detectionBasedTracker; - cv::CascadeClassifier cascadeInThread; + cv::Ptr cascadeInThread; pthread_t second_workthread; pthread_mutex_t mutex; @@ -105,7 +106,7 @@ class DetectionBasedTracker::SeparateDetectionWork long long timeWhenDetectingThreadStartedWork; }; -DetectionBasedTracker::SeparateDetectionWork::SeparateDetectionWork(DetectionBasedTracker& _detectionBasedTracker, const std::string& cascadeFilename) +DetectionBasedTracker::SeparateDetectionWork::SeparateDetectionWork(DetectionBasedTracker& _detectionBasedTracker, cv::Ptr _detector) :detectionBasedTracker(_detectionBasedTracker), cascadeInThread(), isObjectDetectingReady(false), @@ -113,9 +114,10 @@ DetectionBasedTracker::SeparateDetectionWork::SeparateDetectionWork(DetectionBas stateThread(STATE_THREAD_STOPPED), timeWhenDetectingThreadStartedWork(-1) { - if(!cascadeInThread.load(cascadeFilename)) { - CV_Error(CV_StsBadArg, "DetectionBasedTracker::SeparateDetectionWork::SeparateDetectionWork: Cannot load a cascade from the file '"+cascadeFilename+"'"); - } + CV_Assert(!_detector.empty()); + + cascadeInThread = _detector; + int res=0; res=pthread_mutex_init(&mutex, NULL);//TODO: should be attributes? if (res) { @@ -274,20 +276,17 @@ void DetectionBasedTracker::SeparateDetectionWork::workcycleObjectDetector() int64 t1_detect=getTickCount(); - int minObjectSize=detectionBasedTracker.parameters.minObjectSize; - Size min_objectSize=Size(minObjectSize, minObjectSize); + cascadeInThread->detect(imageSeparateDetecting, objects); - int maxObjectSize=detectionBasedTracker.parameters.maxObjectSize; - Size max_objectSize(maxObjectSize, maxObjectSize); - - - cascadeInThread.detectMultiScale( imageSeparateDetecting, objects, + /*cascadeInThread.detectMultiScale( imageSeparateDetecting, objects, detectionBasedTracker.parameters.scaleFactor, detectionBasedTracker.parameters.minNeighbors, 0 |CV_HAAR_SCALE_IMAGE , min_objectSize, max_objectSize ); + */ + LOGD("DetectionBasedTracker::SeparateDetectionWork::workcycleObjectDetector() --- end handling imageSeparateDetecting"); if (!isWorking()) { @@ -422,16 +421,10 @@ bool DetectionBasedTracker::SeparateDetectionWork::communicateWithDetectingThrea DetectionBasedTracker::Parameters::Parameters() { - minObjectSize=96; - maxObjectSize=INT_MAX; - scaleFactor=1.1; maxTrackLifetime=5; - minNeighbors=2; minDetectionPeriod=0; } - - DetectionBasedTracker::InnerParameters::InnerParameters() { numLastPositionsToTrack=4; @@ -444,39 +437,32 @@ DetectionBasedTracker::InnerParameters::InnerParameters() coeffObjectSpeedUsingInPrediction=0.8; } -DetectionBasedTracker::DetectionBasedTracker(const std::string& cascadeFilename, const Parameters& params) + +DetectionBasedTracker::DetectionBasedTracker(cv::Ptr MainDetector, cv::Ptr TrackingDetector, const Parameters& params) :separateDetectionWork(), innerParameters(), + cascadeForTracking(TrackingDetector), + parameters(params), numTrackedSteps(0) { - CV_Assert( (params.minObjectSize > 0) - && (params.maxObjectSize >= 0) - && (params.scaleFactor > 1.0) - && (params.maxTrackLifetime >= 0) ); + CV_Assert( (params.maxTrackLifetime >= 0) + && (!MainDetector.empty()) + && (!TrackingDetector.empty()) ); - if (!cascadeForTracking.load(cascadeFilename)) { - CV_Error(CV_StsBadArg, "DetectionBasedTracker::DetectionBasedTracker: Cannot load a cascade from the file '"+cascadeFilename+"'"); - } - - parameters=params; - - separateDetectionWork=new SeparateDetectionWork(*this, cascadeFilename); + separateDetectionWork = new SeparateDetectionWork(*this, MainDetector); weightsPositionsSmoothing.push_back(1); weightsSizesSmoothing.push_back(0.5); weightsSizesSmoothing.push_back(0.3); weightsSizesSmoothing.push_back(0.2); - } + DetectionBasedTracker::~DetectionBasedTracker() { } - - void DetectionBasedTracker::process(const Mat& imageGray) { - CV_Assert(imageGray.type()==CV_8UC1); if (!separateDetectionWork->isWorking()) { @@ -494,15 +480,9 @@ void DetectionBasedTracker::process(const Mat& imageGray) Mat imageDetect=imageGray; - int D=parameters.minObjectSize; - if (D < 1) - D=1; - vector rectsWhereRegions; bool shouldHandleResult=separateDetectionWork->communicateWithDetectingThread(imageGray, rectsWhereRegions); - - if (shouldHandleResult) { LOGD("DetectionBasedTracker::process: get _rectsWhereRegions were got from resultDetect"); } else { @@ -517,7 +497,6 @@ void DetectionBasedTracker::process(const Mat& imageGray) continue; } - //correction by speed of rectangle if (n > 1) { Point2f center=centerRect(r); @@ -560,6 +539,7 @@ void DetectionBasedTracker::getObjects(std::vector& result) const LOGD("DetectionBasedTracker::process: found a object with SIZE %d x %d, rect={%d, %d, %d x %d}", r.width, r.height, r.x, r.y, r.width, r.height); } } + void DetectionBasedTracker::getObjects(std::vector& result) const { result.clear(); @@ -574,8 +554,6 @@ void DetectionBasedTracker::getObjects(std::vector& result) const } } - - bool DetectionBasedTracker::run() { return separateDetectionWork->run(); @@ -711,6 +689,7 @@ void DetectionBasedTracker::updateTrackedObjects(const vector& detectedObj } } } + Rect DetectionBasedTracker::calcTrackedObjectPositionToShow(int i) const { if ( (i < 0) || (i >= (int)trackedObjects.size()) ) { @@ -743,8 +722,8 @@ Rect DetectionBasedTracker::calcTrackedObjectPositionToShow(int i) const double sum=0; for(int j=0; j < Nsize; j++) { int k=N-j-1; - w+= lastPositions[k].width * weightsSizesSmoothing[j]; - h+= lastPositions[k].height * weightsSizesSmoothing[j]; + w += lastPositions[k].width * weightsSizesSmoothing[j]; + h += lastPositions[k].height * weightsSizesSmoothing[j]; sum+=weightsSizesSmoothing[j]; } w /= sum; @@ -762,7 +741,7 @@ Rect DetectionBasedTracker::calcTrackedObjectPositionToShow(int i) const Point br(lastPositions[k].br()); Point2f c1; c1=tl; - c1=c1* 0.5f; + c1=c1* 0.5f; Point2f c2; c2=br; c2=c2*0.5f; @@ -802,8 +781,7 @@ void DetectionBasedTracker::detectInRegion(const Mat& img, const Rect& r, vector return; } - int d=std::min(r.width, r.height); - d=cvRound(d * innerParameters.coeffObjectSizeToTrack); + int d = cvRound(std::min(r.width, r.height) * innerParameters.coeffObjectSizeToTrack); vector tmpobjects; @@ -811,17 +789,17 @@ void DetectionBasedTracker::detectInRegion(const Mat& img, const Rect& r, vector LOGD("DetectionBasedTracker::detectInRegion: img1.size()=%d x %d, d=%d", img1.size().width, img1.size().height, d); - int maxObjectSize=parameters.maxObjectSize; - Size max_objectSize(maxObjectSize, maxObjectSize); - - cascadeForTracking.detectMultiScale( img1, tmpobjects, + cascadeForTracking->setMinObjectSize(Size(d, d)); + cascadeForTracking->detect(img1, tmpobjects); + /* + detectMultiScale( img1, tmpobjects, parameters.scaleFactor, parameters.minNeighbors, 0 |CV_HAAR_FIND_BIGGEST_OBJECT |CV_HAAR_SCALE_IMAGE , Size(d,d), max_objectSize - ); + );*/ for(size_t i=0; i < tmpobjects.size(); i++) { Rect curres(tmpobjects[i].tl() + r1.tl(), tmpobjects[i].size()); @@ -831,10 +809,7 @@ void DetectionBasedTracker::detectInRegion(const Mat& img, const Rect& r, vector bool DetectionBasedTracker::setParameters(const Parameters& params) { - if ( (params.minObjectSize <= 0) - || (params.maxObjectSize < 0) - || (params.scaleFactor <= 1.0) - || (params.maxTrackLifetime < 0) ) + if ( params.maxTrackLifetime < 0 ) { LOGE("DetectionBasedTracker::setParameters: ERROR: wrong parameters value"); return false; diff --git a/samples/cpp/dbt_face_detection.cpp b/samples/cpp/dbt_face_detection.cpp new file mode 100644 index 000000000..53bb7cf25 --- /dev/null +++ b/samples/cpp/dbt_face_detection.cpp @@ -0,0 +1,90 @@ +#include // Gaussian Blur +#include // Basic OpenCV structures (cv::Mat, Scalar) +#include // OpenCV window I/O +#include +#include + +#include +#include +#include +using namespace std; +using namespace cv; + +const string WindowName = "Face Detection example"; + +class CascadeDetectorAdapter: public DetectionBasedTracker::IDetector +{ + public: + CascadeDetectorAdapter(cv::Ptr detector): + Detector(detector) + { + CV_Assert(!detector.empty()); + } + + void detect(const cv::Mat &Image, std::vector &objects) + { + Detector->detectMultiScale(Image, objects, ScaleFactor, MinNeighbours, 0, MinObjSize, MaxObjSize); + } + virtual ~CascadeDetectorAdapter() + {} + + private: + CascadeDetectorAdapter(); + cv::Ptr Detector; + }; + +int main(int argc, char* argv[]) +{ + namedWindow(WindowName); + + VideoCapture VideoStream(0); + + if (!VideoStream.isOpened()) + { + printf("Error: Cannot open video stream from camera\n"); + return 1; + } + + std::string cascadeFrontalfilename = "../../data/lbpcascades/lbpcascade_frontalface.xml"; + cv::Ptr cascade = new cv::CascadeClassifier(cascadeFrontalfilename); + cv::Ptr MainDetector = new CascadeDetectorAdapter(cascade); + + cascade = new cv::CascadeClassifier(cascadeFrontalfilename); + cv::Ptr TrackingDetector = new CascadeDetectorAdapter(cascade); + + DetectionBasedTracker::Parameters params; + DetectionBasedTracker Detector(MainDetector, TrackingDetector, params); + + if (!Detector.run()) + { + printf("Error: Detector initialization failed\n"); + return 2; + } + + Mat ReferenceFrame; + Mat GrayFrame; + vector Faces; + + while(true) + { + VideoStream >> ReferenceFrame; + cvtColor(ReferenceFrame, GrayFrame, COLOR_RGB2GRAY); + Detector.process(GrayFrame); + Detector.getObjects(Faces); + + for (size_t i = 0; i < Faces.size(); i++) + { + rectangle(ReferenceFrame, Faces[i], CV_RGB(0,255,0)); + } + + imshow(WindowName, ReferenceFrame); + + if (cvWaitKey(30) >= 0) break; + } + + Detector.stop(); + + return 0; +} + + diff --git a/samples/cpp/detection_based_tracker_sample.cpp b/samples/cpp/detection_based_tracker_sample.cpp index 6aeb1b245..470304790 100644 --- a/samples/cpp/detection_based_tracker_sample.cpp +++ b/samples/cpp/detection_based_tracker_sample.cpp @@ -43,8 +43,6 @@ #define LOGE(...) do{} while(0) #endif - - using namespace cv; using namespace std; @@ -63,9 +61,31 @@ static void usage() LOGE0("\t (e.g.\"opencv/data/lbpcascades/lbpcascade_frontalface.xml\" "); } +class CascadeDetectorAdapter: public DetectionBasedTracker::IDetector +{ + public: + CascadeDetectorAdapter(cv::Ptr detector): + Detector(detector) + { + CV_Assert(!detector.empty()); + } + + void detect(const cv::Mat &Image, std::vector &objects) + { + Detector->detectMultiScale(Image, objects, 1.1, 3, 0, MinObjSize, MaxObjSize); + } + virtual ~CascadeDetectorAdapter() + {} + + private: + CascadeDetectorAdapter(); + cv::Ptr Detector; + }; + static int test_FaceDetector(int argc, char *argv[]) { - if (argc < 4) { + if (argc < 4) + { usage(); return -1; } @@ -80,12 +100,14 @@ static int test_FaceDetector(int argc, char *argv[]) vector images; { char filename[256]; - for(int n=1; ; n++) { + for(int n=1; ; n++) + { snprintf(filename, sizeof(filename), filepattern, n); LOGD("filename='%s'", filename); Mat m0; m0=imread(filename); - if (m0.empty()) { + if (m0.empty()) + { LOGI0("Cannot read the file --- break"); break; } @@ -94,10 +116,15 @@ static int test_FaceDetector(int argc, char *argv[]) LOGD("read %d images", (int)images.size()); } - DetectionBasedTracker::Parameters params; std::string cascadeFrontalfilename=cascadefile; + cv::Ptr cascade = new cv::CascadeClassifier(cascadeFrontalfilename); + cv::Ptr MainDetector = new CascadeDetectorAdapter(cascade); - DetectionBasedTracker fd(cascadeFrontalfilename, params); + cascade = new cv::CascadeClassifier(cascadeFrontalfilename); + cv::Ptr TrackingDetector = new CascadeDetectorAdapter(cascade); + + DetectionBasedTracker::Parameters params; + DetectionBasedTracker fd(MainDetector, TrackingDetector, params); fd.run(); @@ -108,12 +135,13 @@ static int test_FaceDetector(int argc, char *argv[]) double freq=getTickFrequency(); int num_images=images.size(); - for(int n=1; n <= num_images; n++) { + for(int n=1; n <= num_images; n++) + { int64 tcur=getTickCount(); int64 dt=tcur-tprev; tprev=tcur; double t_ms=((double)dt)/freq * 1000.0; - LOGD("\n\nSTEP n=%d from prev step %f ms\n\n", n, t_ms); + LOGD("\n\nSTEP n=%d from prev step %f ms\n", n, t_ms); m=images[n-1]; CV_Assert(! m.empty()); cvtColor(m, gray, CV_BGR2GRAY); @@ -123,11 +151,8 @@ static int test_FaceDetector(int argc, char *argv[]) vector result; fd.getObjects(result); - - - - - for(size_t i=0; i < result.size(); i++) { + for(size_t i=0; i < result.size(); i++) + { Rect r=result[i]; CV_Assert(r.area() > 0); Point tl=r.tl(); @@ -136,14 +161,14 @@ static int test_FaceDetector(int argc, char *argv[]) rectangle(m, tl, br, color, 3); } } + + char outfilename[256]; + for(int n=1; n <= num_images; n++) { - char outfilename[256]; - for(int n=1; n <= num_images; n++) { - snprintf(outfilename, sizeof(outfilename), outfilepattern, n); - LOGD("outfilename='%s'", outfilename); - m=images[n-1]; - imwrite(outfilename, m); - } + snprintf(outfilename, sizeof(outfilename), outfilepattern, n); + LOGD("outfilename='%s'", outfilename); + m=images[n-1]; + imwrite(outfilename, m); } fd.stop(); @@ -151,8 +176,6 @@ static int test_FaceDetector(int argc, char *argv[]) return 0; } - - int main(int argc, char *argv[]) { return test_FaceDetector(argc, argv);