commit 603143551e592fd1fe22f5241b8d33d6d69a9e53 Author: Zer01HD Date: Wed Apr 25 23:49:19 2018 -0500 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..84046eb --- /dev/null +++ b/.gitignore @@ -0,0 +1,98 @@ +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app +# Created by https://www.gitignore.io/api/eclipse + +### Eclipse ### + +.metadata +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.settings/ +.loadpath +.recommenders + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# PyDev specific (Python IDE for Eclipse) +*.pydevproject + +# CDT-specific (C/C++ Development Tooling) +.cproject + +# Java annotation processor (APT) +.factorypath + +# PDT-specific (PHP Development Tools) +.buildpath + +# sbteclipse plugin +.target + +# Tern plugin +.tern-project + +# TeXlipse plugin +.texlipse + +# STS (Spring Tool Suite) +.springBeans + +# Code Recommenders +.recommenders/ +: +# Scala IDE specific (Scala & Java development for Eclipse) +.cache-main +.scala_dependencies +.worksheet + +### Eclipse Patch ### +# Eclipse Core +.project + +# JDT-specific (Eclipse Java Development Tools) +.classpath + +# Annotation Processing +.apt_generated + + +# End of https://www.gitignore.io/api/eclipse diff --git a/src/detection/shape/ContourAnalyzer.cpp b/src/detection/shape/ContourAnalyzer.cpp new file mode 100755 index 0000000..c9f5a7b --- /dev/null +++ b/src/detection/shape/ContourAnalyzer.cpp @@ -0,0 +1,87 @@ +/* + * ContourAnalyzer.cpp + * + * Created on: Apr 22, 2018 + * Author: Yunyang + */ + +#include "ContourAnalyzer.h" +#include + +ContourAnalyzer::ContourAnalyzer() { + +} + +void ContourAnalyzer::setFrame(cv::Mat frame) { + ContourAnalyzer::originFrame = frame; +} + +int ContourAnalyzer::analyze() { + prunedContours.clear(); + + cv::cvtColor(originFrame, stepFrames[0], cv::COLOR_BGR2GRAY); + cv::GaussianBlur(stepFrames[0], stepFrames[1], cv::Size(5, 5), 0); + cv::Canny(stepFrames[1], stepFrames[2], 35, 125); + cv::findContours(stepFrames[2], contours, cv::RETR_LIST, cv::CHAIN_APPROX_SIMPLE); + + for (unsigned i = 0; i < contours.size(); i++) { + double perimeter = cv::arcLength(contours[i], true); + cv::approxPolyDP(contours[i], contours[i], 0.04*perimeter, true); + if ((contours[i].size() == 4) && (cv::contourArea(contours[i]) > 81) && (cv::isContourConvex(contours[i]))) { + if (prunedContours.size() != 0) { + bool different = true; + for (unsigned comparedTo = 0; comparedTo < prunedContours.size(); comparedTo++) { + cv::Moments m1 = cv::moments(prunedContours[comparedTo]); + int cx1 = (m1.m10/m1.m00); + int cy1 = (m1.m01/m1.m00); + + cv::Moments m2 = cv::moments(contours[i]); + int cx2 = (m2.m10/m2.m00); + int cy2 = (m2.m01/m2.m00); + + if ((std::abs(cx1 - cx2) < 3) && (std::abs(cy1 - cy2) < 3)) { + different = false; + break; + } + } + if (different) { + prunedContours.insert(prunedContours.begin(), contours[i]); + } + } else { + prunedContours.insert(prunedContours.begin(), contours[i]); + } + } + } + + return contours.size(); +} + +void ContourAnalyzer::drawShapePositions(cv::Mat &frame) { + for (unsigned i = 0; i < prunedContours.size(); i++) { + cv::Moments m = cv::moments(prunedContours[i]); + int cx = (m.m10/m.m00); + int cy = (m.m01/m.m00); + cv::putText(frame, "rectangle", cv::Point{cx, cy}, cv::FONT_HERSHEY_PLAIN, 1, fontColor, 2); + cv::drawContours(frame, prunedContours, i, selectColor, 1); + } +} + +std::string ContourAnalyzer::contourToString(std::vector contour) { + switch (contour.size()) { + case 4: + if (cv::isContourConvex(contour)) { + return "rectangle"; + } + /* no break */ + default: + throw std::invalid_argument("Shape too complex!"); + } +} + +cv::Mat ContourAnalyzer::getDebugFrame(int step) { + return stepFrames[step]; +} + +ContourAnalyzer::~ContourAnalyzer() { +} + diff --git a/src/detection/shape/ContourAnalyzer.h b/src/detection/shape/ContourAnalyzer.h new file mode 100755 index 0000000..094aea7 --- /dev/null +++ b/src/detection/shape/ContourAnalyzer.h @@ -0,0 +1,34 @@ +/* + * ContourAnalyzer.h + * + * Created on: Apr 22, 2018 + * Author: Yunyang + */ + +#ifndef DETECTION_SHAPE_CONTOURANALYZER_H_ +#define DETECTION_SHAPE_CONTOURANALYZER_H_ +#include +#include + +class ContourAnalyzer { +cv::Mat originFrame; +std::vector stepFrames{4}; +std::vector> contours; +std::vector> prunedContours; + +public: + ContourAnalyzer(); + virtual ~ContourAnalyzer(); + + cv::Scalar selectColor{0, 255, 0}; + cv::Scalar fontColor{0, 0, 255}; + + int analyze(); + void setFrame(cv::Mat frame); + void drawShapePositions(cv::Mat &frame); + std::string contourToString(std::vector); + + cv::Mat getDebugFrame(int step); +}; + +#endif /* DETECTION_SHAPE_CONTOURANALYZER_H_ */ diff --git a/src/main.cpp b/src/main.cpp new file mode 100755 index 0000000..e77bb3d --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,58 @@ +#include +#include "webcam/Webcam.h" +#include "detection/shape/ContourAnalyzer.h" + +int main(int argc, char** argv) { + Webcam webcam = 0; + ContourAnalyzer ca; + bool debug = false; + int debugFrame = 0; + int lastKey; + int state = 0; + while (true) { + webcam.update(); + cv::Mat frame = webcam.getFrame(); + ca.setFrame(frame); + ca.analyze(); + ca.drawShapePositions(frame); + + + if (debug) { + cv::imshow("debug", ca.getDebugFrame(debugFrame)); + } + + cv::imshow("Normal", frame); + if (lastKey > 0) { + std::cout << "key pressed: " << lastKey << std::endl; + if (lastKey == 27) { + break; + } else { + if (lastKey < 52 && lastKey > 48) { + debugFrame = lastKey - 49; + } + + if (lastKey == 32) { + state++; + if (state >= 3) { + state = 0; + } + printf("state set to: " + state); + } + + if (lastKey == 100) { + if (debug) { + cv::destroyWindow("debug"); + debug = false; + } else { + debug = true; + } + } + } + lastKey = 0; + } + lastKey = cv::waitKey(33); + } + + cv::destroyAllWindows(); + return 0; +} diff --git a/src/webcam/Webcam.cpp b/src/webcam/Webcam.cpp new file mode 100755 index 0000000..f6a8646 --- /dev/null +++ b/src/webcam/Webcam.cpp @@ -0,0 +1,29 @@ +/* + * Webcam.cpp + * + * Created on: Apr 21, 2018 + * Author: Yunyang + */ + +#include "Webcam.h" + +Webcam::Webcam(int webcamID) { + stream = new cv::VideoCapture(webcamID); +} + +void Webcam::update() { + stream->read(frame); +} + +bool Webcam::isConnected() const { + return webcamConnected; +} + +cv::Mat Webcam::getFrame() const { + return frame; +} + +Webcam::~Webcam() { + delete stream; +} + diff --git a/src/webcam/Webcam.h b/src/webcam/Webcam.h new file mode 100755 index 0000000..a5b7dc1 --- /dev/null +++ b/src/webcam/Webcam.h @@ -0,0 +1,25 @@ +/* + * Webcam.h + * + * Created on: Apr 21, 2018 + * Author: Yunyang + */ + +#ifndef WEBCAM_H_ +#define WEBCAM_H_ +#include + +class Webcam { + cv::VideoCapture* stream; + cv::Mat frame; + bool webcamConnected = false; +public: + Webcam(int webcamID); + virtual ~Webcam(); + + void update(); + bool isConnected() const; + cv::Mat getFrame() const; +}; + +#endif /* WEBCAM_H_ */