ruler object working

This commit is contained in:
Harrison Deng 2018-05-08 16:47:47 -05:00
parent 96dc6f448a
commit 31089cf647
9 changed files with 108 additions and 66 deletions

View File

@ -2,9 +2,9 @@
Confidence::Confidence(int *lastKey, UI *ui, unsigned validityLength, float similarity) { Confidence::Confidence(int *lastKey, UI *ui, unsigned validityLength, float similarity) {
queueLength = validityLength; queueLength = validityLength;
Confidence::lastKey = lastKey; this->lastKey = lastKey;
Confidence::ui = ui; this->ui = ui;
Confidence::similarity = similarity; this->similarity = similarity;
} }
bool Confidence::check(std::vector<cv::Rect> bounds) { bool Confidence::check(std::vector<cv::Rect> bounds) {

View File

@ -4,7 +4,7 @@
#include <algorithm> #include <algorithm>
ContourAnalyzer::ContourAnalyzer(UI *ui, int *lastKey) { ContourAnalyzer::ContourAnalyzer(UI *ui, int *lastKey) {
ContourAnalyzer::ui = ui; this->ui = ui;
ui->UIListeners.push_back(this); ui->UIListeners.push_back(this);
this->lastKey = lastKey; this->lastKey = lastKey;
} }
@ -22,7 +22,7 @@ void ContourAnalyzer::analyze() {
if (drawContours) { if (drawContours) {
drawContoursOntoMat(*(ui->drawnFrame())); drawContoursOntoMat(*(ui->drawnFrame()));
cv::putText(*(ui->drawnFrame()), "Showing possible triangles rectangles.", cv::putText(*(ui->drawnFrame()), "Showing possible rectangles.",
cv::Point{5, 30}, cv::FONT_HERSHEY_PLAIN, 0.8, selectColor); cv::Point{5, 30}, cv::FONT_HERSHEY_PLAIN, 0.8, selectColor);
} }
} }
@ -104,6 +104,13 @@ void ContourAnalyzer::convertContoursToBounds() {
} }
} }
void ContourAnalyzer::convertContoursToRotatedBounds() {
rotatedBounds.clear();
for (unsigned i = 0; i < prunedContours.size(); i++) {
rotatedBounds.push_back(cv::minAreaRect(prunedContours[i]));
}
}
std::string ContourAnalyzer::contourToString(std::vector<cv::Point> contour) { std::string ContourAnalyzer::contourToString(std::vector<cv::Point> contour) {
switch (contour.size()) { switch (contour.size()) {
case 4: case 4:
@ -120,6 +127,10 @@ std::vector<cv::Rect> ContourAnalyzer::getBounds() const {
return bounds; return bounds;
} }
std::vector<cv::RotatedRect> ContourAnalyzer::getRotatedBounds() const {
return rotatedBounds;
}
void ContourAnalyzer::componentSetup() { void ContourAnalyzer::componentSetup() {
cv::createTrackbar("Bin. Lower", UI::DEBUG_WINDOW, &binLower , 255); cv::createTrackbar("Bin. Lower", UI::DEBUG_WINDOW, &binLower , 255);
cv::createTrackbar("Can. Lower", UI::DEBUG_WINDOW, &cannyLower , 255); cv::createTrackbar("Can. Lower", UI::DEBUG_WINDOW, &cannyLower , 255);

View File

@ -21,18 +21,19 @@ class ContourAnalyzer: public UIListener {
std::vector<std::vector<cv::Point>> consistentContours; std::vector<std::vector<cv::Point>> consistentContours;
std::vector<std::vector<cv::Point>> prunedContours; std::vector<std::vector<cv::Point>> prunedContours;
std::vector<cv::Rect> bounds; std::vector<cv::Rect> bounds;
std::vector<cv::RotatedRect> rotatedBounds;
void removeRedundancy(); void removeRedundancy();
void preAnalyze(); void preAnalyze();
public: public:
int binLower = 58; int binLower = 54;
int minSize = 0; int minSize = 0;
int minSizeScale = 18; int minSizeScale = 18;
int cannyLower = 57; int cannyLower = 45;
int cannyUpper = 3*cannyLower; int cannyUpper = 3*cannyLower;
int epsilon = 57; int epsilon = 56;
ContourAnalyzer(UI* ui, int *lastKey); ContourAnalyzer(UI* ui, int *lastKey);
virtual ~ContourAnalyzer(); virtual ~ContourAnalyzer();
@ -43,8 +44,9 @@ public:
void drawContoursOntoMat(cv::Mat &frame); void drawContoursOntoMat(cv::Mat &frame);
std::string contourToString(std::vector<cv::Point>); std::string contourToString(std::vector<cv::Point>);
void convertContoursToBounds(); void convertContoursToBounds();
void convertContoursToRotatedBounds();
std::vector<cv::Rect> getBounds() const; std::vector<cv::Rect> getBounds() const;
std::vector<cv::RotatedRect> getRotatedBounds() const;
void componentSetup(); void componentSetup();
}; };

View File

@ -1,49 +1,49 @@
/*
* Ruler.cpp
*
* Created on: May 8, 2018
* Author: yunya
*/
#include "Ruler.h" #include "Ruler.h"
#include <sstream> #include <sstream>
Ruler::Ruler(UI *ui, int *lastKey) { Ruler::Ruler(UI *ui, int *lastKey) {
Ruler::ui = ui; this->ui = ui;
Ruler::lastKey = lastKey; this->lastKey = lastKey;
focalLength = estimateFocalLength(HFOV);
} }
void Ruler::update(cv::Rect rect) { void Ruler::update() {
focalLength = estimateFocalLength(HFOV); focalLength = estimateFocalLength(HFOV);
distance = estimateDistance(rect); distance = estimateDistance(rect);
inputUpdate(); inputUpdate();
updateUI(); updateUI();
} }
float Ruler::estimateFocalLength(int HFOV) { float Ruler::estimateFocalLength(float HFOV) {
return (ui->getWidth()/2.0)*(1/(std::tan(HFOV/2.0))); float fl = (ui->getWidth()/2.0) * (cos((HFOV * M_PI)/(180*2.0))/sin(HFOV*M_PI/(180*2.0)));
return fl;
} }
void Ruler::updateUI() { void Ruler::updateUI() {
if (inputtingVal) { if (inputtingVal) {
cv::putText(*(ui->drawnFrame()), ("Given width: " + std::to_string(widthInCM)), confTextPos, cv::FONT_HERSHEY_DUPLEX, 0.7, textFontColor, 2); cv::putText(*(ui->drawnFrame()), ("Given width: " + std::to_string(givenWidth)), confTextPos, cv::FONT_HERSHEY_PLAIN, 0.7, textFontColor, 2);
} else { } else {
cv::putText(*(ui->drawnFrame()), ("Given width: " + std::to_string(widthInCM)), confTextPos, cv::FONT_HERSHEY_DUPLEX, 0.7, textFontColor); cv::putText(*(ui->drawnFrame()), ("Given width: " + std::to_string(givenWidth)), confTextPos, cv::FONT_HERSHEY_PLAIN, 0.7, textFontColor);
} }
cv::putText(*(ui->drawnFrame()), ("distance: " + std::to_string(distance) + "cm"), distanceTextPos, cv::FONT_HERSHEY_DUPLEX, 0.7, textFontColor); cv::putText(*(ui->drawnFrame()), ("distance: " + std::to_string(distance) + "cm"), distanceTextPos, cv::FONT_HERSHEY_PLAIN, 0.7, textFontColor);
std::cout << "focal length: " + std::to_string(focalLength) << std::endl;
} }
void Ruler::toggleInput() { void Ruler::toggleInput() {
inputtingVal = !inputtingVal; inputtingVal = !inputtingVal;
if (!inputtingVal) { if (!inputtingVal) {
numBuild.clear(); numBuild.clear();
} else {
givenWidth = 0;
} }
} }
int Ruler::estimateDistance(cv::Rect rect) { int Ruler::estimateDistance(cv::RotatedRect rect) {
return (widthInCM*focalLength) / rect.width; if (rect.size.area() > 0) {
return (givenWidth*focalLength) / rect.size.width;
} else {
return 0;
}
} }
void Ruler::inputUpdate() { void Ruler::inputUpdate() {
@ -55,9 +55,15 @@ void Ruler::inputUpdate() {
char val = '0' + (*lastKey - 48); char val = '0' + (*lastKey - 48);
numBuild.push_back(val); numBuild.push_back(val);
} }
if (numBuild.size() > 0) {
std::string numString{numBuild.begin(), numBuild.end()}; std::string numString{numBuild.begin(), numBuild.end()};
widthInCM = std::stod(numString); givenWidth = std::stof(numString);
} }
}
}
void Ruler::updateRectangle(cv::RotatedRect rect) {
this->rect = rect;
} }
void Ruler::componentSetup() { void Ruler::componentSetup() {

View File

@ -1,10 +1,3 @@
/*
* Ruler.h
*
* Created on: May 8, 2018
* Author: yunya
*/
#ifndef RECTANGLE_RULER_H_ #ifndef RECTANGLE_RULER_H_
#define RECTANGLE_RULER_H_ #define RECTANGLE_RULER_H_
#include "../UI.h" #include "../UI.h"
@ -15,20 +8,22 @@ class Ruler: public UIListener {
cv::Point confTextPos {5, 75}; cv::Point confTextPos {5, 75};
cv::Scalar textFontColor {20, 20, 20}; cv::Scalar textFontColor {20, 20, 20};
cv::RotatedRect rect;
UI *ui; UI *ui;
int *lastKey; int *lastKey;
float distance = 0; float distance = 0;
float widthInCM = 0; float givenWidth = 0;
float focalLength; float focalLength = 0;
int HFOV = 65; float HFOV = 65;
bool inputtingVal = false; bool inputtingVal = false;
std::deque<char> numBuild; std::deque<char> numBuild;
public: public:
Ruler(UI *ui, int *lastKey); Ruler(UI *ui, int *lastKey);
float estimateFocalLength(int HFOV); float estimateFocalLength(float HFOV);
int estimateDistance(cv::Rect rect); int estimateDistance(cv::RotatedRect rect);
void update(cv::Rect rect); void update();
void updateRectangle(cv::RotatedRect rect);
void componentSetup(); void componentSetup();
void updateUI(); void updateUI();
void toggleInput(); void toggleInput();

View File

@ -1,17 +1,23 @@
#include "UI.h" #include "UI.h"
const std::string UI::NORMAL_WINDOW = "Normal";
const std::string UI::DEBUG_WINDOW = "Debug";
UI::UI(int *lastKey) { UI::UI(int *lastKey) {
this->lastKey = lastKey; this->lastKey = lastKey;
} }
const std::string UI::NORMAL_WINDOW = "Normal";
const std::string UI::DEBUG_WINDOW = "Debug";
void UI::render() { void UI::render() {
if (state < frames.size() -1) { if (state < frames.size() -1) {
frames.resize(state + 1); frames.resize(state + 1);
lastDebugFrame = debugFrame;
debugFrame = std::min(state, debugFrame); debugFrame = std::min(state, debugFrame);
} }
if (lastDebugFrame != 0 && lastDebugFrame <= frames.size()-1) {
debugFrame = lastDebugFrame;
lastDebugFrame = 0;
}
state = 0; state = 0;
cv::imshow(UI::NORMAL_WINDOW, frame); cv::imshow(UI::NORMAL_WINDOW, frame);
if (debug) { if (debug) {
@ -40,7 +46,8 @@ void UI::render() {
cv::Mat* UI::nextFrame() { cv::Mat* UI::nextFrame() {
state++; state++;
if (state + 1 > frames.size()) { if (state + 1 > frames.size()) {
frames.push_back(cv::Mat { }); frames.push_back(cv::Mat {});
} }
return &(frames[state]); return &(frames[state]);
} }

View File

@ -13,6 +13,7 @@
class UI { class UI {
bool debug = false, showSlider = false; bool debug = false, showSlider = false;
unsigned lastDebugFrame = 0;
unsigned debugFrame = 0; unsigned debugFrame = 0;
int *lastKey; int *lastKey;
int width = 0, height = 0; int width = 0, height = 0;

View File

@ -5,7 +5,7 @@
#include "UI.h" #include "UI.h"
#include "Rectangle/Confidence.h" #include "Rectangle/Confidence.h"
#include "Rectangle/BoundTracker.h" #include "Rectangle/BoundTracker.h"
#include "Rectangle/Ruler.h"
enum State { enum State {
detection, track, cross_check detection, track, cross_check
}; };
@ -15,12 +15,14 @@ Webcam webcam = 0;
int *lastKey = new int(0); int *lastKey = new int(0);
UI *ui = new UI(lastKey); UI *ui = new UI(lastKey);
ContourAnalyzer ca { ui, lastKey }; ContourAnalyzer ca { ui, lastKey };
Confidence conf { lastKey, ui, 6, 0.7}; Confidence conf { lastKey, ui, 6, 0.78};
BoundTracker tracker { lastKey, ui }; BoundTracker tracker { lastKey, ui };
cv::Point statusTextPos {5, 15}; cv::Point statusTextPos {5, 15};
cv::Scalar textFontColor { 20, 20, 20}; cv::Scalar textFontColor { 20, 20, 20};
cv::Scalar rectangleBoundColor { 255, 0, 0 }; cv::Scalar rectangleBoundColor { 255, 0, 0 };
cv::Rect subject; Ruler ruler{ui, lastKey};
cv::RotatedRect subject;
unsigned frameCount = 0; unsigned frameCount = 0;
void run() { void run() {
switch (state) { switch (state) {
@ -45,7 +47,7 @@ void run() {
case track: case track:
{ {
int growBy = 20; int growBy = 30;
cv::Rect scaledSearchArea; cv::Rect scaledSearchArea;
cv::putText(*(ui->drawnFrame()), "Tracking...", statusTextPos, cv::FONT_HERSHEY_PLAIN, 0.8, textFontColor); cv::putText(*(ui->drawnFrame()), "Tracking...", statusTextPos, cv::FONT_HERSHEY_PLAIN, 0.8, textFontColor);
if (!tracker.track()) { if (!tracker.track()) {
@ -65,22 +67,26 @@ void run() {
ca.analyze(scaledSearchArea); ca.analyze(scaledSearchArea);
ca.convertContoursToBounds(); ca.convertContoursToBounds();
ca.convertContoursToRotatedBounds();
if (ca.getBounds().size() > 0) { if (ca.getBounds().size() > 0) {
cv::Rect largest; cv::Rect largest;
unsigned index;
for (unsigned i = 0; i < ca.getBounds().size(); i++) { for (unsigned i = 0; i < ca.getBounds().size(); i++) {
if (ca.getBounds()[i].area() > largest.area()) { if (ca.getBounds()[i].area() > largest.area()) {
largest = ca.getBounds()[i]; largest = ca.getBounds()[i];
index = i;
} }
} }
ruler.updateRectangle(ca.getRotatedBounds()[index]);
largest.x += scaledSearchArea.x; largest.x += scaledSearchArea.x;
largest.y += scaledSearchArea.y; largest.y += scaledSearchArea.y;
tracker.setROI(largest); tracker.init(largest);
} }
cv::rectangle(*(ui->drawnFrame()), scaledSearchArea, cv::Scalar {150, 0, 0}, 1);
cv::rectangle(*(ui->drawnFrame()), tracker.getROI(), cv::Scalar {255, 0, 0}, 2); cv::rectangle(*(ui->drawnFrame()), tracker.getROI(), cv::Scalar {255, 0, 0}, 2);
} }
break; break;
@ -89,21 +95,23 @@ void run() {
cv::FONT_HERSHEY_PLAIN, 0.8, textFontColor); cv::FONT_HERSHEY_PLAIN, 0.8, textFontColor);
ca.analyze(); ca.analyze();
ca.convertContoursToBounds(); ca.convertContoursToBounds();
cv::Rect2d largest; tracker.track();
std::vector<cv::Rect> rects = ca.getBounds(); std::vector<cv::Rect> rects = ca.getBounds();
cv::Rect2d largest;
if (rects.size() > 0) {
for (unsigned i = 0; i < rects.size(); i++) { for (unsigned i = 0; i < rects.size(); i++) {
if (rects[i].area() > largest.area()) { if (rects[i].area() > largest.area()) {
largest = rects[i]; largest = rects[i];
} }
} }
tracker.track();
unsigned largestArea = tracker.getROI().area() > largest.area() ? tracker.getROI().area() : largest.area(); unsigned largestArea = tracker.getROI().area() > largest.area() ? tracker.getROI().area() : largest.area();
if (largest.area() != 0 && (tracker.getROI() | largest).area() <= largestArea * (1.2)) { if ((tracker.getROI() | largest).area() <= largestArea * (1.25)) {
tracker.setROI(largest); tracker.init(largest);
state = track; state = track;
frameCount = 0;
} else { } else {
frameCount++; frameCount++;
if (frameCount > 30) { if (frameCount > 30) {
@ -111,11 +119,21 @@ void run() {
frameCount = 0; frameCount = 0;
} }
} }
cv::rectangle(*(ui->drawnFrame()), largest, cv::Scalar { 255, 0, 0 }, 1);
} else {
frameCount++;
if (frameCount > 30) {
state = detection;
frameCount = 0;
}
}
cv::rectangle(*(ui->drawnFrame()), tracker.getROI(), cv::Scalar { 255, 0, 0 }, 2); cv::rectangle(*(ui->drawnFrame()), tracker.getROI(), cv::Scalar { 255, 0, 0 }, 2);
cv::rectangle(*(ui->drawnFrame()), largest, cv::Scalar { 255, 30, 30 }, 1);
break; break;
} }
ruler.update();
ui->render(); ui->render();
} }

View File

@ -9,6 +9,8 @@
Webcam::Webcam(int webcamID) { Webcam::Webcam(int webcamID) {
stream = new cv::VideoCapture(webcamID); stream = new cv::VideoCapture(webcamID);
stream->set(cv::CAP_PROP_FRAME_WIDTH, 1920);
stream->set(cv::CAP_PROP_FRAME_HEIGHT, 1080);
} }
void Webcam::update() { void Webcam::update() {