new tracking system
This commit is contained in:
		
							
								
								
									
										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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Confidence::check(std::vector<cv::Rect> contours) {
 | 
			
		||||
bool Confidence::check(std::vector<cv::Rect> bounds) {
 | 
			
		||||
	bool consistent;
 | 
			
		||||
	confident.clear();
 | 
			
		||||
 | 
			
		||||
@@ -14,9 +14,13 @@ bool Confidence::check(std::vector<cv::Rect> 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<cv::Rect> 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<cv::Rect> Confidence::rectangleBounds() const {
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@
 | 
			
		||||
#include "../UI.h"
 | 
			
		||||
 | 
			
		||||
class Confidence {
 | 
			
		||||
	float minimumDifference = 0.76;
 | 
			
		||||
	unsigned queueLength = 0;
 | 
			
		||||
	int *lastKey;
 | 
			
		||||
	UI *ui;
 | 
			
		||||
 
 | 
			
		||||
@@ -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()));
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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();
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										21
									
								
								src/UI.cpp
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								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() {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										7
									
								
								src/UI.h
									
									
									
									
									
								
							
							
						
						
									
										7
									
								
								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<cv::Mat> 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();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										97
									
								
								src/main.cpp
									
									
									
									
									
								
							
							
						
						
									
										97
									
								
								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<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) {
 | 
			
		||||
	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;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user