Commit 268836ed authored by UWNRG Controls's avatar UWNRG Controls

OpenCV riggeroni

parent e919502b
......@@ -25,6 +25,8 @@ find_package(PythonLibs 3.4 REQUIRED)
find_package(Qt5Widgets REQUIRED)
find_package(Qt5Core REQUIRED)
find_package(Qt5Gui REQUIRED)
find_package(Qt5Multimedia REQUIRED)
find_package(Qt5MultimediaWidgets REQUIRED)
find_package(Threads REQUIRED)
if (Qt5_POSITION_INDEPENDENT_CODE)
......@@ -90,7 +92,11 @@ set(CMAKE_AUTOUIC ON)
get_target_property(QtCore_location Qt5::Core LOCATION)
add_executable(minotaur-cpp ${SOURCE_FILES} ${HEADER_FILES} ${FORM_FILES} ${THIRD_PARTY} ${THIRD_PARTY_COMMON})
target_link_libraries(minotaur-cpp Qt5::Widgets Qt5::Core Qt5::Gui)
find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})
target_link_libraries(minotaur-cpp ${OpenCV_LIBS})
target_link_libraries(minotaur-cpp Qt5::Widgets Qt5::Core Qt5::Gui Qt5::Multimedia Qt5::MultimediaWidgets)
target_link_libraries(minotaur-cpp ${PYTHON_LIBRARIES})
target_link_libraries(minotaur-cpp "${CMAKE_THREAD_LIBS_INIT}")
target_include_directories(minotaur-cpp PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
......
......@@ -5,7 +5,7 @@ Solenoid::Solenoid(const QString& serial_port): Controller(1, 1) {
// TODO: change actuator setup to be used for general serial set up
if ( serial_port.isEmpty() ) {
// TODO: provide error if this does not succeed
stream.open("/dev/ttyACM0"); // manually changed to match port indicated in arduino IDE
stream.open("/dev/ttyACM1"); // manually changed to match port indicated in arduino IDE
} else {
stream.open(serial_port.toStdString());
}
......@@ -19,6 +19,7 @@ void Solenoid::move(Vector2i dir, int timer) {
// TODO: user timer for movement control
bool success = true;
#ifndef NDEBUG
Logger::log("Moving Solenoid controller", Logger::DEBUG);
Logger::log("Attempting move (" + std::to_string(dir.x_comp) + ", " + std::to_string(dir.y_comp) + ")",
Logger::DEBUG);
#endif
......
......@@ -15,7 +15,7 @@ MainWindow::MainWindow(QWidget *parent, const char *) :
m_solenoid = std::shared_ptr<Solenoid>(new Solenoid);
m_simulator = std::shared_ptr<Simulator>(new Simulator(1, -1));
m_controller = m_solenoid;
m_controller_type = Controller::Type::ACTUATOR;
m_controller_type = Controller::Type::SOLENOID;
// Bind controller to Python Engine
EmbeddedController::getInstance().bind_controller(&m_controller);
......
......@@ -3,11 +3,147 @@
#include "gui/mainwindow.h"
#include <QApplication>
#include <QCameraInfo>
#include <QCameraViewfinder>
#include <opencv2/videoio.hpp>
#include <opencv2/opencv.hpp>
int thresh = 0;
int N = 50;
using std::vector;
using namespace cv;
static double angle(Point pt1, Point pt2, Point pt0) {
double dx1 = pt1.x - pt0.x;
double dy1 = pt1.y - pt0.y;
double dx2 = pt2.x - pt0.x;
double dy2 = pt2.y - pt0.y;
return (dx1 * dx2 + dy1 * dy2) / sqrt((dx1 * dx1 + dy1 * dy1) * (dx2 * dx2 + dy2 * dy2) + 1e-10);
}
// returns sequence of squares detected on the image.
// the sequence is stored in the specified memory storage
static void findSquares(const Mat &image, vector<vector<Point> > &squares) {
squares.clear();
Mat pyr, timg, gray0(image.size(), CV_8U), gray;
// down-scale and upscale the image to filter out the noise
pyrDown(image, pyr, Size(image.cols / 2, image.rows / 2));
pyrUp(pyr, timg, image.size());
vector<vector<Point> > contours;
// find squares in every color plane of the image
for (int c = 0; c < 3; c++) {
int ch[] = {c, 0};
mixChannels(&timg, 1, &gray0, 1, ch, 1);
// try several threshold levels
for (int l = 0; l < N; l++) {
// hack: use Canny instead of zero threshold level.
// Canny helps to catch squares with gradient shading
if (l == 0) {
// apply Canny. Take the upper threshold from slider
// and set the lower to 0 (which forces edges merging)
Canny(gray0, gray, 0, thresh, 5);
// dilate canny output to remove potential
// holes between edge segments
dilate(gray, gray, Mat(), Point(-1, -1));
} else {
// apply threshold if l!=0:
// tgray(x,y) = gray(x,y) < (l+1)*255/N ? 255 : 0
gray = gray0 >= (l + 1) * 255 / N;
}
// find contours and store them all as a list
findContours(gray, contours, RETR_LIST, CHAIN_APPROX_SIMPLE);
vector<Point> approx;
// test each contour
for (size_t i = 0; i < contours.size(); i++) {
// approximate contour with accuracy proportional
// to the contour perimeter
approxPolyDP(Mat(contours[i]), approx, arcLength(Mat(contours[i]), true) * 0.02, true);
// square contours should have 4 vertices after approximation
// relatively large area (to filter out noisy contours)
// and be convex.
// Note: absolute value of an area is used because
// area may be positive or negative - in accordance with the
// contour orientation
if (approx.size() == 4 &&
fabs(contourArea(Mat(approx))) > 1000 &&
isContourConvex(Mat(approx))) {
double maxCosine = 0;
for (int j = 2; j < 5; j++) {
// find the maximum cosine of the angle between joint edges
double cosine = fabs(angle(approx[j % 4], approx[j - 2], approx[j - 1]));
maxCosine = MAX(maxCosine, cosine);
}
// if cosines of all angles are small
// (all angles are ~90 degree) then write quandrange
// vertices to resultant sequence
if (maxCosine < 0.3)
squares.push_back(approx);
}
}
}
}
}
// the function draws all the squares in the image
static void drawSquares(Mat &image, const vector<vector<Point> > &squares) {
for (size_t i = 0; i < squares.size(); i++) {
const Point *p = &squares[i][0];
int n = (int) squares[i].size();
polylines(image, &p, &n, 1, true, Scalar(0, 255, 0), 3, LINE_AA);
}
}
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
/*QApplication app(argc, argv);
MainWindow *w = new MainWindow();
w->show();
return app.exec();*/
using namespace cv;
VideoCapture cap(0);
if (!cap.isOpened()) {
return 1;
}
//Mat edges;
namedWindow("edges", 1);
for (;;) {
Mat frame;
cap >> frame; // get a new frame from camera
//frame *= 25;
//cvtColor(frame, edges, COLOR_BGR2GRAY);
vector<vector<Point>> squares;
//GaussianBlur(edges, edges, Size(7, 7), 1.5, 1.5);
//Canny(edges, edges, 20, 100, 3);
//findSquares(edges, squares);
//drawSquares(frame, squares);
//std::cout << squares.size() << std::endl;
findSquares(frame, squares);
drawSquares(frame, squares);
imshow("frame", frame);
if (waitKey(1)) {
MainWindow *w = new MainWindow();
w->show();
}
}
// the camera will be deinitialized automatically in VideoCapture destructor
return 0;
return app.exec();
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment