new tracking system

This commit is contained in:
Harrison Deng 2018-05-08 03:44:28 -05:00
parent b595e557be
commit 4f98c2187a
9 changed files with 187 additions and 32 deletions

40
src/Rectangle/BoundTracker.cpp Executable file
View File

@ -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() {
}

24
src/Rectangle/BoundTracker.h Executable file
View File

@ -0,0 +1,24 @@
#ifndef RECTANGLE_BOUNDTRACKER_H_
#define RECTANGLE_BOUNDTRACKER_H_
#include <opencv2/opencv.hpp>
#include <opencv2/tracking.hpp>
#include "../UI.h"
class BoundTracker {
int *lastKey;
UI *ui;
cv::Rect2d roi;
unsigned queueSize = 20;
std::deque<cv::Rect2d> deadConsistency;
cv::Ptr<cv::Tracker> 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_ */

View File

@ -6,7 +6,7 @@ Confidence::Confidence(int *lastKey, UI *ui, unsigned validityLength) {
Confidence::ui = ui; Confidence::ui = ui;
} }
bool Confidence::check(std::vector<cv::Rect> contours) { bool Confidence::check(std::vector<cv::Rect> bounds) {
bool consistent; bool consistent;
confident.clear(); confident.clear();
@ -14,9 +14,13 @@ bool Confidence::check(std::vector<cv::Rect> contours) {
drawBounds = !drawBounds; drawBounds = !drawBounds;
} }
for (unsigned rectangleID = 0; rectangleID < contours.size(); rectangleID++) { for (unsigned rectangleID = 0; rectangleID < bounds.size(); rectangleID++) {
consistent = true; 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++) { for (unsigned frameID = 0; frameID < confidenceQueue.size(); frameID++) {
if (confidenceQueue[frameID].size() == 0) { if (confidenceQueue[frameID].size() == 0) {
@ -25,27 +29,28 @@ bool Confidence::check(std::vector<cv::Rect> contours) {
} }
for (unsigned frameRectID = 0; frameRectID < confidenceQueue[frameID].size(); frameRectID++) { for (unsigned frameRectID = 0; frameRectID < confidenceQueue[frameID].size(); frameRectID++) {
cv::Rect previous = confidenceQueue[frameID][frameRectID]; cv::Rect previous = confidenceQueue[frameID][frameRectID];
if ((current & previous).area() < 0.78*(current.area())) { if ((current & previous).area() < minimumDifference*(current.area())) {
consistent = false; consistent = false;
break; break;
} }
} }
} }
if (consistent) { if (consistent) {
confident.push_back(contours[rectangleID]); confident.push_back(bounds[rectangleID]);
} }
} }
confidenceQueue.push_front(contours); confidenceQueue.push_front(bounds);
if (confidenceQueue.size() > queueLength) { if (confidenceQueue.size() > queueLength) {
confidenceQueue.pop_back(); confidenceQueue.pop_back();
} }
if (drawBounds) { if (drawBounds) {
drawBoundsOnMat(*(ui->originalFrame())); drawBoundsOnMat(*(ui->drawnFrame()));
} }
return confident.size() != 0; // std::cout << confident.size() << std::endl;
return (confident.size() > 0);
} }
std::vector<cv::Rect> Confidence::rectangleBounds() const { std::vector<cv::Rect> Confidence::rectangleBounds() const {

View File

@ -6,6 +6,7 @@
#include "../UI.h" #include "../UI.h"
class Confidence { class Confidence {
float minimumDifference = 0.76;
unsigned queueLength = 0; unsigned queueLength = 0;
int *lastKey; int *lastKey;
UI *ui; UI *ui;

View File

@ -16,7 +16,7 @@ void ContourAnalyzer::analyze() {
} else if (*lastKey == 118) { } else if (*lastKey == 118) {
drawContours = !drawContours; drawContours = !drawContours;
} }
minSize = ((ui->originalFrame()->cols)*(ui->originalFrame()->rows))*(minSizeScale/(float)10000); minSize = ui->getWidth()*ui->getHeight()*(minSizeScale/(float)10000);
if (cannyRec) { if (cannyRec) {
cannyUpper = std::min(3*cannyLower, 255); cannyUpper = std::min(3*cannyLower, 255);
@ -64,7 +64,7 @@ void ContourAnalyzer::analyze() {
} }
if (drawContours) { if (drawContours) {
drawContoursOntoMat(*(ui->originalFrame())); drawContoursOntoMat(*(ui->drawnFrame()));
} }
} }

View File

@ -26,11 +26,11 @@ public:
int binLower = 52; int binLower = 52;
int minSize = 0; int minSize = 0;
int minSizeScale = 15; int minSizeScale = 18;
int cannyLower = 57; int cannyLower = 57;
int cannyUpper = 3*cannyLower; int cannyUpper = 3*cannyLower;
int epsilon = 53; int epsilon = 57;
ContourAnalyzer(UI* ui, int *lastKey); ContourAnalyzer(UI* ui, int *lastKey);
virtual ~ContourAnalyzer(); virtual ~ContourAnalyzer();

View File

@ -12,7 +12,7 @@ void UI::render() {
frames.resize(state + 1); frames.resize(state + 1);
} }
state = 0; state = 0;
cv::imshow(UI::NORMAL_WINDOW, frames[0]); cv::imshow(UI::NORMAL_WINDOW, frame);
if (debug) { if (debug) {
cv::imshow(UI::DEBUG_WINDOW, frames[debugFrame]); cv::imshow(UI::DEBUG_WINDOW, frames[debugFrame]);
} }
@ -56,11 +56,26 @@ void UI::nextDebugFrame() {
} }
void UI::setOriginalFrame(cv::Mat frame) { void UI::setOriginalFrame(cv::Mat frame) {
width = frame.cols;
height = frame.rows;
frames[0] = frame; frames[0] = frame;
frames[0].copyTo(UI::frame);
} }
cv::Mat* UI::originalFrame() { cv::Mat* UI::drawnFrame() {
return &frames[0]; return &frame;
}
cv::Mat UI::getOriginalFrame() const {
return frames[0];
}
unsigned UI::getWidth() const {
return width;
}
unsigned UI::getHeight() const {
return height;
} }
UI::~UI() { UI::~UI() {

View File

@ -15,8 +15,10 @@ class UI {
bool debug = false, showSlider = false; bool debug = false, showSlider = false;
unsigned debugFrame = 0; unsigned debugFrame = 0;
int *lastKey; int *lastKey;
unsigned width = 0, height = 0;
unsigned state = 0; unsigned state = 0;
std::vector<cv::Mat> frames = {cv::Mat()}; std::vector<cv::Mat> frames = {cv::Mat()};
cv::Mat frame;
public: public:
static const std::string NORMAL_WINDOW; static const std::string NORMAL_WINDOW;
@ -30,8 +32,11 @@ public:
cv::Mat* currentFrame(int offset = 0); cv::Mat* currentFrame(int offset = 0);
void setOriginalFrame(cv::Mat frame); void setOriginalFrame(cv::Mat frame);
cv::Mat* originalFrame(); cv::Mat* drawnFrame();
cv::Mat getOriginalFrame() const;
unsigned getWidth() const;
unsigned getHeight() const;
virtual ~UI(); virtual ~UI();
}; };

View File

@ -4,35 +4,100 @@
#include "webcam/Webcam.h" #include "webcam/Webcam.h"
#include "UI.h" #include "UI.h"
#include "Rectangle/Confidence.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<cv::Rect> 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<cv::Rect> 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) { 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) { while (true) {
webcam.update(); webcam.update();
cv::Mat frame = webcam.getFrame(); cv::Mat frame = webcam.getFrame();
ui->setOriginalFrame(frame); ui->setOriginalFrame(frame);
*lastKey = cv::waitKey(33); *lastKey = cv::waitKey(33);
if (*lastKey != 255) { if (*lastKey > 0) {
std::cout << "key pressed: " << *lastKey << std::endl; std::cout << "key pressed: " << *lastKey << std::endl;
if (*lastKey == 27) { if (*lastKey == 27) {
break; break;
} }
} }
run();
*lastKey = -1;
ca.analyze();
ca.convertContoursToBounds();
conf.check(ca.getBounds());
ui->render();
*lastKey = 255;
} }
delete ui; delete ui;