From 86cebd3e6c20a507f33971c648eed4de060aaa96 Mon Sep 17 00:00:00 2001 From: Lukas Moungos Date: Thu, 11 May 2023 14:29:48 +0200 Subject: [PATCH] init --- .gitignore | 2 ++ CMakeLists.txt | 17 +++++++++++ MarkerTracking.cpp | 74 +++++++++++++++++++++++++++++++++++++++++++++ src/Detector.cpp | 75 ++++++++++++++++++++++++++++++++++++++++++++++ src/Detector.hpp | 14 +++++++++ 5 files changed, 182 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 MarkerTracking.cpp create mode 100644 src/Detector.cpp create mode 100644 src/Detector.hpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bc95448 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.cache/ +build/ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..326c131 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 3.26) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE INTERNAL "") # works + +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules) + +find_package(OpenCV REQUIRED) + +project(MarkerTracking) + +include_directories( ${OpenCV_INCLUDE_DIRS} ) + +set(SOURCES + MarkerTracking.cpp + src/Detector.hpp + src/Detector.cpp) +add_executable(MarkerTracking ${SOURCES}) +target_link_libraries (MarkerTracking ${OpenCV_LIBS}) diff --git a/MarkerTracking.cpp b/MarkerTracking.cpp new file mode 100644 index 0000000..950e542 --- /dev/null +++ b/MarkerTracking.cpp @@ -0,0 +1,74 @@ +#include +#include +#include "src/Detector.hpp" + +using namespace cv; +using namespace std; + + +// List of points +typedef vector contour_t; +// List of contours +typedef vector contour_vector_t; + +Mat videoStreamFrameGray; +Mat videoStreamFrameOutput; + +// Pos is from UI, dereferencing of the pointer +static void on_trackbar(/* ??? */) { + //*((???*)???) = ???; +} + +int main() { + + Mat frame; + VideoCapture cap(0); + + if (!cap.isOpened()) { + cout << "No webcam, using video file" << endl; + cap.open("MarkerMovie.MP4"); + if (cap.isOpened() == false) { + cout << "No video!" << endl; + exit(0); + } + } + + const string contoursWindow = "Contours"; + const string thresholdWindow = "Threshold"; + + namedWindow(contoursWindow, WINDOW_FREERATIO); + namedWindow(thresholdWindow, WINDOW_FREERATIO); + + const string UI = "Threshold"; + int threshold = 65; + createTrackbar(UI, thresholdWindow, &threshold, 255); + + + Mat imgFiltered; + Detector detector; + + while (cap.read(frame)) { + + // --- Process Frame --- + Mat grayScale; + imgFiltered = frame.clone(); + cvtColor(imgFiltered,grayScale, COLOR_BGR2GRAY); + + // Threshold to reduce the noise + adaptiveThreshold(grayScale, grayScale, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 45, 15); + cv::threshold(grayScale, videoStreamFrameGray, threshold, 255, THRESH_OTSU); + + detector.detect(videoStreamFrameGray, imgFiltered); + + imshow(contoursWindow, imgFiltered); + imshow(thresholdWindow, videoStreamFrameGray); + + if (waitKey(10) == 27) { + break; + } + } + + destroyWindow(contoursWindow); + + return (0); +} diff --git a/src/Detector.cpp b/src/Detector.cpp new file mode 100644 index 0000000..8496fcb --- /dev/null +++ b/src/Detector.cpp @@ -0,0 +1,75 @@ +#include "Detector.hpp" + +using namespace cv; + +void Detector::detect(Mat thresholdFrame, Mat &output){ + /* TASK: Try to understand this data structure! */ + contour_vector_t contours; + + /* TASK: Research the different parameters it takes and play around with them */ + findContours(thresholdFrame, contours, RETR_LIST, CHAIN_APPROX_SIMPLE); + + //DEBUG + //drawContours(imgFiltered, contours, -1, Scalar(0, 255, 0), 4); + + // size is always positive, so unsigned int -> size_t; if you have not + // initialized the vector it is -1, hence crash + for (size_t k = 0; k < contours.size(); k++) { + + contour_t approx_contour; + approxPolyDP(contours[k], approx_contour, arcLength(contours[k], true) * 0.02, true); + + // Convert to a usable rectangle + Rect r = boundingRect(approx_contour); + + // TASK: 4 Corners -> How to color them in the frame? + if(approx_contour.size() != 4){ + continue; + } + + // --- Filter tiny ones --- If the found contour is too small (20 -> + // pixels, frame.cols - 10 to prevent extreme big contours) + if (r.width < 20 || r.height < 20 || r.width > output.cols - 10 || r.height > output.cols - 10) { + continue; + } + + //DEBUG + //rectangle(filteredFrame, r, Scalar(0,0,255),4); + + drawRectangle(output, approx_contour); + } + } + +void Detector::drawRectangle(Mat &output, contour_t contour){ + // -> Cleaning done! + + // 1 -> 1 contour, we have a closed contour, true -> closed , 4 -> + // thickness + polylines(output, contour, true, Scalar(0,0,255), THICKNESS_VALUE); + + // ----------------------------- + + // --- Process Corners --- + for (size_t i = 0; i < 4; i++) { + // Render the corners, 3 -> Radius, -1 filled circle + circle(output, contour[i], 3, CV_RGB(0, 255, 0), -1); + + // Euclidic distance, 7 -> parts, both directions dx and dy + /* TASK: How to achieve that? */ + double dx = (double)(contour[(i+1)%4].x - contour[i].x) / 7; + double dy = (double)(contour[(i+1)%4].y - contour[i].y) / 7; + + // First point already rendered, now the other 6 points + for (size_t j = 1; j < 7; j++) { + // Position calculation + double px = dx * j + contour[i].x; + double py = dy * j + contour[i].y; + + Point p; + p.x = (int)px; + p.y = (int)py; + + circle(output, p, 3, CV_RGB(0, 0, 255), -1); + } + } +} diff --git a/src/Detector.hpp b/src/Detector.hpp new file mode 100644 index 0000000..61a9bfb --- /dev/null +++ b/src/Detector.hpp @@ -0,0 +1,14 @@ +#include + +#define THICKNESS_VALUE 4 + +class Detector{ + public: + void detect(cv::Mat thresholdFrame, cv::Mat &output); + private: + // List of points + typedef std::vector contour_t; + // List of contours + typedef std::vector contour_vector_t; + void drawRectangle(cv::Mat &output, contour_t contour); +};