new tracking system
This commit is contained in:
parent
b595e557be
commit
4f98c2187a
40
src/Rectangle/BoundTracker.cpp
Executable file
40
src/Rectangle/BoundTracker.cpp
Executable 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
24
src/Rectangle/BoundTracker.h
Executable 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_ */
|
@ -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 {
|
||||||
|
@ -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;
|
||||||
|
@ -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()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
21
src/UI.cpp
21
src/UI.cpp
@ -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() {
|
||||||
|
7
src/UI.h
7
src/UI.h
@ -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();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
97
src/main.cpp
97
src/main.cpp
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user