initial commit
This commit is contained in:
commit
603143551e
98
.gitignore
vendored
Normal file
98
.gitignore
vendored
Normal file
@ -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
|
87
src/detection/shape/ContourAnalyzer.cpp
Executable file
87
src/detection/shape/ContourAnalyzer.cpp
Executable file
@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* ContourAnalyzer.cpp
|
||||||
|
*
|
||||||
|
* Created on: Apr 22, 2018
|
||||||
|
* Author: Yunyang
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ContourAnalyzer.h"
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
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<cv::Point> 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() {
|
||||||
|
}
|
||||||
|
|
34
src/detection/shape/ContourAnalyzer.h
Executable file
34
src/detection/shape/ContourAnalyzer.h
Executable file
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* ContourAnalyzer.h
|
||||||
|
*
|
||||||
|
* Created on: Apr 22, 2018
|
||||||
|
* Author: Yunyang
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DETECTION_SHAPE_CONTOURANALYZER_H_
|
||||||
|
#define DETECTION_SHAPE_CONTOURANALYZER_H_
|
||||||
|
#include <string>
|
||||||
|
#include <opencv2/opencv.hpp>
|
||||||
|
|
||||||
|
class ContourAnalyzer {
|
||||||
|
cv::Mat originFrame;
|
||||||
|
std::vector<cv::Mat> stepFrames{4};
|
||||||
|
std::vector<std::vector<cv::Point>> contours;
|
||||||
|
std::vector<std::vector<cv::Point>> 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::Point>);
|
||||||
|
|
||||||
|
cv::Mat getDebugFrame(int step);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* DETECTION_SHAPE_CONTOURANALYZER_H_ */
|
58
src/main.cpp
Executable file
58
src/main.cpp
Executable file
@ -0,0 +1,58 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#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;
|
||||||
|
}
|
29
src/webcam/Webcam.cpp
Executable file
29
src/webcam/Webcam.cpp
Executable file
@ -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;
|
||||||
|
}
|
||||||
|
|
25
src/webcam/Webcam.h
Executable file
25
src/webcam/Webcam.h
Executable file
@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Webcam.h
|
||||||
|
*
|
||||||
|
* Created on: Apr 21, 2018
|
||||||
|
* Author: Yunyang
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef WEBCAM_H_
|
||||||
|
#define WEBCAM_H_
|
||||||
|
#include <opencv2/opencv.hpp>
|
||||||
|
|
||||||
|
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_ */
|
Loading…
x
Reference in New Issue
Block a user