From 099f2c07b59da29c43f2b35c76fe18702f819e70 Mon Sep 17 00:00:00 2001 From: ayberkozgur Date: Sun, 16 Nov 2014 12:38:59 +0100 Subject: [PATCH 01/23] Cleaned up tracking update and ensure grayscale --- src/Chilitags.cpp | 27 +++++++++++---------------- src/Track.cpp | 28 ++++++++++------------------ src/Track.hpp | 9 +++------ 3 files changed, 24 insertions(+), 40 deletions(-) diff --git a/src/Chilitags.cpp b/src/Chilitags.cpp index c5a06fd..d04b7d9 100644 --- a/src/Chilitags.cpp +++ b/src/Chilitags.cpp @@ -52,7 +52,7 @@ class Chilitags::Impl Impl() : mMaxInputWidth(0), - mResizedInput(), + mResizedGrayscaleInput(), mEnsureGreyscale(), mDecode(), @@ -115,10 +115,12 @@ TagCornerMap find( float scaleFactor = 1.0f; if (mMaxInputWidth > 0 && inputImage.cols > mMaxInputWidth) { scaleFactor =(float) inputImage.cols/(float)mMaxInputWidth; + static cv::Mat mResizedInput; cv::resize(inputImage, mResizedInput, cv::Size(), 1.0f/scaleFactor , 1.0f/scaleFactor , cv::INTER_NEAREST); + mResizedGrayscaleInput = mEnsureGreyscale(mResizedInput); } else { - mResizedInput = inputImage; + mResizedGrayscaleInput = mEnsureGreyscale(inputImage); } mCallsBeforeNextDetection = std::max(mCallsBeforeNextDetection-1, 0); @@ -127,28 +129,21 @@ TagCornerMap find( } if (detectionTrigger == TRACK_ONLY) - return scaleBy(mTrack(mResizedInput), scaleFactor); + return scaleBy(mTrack(mResizedGrayscaleInput), scaleFactor); // now we're going to do a full detection mCallsBeforeNextDetection = mCallsBeforeDetection; - cv::Mat greyscaleImage = mEnsureGreyscale(mResizedInput); TagCornerMap tags; - if (detectionTrigger == TRACK_AND_DETECT) { - // track first to override tracked tags with actually detected tags - tags = mTrack(mResizedInput); - } + // track first to override tracked tags with actually detected tags + if (detectionTrigger == TRACK_AND_DETECT) + tags = mTrack(mResizedGrayscaleInput); - mDetect(greyscaleImage, tags); + mDetect(mResizedGrayscaleInput, tags); - if (detectionTrigger == TRACK_AND_DETECT) { - // the current input image has already been updated in mTrack() + if (detectionTrigger == TRACK_AND_DETECT) mTrack.update(tags); - } - else { - mTrack.update(greyscaleImage, tags); - } return scaleBy(mFilter(tags), scaleFactor); }; @@ -201,7 +196,7 @@ cv::Mat draw(int id, int cellSize, bool withMargin, cv::Scalar color) const { protected: int mMaxInputWidth; -cv::Mat mResizedInput; +cv::Mat mResizedGrayscaleInput; EnsureGreyscale mEnsureGreyscale; diff --git a/src/Track.cpp b/src/Track.cpp index 734666a..d4498ab 100644 --- a/src/Track.cpp +++ b/src/Track.cpp @@ -27,9 +27,8 @@ namespace chilitags{ Track::Track(): mRefine(), -mEnsureGreyscale(), -mFromImage(), -mToImage(), +mPrevFrame(), +mCurrentFrame(), mFromTags() { } @@ -38,18 +37,12 @@ void Track::update(const TagCornerMap &tags) { mFromTags = tags; } -void Track::update( - const cv::Mat &inputImage, - const TagCornerMap &tags) { - mToImage = inputImage; - mFromTags = tags; -} - -TagCornerMap Track::operator()( - const cv::Mat &inputImage) { +TagCornerMap chilitags::Track::operator()(cv::Mat const& grayscaleInputImage) +{ - mEnsureGreyscale(mToImage).copyTo(mFromImage); - mToImage = mEnsureGreyscale(inputImage); + //Swap current and previous frames and get new frame + mCurrentFrame.copyTo(mPrevFrame); + grayscaleInputImage.copyTo(mCurrentFrame); std::vector status; std::vector errors; @@ -59,8 +52,7 @@ TagCornerMap Track::operator()( Quad result; static const float GROWTH_RATIO = 20.0f/10.0f; - cv::Rect roi = growRoi(mToImage, cv::Mat_(tag.second), GROWTH_RATIO); - + cv::Rect roi = growRoi(mCurrentFrame, cv::Mat_(tag.second), GROWTH_RATIO); cv::Point2f roiOffset = roi.tl(); for (int i : {0,1,2,3}) { tag.second(i,0) -= roiOffset.x; @@ -68,7 +60,7 @@ TagCornerMap Track::operator()( } cv::calcOpticalFlowPyrLK( - mFromImage(roi), mToImage(roi), + mPrevFrame(roi), mCurrentFrame(roi), tag.second, result, status, errors, //TODO play with parameters (with tests) @@ -82,7 +74,7 @@ TagCornerMap Track::operator()( } if (cv::sum(cv::Mat(status))[0] == status.size()) { - trackedTags[tag.first] = mRefine(mToImage, result, 0.5f/10.0f); + trackedTags[tag.first] = mRefine(mCurrentFrame, result, 0.5f/10.0f); } } diff --git a/src/Track.hpp b/src/Track.hpp index 96c535d..2c1d69e 100644 --- a/src/Track.hpp +++ b/src/Track.hpp @@ -26,7 +26,6 @@ #include #include "Refine.hpp" -#include "EnsureGreyscale.hpp" namespace chilitags { @@ -37,16 +36,14 @@ class Track Track(); void update(TagCornerMap const& tags); -void update(const cv::Mat &inputImage, TagCornerMap const& tags); -TagCornerMap operator()(const cv::Mat &inputImage); +TagCornerMap operator()(cv::Mat const& inputImage); protected: Refine mRefine; -EnsureGreyscale mEnsureGreyscale; -cv::Mat mFromImage; -cv::Mat mToImage; +cv::Mat mPrevFrame; +cv::Mat mCurrentFrame; TagCornerMap mFromTags; }; From 15159c3b39c0ff02e42d9947c1130587c995cb35 Mon Sep 17 00:00:00 2001 From: ayberkozgur Date: Sun, 16 Nov 2014 13:05:46 +0100 Subject: [PATCH 02/23] Tidied up detection trigger stuff in find() --- src/Chilitags.cpp | 58 ++++++++++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 23 deletions(-) diff --git a/src/Chilitags.cpp b/src/Chilitags.cpp index d04b7d9..54510e0 100644 --- a/src/Chilitags.cpp +++ b/src/Chilitags.cpp @@ -123,30 +123,42 @@ TagCornerMap find( mResizedGrayscaleInput = mEnsureGreyscale(inputImage); } - mCallsBeforeNextDetection = std::max(mCallsBeforeNextDetection-1, 0); - if (detectionTrigger == DETECT_PERIODICALLY) { - detectionTrigger = (mCallsBeforeNextDetection > 0)?TRACK_ONLY:TRACK_AND_DETECT; - } - - if (detectionTrigger == TRACK_ONLY) - return scaleBy(mTrack(mResizedGrayscaleInput), scaleFactor); - - // now we're going to do a full detection - mCallsBeforeNextDetection = mCallsBeforeDetection; - + // Do detection/tracking/both depending on detection trigger TagCornerMap tags; - - // track first to override tracked tags with actually detected tags - if (detectionTrigger == TRACK_AND_DETECT) - tags = mTrack(mResizedGrayscaleInput); - - mDetect(mResizedGrayscaleInput, tags); - - if (detectionTrigger == TRACK_AND_DETECT) - mTrack.update(tags); - - return scaleBy(mFilter(tags), scaleFactor); -}; + switch(detectionTrigger){ + + case DETECT_ONLY: + mDetect(mResizedGrayscaleInput, tags); + return scaleBy(mFilter(tags), scaleFactor); + + case TRACK_ONLY: + return scaleBy(mTrack(mResizedGrayscaleInput), scaleFactor); + + case TRACK_AND_DETECT: + + //Track and do one detection on top, overwriting track results + tags = mTrack(mResizedGrayscaleInput); + mDetect(mResizedGrayscaleInput, tags); + mTrack.update(tags); + return scaleBy(mFilter(tags), scaleFactor); + + case DETECT_PERIODICALLY: + mCallsBeforeNextDetection = std::max(mCallsBeforeNextDetection - 1, 0); + + //If detection period is not yet reaced, track only + if(mCallsBeforeNextDetection > 0) + return scaleBy(mTrack(mResizedGrayscaleInput), scaleFactor); + + //If detection period is reached, track and do one detection on top, overwriting track results + else{ + mCallsBeforeNextDetection = mCallsBeforeDetection; + tags = mTrack(mResizedGrayscaleInput); + mDetect(mResizedGrayscaleInput, tags); + mTrack.update(tags); + return scaleBy(mFilter(tags), scaleFactor); + } + } +} cv::Matx encode(int id) const { cv::Matx encodedId; From 1581ef7a44283ebb804d50454585db156741fa6a Mon Sep 17 00:00:00 2001 From: ayberkozgur Date: Sun, 16 Nov 2014 13:50:19 +0100 Subject: [PATCH 03/23] Added multithreaded detection trigger enums --- include/chilitags.hpp | 24 ++++++++++++++++++++++++ src/Chilitags.cpp | 8 ++++++++ 2 files changed, 32 insertions(+) diff --git a/include/chilitags.hpp b/include/chilitags.hpp index 45e7997..221e81d 100644 --- a/include/chilitags.hpp +++ b/include/chilitags.hpp @@ -148,6 +148,30 @@ enum DetectionTrigger { previous results. */ DETECT_PERIODICALLY, + + /** + * @brief Runs the detection in the background, with a period + * + * Runs the detection in a background thread, only tracking in the call to + * `find()`. + * + * `setDetectionPeriod()` allows to specify the number of calls between two + * detections. It defaults to 15, i.e. out of 15 consecutive calls to + * `find()`, the background thread will be informed to run detection. If + * the background thread takes more time than 15 calls to `find()`, it will + * be running as frequently as possible, i.e the same as + * `BACKGROUND_DETECT_ALWAYS`. + */ + BACKGROUND_DETECT_PERIODICALLY, + + /** + * @brief Runs the detection in the background, as frequently as possible + * + * Runs the detection in a background thread, only tracking in the call to + * `find()`. The detection is run as frequently as possible, i.e a new + * detection is started as soon as the previous one is finished. + */ + BACKGROUND_DETECT_ALWAYS }; /** diff --git a/src/Chilitags.cpp b/src/Chilitags.cpp index 54510e0..1592a61 100644 --- a/src/Chilitags.cpp +++ b/src/Chilitags.cpp @@ -157,6 +157,14 @@ TagCornerMap find( mTrack.update(tags); return scaleBy(mFilter(tags), scaleFactor); } + + case BACKGROUND_DETECT_PERIODICALLY: + + return tags; + + case BACKGROUND_DETECT_ALWAYS: + + return tags; } } From c64640fd3cde17365a9d305d96a58b0ee4175262 Mon Sep 17 00:00:00 2001 From: ayberkozgur Date: Sun, 16 Nov 2014 17:18:46 +0100 Subject: [PATCH 04/23] Initial background detection prototypes --- src/CMakeLists.txt | 4 +- src/Chilitags.cpp | 9 ++++- src/Detect.cpp | 95 +++++++++++++++++++++++++++++++++++++++------- src/Detect.hpp | 26 +++++++++++++ src/Track.cpp | 26 ++++++++++--- src/Track.hpp | 7 ++++ 6 files changed, 146 insertions(+), 21 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index eb38994..abc8289 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -32,8 +32,8 @@ add_library( ) -target_link_libraries(chilitags ${OpenCV_LIBS}) -target_link_libraries(chilitags_static ${OpenCV_LIBS}) +target_link_libraries(chilitags ${OpenCV_LIBS} pthread) +target_link_libraries(chilitags_static ${OpenCV_LIBS} pthread) install (TARGETS chilitags chilitags_static diff --git a/src/Chilitags.cpp b/src/Chilitags.cpp index 1592a61..9da8a6f 100644 --- a/src/Chilitags.cpp +++ b/src/Chilitags.cpp @@ -159,8 +159,15 @@ TagCornerMap find( } case BACKGROUND_DETECT_PERIODICALLY: + mDetect.launchBackgroundThread(mTrack); - return tags; + mCallsBeforeNextDetection = std::max(mCallsBeforeNextDetection - 1, 0); + + if(mCallsBeforeNextDetection == 0){ + mCallsBeforeNextDetection = mCallsBeforeDetection; + mDetect(mResizedGrayscaleInput, tags); //This does not update tags, nor does it block for computation + } + return mTrack(mResizedGrayscaleInput); case BACKGROUND_DETECT_ALWAYS: diff --git a/src/Detect.cpp b/src/Detect.cpp index 34a8088..eeb7fe0 100644 --- a/src/Detect.cpp +++ b/src/Detect.cpp @@ -28,39 +28,108 @@ Detect::Detect() : mFindQuads(), mRefine(), mReadBits(), - mDecode() + mDecode(), + mFrame(), + mTags(), + mBackgroundThread(), + mBackgroundRunning(false), + mNeedFrame(true), + mFrameDelivered(false) { } -void Detect::setMinInputWidth(int minWidth) { +void Detect::setMinInputWidth(int minWidth) +{ mFindQuads.setMinInputWidth(minWidth); } -void Detect::setCornerRefinement(bool refineCorners) { +void Detect::setCornerRefinement(bool refineCorners) +{ mRefineCorners = refineCorners; } -void Detect::operator()(cv::Mat const& greyscaleImage, TagCornerMap& tags) { +void Detect::launchBackgroundThread(Track& track) +{ + if(!mBackgroundRunning){ + mTrack = &track; + mBackgroundShouldRun = true; + mBackgroundRunning = true; + if(pthread_create(&mBackgroundThread, NULL, dispatchRun, (void*)this)){ + mBackgroundShouldRun = false; + mBackgroundRunning = false; + //TODO: Alarm that background thread could not be created + } + } +} + +void Detect::operator()(cv::Mat const& greyscaleImage, TagCornerMap& tags) +{ + + //Run single threaded + if(!mBackgroundRunning){ + mFrame = greyscaleImage; + mTags = tags; + doDetection(); + tags = mTags; //TODO: We can do better than copy back here + } + + //Detection thread running in the background, just deliver the frames and tags + else{ + if(mNeedFrame){ + pthread_mutex_lock(&inputLock); + greyscaleImage.copyTo(mFrame); + mTags = tags; //TODO: Do we really need to deliver tags here? + mFrameDelivered = true; + pthread_mutex_unlock(&inputLock); + } + } +} + +void* Detect::dispatchRun(void* args) +{ + static_cast(args)->run(); + return NULL; +} + +void Detect::run() +{ + while(mBackgroundShouldRun){ + while(!mFrameDelivered); //TODO: Replace this disgusting thing with a wait condition + + pthread_mutex_lock(&inputLock); + mNeedFrame = false; + doDetection(); + mTrack->update(mTags); + mNeedFrame = true; + mFrameDelivered = false; + pthread_mutex_unlock(&inputLock); + } + mBackgroundRunning = false; +} + +void Detect::doDetection() +{ if(mRefineCorners){ - for(const auto& quad : mFindQuads(greyscaleImage)){ - auto refinedQuad = mRefine(greyscaleImage, quad, 1.5f/10.0f); - auto tag = mDecode(mReadBits(greyscaleImage, refinedQuad), refinedQuad); + for(const auto& quad : mFindQuads(mFrame)){ + auto refinedQuad = mRefine(mFrame, quad, 1.5/10.); + auto tag = mDecode(mReadBits(mFrame, refinedQuad), refinedQuad); if(tag.first != Decode::INVALID_TAG) - tags[tag.first] = tag.second; + mTags[tag.first] = tag.second; else{ - tag = mDecode(mReadBits(greyscaleImage, quad), quad); + tag = mDecode(mReadBits(mFrame, quad), quad); if(tag.first != Decode::INVALID_TAG) - tags[tag.first] = tag.second; + mTags[tag.first] = tag.second; } } } else{ - for(const auto& quad : mFindQuads(greyscaleImage)){ - auto tag = mDecode(mReadBits(greyscaleImage, quad), quad); + for(const auto& quad : mFindQuads(mFrame)){ + auto tag = mDecode(mReadBits(mFrame, quad), quad); if(tag.first != Decode::INVALID_TAG) - tags[tag.first] = tag.second; + mTags[tag.first] = tag.second; } } } } /* namespace chilitags */ + diff --git a/src/Detect.hpp b/src/Detect.hpp index 9b944ad..b3371c5 100644 --- a/src/Detect.hpp +++ b/src/Detect.hpp @@ -23,11 +23,15 @@ #define DETECT_HPP #include +#include + #include + #include "FindQuads.hpp" #include "Decode.hpp" #include "Refine.hpp" #include "ReadBits.hpp" +#include "Track.hpp" namespace chilitags { @@ -41,15 +45,37 @@ class Detect { void setCornerRefinement(bool refineCorners); + void launchBackgroundThread(Track& track); + void operator()(cv::Mat const& inputImage, TagCornerMap& tags); protected: bool mRefineCorners; + FindQuads mFindQuads; Refine mRefine; ReadBits mReadBits; Decode mDecode; + + cv::Mat mFrame; + std::map mTags; + + Track* mTrack; + + pthread_t mBackgroundThread; + + bool mBackgroundRunning; + bool mBackgroundShouldRun; + bool mNeedFrame; + bool mFrameDelivered; + + pthread_mutex_t inputLock = PTHREAD_MUTEX_INITIALIZER; + + void doDetection(); + + static void* dispatchRun(void* args); + void run(); }; } /* namespace chilitags */ diff --git a/src/Track.cpp b/src/Track.cpp index d4498ab..1c4bb99 100644 --- a/src/Track.cpp +++ b/src/Track.cpp @@ -1,6 +1,7 @@ /******************************************************************************* * Copyright 2013-2014 EPFL * * Copyright 2013-2014 Quentin Bonnard * +* Copyright 2013-2014 Ayberk Özgür * * * * This file is part of chilitags. * * * @@ -29,24 +30,36 @@ Track::Track(): mRefine(), mPrevFrame(), mCurrentFrame(), -mFromTags() +mFromTags(), +inputLock(PTHREAD_MUTEX_INITIALIZER) { } -void Track::update(const TagCornerMap &tags) { - mFromTags = tags; +void Track::update(TagCornerMap const& tags) +{ + pthread_mutex_lock(&inputLock); + + //TODO: Hopefully there is a faster way to do this but might not worth the performance improvement; also `std::map::insert()` will not overwrite already existing key value pairs + + for(const auto& tag : tags) + mFromTags[tag.first] = tag.second; + + pthread_mutex_unlock(&inputLock); } -TagCornerMap chilitags::Track::operator()(cv::Mat const& grayscaleInputImage) +TagCornerMap Track::operator()(cv::Mat const& grayscaleInputImage) { //Swap current and previous frames and get new frame mCurrentFrame.copyTo(mPrevFrame); grayscaleInputImage.copyTo(mCurrentFrame); + //TODO: We can get by with only one copy here since track is always in the same thread as the one that delivers the input images std::vector status; std::vector errors; + //Do the tracking + pthread_mutex_lock(&inputLock); TagCornerMap trackedTags; for (auto tag : mFromTags) { Quad result; @@ -79,7 +92,10 @@ TagCornerMap chilitags::Track::operator()(cv::Mat const& grayscaleInputImage) } mFromTags = std::move(trackedTags); - return mFromTags; + std::map tagsCopy = mFromTags; //TODO: Try to get around this copy + pthread_mutex_unlock(&inputLock); + + return tagsCopy; } } /* namespace chilitags */ diff --git a/src/Track.hpp b/src/Track.hpp index 2c1d69e..ec892ab 100644 --- a/src/Track.hpp +++ b/src/Track.hpp @@ -1,6 +1,7 @@ /******************************************************************************* * Copyright 2013-2014 EPFL * * Copyright 2013-2014 Quentin Bonnard * +* Copyright 2013-2014 Ayberk Özgür * * * * This file is part of chilitags. * * * @@ -21,7 +22,10 @@ #ifndef Track_HPP #define Track_HPP +#include #include +#include + #include #include @@ -35,6 +39,7 @@ class Track Track(); +//Both these methods are thread-safe void update(TagCornerMap const& tags); TagCornerMap operator()(cv::Mat const& inputImage); @@ -46,6 +51,8 @@ cv::Mat mPrevFrame; cv::Mat mCurrentFrame; TagCornerMap mFromTags; +pthread_mutex_t inputLock; + }; } From 26c67b852ae1c3cf3884e255a0121a839ce2334b Mon Sep 17 00:00:00 2001 From: ayberkozgur Date: Sun, 16 Nov 2014 17:34:26 +0100 Subject: [PATCH 05/23] Implemented BACKGROUND_DETECT_ALWAYS prototype --- src/Chilitags.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Chilitags.cpp b/src/Chilitags.cpp index 9da8a6f..28953d6 100644 --- a/src/Chilitags.cpp +++ b/src/Chilitags.cpp @@ -160,19 +160,20 @@ TagCornerMap find( case BACKGROUND_DETECT_PERIODICALLY: mDetect.launchBackgroundThread(mTrack); - mCallsBeforeNextDetection = std::max(mCallsBeforeNextDetection - 1, 0); + //If the detection period is reached, deliver new frame to background detection thread if(mCallsBeforeNextDetection == 0){ mCallsBeforeNextDetection = mCallsBeforeDetection; mDetect(mResizedGrayscaleInput, tags); //This does not update tags, nor does it block for computation } - return mTrack(mResizedGrayscaleInput); + return scaleBy(mTrack(mResizedGrayscaleInput), scaleFactor); case BACKGROUND_DETECT_ALWAYS: - - return tags; - } + mDetect.launchBackgroundThread(mTrack); + mDetect(mResizedGrayscaleInput, tags); //This does not update tags, nor does it block for computation + return scaleBy(mTrack(mResizedGrayscaleInput), scaleFactor); + } } cv::Matx encode(int id) const { From 88c3ce144b36659792fd63931a617ebe10e4ff02 Mon Sep 17 00:00:00 2001 From: ayberkozgur Date: Sun, 16 Nov 2014 18:29:16 +0100 Subject: [PATCH 06/23] Replaced busy wait with condition wait in detection --- src/Detect.cpp | 24 +++++++++++++++--------- src/Detect.hpp | 4 ++-- src/Track.cpp | 10 +++++----- src/Track.hpp | 2 +- 4 files changed, 23 insertions(+), 17 deletions(-) diff --git a/src/Detect.cpp b/src/Detect.cpp index eeb7fe0..c661f84 100644 --- a/src/Detect.cpp +++ b/src/Detect.cpp @@ -34,7 +34,8 @@ Detect::Detect() : mBackgroundThread(), mBackgroundRunning(false), mNeedFrame(true), - mFrameDelivered(false) + mInputCond(PTHREAD_COND_INITIALIZER), + mInputLock(PTHREAD_MUTEX_INITIALIZER) { } @@ -73,14 +74,17 @@ void Detect::operator()(cv::Mat const& greyscaleImage, TagCornerMap& tags) tags = mTags; //TODO: We can do better than copy back here } - //Detection thread running in the background, just deliver the frames and tags + //Detection thread running in the background, just deliver the frame and tags else{ if(mNeedFrame){ - pthread_mutex_lock(&inputLock); + pthread_mutex_lock(&mInputLock); + greyscaleImage.copyTo(mFrame); mTags = tags; //TODO: Do we really need to deliver tags here? - mFrameDelivered = true; - pthread_mutex_unlock(&inputLock); + + //Wake up detection thread if it's waiting for the input frame + pthread_cond_signal(&mInputCond); + pthread_mutex_unlock(&mInputLock); } } } @@ -94,15 +98,17 @@ void* Detect::dispatchRun(void* args) void Detect::run() { while(mBackgroundShouldRun){ - while(!mFrameDelivered); //TODO: Replace this disgusting thing with a wait condition + pthread_mutex_lock(&mInputLock); + + //Wait for the input frame to arrive + pthread_cond_wait(&mInputCond, &mInputLock); - pthread_mutex_lock(&inputLock); mNeedFrame = false; doDetection(); mTrack->update(mTags); mNeedFrame = true; - mFrameDelivered = false; - pthread_mutex_unlock(&inputLock); + + pthread_mutex_unlock(&mInputLock); } mBackgroundRunning = false; } diff --git a/src/Detect.hpp b/src/Detect.hpp index b3371c5..b812178 100644 --- a/src/Detect.hpp +++ b/src/Detect.hpp @@ -68,9 +68,9 @@ class Detect { bool mBackgroundRunning; bool mBackgroundShouldRun; bool mNeedFrame; - bool mFrameDelivered; - pthread_mutex_t inputLock = PTHREAD_MUTEX_INITIALIZER; + pthread_cond_t mInputCond; + pthread_mutex_t mInputLock; void doDetection(); diff --git a/src/Track.cpp b/src/Track.cpp index 1c4bb99..d82c8c0 100644 --- a/src/Track.cpp +++ b/src/Track.cpp @@ -31,20 +31,20 @@ mRefine(), mPrevFrame(), mCurrentFrame(), mFromTags(), -inputLock(PTHREAD_MUTEX_INITIALIZER) +mInputLock(PTHREAD_MUTEX_INITIALIZER) { } void Track::update(TagCornerMap const& tags) { - pthread_mutex_lock(&inputLock); + pthread_mutex_lock(&mInputLock); //TODO: Hopefully there is a faster way to do this but might not worth the performance improvement; also `std::map::insert()` will not overwrite already existing key value pairs for(const auto& tag : tags) mFromTags[tag.first] = tag.second; - pthread_mutex_unlock(&inputLock); + pthread_mutex_unlock(&mInputLock); } TagCornerMap Track::operator()(cv::Mat const& grayscaleInputImage) @@ -59,7 +59,7 @@ TagCornerMap Track::operator()(cv::Mat const& grayscaleInputImage) std::vector errors; //Do the tracking - pthread_mutex_lock(&inputLock); + pthread_mutex_lock(&mInputLock); TagCornerMap trackedTags; for (auto tag : mFromTags) { Quad result; @@ -93,7 +93,7 @@ TagCornerMap Track::operator()(cv::Mat const& grayscaleInputImage) mFromTags = std::move(trackedTags); std::map tagsCopy = mFromTags; //TODO: Try to get around this copy - pthread_mutex_unlock(&inputLock); + pthread_mutex_unlock(&mInputLock); return tagsCopy; } diff --git a/src/Track.hpp b/src/Track.hpp index ec892ab..8721d2b 100644 --- a/src/Track.hpp +++ b/src/Track.hpp @@ -51,7 +51,7 @@ cv::Mat mPrevFrame; cv::Mat mCurrentFrame; TagCornerMap mFromTags; -pthread_mutex_t inputLock; +pthread_mutex_t mInputLock; }; From 8f09c2cef60814bb5555977e02f7d0265bf01c3a Mon Sep 17 00:00:00 2001 From: ayberkozgur Date: Sun, 16 Nov 2014 19:56:44 +0100 Subject: [PATCH 07/23] Added background detection sample --- CMakeLists.txt | 17 ++- samples/CMakeLists.txt | 10 ++ .../multithreaded/background-detection.cpp | 139 ++++++++++++++++++ src/Detect.cpp | 20 +++ src/Detect.hpp | 6 + 5 files changed, 187 insertions(+), 5 deletions(-) create mode 100644 samples/multithreaded/background-detection.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index b3e1ea2..0775486 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -64,14 +64,24 @@ else() option(WITH_TOOLS "provides the marker generation tool" ON) endif() +########################################## +## Chilitags lib ### +########################################## + if(${OpenCV_VERSION} VERSION_GREATER 2.9.0) add_definitions(-DOPENCV3) endif() +if(WITH_SAMPLES) + add_definitions(-DDEBUG_DETECT_TIMES) +endif() include_directories(include) add_subdirectory(src) -# documentation generation +########################################## +## Modules ### +########################################## + include("${CMAKE_SOURCE_DIR}/cmake/TargetDoc.cmake" OPTIONAL) if (WITH_TOOLS) @@ -83,10 +93,6 @@ if (WITH_TOOLS) endif() if (WITH_SAMPLES) - if(NOT OPENCV_HIGHGUI_FOUND) - message(FATAL_ERROR "OpenCV compiled without support for highgui! Can not compile creator.") - endif() - add_subdirectory(samples) endif() @@ -103,3 +109,4 @@ if(ANDROID_INSTALL_LIBRARIES) message(FATAL_ERROR "ANDROID_PROJECT_ROOT undefined, can't install libraries inside Android project.") endif() endif() + diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index 67cef6a..2d02223 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -18,6 +18,10 @@ # along with Chilitags. If not, see . # ################################################################################ +if(NOT OPENCV_HIGHGUI_FOUND) + message(FATAL_ERROR "OpenCV compiled without support for highgui, cannot compile samples!") +endif() + add_executable( estimate3d 3destimation/estimate3d.cpp) target_link_libraries( estimate3d chilitags_static ) target_link_libraries( estimate3d ${OpenCV_LIBS} ) @@ -42,3 +46,9 @@ add_executable( tracking tracking/tracking.cpp) target_link_libraries( tracking chilitags ) target_link_libraries( tracking ${OpenCV_LIBS} ) install (TARGETS tracking RUNTIME DESTINATION bin) + +add_executable( background-detection multithreaded/background-detection.cpp) +target_link_libraries( background-detection chilitags ) +target_link_libraries( background-detection ${OpenCV_LIBS} ) +install (TARGETS background-detection RUNTIME DESTINATION bin) + diff --git a/samples/multithreaded/background-detection.cpp b/samples/multithreaded/background-detection.cpp new file mode 100644 index 0000000..290fe88 --- /dev/null +++ b/samples/multithreaded/background-detection.cpp @@ -0,0 +1,139 @@ +/******************************************************************************* + * Copyright 2013-2014 EPFL * + * Copyright 2013-2014 Quentin Bonnard * + * Copyright 2013-2014 Ayberk Özgür + * * + * This file is part of chilitags. * + * * + * Chilitags is free software: you can redistribute it and/or modify * + * it under the terms of the Lesser GNU General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * Chilitags is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public License * + * along with Chilitags. If not, see . * + *******************************************************************************/ + +#include + +#ifdef OPENCV3 +#include // getTickCount... +#include +#endif + +#include // CV_AA + +#include + +#include + +cv::Scalar COLOR = cv::Scalar(0, 0, 255); + +void drawTags(cv::Mat outputImage, std::map const& tags); + +int main(int argc, char* argv[]) +{ + // Initialising input video + int xRes = 640; + int yRes = 480; + int cameraIndex = 0; + if (argc > 2) { + xRes = std::atoi(argv[1]); + yRes = std::atoi(argv[2]); + } + if (argc > 3) { + cameraIndex = std::atoi(argv[3]); + } + + // The source of input images + cv::VideoCapture capture(cameraIndex); + if (!capture.isOpened()) + { + std::cerr << "Unable to initialise video capture." << std::endl; + return 1; + } +#ifdef OPENCV3 + capture.set(cv::CAP_PROP_FRAME_WIDTH, xRes); + capture.set(cv::CAP_PROP_FRAME_HEIGHT, yRes); +#else + capture.set(CV_CAP_PROP_FRAME_WIDTH, xRes); + capture.set(CV_CAP_PROP_FRAME_HEIGHT, yRes); +#endif + cv::Mat inputImage; + + chilitags::Chilitags chilitags; + chilitags.setFilter(0, 0.); + + cv::namedWindow("DisplayChilitags"); + + bool showPeriodic = true; + + char keyPressed; + while ('q' != (keyPressed = (char) cv::waitKey(1))) { + + // toggle the processing mode, according to user input + if (keyPressed == 't') showPeriodic = !showPeriodic; + + capture.read(inputImage); + + cv::Mat outputImage = inputImage.clone(); + + int64 startTime = cv::getTickCount(); + auto tags = chilitags.find(inputImage, showPeriodic ? chilitags::Chilitags::BACKGROUND_DETECT_PERIODICALLY : chilitags::Chilitags::BACKGROUND_DETECT_ALWAYS); + int64 endTime = cv::getTickCount(); + drawTags(outputImage, tags); + + //Print tracking time + double trackTime = 1000.0*((double) endTime - startTime)/cv::getTickFrequency(); + cv::putText(outputImage, + cv::format("[Main thread] Tracking took %4.2f ms", trackTime), + cv::Point(8,20), + cv::FONT_HERSHEY_SIMPLEX, 0.5, COLOR); + + //Print detection trigger + cv::putText(outputImage, + cv::format("Detection trigger: %s (press 't' to toggle)", showPeriodic ? "BACKGROUND_DETECT_PERIODICALLY" : "BACKGROUND_DETECT_ALWAYS"), + cv::Point(8,yRes - 8), + cv::FONT_HERSHEY_SIMPLEX, 0.5, COLOR); + + cv::imshow("DisplayChilitags", outputImage); + } + + cv::destroyWindow("DisplayChilitags"); + capture.release(); + + return 0; +} + +void drawTags( + cv::Mat outputImage, + const std::map &tags) +{ + for(const auto& tag : tags){ + + const cv::Mat_ corners(tag.second); + + for(size_t i = 0; i < 4; ++i){ + const int SHIFT = 16; + const float PRECISION = 1 << SHIFT; + cv::line( + outputImage, + PRECISION*corners(i), + PRECISION*corners((i+1)%4), +#ifdef OPENCV3 + COLOR, 3, cv::LINE_AA, SHIFT); +#else + COLOR, 3, CV_AA, SHIFT); +#endif + } + + cv::Point2f center = 0.5*(corners(0) + corners(2)); + cv::putText(outputImage, cv::format("%d", tag.first), center, + cv::FONT_HERSHEY_SIMPLEX, 0.5, COLOR); + } +} diff --git a/src/Detect.cpp b/src/Detect.cpp index c661f84..0a01b4f 100644 --- a/src/Detect.cpp +++ b/src/Detect.cpp @@ -100,12 +100,32 @@ void Detect::run() while(mBackgroundShouldRun){ pthread_mutex_lock(&mInputLock); +#ifdef DEBUG_DETECT_TIMES + int64 startTime = cv::getTickCount(); +#endif + //Wait for the input frame to arrive pthread_cond_wait(&mInputCond, &mInputLock); +#ifdef DEBUG_DETECT_TIMES + printf("[Detection thread] Waiting took %4.2f ms\n", + 1000.0*((double)cv::getTickCount() - (double)startTime)/cv::getTickFrequency()); +#endif + mNeedFrame = false; + +#ifdef DEBUG_DETECT_TIMES + startTime = cv::getTickCount(); +#endif + doDetection(); mTrack->update(mTags); + +#ifdef DEBUG_DETECT_TIMES + printf("[Detection thread] Detection took %4.2f ms \n", + 1000.0*((double)cv::getTickCount() - (double)startTime)/cv::getTickFrequency()); +#endif + mNeedFrame = true; pthread_mutex_unlock(&mInputLock); diff --git a/src/Detect.hpp b/src/Detect.hpp index b812178..195cc92 100644 --- a/src/Detect.hpp +++ b/src/Detect.hpp @@ -27,6 +27,12 @@ #include +#ifdef DEBUG_DETECT_TIMES +#ifdef OPENCV3 +#include +#endif +#endif + #include "FindQuads.hpp" #include "Decode.hpp" #include "Refine.hpp" From e409250433cec59249f05abba86b5927fc281b39 Mon Sep 17 00:00:00 2001 From: ayberkozgur Date: Mon, 17 Nov 2014 10:39:45 +0100 Subject: [PATCH 08/23] Typo corrections, ameliorations, updates --- README.md | 2 +- include/chilitags.hpp | 12 +++++++----- samples/multithreaded/background-detection.cpp | 1 - src/Chilitags.cpp | 14 +++++++------- src/Detect.cpp | 1 - src/Detect.hpp | 1 - src/Track.cpp | 1 - src/Track.hpp | 2 -- 8 files changed, 15 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 3a57da0..78271f0 100644 --- a/README.md +++ b/README.md @@ -176,7 +176,7 @@ for a research project. Let us make that easy for you: ``` @misc{chilitags, title = {Chilitags 2: Robust Fiducial Markers for Augmented Reality and Robotics.}, - author={Bonnard, Quentin and Lemaignan, S\'{e}verin and Zufferey, Guillaume and Mazzei, Andrea and Cuendet, S\'{e}bastien and Li, Nan and Dillenbourg, Pierre}, + author={Bonnard, Quentin and Lemaignan, S\'{e}verin and Zufferey, Guillaume and Mazzei, Andrea and Cuendet, S\'{e}bastien and Li, Nan and \"{O}zg\"{u}r, Ayberk and Dillenbourg, Pierre}, publisher={CHILI, EPFL, Switzerland}, url={http://chili.epfl.ch/software}, year={2013} diff --git a/include/chilitags.hpp b/include/chilitags.hpp index 221e81d..b6f4c89 100644 --- a/include/chilitags.hpp +++ b/include/chilitags.hpp @@ -157,10 +157,11 @@ enum DetectionTrigger { * * `setDetectionPeriod()` allows to specify the number of calls between two * detections. It defaults to 15, i.e. out of 15 consecutive calls to - * `find()`, the background thread will be informed to run detection. If - * the background thread takes more time than 15 calls to `find()`, it will - * be running as frequently as possible, i.e the same as - * `BACKGROUND_DETECT_ALWAYS`. + * `find()`, the background thread will be informed to run detection. After + * this, a new detection will be done as soon as a new image frame is + * presented in the call to `find()`. If the background thread takes more + * time than 15 calls to `find()`, it will be running as frequently as + * possible, i.e the same as `BACKGROUND_DETECT_ALWAYS`. */ BACKGROUND_DETECT_PERIODICALLY, @@ -169,7 +170,8 @@ enum DetectionTrigger { * * Runs the detection in a background thread, only tracking in the call to * `find()`. The detection is run as frequently as possible, i.e a new - * detection is started as soon as the previous one is finished. + * detection is started as soon as the new image frame is presented in the + * call to `find()` after the previous detection is finished. */ BACKGROUND_DETECT_ALWAYS }; diff --git a/samples/multithreaded/background-detection.cpp b/samples/multithreaded/background-detection.cpp index 290fe88..66b3301 100644 --- a/samples/multithreaded/background-detection.cpp +++ b/samples/multithreaded/background-detection.cpp @@ -1,7 +1,6 @@ /******************************************************************************* * Copyright 2013-2014 EPFL * * Copyright 2013-2014 Quentin Bonnard * - * Copyright 2013-2014 Ayberk Özgür * * * This file is part of chilitags. * * * diff --git a/src/Chilitags.cpp b/src/Chilitags.cpp index 28953d6..5de6666 100644 --- a/src/Chilitags.cpp +++ b/src/Chilitags.cpp @@ -115,9 +115,9 @@ TagCornerMap find( float scaleFactor = 1.0f; if (mMaxInputWidth > 0 && inputImage.cols > mMaxInputWidth) { scaleFactor =(float) inputImage.cols/(float)mMaxInputWidth; - static cv::Mat mResizedInput; - cv::resize(inputImage, mResizedInput, cv::Size(), 1.0f/scaleFactor , 1.0f/scaleFactor , cv::INTER_NEAREST); - mResizedGrayscaleInput = mEnsureGreyscale(mResizedInput); + static cv::Mat resizedInput; + cv::resize(inputImage, resizedInput, cv::Size(), 1.0f/scaleFactor , 1.0f/scaleFactor , cv::INTER_NEAREST); + mResizedGrayscaleInput = mEnsureGreyscale(resizedInput); } else { mResizedGrayscaleInput = mEnsureGreyscale(inputImage); @@ -143,9 +143,9 @@ TagCornerMap find( return scaleBy(mFilter(tags), scaleFactor); case DETECT_PERIODICALLY: - mCallsBeforeNextDetection = std::max(mCallsBeforeNextDetection - 1, 0); + mCallsBeforeNextDetection--; - //If detection period is not yet reaced, track only + //If detection period is not yet reached, track only if(mCallsBeforeNextDetection > 0) return scaleBy(mTrack(mResizedGrayscaleInput), scaleFactor); @@ -160,10 +160,10 @@ TagCornerMap find( case BACKGROUND_DETECT_PERIODICALLY: mDetect.launchBackgroundThread(mTrack); - mCallsBeforeNextDetection = std::max(mCallsBeforeNextDetection - 1, 0); + mCallsBeforeNextDetection--; //If the detection period is reached, deliver new frame to background detection thread - if(mCallsBeforeNextDetection == 0){ + if(mCallsBeforeNextDetection <= 0){ mCallsBeforeNextDetection = mCallsBeforeDetection; mDetect(mResizedGrayscaleInput, tags); //This does not update tags, nor does it block for computation } diff --git a/src/Detect.cpp b/src/Detect.cpp index 0a01b4f..2b9e7bd 100644 --- a/src/Detect.cpp +++ b/src/Detect.cpp @@ -1,7 +1,6 @@ /******************************************************************************* * Copyright 2013-2014 EPFL * * Copyright 2013-2014 Quentin Bonnard * - * Copyright 2013-2014 Ayberk Özgür * * * * This file is part of chilitags. * * * diff --git a/src/Detect.hpp b/src/Detect.hpp index 195cc92..a19a8b7 100644 --- a/src/Detect.hpp +++ b/src/Detect.hpp @@ -1,7 +1,6 @@ /******************************************************************************* * Copyright 2013-2014 EPFL * * Copyright 2013-2014 Quentin Bonnard * - * Copyright 2013-2014 Ayberk Özgür * * * * This file is part of chilitags. * * * diff --git a/src/Track.cpp b/src/Track.cpp index d82c8c0..7f50b39 100644 --- a/src/Track.cpp +++ b/src/Track.cpp @@ -1,7 +1,6 @@ /******************************************************************************* * Copyright 2013-2014 EPFL * * Copyright 2013-2014 Quentin Bonnard * -* Copyright 2013-2014 Ayberk Özgür * * * * This file is part of chilitags. * * * diff --git a/src/Track.hpp b/src/Track.hpp index 8721d2b..7216c17 100644 --- a/src/Track.hpp +++ b/src/Track.hpp @@ -1,7 +1,6 @@ /******************************************************************************* * Copyright 2013-2014 EPFL * * Copyright 2013-2014 Quentin Bonnard * -* Copyright 2013-2014 Ayberk Özgür * * * * This file is part of chilitags. * * * @@ -22,7 +21,6 @@ #ifndef Track_HPP #define Track_HPP -#include #include #include From b4deeba2722fde75c5bfa42c7c36ae6d018f3fc2 Mon Sep 17 00:00:00 2001 From: ayberkozgur Date: Mon, 17 Nov 2014 10:58:16 +0100 Subject: [PATCH 09/23] Changed BACKGROUND to ASYNC --- include/chilitags.hpp | 4 ++-- samples/multithreaded/background-detection.cpp | 4 ++-- src/Chilitags.cpp | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/chilitags.hpp b/include/chilitags.hpp index b6f4c89..4a9eca4 100644 --- a/include/chilitags.hpp +++ b/include/chilitags.hpp @@ -163,7 +163,7 @@ enum DetectionTrigger { * time than 15 calls to `find()`, it will be running as frequently as * possible, i.e the same as `BACKGROUND_DETECT_ALWAYS`. */ - BACKGROUND_DETECT_PERIODICALLY, + ASYNC_DETECT_PERIODICALLY, /** * @brief Runs the detection in the background, as frequently as possible @@ -173,7 +173,7 @@ enum DetectionTrigger { * detection is started as soon as the new image frame is presented in the * call to `find()` after the previous detection is finished. */ - BACKGROUND_DETECT_ALWAYS + ASYNC_DETECT_ALWAYS }; /** diff --git a/samples/multithreaded/background-detection.cpp b/samples/multithreaded/background-detection.cpp index 66b3301..b1e7b47 100644 --- a/samples/multithreaded/background-detection.cpp +++ b/samples/multithreaded/background-detection.cpp @@ -83,7 +83,7 @@ int main(int argc, char* argv[]) cv::Mat outputImage = inputImage.clone(); int64 startTime = cv::getTickCount(); - auto tags = chilitags.find(inputImage, showPeriodic ? chilitags::Chilitags::BACKGROUND_DETECT_PERIODICALLY : chilitags::Chilitags::BACKGROUND_DETECT_ALWAYS); + auto tags = chilitags.find(inputImage, showPeriodic ? chilitags::Chilitags::ASYNC_DETECT_PERIODICALLY : chilitags::Chilitags::ASYNC_DETECT_ALWAYS); int64 endTime = cv::getTickCount(); drawTags(outputImage, tags); @@ -96,7 +96,7 @@ int main(int argc, char* argv[]) //Print detection trigger cv::putText(outputImage, - cv::format("Detection trigger: %s (press 't' to toggle)", showPeriodic ? "BACKGROUND_DETECT_PERIODICALLY" : "BACKGROUND_DETECT_ALWAYS"), + cv::format("Detection trigger: %s (press 't' to toggle)", showPeriodic ? "ASYNC_DETECT_PERIODICALLY" : "ASYNC_DETECT_ALWAYS"), cv::Point(8,yRes - 8), cv::FONT_HERSHEY_SIMPLEX, 0.5, COLOR); diff --git a/src/Chilitags.cpp b/src/Chilitags.cpp index 5de6666..7a599e9 100644 --- a/src/Chilitags.cpp +++ b/src/Chilitags.cpp @@ -158,7 +158,7 @@ TagCornerMap find( return scaleBy(mFilter(tags), scaleFactor); } - case BACKGROUND_DETECT_PERIODICALLY: + case ASYNC_DETECT_PERIODICALLY: mDetect.launchBackgroundThread(mTrack); mCallsBeforeNextDetection--; @@ -169,7 +169,7 @@ TagCornerMap find( } return scaleBy(mTrack(mResizedGrayscaleInput), scaleFactor); - case BACKGROUND_DETECT_ALWAYS: + case ASYNC_DETECT_ALWAYS: mDetect.launchBackgroundThread(mTrack); mDetect(mResizedGrayscaleInput, tags); //This does not update tags, nor does it block for computation return scaleBy(mTrack(mResizedGrayscaleInput), scaleFactor); From 07fb1394b764eb5fc63bf09bee3ad3dde0218e8e Mon Sep 17 00:00:00 2001 From: ayberkozgur Date: Mon, 17 Nov 2014 11:23:25 +0100 Subject: [PATCH 10/23] Thread error message --- src/Detect.cpp | 3 ++- src/Detect.hpp | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Detect.cpp b/src/Detect.cpp index 2b9e7bd..f796ab0 100644 --- a/src/Detect.cpp +++ b/src/Detect.cpp @@ -57,7 +57,8 @@ void Detect::launchBackgroundThread(Track& track) if(pthread_create(&mBackgroundThread, NULL, dispatchRun, (void*)this)){ mBackgroundShouldRun = false; mBackgroundRunning = false; - //TODO: Alarm that background thread could not be created + std::cerr << "Error: Thread could not be launched in " << __PRETTY_FUNCTION__ + << ", not enough resources or PTHREAD_THREADS_MAX was hit!" << std::endl; } } } diff --git a/src/Detect.hpp b/src/Detect.hpp index a19a8b7..69b5e63 100644 --- a/src/Detect.hpp +++ b/src/Detect.hpp @@ -21,6 +21,7 @@ #ifndef DETECT_HPP #define DETECT_HPP +#include #include #include From 5c3156830c6fe4a01e99d07a33f3cc40f86c5044 Mon Sep 17 00:00:00 2001 From: ayberkozgur Date: Mon, 17 Nov 2014 12:59:28 +0100 Subject: [PATCH 11/23] Removed current frame copy in Track --- src/Track.cpp | 15 ++++++--------- src/Track.hpp | 1 - 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/Track.cpp b/src/Track.cpp index 7f50b39..1f7dece 100644 --- a/src/Track.cpp +++ b/src/Track.cpp @@ -28,7 +28,6 @@ namespace chilitags{ Track::Track(): mRefine(), mPrevFrame(), -mCurrentFrame(), mFromTags(), mInputLock(PTHREAD_MUTEX_INITIALIZER) { @@ -49,11 +48,6 @@ void Track::update(TagCornerMap const& tags) TagCornerMap Track::operator()(cv::Mat const& grayscaleInputImage) { - //Swap current and previous frames and get new frame - mCurrentFrame.copyTo(mPrevFrame); - grayscaleInputImage.copyTo(mCurrentFrame); - //TODO: We can get by with only one copy here since track is always in the same thread as the one that delivers the input images - std::vector status; std::vector errors; @@ -64,7 +58,7 @@ TagCornerMap Track::operator()(cv::Mat const& grayscaleInputImage) Quad result; static const float GROWTH_RATIO = 20.0f/10.0f; - cv::Rect roi = growRoi(mCurrentFrame, cv::Mat_(tag.second), GROWTH_RATIO); + cv::Rect roi = growRoi(grayscaleInputImage, cv::Mat_(tag.second), GROWTH_RATIO); cv::Point2f roiOffset = roi.tl(); for (int i : {0,1,2,3}) { tag.second(i,0) -= roiOffset.x; @@ -72,7 +66,7 @@ TagCornerMap Track::operator()(cv::Mat const& grayscaleInputImage) } cv::calcOpticalFlowPyrLK( - mPrevFrame(roi), mCurrentFrame(roi), + mPrevFrame(roi), grayscaleInputImage(roi), tag.second, result, status, errors, //TODO play with parameters (with tests) @@ -86,7 +80,7 @@ TagCornerMap Track::operator()(cv::Mat const& grayscaleInputImage) } if (cv::sum(cv::Mat(status))[0] == status.size()) { - trackedTags[tag.first] = mRefine(mCurrentFrame, result, 0.5f/10.0f); + trackedTags[tag.first] = mRefine(grayscaleInputImage, result, 0.5f/10.0f); } } @@ -94,6 +88,9 @@ TagCornerMap Track::operator()(cv::Mat const& grayscaleInputImage) std::map tagsCopy = mFromTags; //TODO: Try to get around this copy pthread_mutex_unlock(&mInputLock); + //Swap current and previous frames + grayscaleInputImage.copyTo(mPrevFrame); + return tagsCopy; } diff --git a/src/Track.hpp b/src/Track.hpp index 7216c17..ad8541b 100644 --- a/src/Track.hpp +++ b/src/Track.hpp @@ -46,7 +46,6 @@ TagCornerMap operator()(cv::Mat const& inputImage); Refine mRefine; cv::Mat mPrevFrame; -cv::Mat mCurrentFrame; TagCornerMap mFromTags; pthread_mutex_t mInputLock; From de8ced6b6fc4c2d2b6fbddd48f00a4f27b2d2ea2 Mon Sep 17 00:00:00 2001 From: ayberkozgur Date: Mon, 17 Nov 2014 13:43:18 +0100 Subject: [PATCH 12/23] Changed async thread timing --- CMakeLists.txt | 3 -- include/chilitags.hpp | 24 +++++++++++++ .../multithreaded/background-detection.cpp | 19 ++++++++-- src/Chilitags.cpp | 16 +++++++++ src/Detect.cpp | 36 +++++++++---------- src/Detect.hpp | 9 +++-- 6 files changed, 81 insertions(+), 26 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0775486..f7d4e3e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -71,9 +71,6 @@ endif() if(${OpenCV_VERSION} VERSION_GREATER 2.9.0) add_definitions(-DOPENCV3) endif() -if(WITH_SAMPLES) - add_definitions(-DDEBUG_DETECT_TIMES) -endif() include_directories(include) add_subdirectory(src) diff --git a/include/chilitags.hpp b/include/chilitags.hpp index 4a9eca4..dffb8db 100644 --- a/include/chilitags.hpp +++ b/include/chilitags.hpp @@ -202,6 +202,30 @@ TagCornerMap find( */ void setDetectionPeriod(int period); +/** + * @brief Gets the latest idle time in case of asynchronous detection + * + * In `ASYNC_DETECT_PERIODICALLY` and `ASYNC_DETECT_ALWAYS` triggers, returns + * the latest idle time of the asynchronous detection thread. Together with + * `getLatestAsyncDetectionWorkMillis()`, they make 100% of the detection + * thread's time. + * + * @return Detection thread's latest idle time in ms + */ +float getLatestAsyncDetectionIdleMillis(); + +/** + * @brief Gets the latest work time in case of asynchronous detection + * + * In `ASYNC_DETECT_PERIODICALLY` and `ASYNC_DETECT_ALWAYS` triggers, returns + * the latest work time of the asynchronous detection thread.Together with + * `getLatestAsyncDetectionIdleMillis()`, they make 100% of the detection + * thread's time. + * + * @return Detection thread's latest work time in ms + */ +float getLatestAsyncDetectionWorkMillis(); + /** Preset groups of parameters (for setPerformance()) to adjust the compromise between processing time and accuracy of detection. diff --git a/samples/multithreaded/background-detection.cpp b/samples/multithreaded/background-detection.cpp index b1e7b47..c6b9102 100644 --- a/samples/multithreaded/background-detection.cpp +++ b/samples/multithreaded/background-detection.cpp @@ -73,6 +73,7 @@ int main(int argc, char* argv[]) bool showPeriodic = true; char keyPressed; + float trackTime = 0, idleTime = 0, detectTime = 0; while ('q' != (keyPressed = (char) cv::waitKey(1))) { // toggle the processing mode, according to user input @@ -88,12 +89,26 @@ int main(int argc, char* argv[]) drawTags(outputImage, tags); //Print tracking time - double trackTime = 1000.0*((double) endTime - startTime)/cv::getTickFrequency(); + trackTime = 0.98f*trackTime + 0.02f*1000.0f*(((float)endTime - (float)startTime)/cv::getTickFrequency()); cv::putText(outputImage, - cv::format("[Main thread] Tracking took %4.2f ms", trackTime), + cv::format("[Main thread] Tracking time %4.2f ms", trackTime), cv::Point(8,20), cv::FONT_HERSHEY_SIMPLEX, 0.5, COLOR); + //Print detection idle time + idleTime = 0.98f*idleTime + 0.02f*chilitags.getLatestAsyncDetectionIdleMillis(); + cv::putText(outputImage, + cv::format("[Detection thread] Idle time %4.2f ms", idleTime), + cv::Point(8,36), + cv::FONT_HERSHEY_SIMPLEX, 0.5, COLOR); + + //Print detection work time + detectTime = 0.98f*detectTime + 0.02f*chilitags.getLatestAsyncDetectionWorkMillis(); + cv::putText(outputImage, + cv::format("[Detection thread] Work time %4.2f ms", detectTime), + cv::Point(8,52), + cv::FONT_HERSHEY_SIMPLEX, 0.5, COLOR); + //Print detection trigger cv::putText(outputImage, cv::format("Detection trigger: %s (press 't' to toggle)", showPeriodic ? "ASYNC_DETECT_PERIODICALLY" : "ASYNC_DETECT_ALWAYS"), diff --git a/src/Chilitags.cpp b/src/Chilitags.cpp index 7a599e9..6c125e9 100644 --- a/src/Chilitags.cpp +++ b/src/Chilitags.cpp @@ -107,6 +107,14 @@ void setDetectionPeriod(int period) { mCallsBeforeDetection = period; } +float getLatestAsyncDetectionIdleMillis(){ + return mDetect.getLatestAsyncIdleMillis(); +} + +float getLatestAsyncDetectionWorkMillis(){ + return mDetect.getLatestAsyncWorkMillis(); +} + TagCornerMap find( const cv::Mat &inputImage, DetectionTrigger detectionTrigger){ @@ -266,6 +274,14 @@ void Chilitags::setMinInputWidth(int minWidth) { mImpl->setMinInputWidth(minWidth); } +float Chilitags::getLatestAsyncDetectionIdleMillis(){ + return mImpl->getLatestAsyncDetectionIdleMillis(); +} + +float Chilitags::getLatestAsyncDetectionWorkMillis(){ + return mImpl->getLatestAsyncDetectionWorkMillis(); +} + TagCornerMap Chilitags::find( const cv::Mat &inputImage, DetectionTrigger trigger diff --git a/src/Detect.cpp b/src/Detect.cpp index f796ab0..a14f307 100644 --- a/src/Detect.cpp +++ b/src/Detect.cpp @@ -34,7 +34,9 @@ Detect::Detect() : mBackgroundRunning(false), mNeedFrame(true), mInputCond(PTHREAD_COND_INITIALIZER), - mInputLock(PTHREAD_MUTEX_INITIALIZER) + mInputLock(PTHREAD_MUTEX_INITIALIZER), + mLatestAsyncIdleMillis(0), + mLatestAsyncWorkMillis(0) { } @@ -100,31 +102,17 @@ void Detect::run() while(mBackgroundShouldRun){ pthread_mutex_lock(&mInputLock); -#ifdef DEBUG_DETECT_TIMES - int64 startTime = cv::getTickCount(); -#endif - //Wait for the input frame to arrive - pthread_cond_wait(&mInputCond, &mInputLock); - -#ifdef DEBUG_DETECT_TIMES - printf("[Detection thread] Waiting took %4.2f ms\n", - 1000.0*((double)cv::getTickCount() - (double)startTime)/cv::getTickFrequency()); -#endif + int64 startTime = cv::getTickCount(); + pthread_cond_wait(&mInputCond, &mInputLock); //This releases the lock while waiting + mLatestAsyncIdleMillis = 1000.0f*(((float)cv::getTickCount() - (float)startTime)/cv::getTickFrequency()); mNeedFrame = false; -#ifdef DEBUG_DETECT_TIMES startTime = cv::getTickCount(); -#endif - doDetection(); mTrack->update(mTags); - -#ifdef DEBUG_DETECT_TIMES - printf("[Detection thread] Detection took %4.2f ms \n", - 1000.0*((double)cv::getTickCount() - (double)startTime)/cv::getTickFrequency()); -#endif + mLatestAsyncWorkMillis = 1000.0f*(((float)cv::getTickCount() - (float)startTime)/cv::getTickFrequency()); mNeedFrame = true; @@ -157,5 +145,15 @@ void Detect::doDetection() } } +float Detect::getLatestAsyncIdleMillis() +{ + return mLatestAsyncIdleMillis; +} + +float Detect::getLatestAsyncWorkMillis() +{ + return mLatestAsyncWorkMillis; +} + } /* namespace chilitags */ diff --git a/src/Detect.hpp b/src/Detect.hpp index 69b5e63..f81ae07 100644 --- a/src/Detect.hpp +++ b/src/Detect.hpp @@ -27,11 +27,9 @@ #include -#ifdef DEBUG_DETECT_TIMES #ifdef OPENCV3 #include #endif -#endif #include "FindQuads.hpp" #include "Decode.hpp" @@ -51,6 +49,10 @@ class Detect { void setCornerRefinement(bool refineCorners); + float getLatestAsyncIdleMillis(); + + float getLatestAsyncWorkMillis(); + void launchBackgroundThread(Track& track); void operator()(cv::Mat const& inputImage, TagCornerMap& tags); @@ -78,6 +80,9 @@ class Detect { pthread_cond_t mInputCond; pthread_mutex_t mInputLock; + float mLatestAsyncIdleMillis; + float mLatestAsyncWorkMillis; + void doDetection(); static void* dispatchRun(void* args); From eaf756a607692eb69f6ef5c031eb8bc5251e65cd Mon Sep 17 00:00:00 2001 From: ayberkozgur Date: Mon, 17 Nov 2014 13:58:38 +0100 Subject: [PATCH 13/23] Removed tag list member copy when single threaded detection --- src/Detect.cpp | 16 +++++++--------- src/Detect.hpp | 4 ++-- src/Track.cpp | 2 +- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/Detect.cpp b/src/Detect.cpp index a14f307..c6adf03 100644 --- a/src/Detect.cpp +++ b/src/Detect.cpp @@ -71,9 +71,7 @@ void Detect::operator()(cv::Mat const& greyscaleImage, TagCornerMap& tags) //Run single threaded if(!mBackgroundRunning){ mFrame = greyscaleImage; - mTags = tags; - doDetection(); - tags = mTags; //TODO: We can do better than copy back here + doDetection(tags); } //Detection thread running in the background, just deliver the frame and tags @@ -110,7 +108,7 @@ void Detect::run() mNeedFrame = false; startTime = cv::getTickCount(); - doDetection(); + doDetection(mTags); mTrack->update(mTags); mLatestAsyncWorkMillis = 1000.0f*(((float)cv::getTickCount() - (float)startTime)/cv::getTickFrequency()); @@ -121,18 +119,18 @@ void Detect::run() mBackgroundRunning = false; } -void Detect::doDetection() +void Detect::doDetection(TagCornerMap& tags) { if(mRefineCorners){ for(const auto& quad : mFindQuads(mFrame)){ - auto refinedQuad = mRefine(mFrame, quad, 1.5/10.); + auto refinedQuad = mRefine(mFrame, quad, 1.5f/10.0f); auto tag = mDecode(mReadBits(mFrame, refinedQuad), refinedQuad); if(tag.first != Decode::INVALID_TAG) - mTags[tag.first] = tag.second; + tags[tag.first] = tag.second; else{ tag = mDecode(mReadBits(mFrame, quad), quad); if(tag.first != Decode::INVALID_TAG) - mTags[tag.first] = tag.second; + tags[tag.first] = tag.second; } } } @@ -140,7 +138,7 @@ void Detect::doDetection() for(const auto& quad : mFindQuads(mFrame)){ auto tag = mDecode(mReadBits(mFrame, quad), quad); if(tag.first != Decode::INVALID_TAG) - mTags[tag.first] = tag.second; + tags[tag.first] = tag.second; } } } diff --git a/src/Detect.hpp b/src/Detect.hpp index f81ae07..c689c11 100644 --- a/src/Detect.hpp +++ b/src/Detect.hpp @@ -67,7 +67,7 @@ class Detect { Decode mDecode; cv::Mat mFrame; - std::map mTags; + TagCornerMap mTags; Track* mTrack; @@ -83,7 +83,7 @@ class Detect { float mLatestAsyncIdleMillis; float mLatestAsyncWorkMillis; - void doDetection(); + void doDetection(TagCornerMap& tags); static void* dispatchRun(void* args); void run(); diff --git a/src/Track.cpp b/src/Track.cpp index 1f7dece..1b83fa7 100644 --- a/src/Track.cpp +++ b/src/Track.cpp @@ -85,7 +85,7 @@ TagCornerMap Track::operator()(cv::Mat const& grayscaleInputImage) } mFromTags = std::move(trackedTags); - std::map tagsCopy = mFromTags; //TODO: Try to get around this copy + TagCornerMap tagsCopy = mFromTags; //TODO: Try to get around this copy pthread_mutex_unlock(&mInputLock); //Swap current and previous frames From 58576e026a6f9e8510bc11caddb4426cab1dc8bb Mon Sep 17 00:00:00 2001 From: ayberkozgur Date: Mon, 17 Nov 2014 14:04:48 +0100 Subject: [PATCH 14/23] Don't pass tags to detection when async --- src/Detect.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Detect.cpp b/src/Detect.cpp index c6adf03..2a3a27a 100644 --- a/src/Detect.cpp +++ b/src/Detect.cpp @@ -80,7 +80,7 @@ void Detect::operator()(cv::Mat const& greyscaleImage, TagCornerMap& tags) pthread_mutex_lock(&mInputLock); greyscaleImage.copyTo(mFrame); - mTags = tags; //TODO: Do we really need to deliver tags here? + mTags.clear(); //Wake up detection thread if it's waiting for the input frame pthread_cond_signal(&mInputCond); From c7f0299f774bcc41a2d0df481095909ce13df95f Mon Sep 17 00:00:00 2001 From: ayberkozgur Date: Mon, 17 Nov 2014 14:50:47 +0100 Subject: [PATCH 15/23] Replaced tag update code --- src/Track.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/Track.cpp b/src/Track.cpp index 1b83fa7..635289c 100644 --- a/src/Track.cpp +++ b/src/Track.cpp @@ -37,10 +37,16 @@ void Track::update(TagCornerMap const& tags) { pthread_mutex_lock(&mInputLock); - //TODO: Hopefully there is a faster way to do this but might not worth the performance improvement; also `std::map::insert()` will not overwrite already existing key value pairs - - for(const auto& tag : tags) - mFromTags[tag.first] = tag.second; + auto targetIt = mFromTags.begin(); + for(const auto& tag : tags){ + while(targetIt != mFromTags.end() && targetIt->first < tag.first) + targetIt++; + + if(targetIt != mFromTags.end() && targetIt->first == tag.first) + targetIt->second = tag.second; + else + targetIt = mFromTags.insert(targetIt, tag); + } pthread_mutex_unlock(&mInputLock); } From bd9ce1782b55f69ca1207a8c51c85ba150b30612 Mon Sep 17 00:00:00 2001 From: ayberkozgur Date: Mon, 17 Nov 2014 15:22:04 +0100 Subject: [PATCH 16/23] Moved opencv utility header include to Detect source --- src/Detect.cpp | 4 ++++ src/Detect.hpp | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Detect.cpp b/src/Detect.cpp index 2a3a27a..a06eebd 100644 --- a/src/Detect.cpp +++ b/src/Detect.cpp @@ -22,6 +22,10 @@ namespace chilitags{ +#ifdef OPENCV3 +#include +#endif + Detect::Detect() : mRefineCorners(true), mFindQuads(), diff --git a/src/Detect.hpp b/src/Detect.hpp index c689c11..4e582d2 100644 --- a/src/Detect.hpp +++ b/src/Detect.hpp @@ -27,10 +27,6 @@ #include -#ifdef OPENCV3 -#include -#endif - #include "FindQuads.hpp" #include "Decode.hpp" #include "Refine.hpp" From 67fbf0002eb542fd976a3b02c8e490f4ab44adee Mon Sep 17 00:00:00 2001 From: ayberkozgur Date: Tue, 25 Nov 2014 09:17:32 +0100 Subject: [PATCH 17/23] Removed iostream from Detect.hpp --- src/Detect.cpp | 2 ++ src/Detect.hpp | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Detect.cpp b/src/Detect.cpp index a06eebd..8d07fa2 100644 --- a/src/Detect.cpp +++ b/src/Detect.cpp @@ -20,6 +20,8 @@ #include "Detect.hpp" +#include + namespace chilitags{ #ifdef OPENCV3 diff --git a/src/Detect.hpp b/src/Detect.hpp index 4e582d2..e7efc1c 100644 --- a/src/Detect.hpp +++ b/src/Detect.hpp @@ -21,7 +21,6 @@ #ifndef DETECT_HPP #define DETECT_HPP -#include #include #include From 68ddd198c1b6d57560bd21a401c097a48baa7ec1 Mon Sep 17 00:00:00 2001 From: ayberkozgur Date: Tue, 25 Nov 2014 09:50:54 +0100 Subject: [PATCH 18/23] Made pthread support optional --- CMakeLists.txt | 17 ++++----- include/chilitags.hpp | 4 +++ samples/CMakeLists.txt | 10 +++--- src/CMakeLists.txt | 18 +++++----- src/Chilitags.cpp | 11 ++++-- src/Detect.cpp | 82 +++++++++++++++++++++++------------------- src/Detect.hpp | 16 ++++++--- tools/CMakeLists.txt | 4 +++ 8 files changed, 98 insertions(+), 64 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f7d4e3e..8deba8f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,10 +36,11 @@ message(STATUS "OpenCV version: ${OpenCV_VERSION}") ## Options ### ########################################## -option(WITH_SAMPLES "compile misc demos" OFF) -option(WITH_TESTS "build tests" OFF) -option(WITH_JNI_BINDINGS "JNI bindings compatible with ordinary Java and Android" OFF) -option(ANDROID_INSTALL_LIBRARIES "Whether to install the chilitag libraries inside project at ANDROID_PROJECT_ROOT" OFF) +option(WITH_PTHREADS "Multithreading support with pthreads" ON) +option(WITH_SAMPLES "Build demos" OFF) +option(WITH_TESTS "Build tests" OFF) +option(WITH_JNI_BINDINGS "Build JNI bindings compatible with ordinary Java and Android" OFF) +option(ANDROID_INSTALL_LIBRARIES "Install the chilitag libraries inside project at ANDROID_PROJECT_ROOT" OFF) if(DEFINED ANDROID) #OPENCV has a nice macro for this: OCV_OPTION, consider using it. option(WITH_TOOLS "provides the marker generation tool" OFF) @@ -68,6 +69,10 @@ endif() ## Chilitags lib ### ########################################## +if(WITH_PTHREADS) + add_definitions(-DWITH_PTHREADS) +endif() + if(${OpenCV_VERSION} VERSION_GREATER 2.9.0) add_definitions(-DOPENCV3) endif() @@ -82,10 +87,6 @@ add_subdirectory(src) include("${CMAKE_SOURCE_DIR}/cmake/TargetDoc.cmake" OPTIONAL) if (WITH_TOOLS) - if(NOT OPENCV_HIGHGUI_FOUND) - message(FATAL_ERROR "OpenCV compiled without support for highgui! Can not compile detector.") - endif() - add_subdirectory(tools) endif() diff --git a/include/chilitags.hpp b/include/chilitags.hpp index dffb8db..0b9749b 100644 --- a/include/chilitags.hpp +++ b/include/chilitags.hpp @@ -149,6 +149,7 @@ enum DetectionTrigger { */ DETECT_PERIODICALLY, +#ifdef WITH_PTHREADS /** * @brief Runs the detection in the background, with a period * @@ -174,6 +175,7 @@ enum DetectionTrigger { * call to `find()` after the previous detection is finished. */ ASYNC_DETECT_ALWAYS +#endif }; /** @@ -202,6 +204,7 @@ TagCornerMap find( */ void setDetectionPeriod(int period); +#ifdef WITH_PTHREADS /** * @brief Gets the latest idle time in case of asynchronous detection * @@ -225,6 +228,7 @@ float getLatestAsyncDetectionIdleMillis(); * @return Detection thread's latest work time in ms */ float getLatestAsyncDetectionWorkMillis(); +#endif /** Preset groups of parameters (for setPerformance()) to adjust the diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index 2d02223..e3cbc78 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -47,8 +47,10 @@ target_link_libraries( tracking chilitags ) target_link_libraries( tracking ${OpenCV_LIBS} ) install (TARGETS tracking RUNTIME DESTINATION bin) -add_executable( background-detection multithreaded/background-detection.cpp) -target_link_libraries( background-detection chilitags ) -target_link_libraries( background-detection ${OpenCV_LIBS} ) -install (TARGETS background-detection RUNTIME DESTINATION bin) +if(WITH_PTHREADS) + add_executable( background-detection multithreaded/background-detection.cpp) + target_link_libraries( background-detection chilitags ) + target_link_libraries( background-detection ${OpenCV_LIBS} ) + install (TARGETS background-detection RUNTIME DESTINATION bin) +endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index abc8289..a683943 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -31,15 +31,17 @@ add_library( ${chilitags_source} ) +target_link_libraries(chilitags ${OpenCV_LIBS}) +target_link_libraries(chilitags_static ${OpenCV_LIBS}) -target_link_libraries(chilitags ${OpenCV_LIBS} pthread) -target_link_libraries(chilitags_static ${OpenCV_LIBS} pthread) - +if(WITH_PTHREADS) + target_link_libraries(chilitags pthread) + target_link_libraries(chilitags_static pthread) +endif() install (TARGETS chilitags chilitags_static - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib -# PUBLIC_HEADER DESTINATION include/chilitags + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib ) if(ANDROID_INSTALL_LIBRARIES) @@ -52,8 +54,8 @@ endif() file(GLOB_RECURSE chilitags_headers ../include/*) install(FILES - ${chilitags_headers} - DESTINATION include/chilitags + ${chilitags_headers} + DESTINATION include/chilitags ) ########################################## diff --git a/src/Chilitags.cpp b/src/Chilitags.cpp index 6c125e9..9c90114 100644 --- a/src/Chilitags.cpp +++ b/src/Chilitags.cpp @@ -27,8 +27,6 @@ #include -#include - // The class that takes care of all the detection of Chilitags. namespace chilitags { @@ -107,6 +105,7 @@ void setDetectionPeriod(int period) { mCallsBeforeDetection = period; } +#ifdef WITH_PTHREADS float getLatestAsyncDetectionIdleMillis(){ return mDetect.getLatestAsyncIdleMillis(); } @@ -114,6 +113,7 @@ float getLatestAsyncDetectionIdleMillis(){ float getLatestAsyncDetectionWorkMillis(){ return mDetect.getLatestAsyncWorkMillis(); } +#endif TagCornerMap find( const cv::Mat &inputImage, @@ -166,6 +166,7 @@ TagCornerMap find( return scaleBy(mFilter(tags), scaleFactor); } +#ifdef WITH_PTHREADS case ASYNC_DETECT_PERIODICALLY: mDetect.launchBackgroundThread(mTrack); mCallsBeforeNextDetection--; @@ -181,7 +182,9 @@ TagCornerMap find( mDetect.launchBackgroundThread(mTrack); mDetect(mResizedGrayscaleInput, tags); //This does not update tags, nor does it block for computation return scaleBy(mTrack(mResizedGrayscaleInput), scaleFactor); - } +#endif + + } } cv::Matx encode(int id) const { @@ -274,6 +277,7 @@ void Chilitags::setMinInputWidth(int minWidth) { mImpl->setMinInputWidth(minWidth); } +#ifdef WITH_PTHREADS float Chilitags::getLatestAsyncDetectionIdleMillis(){ return mImpl->getLatestAsyncDetectionIdleMillis(); } @@ -281,6 +285,7 @@ float Chilitags::getLatestAsyncDetectionIdleMillis(){ float Chilitags::getLatestAsyncDetectionWorkMillis(){ return mImpl->getLatestAsyncDetectionWorkMillis(); } +#endif TagCornerMap Chilitags::find( const cv::Mat &inputImage, diff --git a/src/Detect.cpp b/src/Detect.cpp index 8d07fa2..a44ea30 100644 --- a/src/Detect.cpp +++ b/src/Detect.cpp @@ -35,14 +35,16 @@ Detect::Detect() : mReadBits(), mDecode(), mFrame(), - mTags(), - mBackgroundThread(), + mTags() +#ifdef WITH_PTHREADS + ,mBackgroundThread(), mBackgroundRunning(false), mNeedFrame(true), mInputCond(PTHREAD_COND_INITIALIZER), mInputLock(PTHREAD_MUTEX_INITIALIZER), mLatestAsyncIdleMillis(0), mLatestAsyncWorkMillis(0) +#endif { } @@ -56,24 +58,33 @@ void Detect::setCornerRefinement(bool refineCorners) mRefineCorners = refineCorners; } -void Detect::launchBackgroundThread(Track& track) +void Detect::doDetection(TagCornerMap& tags) { - if(!mBackgroundRunning){ - mTrack = &track; - mBackgroundShouldRun = true; - mBackgroundRunning = true; - if(pthread_create(&mBackgroundThread, NULL, dispatchRun, (void*)this)){ - mBackgroundShouldRun = false; - mBackgroundRunning = false; - std::cerr << "Error: Thread could not be launched in " << __PRETTY_FUNCTION__ - << ", not enough resources or PTHREAD_THREADS_MAX was hit!" << std::endl; + if(mRefineCorners){ + for(const auto& quad : mFindQuads(mFrame)){ + auto refinedQuad = mRefine(mFrame, quad, 1.5f/10.0f); + auto tag = mDecode(mReadBits(mFrame, refinedQuad), refinedQuad); + if(tag.first != Decode::INVALID_TAG) + tags[tag.first] = tag.second; + else{ + tag = mDecode(mReadBits(mFrame, quad), quad); + if(tag.first != Decode::INVALID_TAG) + tags[tag.first] = tag.second; + } + } + } + else{ + for(const auto& quad : mFindQuads(mFrame)){ + auto tag = mDecode(mReadBits(mFrame, quad), quad); + if(tag.first != Decode::INVALID_TAG) + tags[tag.first] = tag.second; } } } void Detect::operator()(cv::Mat const& greyscaleImage, TagCornerMap& tags) { - +#ifdef WITH_PTHREADS //Run single threaded if(!mBackgroundRunning){ mFrame = greyscaleImage; @@ -93,6 +104,26 @@ void Detect::operator()(cv::Mat const& greyscaleImage, TagCornerMap& tags) pthread_mutex_unlock(&mInputLock); } } +#else + mFrame = greyscaleImage; + doDetection(tags); +#endif +} + +#ifdef WITH_PTHREADS +void Detect::launchBackgroundThread(Track& track) +{ + if(!mBackgroundRunning){ + mTrack = &track; + mBackgroundShouldRun = true; + mBackgroundRunning = true; + if(pthread_create(&mBackgroundThread, NULL, dispatchRun, (void*)this)){ + mBackgroundShouldRun = false; + mBackgroundRunning = false; + std::cerr << "Error: Thread could not be launched in " << __PRETTY_FUNCTION__ + << ", not enough resources or PTHREAD_THREADS_MAX was hit!" << std::endl; + } + } } void* Detect::dispatchRun(void* args) @@ -125,30 +156,6 @@ void Detect::run() mBackgroundRunning = false; } -void Detect::doDetection(TagCornerMap& tags) -{ - if(mRefineCorners){ - for(const auto& quad : mFindQuads(mFrame)){ - auto refinedQuad = mRefine(mFrame, quad, 1.5f/10.0f); - auto tag = mDecode(mReadBits(mFrame, refinedQuad), refinedQuad); - if(tag.first != Decode::INVALID_TAG) - tags[tag.first] = tag.second; - else{ - tag = mDecode(mReadBits(mFrame, quad), quad); - if(tag.first != Decode::INVALID_TAG) - tags[tag.first] = tag.second; - } - } - } - else{ - for(const auto& quad : mFindQuads(mFrame)){ - auto tag = mDecode(mReadBits(mFrame, quad), quad); - if(tag.first != Decode::INVALID_TAG) - tags[tag.first] = tag.second; - } - } -} - float Detect::getLatestAsyncIdleMillis() { return mLatestAsyncIdleMillis; @@ -158,6 +165,7 @@ float Detect::getLatestAsyncWorkMillis() { return mLatestAsyncWorkMillis; } +#endif } /* namespace chilitags */ diff --git a/src/Detect.hpp b/src/Detect.hpp index e7efc1c..11ceee6 100644 --- a/src/Detect.hpp +++ b/src/Detect.hpp @@ -22,7 +22,10 @@ #define DETECT_HPP #include + +#ifdef WITH_PTHREADS #include +#endif #include @@ -44,13 +47,15 @@ class Detect { void setCornerRefinement(bool refineCorners); + void operator()(cv::Mat const& inputImage, TagCornerMap& tags); + +#ifdef WITH_PTHREADS float getLatestAsyncIdleMillis(); float getLatestAsyncWorkMillis(); void launchBackgroundThread(Track& track); - - void operator()(cv::Mat const& inputImage, TagCornerMap& tags); +#endif protected: @@ -64,6 +69,9 @@ class Detect { cv::Mat mFrame; TagCornerMap mTags; + void doDetection(TagCornerMap& tags); + +#ifdef WITH_PTHREADS Track* mTrack; pthread_t mBackgroundThread; @@ -78,10 +86,10 @@ class Detect { float mLatestAsyncIdleMillis; float mLatestAsyncWorkMillis; - void doDetection(TagCornerMap& tags); - static void* dispatchRun(void* args); void run(); +#endif + }; } /* namespace chilitags */ diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 13ab22e..051b327 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -18,6 +18,10 @@ # along with Chilitags. If not, see . # ################################################################################ +if(NOT OPENCV_HIGHGUI_FOUND) + message(FATAL_ERROR "OpenCV compiled without support for highgui! Can not compile detector.") +endif() + add_executable(chilitags-creator creator/creator.cpp) target_link_libraries( chilitags-creator ${OpenCV_LIBS} ) target_link_libraries( chilitags-creator chilitags ) From 21cd9e20d25fd75fc932f3a5a99f85ff31c6a5d4 Mon Sep 17 00:00:00 2001 From: ayberkozgur Date: Tue, 25 Nov 2014 09:59:13 +0100 Subject: [PATCH 19/23] Made Chilitags.cpp resizedInput a member --- src/Chilitags.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Chilitags.cpp b/src/Chilitags.cpp index 9c90114..ce6a41f 100644 --- a/src/Chilitags.cpp +++ b/src/Chilitags.cpp @@ -122,10 +122,9 @@ TagCornerMap find( // Resize the input image to make it at most mMaxInputWidth wide float scaleFactor = 1.0f; if (mMaxInputWidth > 0 && inputImage.cols > mMaxInputWidth) { - scaleFactor =(float) inputImage.cols/(float)mMaxInputWidth; - static cv::Mat resizedInput; - cv::resize(inputImage, resizedInput, cv::Size(), 1.0f/scaleFactor , 1.0f/scaleFactor , cv::INTER_NEAREST); - mResizedGrayscaleInput = mEnsureGreyscale(resizedInput); + scaleFactor = (float)inputImage.cols/(float)mMaxInputWidth; + cv::resize(inputImage, mResizedInput, cv::Size(), 1.0f/scaleFactor , 1.0f/scaleFactor , cv::INTER_NEAREST); + mResizedGrayscaleInput = mEnsureGreyscale(mResizedInput); } else { mResizedGrayscaleInput = mEnsureGreyscale(inputImage); @@ -235,6 +234,7 @@ cv::Mat draw(int id, int cellSize, bool withMargin, cv::Scalar color) const { protected: int mMaxInputWidth; +cv::Mat mResizedInput; cv::Mat mResizedGrayscaleInput; EnsureGreyscale mEnsureGreyscale; From b56a51b9e9d161f0f7ce666b022c064d379c80f0 Mon Sep 17 00:00:00 2001 From: ayberkozgur Date: Tue, 25 Nov 2014 10:08:21 +0100 Subject: [PATCH 20/23] Renamed sample background-detection to async-detection --- samples/CMakeLists.txt | 8 ++++---- .../{background-detection.cpp => async-detection.cpp} | 0 2 files changed, 4 insertions(+), 4 deletions(-) rename samples/multithreaded/{background-detection.cpp => async-detection.cpp} (100%) diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index e3cbc78..c966f3d 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -48,9 +48,9 @@ target_link_libraries( tracking ${OpenCV_LIBS} ) install (TARGETS tracking RUNTIME DESTINATION bin) if(WITH_PTHREADS) - add_executable( background-detection multithreaded/background-detection.cpp) - target_link_libraries( background-detection chilitags ) - target_link_libraries( background-detection ${OpenCV_LIBS} ) - install (TARGETS background-detection RUNTIME DESTINATION bin) + add_executable( async-detection multithreaded/async-detection.cpp) + target_link_libraries( async-detection chilitags ) + target_link_libraries( async-detection ${OpenCV_LIBS} ) + install (TARGETS async-detection RUNTIME DESTINATION bin) endif() diff --git a/samples/multithreaded/background-detection.cpp b/samples/multithreaded/async-detection.cpp similarity index 100% rename from samples/multithreaded/background-detection.cpp rename to samples/multithreaded/async-detection.cpp From 85c0a2d7eac4f556fcfb0ea4023610b701f199a6 Mon Sep 17 00:00:00 2001 From: ayberkozgur Date: Tue, 25 Nov 2014 10:32:05 +0100 Subject: [PATCH 21/23] Platform specific pthread inclusion --- CMakeLists.txt | 6 +++++- src/CMakeLists.txt | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8deba8f..c1b205e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,13 +36,13 @@ message(STATUS "OpenCV version: ${OpenCV_VERSION}") ## Options ### ########################################## -option(WITH_PTHREADS "Multithreading support with pthreads" ON) option(WITH_SAMPLES "Build demos" OFF) option(WITH_TESTS "Build tests" OFF) option(WITH_JNI_BINDINGS "Build JNI bindings compatible with ordinary Java and Android" OFF) option(ANDROID_INSTALL_LIBRARIES "Install the chilitag libraries inside project at ANDROID_PROJECT_ROOT" OFF) if(DEFINED ANDROID) #OPENCV has a nice macro for this: OCV_OPTION, consider using it. + option(WITH_PTHREADS "Multithreading support with pthreads" ON) option(WITH_TOOLS "provides the marker generation tool" OFF) #Set Android install path @@ -61,7 +61,11 @@ if(DEFINED ANDROID) #OPENCV has a nice macro for this: OCV_OPTION, consider usin if(NOT DEFINED ENV{ANDROID_TOOLCHAIN_NAME}) message(FATAL_ERROR "Please define the ANDROID_TOOLCHAIN_NAME environment variable first, e.g arm-linux-androideabi-4.8") endif() +elseif(UNIX) + option(WITH_PTHREADS "Multithreading support with pthreads" ON) + option(WITH_TOOLS "provides the marker generation tool" ON) else() + option(WITH_PTHREADS "Multithreading support with pthreads" OFF) option(WITH_TOOLS "provides the marker generation tool" ON) endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a683943..9a81a73 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -34,7 +34,7 @@ add_library( target_link_libraries(chilitags ${OpenCV_LIBS}) target_link_libraries(chilitags_static ${OpenCV_LIBS}) -if(WITH_PTHREADS) +if(WITH_PTHREADS AND NOT DEFINED ANDROID) #Android pthreads don't require -lpthread target_link_libraries(chilitags pthread) target_link_libraries(chilitags_static pthread) endif() From dfe47406d38b9e4650524955637d1f196c1c95bf Mon Sep 17 00:00:00 2001 From: ayberkozgur Date: Tue, 25 Nov 2014 13:22:44 +0100 Subject: [PATCH 22/23] Replaced WITH_PTHREADS with HAS_MULTITHREADING in source --- CMakeLists.txt | 2 +- include/chilitags.hpp | 4 ++-- src/Chilitags.cpp | 6 +++--- src/Detect.cpp | 6 +++--- src/Detect.hpp | 6 +++--- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c1b205e..34b0022 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -74,7 +74,7 @@ endif() ########################################## if(WITH_PTHREADS) - add_definitions(-DWITH_PTHREADS) + add_definitions(-DHAS_MULTITHREADING) endif() if(${OpenCV_VERSION} VERSION_GREATER 2.9.0) diff --git a/include/chilitags.hpp b/include/chilitags.hpp index 0b9749b..fd4e93b 100644 --- a/include/chilitags.hpp +++ b/include/chilitags.hpp @@ -149,7 +149,7 @@ enum DetectionTrigger { */ DETECT_PERIODICALLY, -#ifdef WITH_PTHREADS +#ifdef HAS_MULTITHREADING /** * @brief Runs the detection in the background, with a period * @@ -204,7 +204,7 @@ TagCornerMap find( */ void setDetectionPeriod(int period); -#ifdef WITH_PTHREADS +#ifdef HAS_MULTITHREADING /** * @brief Gets the latest idle time in case of asynchronous detection * diff --git a/src/Chilitags.cpp b/src/Chilitags.cpp index ce6a41f..6864691 100644 --- a/src/Chilitags.cpp +++ b/src/Chilitags.cpp @@ -105,7 +105,7 @@ void setDetectionPeriod(int period) { mCallsBeforeDetection = period; } -#ifdef WITH_PTHREADS +#ifdef HAS_MULTITHREADING float getLatestAsyncDetectionIdleMillis(){ return mDetect.getLatestAsyncIdleMillis(); } @@ -165,7 +165,7 @@ TagCornerMap find( return scaleBy(mFilter(tags), scaleFactor); } -#ifdef WITH_PTHREADS +#ifdef HAS_MULTITHREADING case ASYNC_DETECT_PERIODICALLY: mDetect.launchBackgroundThread(mTrack); mCallsBeforeNextDetection--; @@ -277,7 +277,7 @@ void Chilitags::setMinInputWidth(int minWidth) { mImpl->setMinInputWidth(minWidth); } -#ifdef WITH_PTHREADS +#ifdef HAS_MULTITHREADING float Chilitags::getLatestAsyncDetectionIdleMillis(){ return mImpl->getLatestAsyncDetectionIdleMillis(); } diff --git a/src/Detect.cpp b/src/Detect.cpp index a44ea30..3b2200b 100644 --- a/src/Detect.cpp +++ b/src/Detect.cpp @@ -36,7 +36,7 @@ Detect::Detect() : mDecode(), mFrame(), mTags() -#ifdef WITH_PTHREADS +#ifdef HAS_MULTITHREADING ,mBackgroundThread(), mBackgroundRunning(false), mNeedFrame(true), @@ -84,7 +84,7 @@ void Detect::doDetection(TagCornerMap& tags) void Detect::operator()(cv::Mat const& greyscaleImage, TagCornerMap& tags) { -#ifdef WITH_PTHREADS +#ifdef HAS_MULTITHREADING //Run single threaded if(!mBackgroundRunning){ mFrame = greyscaleImage; @@ -110,7 +110,7 @@ void Detect::operator()(cv::Mat const& greyscaleImage, TagCornerMap& tags) #endif } -#ifdef WITH_PTHREADS +#ifdef HAS_MULTITHREADING void Detect::launchBackgroundThread(Track& track) { if(!mBackgroundRunning){ diff --git a/src/Detect.hpp b/src/Detect.hpp index 11ceee6..b33bd82 100644 --- a/src/Detect.hpp +++ b/src/Detect.hpp @@ -23,7 +23,7 @@ #include -#ifdef WITH_PTHREADS +#ifdef HAS_MULTITHREADING #include #endif @@ -49,7 +49,7 @@ class Detect { void operator()(cv::Mat const& inputImage, TagCornerMap& tags); -#ifdef WITH_PTHREADS +#ifdef HAS_MULTITHREADING float getLatestAsyncIdleMillis(); float getLatestAsyncWorkMillis(); @@ -71,7 +71,7 @@ class Detect { void doDetection(TagCornerMap& tags); -#ifdef WITH_PTHREADS +#ifdef HAS_MULTITHREADING Track* mTrack; pthread_t mBackgroundThread; From fe352884def0804f5d4ed93b4304902ad866a8b9 Mon Sep 17 00:00:00 2001 From: ayberkozgur Date: Sat, 29 Nov 2014 20:13:23 +0100 Subject: [PATCH 23/23] Removed async thread timing API, added async thread shutdown --- include/chilitags.hpp | 26 ------------ samples/multithreaded/async-detection.cpp | 48 ++++++++++------------- src/Chilitags.cpp | 38 ++++++++---------- src/Detect.cpp | 28 ++++++------- src/Detect.hpp | 9 +---- 5 files changed, 50 insertions(+), 99 deletions(-) diff --git a/include/chilitags.hpp b/include/chilitags.hpp index fd4e93b..b50ba60 100644 --- a/include/chilitags.hpp +++ b/include/chilitags.hpp @@ -204,32 +204,6 @@ TagCornerMap find( */ void setDetectionPeriod(int period); -#ifdef HAS_MULTITHREADING -/** - * @brief Gets the latest idle time in case of asynchronous detection - * - * In `ASYNC_DETECT_PERIODICALLY` and `ASYNC_DETECT_ALWAYS` triggers, returns - * the latest idle time of the asynchronous detection thread. Together with - * `getLatestAsyncDetectionWorkMillis()`, they make 100% of the detection - * thread's time. - * - * @return Detection thread's latest idle time in ms - */ -float getLatestAsyncDetectionIdleMillis(); - -/** - * @brief Gets the latest work time in case of asynchronous detection - * - * In `ASYNC_DETECT_PERIODICALLY` and `ASYNC_DETECT_ALWAYS` triggers, returns - * the latest work time of the asynchronous detection thread.Together with - * `getLatestAsyncDetectionIdleMillis()`, they make 100% of the detection - * thread's time. - * - * @return Detection thread's latest work time in ms - */ -float getLatestAsyncDetectionWorkMillis(); -#endif - /** Preset groups of parameters (for setPerformance()) to adjust the compromise between processing time and accuracy of detection. diff --git a/samples/multithreaded/async-detection.cpp b/samples/multithreaded/async-detection.cpp index c6b9102..3174e72 100644 --- a/samples/multithreaded/async-detection.cpp +++ b/samples/multithreaded/async-detection.cpp @@ -70,48 +70,42 @@ int main(int argc, char* argv[]) cv::namedWindow("DisplayChilitags"); - bool showPeriodic = true; - char keyPressed; - float trackTime = 0, idleTime = 0, detectTime = 0; + const char* trigName = "DETECT_PERIODICALLY"; + chilitags::Chilitags::DetectionTrigger trig = chilitags::Chilitags::DETECT_PERIODICALLY; while ('q' != (keyPressed = (char) cv::waitKey(1))) { // toggle the processing mode, according to user input - if (keyPressed == 't') showPeriodic = !showPeriodic; + if(keyPressed == 't'){ + if(trig == chilitags::Chilitags::DETECT_PERIODICALLY){ + trig = chilitags::Chilitags::ASYNC_DETECT_PERIODICALLY; + trigName = "ASYNC_DETECT_PERIODICALLY"; + } + else if(trig == chilitags::Chilitags::ASYNC_DETECT_PERIODICALLY){ + trig = chilitags::Chilitags::ASYNC_DETECT_ALWAYS; + trigName = "ASYNC_DETECT_ALWAYS"; + } + else{ + trig = chilitags::Chilitags::DETECT_PERIODICALLY; + trigName = "DETECT_PERIODICALLY"; + } + } capture.read(inputImage); cv::Mat outputImage = inputImage.clone(); - int64 startTime = cv::getTickCount(); - auto tags = chilitags.find(inputImage, showPeriodic ? chilitags::Chilitags::ASYNC_DETECT_PERIODICALLY : chilitags::Chilitags::ASYNC_DETECT_ALWAYS); - int64 endTime = cv::getTickCount(); + auto tags = chilitags.find(inputImage, trig); drawTags(outputImage, tags); - //Print tracking time - trackTime = 0.98f*trackTime + 0.02f*1000.0f*(((float)endTime - (float)startTime)/cv::getTickFrequency()); - cv::putText(outputImage, - cv::format("[Main thread] Tracking time %4.2f ms", trackTime), - cv::Point(8,20), - cv::FONT_HERSHEY_SIMPLEX, 0.5, COLOR); - - //Print detection idle time - idleTime = 0.98f*idleTime + 0.02f*chilitags.getLatestAsyncDetectionIdleMillis(); - cv::putText(outputImage, - cv::format("[Detection thread] Idle time %4.2f ms", idleTime), - cv::Point(8,36), - cv::FONT_HERSHEY_SIMPLEX, 0.5, COLOR); - - //Print detection work time - detectTime = 0.98f*detectTime + 0.02f*chilitags.getLatestAsyncDetectionWorkMillis(); + //Print detection trigger cv::putText(outputImage, - cv::format("[Detection thread] Work time %4.2f ms", detectTime), - cv::Point(8,52), + cv::format("Detection trigger: %s (press 't' to toggle)", trigName), + cv::Point(8,yRes - 24), cv::FONT_HERSHEY_SIMPLEX, 0.5, COLOR); - //Print detection trigger cv::putText(outputImage, - cv::format("Detection trigger: %s (press 't' to toggle)", showPeriodic ? "ASYNC_DETECT_PERIODICALLY" : "ASYNC_DETECT_ALWAYS"), + cv::format("Run 'top -H -p `pgrep async-detection`' to see running threads", trigName), cv::Point(8,yRes - 8), cv::FONT_HERSHEY_SIMPLEX, 0.5, COLOR); diff --git a/src/Chilitags.cpp b/src/Chilitags.cpp index 6864691..1bc51b4 100644 --- a/src/Chilitags.cpp +++ b/src/Chilitags.cpp @@ -105,16 +105,6 @@ void setDetectionPeriod(int period) { mCallsBeforeDetection = period; } -#ifdef HAS_MULTITHREADING -float getLatestAsyncDetectionIdleMillis(){ - return mDetect.getLatestAsyncIdleMillis(); -} - -float getLatestAsyncDetectionWorkMillis(){ - return mDetect.getLatestAsyncWorkMillis(); -} -#endif - TagCornerMap find( const cv::Mat &inputImage, DetectionTrigger detectionTrigger){ @@ -130,6 +120,22 @@ TagCornerMap find( mResizedGrayscaleInput = mEnsureGreyscale(inputImage); } + //Take care of the background thread (if exists) +#ifdef HAS_MULTITHREADING + switch(detectionTrigger){ + case DETECT_ONLY: + case TRACK_ONLY: + case TRACK_AND_DETECT: + case DETECT_PERIODICALLY: + mDetect.shutdownBackgroundThread(); + break; + case ASYNC_DETECT_PERIODICALLY: + case ASYNC_DETECT_ALWAYS: + mDetect.launchBackgroundThread(mTrack); + break; + } +#endif + // Do detection/tracking/both depending on detection trigger TagCornerMap tags; switch(detectionTrigger){ @@ -167,7 +173,6 @@ TagCornerMap find( #ifdef HAS_MULTITHREADING case ASYNC_DETECT_PERIODICALLY: - mDetect.launchBackgroundThread(mTrack); mCallsBeforeNextDetection--; //If the detection period is reached, deliver new frame to background detection thread @@ -178,7 +183,6 @@ TagCornerMap find( return scaleBy(mTrack(mResizedGrayscaleInput), scaleFactor); case ASYNC_DETECT_ALWAYS: - mDetect.launchBackgroundThread(mTrack); mDetect(mResizedGrayscaleInput, tags); //This does not update tags, nor does it block for computation return scaleBy(mTrack(mResizedGrayscaleInput), scaleFactor); #endif @@ -277,16 +281,6 @@ void Chilitags::setMinInputWidth(int minWidth) { mImpl->setMinInputWidth(minWidth); } -#ifdef HAS_MULTITHREADING -float Chilitags::getLatestAsyncDetectionIdleMillis(){ - return mImpl->getLatestAsyncDetectionIdleMillis(); -} - -float Chilitags::getLatestAsyncDetectionWorkMillis(){ - return mImpl->getLatestAsyncDetectionWorkMillis(); -} -#endif - TagCornerMap Chilitags::find( const cv::Mat &inputImage, DetectionTrigger trigger diff --git a/src/Detect.cpp b/src/Detect.cpp index 3b2200b..bf444a4 100644 --- a/src/Detect.cpp +++ b/src/Detect.cpp @@ -41,9 +41,7 @@ Detect::Detect() : mBackgroundRunning(false), mNeedFrame(true), mInputCond(PTHREAD_COND_INITIALIZER), - mInputLock(PTHREAD_MUTEX_INITIALIZER), - mLatestAsyncIdleMillis(0), - mLatestAsyncWorkMillis(0) + mInputLock(PTHREAD_MUTEX_INITIALIZER) #endif { } @@ -126,6 +124,16 @@ void Detect::launchBackgroundThread(Track& track) } } +void Detect::shutdownBackgroundThread() +{ + if(mBackgroundRunning){ + pthread_mutex_lock(&mInputLock); + mBackgroundShouldRun = false; + pthread_cond_signal(&mInputCond); + pthread_mutex_unlock(&mInputLock); + } +} + void* Detect::dispatchRun(void* args) { static_cast(args)->run(); @@ -138,16 +146,12 @@ void Detect::run() pthread_mutex_lock(&mInputLock); //Wait for the input frame to arrive - int64 startTime = cv::getTickCount(); pthread_cond_wait(&mInputCond, &mInputLock); //This releases the lock while waiting - mLatestAsyncIdleMillis = 1000.0f*(((float)cv::getTickCount() - (float)startTime)/cv::getTickFrequency()); mNeedFrame = false; - startTime = cv::getTickCount(); doDetection(mTags); mTrack->update(mTags); - mLatestAsyncWorkMillis = 1000.0f*(((float)cv::getTickCount() - (float)startTime)/cv::getTickFrequency()); mNeedFrame = true; @@ -155,16 +159,6 @@ void Detect::run() } mBackgroundRunning = false; } - -float Detect::getLatestAsyncIdleMillis() -{ - return mLatestAsyncIdleMillis; -} - -float Detect::getLatestAsyncWorkMillis() -{ - return mLatestAsyncWorkMillis; -} #endif } /* namespace chilitags */ diff --git a/src/Detect.hpp b/src/Detect.hpp index b33bd82..1be1621 100644 --- a/src/Detect.hpp +++ b/src/Detect.hpp @@ -50,11 +50,9 @@ class Detect { void operator()(cv::Mat const& inputImage, TagCornerMap& tags); #ifdef HAS_MULTITHREADING - float getLatestAsyncIdleMillis(); - - float getLatestAsyncWorkMillis(); - void launchBackgroundThread(Track& track); + + void shutdownBackgroundThread(); #endif protected: @@ -83,9 +81,6 @@ class Detect { pthread_cond_t mInputCond; pthread_mutex_t mInputLock; - float mLatestAsyncIdleMillis; - float mLatestAsyncWorkMillis; - static void* dispatchRun(void* args); void run(); #endif