From 78a064428fd75aa223e0541e78eaa81cab04e1bf Mon Sep 17 00:00:00 2001 From: TheG1uy Date: Mon, 1 Oct 2018 21:45:43 +0300 Subject: [PATCH 1/2] tracker complete --- include/tracking.hpp | 13 ++++ samples/tracking_demo.cpp | 79 ++++++++++++++++++++ src/tracking.cpp | 147 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 239 insertions(+) create mode 100644 samples/tracking_demo.cpp diff --git a/include/tracking.hpp b/include/tracking.hpp index f80004c..4b9a987 100644 --- a/include/tracking.hpp +++ b/include/tracking.hpp @@ -4,6 +4,7 @@ #include #include "opencv2/core/core.hpp" +#include "opencv2/opencv.hpp" class Tracker { public: @@ -11,3 +12,15 @@ class Tracker { virtual bool Init(const cv::Mat &frame, const cv::Rect &roi) = 0; virtual cv::Rect Track(const cv::Mat &frame) = 0; }; + + +class MedianFlowTracker : public Tracker{ + public: + bool Init(const cv::Mat &frame, const cv::Rect &roi) override; + cv::Rect Track(const cv::Mat &frame) override; + cv::Rect getRect() { return position_; } + + protected: + cv::Rect position_; + cv::Mat frame_; +}; \ No newline at end of file diff --git a/samples/tracking_demo.cpp b/samples/tracking_demo.cpp new file mode 100644 index 0000000..95a5570 --- /dev/null +++ b/samples/tracking_demo.cpp @@ -0,0 +1,79 @@ +#include +#include "detection.hpp" +#include "tracking.hpp" + +using namespace std; +using namespace cv; + +const char* kOptions = +"{ v video | | video to process }" +"{ c camera | | camera to get video from }" +"{ h ? help usage | | print help message }"; + + + +Rect_ roi; +void CallBackFunc(int event, int x, int y, int flags, void* userdata) +{ + + if (event == EVENT_LBUTTONDOWN) + { + static vector points; + points.push_back(Point_(x, y)); + if (points.size() > 1) { + roi = Rect2i(points[0], points[1]); + points.clear(); + } + } + +} + +int main(int argc, const char** argv) { + // Parse command line arguments. + CommandLineParser parser(argc, argv, kOptions); + + // If help option is given, print help message and exit. + if (parser.get("help")) { + parser.printMessage(); + return 0; + } + + std::string filePath; + if (parser.has("v")) { + Mat frame; + VideoCapture video(parser.get("v")); + MedianFlowTracker tracker; + video.read(frame); + imshow("Result", frame); + cvtColor(frame, frame, CV_BGR2GRAY); + setMouseCallback("Result", CallBackFunc, NULL); + + while (true) { + waitKey(1); + if (!roi.empty()) break; + } + tracker.Init(frame, roi); + while (video.read(frame)) { + Mat tmp = frame; + tracker.Track(frame); + cvtColor(frame, frame, CV_BGR2GRAY); + rectangle(tmp, tracker.getRect(), Scalar(250, 150, 10)); + imshow("Result", tmp); + if (waitKey(1) == 27) break; + + } + + video.release(); + } + + else { + cerr << "Error load model"; + return -1; + } + + + return 0; +} + + + \ No newline at end of file diff --git a/src/tracking.cpp b/src/tracking.cpp index 26cbe06..144ec71 100644 --- a/src/tracking.cpp +++ b/src/tracking.cpp @@ -7,7 +7,154 @@ using std::shared_ptr; using namespace cv; shared_ptr Tracker::CreateTracker(const string &name) { + + if (name == "median_flow") { + return std::make_shared(); + } + std::cerr << "Failed to create tracker with name '" << name << "'" << std::endl; return nullptr; } + +double medianFunc(std::vector vec) { + if (vec.empty()) throw - 1; + if (vec.size() % 2 == 0) { + auto median_it1 = vec.begin() + vec.size() / 2 - 1; + auto median_it2 = vec.begin() + vec.size() / 2; + + std::nth_element(vec.begin(), median_it1, vec.end()); + auto p1 = *median_it1; + + std::nth_element(vec.begin(), median_it2, vec.end()); + auto p2 = *median_it2; + + return (p1 + p2) / 2; + + } + else { + const auto median_it = vec.begin() + vec.size() / 2; + std::nth_element(vec.begin(), median_it, vec.end()); + return *median_it; + } +} + + + +bool MedianFlowTracker::Init(const cv::Mat &frame, const cv::Rect &roi) { + + if (frame.empty()) return false; + + //cvtColor(frame, , COLOR_BGR2GRAY); + frame_ = frame; + position_ = roi; + + return true; + +} +cv::Rect MedianFlowTracker::Track(const cv::Mat &frame) { + Mat obj; + std::vector corners; + (frame(position_)).copyTo(obj); + cvtColor(frame(position_), obj, COLOR_BGR2GRAY); + goodFeaturesToTrack(obj, corners, 100, 0.03, 5); + + if (corners.empty()) throw "corners not found"; + + std::vector nextPts; + std::vector status; + std::vector err; + Mat gray_frame; + cvtColor(frame, gray_frame, COLOR_BGR2GRAY); + + Mat cir = obj.clone(); + for (int i = 0; i < corners.size(); i++) + corners[i] += Point2f(position_.x, position_.y); + + calcOpticalFlowPyrLK(frame_, gray_frame, corners, nextPts, status, err); + + int i = 0; + for (int j = 0; j < status.size(); j++) + if (status[j]) { + nextPts[i] = nextPts[j]; + corners[i++] = corners[j]; + } + nextPts.resize(i); + corners.resize(i); + err.clear(); + status.clear(); + + std::vector revPts; + + calcOpticalFlowPyrLK(gray_frame, frame_, nextPts, revPts, status, err); + + i = 0; + for (int j = 0; j < status.size(); j++) + if (status[j]) { + nextPts[i] = nextPts[j]; + revPts[i] = revPts[j]; + status[i] = status[j]; + err[i] = err[j]; + corners[i++] = corners[j]; + } + nextPts.resize(i); + corners.resize(i); + revPts.resize(i); + status.resize(i); + err.resize(i); + + if (corners.size() < 2) + throw "no corners"; + + std::vector revErr; + + for (int j = 0; j < corners.size(); j++) + revErr.emplace_back(norm(corners[j] - revPts[j])); + double median = medianFunc(revErr); + + i = 0; + for (int j = 0; j < revErr.size(); j++) + if (revErr[j] > median) { + nextPts[i] = nextPts[j]; + revPts[i] = revPts[j]; + corners[i++] = corners[j]; + } + nextPts.resize(i + 1); + corners.resize(i + 1); + revPts.resize(i + 1); + + + std::vector diffX, diffY; + for (int j = 0; j < corners.size(); j++) { + diffX.emplace_back(nextPts[j].x - revPts[j].x); + diffY.emplace_back(nextPts[j].y - revPts[j].y); + } + + Point2f newPoint(medianFunc(diffX),medianFunc(diffY)); + + std::vector coeffs; + + for (int i = 0; i < corners.size(); i++) { + for (int j = i + 1; j < corners.size(); j++) { + double nextNorm = norm(nextPts[i] - nextPts[j]); + double prevNorm = norm(corners[i] - corners[j]); + coeffs.emplace_back(nextNorm / prevNorm); + } + } + double coeff; + try { + coeff = medianFunc(coeffs); + } + catch (int a) { + coeff = 1; + } + + Rect next_position = position_ + Point(newPoint); + next_position.width *= coeff; + next_position.height *= coeff; + + position_ = next_position; + frame_ = gray_frame; + + return next_position; +} \ No newline at end of file From 98c3f0421571c37cdfbd3252350f976a0408f839 Mon Sep 17 00:00:00 2001 From: TheG1uy Date: Tue, 2 Oct 2018 14:07:24 +0300 Subject: [PATCH 2/2] cool fix in tracker func --- include/tracking.hpp | 4 ++ samples/tracking_demo.cpp | 21 ++-------- src/tracking.cpp | 80 +++++++++++---------------------------- 3 files changed, 29 insertions(+), 76 deletions(-) diff --git a/include/tracking.hpp b/include/tracking.hpp index 4b9a987..328d76c 100644 --- a/include/tracking.hpp +++ b/include/tracking.hpp @@ -15,10 +15,14 @@ class Tracker { class MedianFlowTracker : public Tracker{ + private: + double medianFunc(std::vector); + void delElements(std::initializer_list < std::vector*>, std::vector* status = nullptr, std::vector* revErr = nullptr, double value = 0); public: bool Init(const cv::Mat &frame, const cv::Rect &roi) override; cv::Rect Track(const cv::Mat &frame) override; cv::Rect getRect() { return position_; } + protected: cv::Rect position_; diff --git a/samples/tracking_demo.cpp b/samples/tracking_demo.cpp index 95a5570..fa2b92c 100644 --- a/samples/tracking_demo.cpp +++ b/samples/tracking_demo.cpp @@ -10,35 +10,26 @@ const char* kOptions = "{ c camera | | camera to get video from }" "{ h ? help usage | | print help message }"; - - -Rect_ roi; void CallBackFunc(int event, int x, int y, int flags, void* userdata) { - if (event == EVENT_LBUTTONDOWN) { static vector points; points.push_back(Point_(x, y)); if (points.size() > 1) { - roi = Rect2i(points[0], points[1]); + *reinterpret_cast *>(userdata) = Rect2i(points[0], points[1]); points.clear(); } } - } int main(int argc, const char** argv) { - // Parse command line arguments. CommandLineParser parser(argc, argv, kOptions); - - // If help option is given, print help message and exit. if (parser.get("help")) { parser.printMessage(); return 0; } - - std::string filePath; + Rect_ roi; if (parser.has("v")) { Mat frame; VideoCapture video(parser.get("v")); @@ -46,8 +37,7 @@ int main(int argc, const char** argv) { video.read(frame); imshow("Result", frame); cvtColor(frame, frame, CV_BGR2GRAY); - setMouseCallback("Result", CallBackFunc, NULL); - + setMouseCallback("Result", CallBackFunc, &roi); while (true) { waitKey(1); if (!roi.empty()) break; @@ -60,18 +50,13 @@ int main(int argc, const char** argv) { rectangle(tmp, tracker.getRect(), Scalar(250, 150, 10)); imshow("Result", tmp); if (waitKey(1) == 27) break; - } - video.release(); } - else { cerr << "Error load model"; return -1; } - - return 0; } diff --git a/src/tracking.cpp b/src/tracking.cpp index 144ec71..7472bd1 100644 --- a/src/tracking.cpp +++ b/src/tracking.cpp @@ -17,7 +17,7 @@ shared_ptr Tracker::CreateTracker(const string &name) { return nullptr; } -double medianFunc(std::vector vec) { +double MedianFlowTracker::medianFunc(std::vector vec) { if (vec.empty()) throw - 1; if (vec.size() % 2 == 0) { auto median_it1 = vec.begin() + vec.size() / 2 - 1; @@ -38,19 +38,27 @@ double medianFunc(std::vector vec) { return *median_it; } } - +void MedianFlowTracker::delElements(std::initializer_list < std::vector*> list, std::vector* status, + std::vector* revErr, double value) { + + int size = status ? status->size() : revErr->size(); + int i = 0; + for (int j = 0; j < size; j++) + if ((status && *(status->begin() + j)) || (revErr && *(revErr->begin() + j) > value)) { + for (auto k = list.begin(); k != list.end(); k++) + ((*k)->begin() + i) = ((*k)->begin() + j); + i++; + } + for (auto k = list.begin(); k != list.end(); k++) + (*k)->resize(i); +} bool MedianFlowTracker::Init(const cv::Mat &frame, const cv::Rect &roi) { - if (frame.empty()) return false; - - //cvtColor(frame, , COLOR_BGR2GRAY); frame_ = frame; position_ = roi; - return true; - } cv::Rect MedianFlowTracker::Track(const cv::Mat &frame) { Mat obj; @@ -58,71 +66,30 @@ cv::Rect MedianFlowTracker::Track(const cv::Mat &frame) { (frame(position_)).copyTo(obj); cvtColor(frame(position_), obj, COLOR_BGR2GRAY); goodFeaturesToTrack(obj, corners, 100, 0.03, 5); - - if (corners.empty()) throw "corners not found"; - + if (corners.empty()) throw "corners not found"; std::vector nextPts; std::vector status; std::vector err; Mat gray_frame; cvtColor(frame, gray_frame, COLOR_BGR2GRAY); - Mat cir = obj.clone(); for (int i = 0; i < corners.size(); i++) corners[i] += Point2f(position_.x, position_.y); - calcOpticalFlowPyrLK(frame_, gray_frame, corners, nextPts, status, err); - - int i = 0; - for (int j = 0; j < status.size(); j++) - if (status[j]) { - nextPts[i] = nextPts[j]; - corners[i++] = corners[j]; - } - nextPts.resize(i); - corners.resize(i); - err.clear(); - status.clear(); - + std::initializer_list < std::vector*> list = { &nextPts, &corners}; + delElements(list, &status); std::vector revPts; - calcOpticalFlowPyrLK(gray_frame, frame_, nextPts, revPts, status, err); - - i = 0; - for (int j = 0; j < status.size(); j++) - if (status[j]) { - nextPts[i] = nextPts[j]; - revPts[i] = revPts[j]; - status[i] = status[j]; - err[i] = err[j]; - corners[i++] = corners[j]; - } - nextPts.resize(i); - corners.resize(i); - revPts.resize(i); - status.resize(i); - err.resize(i); - + list = { &nextPts, &revPts, &corners }; + delElements(list, &status); if (corners.size() < 2) throw "no corners"; std::vector revErr; - for (int j = 0; j < corners.size(); j++) revErr.emplace_back(norm(corners[j] - revPts[j])); - double median = medianFunc(revErr); - - i = 0; - for (int j = 0; j < revErr.size(); j++) - if (revErr[j] > median) { - nextPts[i] = nextPts[j]; - revPts[i] = revPts[j]; - corners[i++] = corners[j]; - } - nextPts.resize(i + 1); - corners.resize(i + 1); - revPts.resize(i + 1); - + list = { &nextPts, &revPts, &corners }; + delElements(list, 0, &revErr, medianFunc(revErr)); std::vector diffX, diffY; for (int j = 0; j < corners.size(); j++) { @@ -131,7 +98,6 @@ cv::Rect MedianFlowTracker::Track(const cv::Mat &frame) { } Point2f newPoint(medianFunc(diffX),medianFunc(diffY)); - std::vector coeffs; for (int i = 0; i < corners.size(); i++) { @@ -152,9 +118,7 @@ cv::Rect MedianFlowTracker::Track(const cv::Mat &frame) { Rect next_position = position_ + Point(newPoint); next_position.width *= coeff; next_position.height *= coeff; - position_ = next_position; frame_ = gray_frame; - return next_position; } \ No newline at end of file