From 4f98c2187a91d8c1604dfcef896b3e559be8296a Mon Sep 17 00:00:00 2001 From: Zer01HD Date: Tue, 8 May 2018 03:44:28 -0500 Subject: [PATCH] new tracking system --- src/Rectangle/BoundTracker.cpp | 40 +++++++++++++ src/Rectangle/BoundTracker.h | 24 ++++++++ src/Rectangle/Confidence.cpp | 21 ++++--- src/Rectangle/Confidence.h | 1 + src/Rectangle/ContourAnalyzer.cpp | 4 +- src/Rectangle/ContourAnalyzer.h | 4 +- src/UI.cpp | 21 ++++++- src/UI.h | 7 ++- src/main.cpp | 97 ++++++++++++++++++++++++++----- 9 files changed, 187 insertions(+), 32 deletions(-) create mode 100755 src/Rectangle/BoundTracker.cpp create mode 100755 src/Rectangle/BoundTracker.h diff --git a/src/Rectangle/BoundTracker.cpp b/src/Rectangle/BoundTracker.cpp new file mode 100755 index 0000000..72d6f58 --- /dev/null +++ b/src/Rectangle/BoundTracker.cpp @@ -0,0 +1,40 @@ +#include "BoundTracker.h" + +BoundTracker::BoundTracker(int *lastKey, UI *ui) { + BoundTracker::lastKey = lastKey; + BoundTracker::ui = ui; +} + +void BoundTracker::init(cv::Rect2d roi) { + BoundTracker::roi = roi; + tracker->init(ui->getOriginalFrame(), BoundTracker::roi); +} + +bool BoundTracker::track() { + tracker->update(ui->getOriginalFrame(), roi); + + if ((roi.x < 0) || (roi.x + roi.width > ui->getWidth()) || (roi.y < 0) || (roi.y + roi.height > ui->getHeight())) { + return false; + } else { + for (unsigned i = 0; i < deadConsistency.size(); i++) { + if ((roi & deadConsistency.back()).area() != roi.area() || deadConsistency.size() < queueSize) { + break; + } + return false; + } + + deadConsistency.push_back(roi); + if (deadConsistency.size() > queueSize) { + deadConsistency.pop_front(); + } + return true; + } +} + +cv::Rect2d BoundTracker::getROI() const { + return roi; +} + +BoundTracker::~BoundTracker() { +} + diff --git a/src/Rectangle/BoundTracker.h b/src/Rectangle/BoundTracker.h new file mode 100755 index 0000000..d097e89 --- /dev/null +++ b/src/Rectangle/BoundTracker.h @@ -0,0 +1,24 @@ +#ifndef RECTANGLE_BOUNDTRACKER_H_ +#define RECTANGLE_BOUNDTRACKER_H_ +#include +#include +#include "../UI.h" + +class BoundTracker { + int *lastKey; + UI *ui; + cv::Rect2d roi; + unsigned queueSize = 20; + std::deque deadConsistency; + + cv::Ptr tracker = cv::TrackerKCF::create();; + +public: + BoundTracker(int *lastKey, UI *ui); + void init(cv::Rect2d roi); + bool track(); + cv::Rect2d getROI() const; + virtual ~BoundTracker(); +}; + +#endif /* RECTANGLE_BOUNDTRACKER_H_ */ diff --git a/src/Rectangle/Confidence.cpp b/src/Rectangle/Confidence.cpp index 5caeab7..f381685 100755 --- a/src/Rectangle/Confidence.cpp +++ b/src/Rectangle/Confidence.cpp @@ -6,7 +6,7 @@ Confidence::Confidence(int *lastKey, UI *ui, unsigned validityLength) { Confidence::ui = ui; } -bool Confidence::check(std::vector contours) { +bool Confidence::check(std::vector bounds) { bool consistent; confident.clear(); @@ -14,9 +14,13 @@ bool Confidence::check(std::vector contours) { drawBounds = !drawBounds; } - for (unsigned rectangleID = 0; rectangleID < contours.size(); rectangleID++) { + for (unsigned rectangleID = 0; rectangleID < bounds.size(); rectangleID++) { consistent = true; - cv::Rect current = contours[rectangleID]; + + if (confidenceQueue.size() < queueLength) { + consistent = false; + } + cv::Rect current = bounds[rectangleID]; for (unsigned frameID = 0; frameID < confidenceQueue.size(); frameID++) { if (confidenceQueue[frameID].size() == 0) { @@ -25,27 +29,28 @@ bool Confidence::check(std::vector contours) { } for (unsigned frameRectID = 0; frameRectID < confidenceQueue[frameID].size(); frameRectID++) { cv::Rect previous = confidenceQueue[frameID][frameRectID]; - if ((current & previous).area() < 0.78*(current.area())) { + if ((current & previous).area() < minimumDifference*(current.area())) { consistent = false; break; } } } if (consistent) { - confident.push_back(contours[rectangleID]); + confident.push_back(bounds[rectangleID]); } } - confidenceQueue.push_front(contours); + confidenceQueue.push_front(bounds); if (confidenceQueue.size() > queueLength) { confidenceQueue.pop_back(); } if (drawBounds) { - drawBoundsOnMat(*(ui->originalFrame())); + drawBoundsOnMat(*(ui->drawnFrame())); } - return confident.size() != 0; +// std::cout << confident.size() << std::endl; + return (confident.size() > 0); } std::vector Confidence::rectangleBounds() const { diff --git a/src/Rectangle/Confidence.h b/src/Rectangle/Confidence.h index d853906..1db1d50 100755 --- a/src/Rectangle/Confidence.h +++ b/src/Rectangle/Confidence.h @@ -6,6 +6,7 @@ #include "../UI.h" class Confidence { + float minimumDifference = 0.76; unsigned queueLength = 0; int *lastKey; UI *ui; diff --git a/src/Rectangle/ContourAnalyzer.cpp b/src/Rectangle/ContourAnalyzer.cpp index b88d86f..e5d6e12 100755 --- a/src/Rectangle/ContourAnalyzer.cpp +++ b/src/Rectangle/ContourAnalyzer.cpp @@ -16,7 +16,7 @@ void ContourAnalyzer::analyze() { } else if (*lastKey == 118) { drawContours = !drawContours; } - minSize = ((ui->originalFrame()->cols)*(ui->originalFrame()->rows))*(minSizeScale/(float)10000); + minSize = ui->getWidth()*ui->getHeight()*(minSizeScale/(float)10000); if (cannyRec) { cannyUpper = std::min(3*cannyLower, 255); @@ -64,7 +64,7 @@ void ContourAnalyzer::analyze() { } if (drawContours) { - drawContoursOntoMat(*(ui->originalFrame())); + drawContoursOntoMat(*(ui->drawnFrame())); } } diff --git a/src/Rectangle/ContourAnalyzer.h b/src/Rectangle/ContourAnalyzer.h index 29cc61a..2735018 100755 --- a/src/Rectangle/ContourAnalyzer.h +++ b/src/Rectangle/ContourAnalyzer.h @@ -26,11 +26,11 @@ public: int binLower = 52; int minSize = 0; - int minSizeScale = 15; + int minSizeScale = 18; int cannyLower = 57; int cannyUpper = 3*cannyLower; - int epsilon = 53; + int epsilon = 57; ContourAnalyzer(UI* ui, int *lastKey); virtual ~ContourAnalyzer(); diff --git a/src/UI.cpp b/src/UI.cpp index 9196f6f..f27696b 100755 --- a/src/UI.cpp +++ b/src/UI.cpp @@ -12,7 +12,7 @@ void UI::render() { frames.resize(state + 1); } state = 0; - cv::imshow(UI::NORMAL_WINDOW, frames[0]); + cv::imshow(UI::NORMAL_WINDOW, frame); if (debug) { cv::imshow(UI::DEBUG_WINDOW, frames[debugFrame]); } @@ -56,11 +56,26 @@ void UI::nextDebugFrame() { } void UI::setOriginalFrame(cv::Mat frame) { + width = frame.cols; + height = frame.rows; frames[0] = frame; + frames[0].copyTo(UI::frame); } -cv::Mat* UI::originalFrame() { - return &frames[0]; +cv::Mat* UI::drawnFrame() { + return &frame; +} + +cv::Mat UI::getOriginalFrame() const { + return frames[0]; +} + +unsigned UI::getWidth() const { + return width; +} + +unsigned UI::getHeight() const { + return height; } UI::~UI() { diff --git a/src/UI.h b/src/UI.h index ec85265..88a0827 100755 --- a/src/UI.h +++ b/src/UI.h @@ -15,8 +15,10 @@ class UI { bool debug = false, showSlider = false; unsigned debugFrame = 0; int *lastKey; + unsigned width = 0, height = 0; unsigned state = 0; std::vector frames = {cv::Mat()}; + cv::Mat frame; public: static const std::string NORMAL_WINDOW; @@ -30,8 +32,11 @@ public: cv::Mat* currentFrame(int offset = 0); void setOriginalFrame(cv::Mat frame); - cv::Mat* originalFrame(); + cv::Mat* drawnFrame(); + cv::Mat getOriginalFrame() const; + unsigned getWidth() const; + unsigned getHeight() const; virtual ~UI(); }; diff --git a/src/main.cpp b/src/main.cpp index 51577e5..d454e4c 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,35 +4,100 @@ #include "webcam/Webcam.h" #include "UI.h" #include "Rectangle/Confidence.h" +#include "Rectangle/BoundTracker.h" + +enum State { + detection, track, cross_check +}; + +State state = detection; +Webcam webcam = 0; +int *lastKey = new int(0); +UI *ui = new UI(lastKey); +ContourAnalyzer ca { ui, lastKey }; +Confidence conf { lastKey, ui, 5}; +BoundTracker tracker {lastKey, ui}; +cv::Point statusTextPos{5, 25}; +cv::Scalar textFontColor{35, 125, 35}; +cv::Scalar rectangleBoundColor{255, 0, 0}; + +unsigned frameCount = 0; +void run() { + switch (state) { + case detection: + cv::putText(*(ui->drawnFrame()), "Looking for rectangle...", statusTextPos, cv::FONT_HERSHEY_PLAIN, 0.7, 35); + ca.analyze(); + ca.convertContoursToBounds(); + if (conf.check(ca.getBounds())) { + cv::Rect largest; + std::vector rects = conf.rectangleBounds(); + for (unsigned i = 0; i < rects.size(); i++) { + if (rects[i].area() > largest.area()) { + largest = rects[i]; + } + } + + tracker.init(largest); + + state = track; + } + break; + + case track: + cv::putText(*(ui->drawnFrame()), "Tracking...", statusTextPos, cv::FONT_HERSHEY_PLAIN, 0.7, 35); + if (!tracker.track()) { + state = cross_check; + } + cv::rectangle(*(ui->drawnFrame()), tracker.getROI(), cv::Scalar{255, 0, 0}, 2); + break; + + case cross_check: + cv::putText(*(ui->drawnFrame()), "Cross checking...", statusTextPos, cv::FONT_HERSHEY_PLAIN, 0.7, 35); + ca.analyze(); + ca.convertContoursToBounds(); + cv::Rect2d largest; + std::vector rects = ca.getBounds(); + for (unsigned i = 0; i < rects.size(); i++) { + if (rects[i].area() > largest.area()) { + largest = rects[i]; + } + } + + tracker.track(); + + unsigned largestArea = tracker.getROI().area() > largest.area() ? tracker.getROI().area() : largest.area(); + if (largest.area() != 0 && (tracker.getROI() & largest).area() >= largestArea*(0.75)) { + state = track; + } else { + frameCount++; + if (frameCount > 15) { + state = detection; + frameCount = 0; + } + } + cv::rectangle(*(ui->drawnFrame()), tracker.getROI(), cv::Scalar{255, 0, 0}, 2); + cv::rectangle(*(ui->drawnFrame()), largest, cv::Scalar{255, 30, 30}, 1); + + break; + } + ui->render(); +} int main(int argc, char** argv) { - Webcam webcam = 0; - int *lastKey = new int(0); - UI *ui = new UI(lastKey); - ContourAnalyzer ca{ui, lastKey}; - Confidence conf{lastKey, ui, 6}; - while (true) { webcam.update(); cv::Mat frame = webcam.getFrame(); ui->setOriginalFrame(frame); - *lastKey = cv::waitKey(33); - if (*lastKey != 255) { + if (*lastKey > 0) { std::cout << "key pressed: " << *lastKey << std::endl; if (*lastKey == 27) { break; } } - - - ca.analyze(); - ca.convertContoursToBounds(); - conf.check(ca.getBounds()); - ui->render(); - - *lastKey = 255; + run(); + *lastKey = -1; } delete ui;