diff options
Diffstat (limited to 'tracker-easy')
-rw-r--r-- | tracker-easy/cv-point-extractor.cpp | 32 | ||||
-rw-r--r-- | tracker-easy/cv-point-extractor.h | 4 | ||||
-rw-r--r-- | tracker-easy/frame.cpp | 30 | ||||
-rw-r--r-- | tracker-easy/frame.hpp | 2 | ||||
-rw-r--r-- | tracker-easy/module.cpp | 9 | ||||
-rw-r--r-- | tracker-easy/point_extractor.cpp | 395 | ||||
-rw-r--r-- | tracker-easy/point_extractor.h | 61 | ||||
-rw-r--r-- | tracker-easy/tracker-easy-api.cpp | 29 | ||||
-rw-r--r-- | tracker-easy/tracker-easy-api.h | 31 | ||||
-rw-r--r-- | tracker-easy/tracker-easy-dialog.cpp | 12 | ||||
-rw-r--r-- | tracker-easy/tracker-easy.cpp | 29 | ||||
-rw-r--r-- | tracker-easy/tracker-easy.h | 9 |
12 files changed, 68 insertions, 575 deletions
diff --git a/tracker-easy/cv-point-extractor.cpp b/tracker-easy/cv-point-extractor.cpp index 42f1a06b..7c0b00b5 100644 --- a/tracker-easy/cv-point-extractor.cpp +++ b/tracker-easy/cv-point-extractor.cpp @@ -30,19 +30,21 @@ CvPointExtractor::CvPointExtractor(const QString& module_name) : s(module_name) } -void CvPointExtractor::extract_points(const cv::Mat& frame, cv::Mat& aPreview, std::vector<vec2>& points, std::vector<vec2>& imagePoints) +void CvPointExtractor::extract_points(const cv::Mat& frame, cv::Mat* aPreview, std::vector<vec2>& aPoints) { // Contours detection std::vector<std::vector<cv::Point> > contours; cv::findContours(frame, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE); - // Workout which countour are valid points - std::vector<std::vector<cv::Point> > balls; - std::vector<cv::Rect> ballsBox; + // Workout which countours are valid points for (size_t i = 0; i < contours.size(); i++) { - cv::drawContours(aPreview, contours, i, CV_RGB(255, 0, 0), 2); + if (aPreview) + { + cv::drawContours(*aPreview, contours, i, CV_RGB(255, 0, 0), 2); + } + cv::Rect bBox; bBox = cv::boundingRect(contours[i]); @@ -63,15 +65,15 @@ void CvPointExtractor::extract_points(const cv::Mat& frame, cv::Mat& aPreview, s && bBox.area() <= maxArea /*&& ratio > 0.75 &&*/) { - balls.push_back(contours[i]); - ballsBox.push_back(bBox); - vec2 center; center[0] = bBox.x + bBox.width / 2; center[1] = bBox.y + bBox.height / 2; - imagePoints.push_back(vec2(center)); + aPoints.push_back(vec2(center)); - cv::rectangle(aPreview, bBox, CV_RGB(0, 255, 0), 2); + if (aPreview) + { + cv::rectangle(*aPreview, bBox, CV_RGB(0, 255, 0), 2); + } } } @@ -80,23 +82,23 @@ void CvPointExtractor::extract_points(const cv::Mat& frame, cv::Mat& aPreview, s // Typically noise comming from zippers and metal parts on your clothing. // With a cap tracker it also successfully discards noise glasses. // However it may not work as good with a clip user wearing glasses. - while (imagePoints.size() > 3) // Until we have no more than three points + while (aPoints.size() > 3) // Until we have no more than three points { int maxY = 0; int index = -1; // Search for the point with highest Y coordinate - for (size_t i = 0; i < imagePoints.size(); i++) + for (size_t i = 0; i < aPoints.size(); i++) { - if (imagePoints[i][1] > maxY) + if (aPoints[i][1] > maxY) { - maxY = imagePoints[i][1]; + maxY = aPoints[i][1]; index = i; } } // Discard it - imagePoints.erase(imagePoints.begin() + index); + aPoints.erase(aPoints.begin() + index); } diff --git a/tracker-easy/cv-point-extractor.h b/tracker-easy/cv-point-extractor.h index 65293e57..8a8ed66b 100644 --- a/tracker-easy/cv-point-extractor.h +++ b/tracker-easy/cv-point-extractor.h @@ -19,12 +19,12 @@ using namespace numeric_types; -class CvPointExtractor final : public pt_point_extractor +class CvPointExtractor final : public IPointExtractor { public: // extracts points from frame and draws some processing info into frame, if draw_output is set // dt: time since last call in seconds - void extract_points(const cv::Mat& frame, cv::Mat& preview_frame, std::vector<vec2>& points, std::vector<vec2>& imagePoints) override; + void extract_points(const cv::Mat& frame, cv::Mat* aPreview, std::vector<vec2>& aPoints) override; CvPointExtractor(const QString& module_name); pt_settings s; diff --git a/tracker-easy/frame.cpp b/tracker-easy/frame.cpp index 90d4c6f9..12f70662 100644 --- a/tracker-easy/frame.cpp +++ b/tracker-easy/frame.cpp @@ -26,15 +26,6 @@ Preview& Preview::operator=(const cv::Mat& aFrame) return *this; } - const bool need_resize = iFrameRgb.cols != frame_out.cols || iFrameRgb.rows != frame_out.rows; - if (need_resize) - { - cv::resize(iFrameRgb, iFrameResized, cv::Size(frame_out.cols, frame_out.rows), 0, 0, cv::INTER_NEAREST); - } - else - { - iFrameRgb.copyTo(iFrameResized); - } return *this; } @@ -58,6 +49,17 @@ QImage Preview::get_bitmap() return QImage(); } + // Resize if needed + const bool need_resize = iFrameRgb.cols != frame_out.cols || iFrameRgb.rows != frame_out.rows; + if (need_resize) + { + cv::resize(iFrameRgb, iFrameResized, cv::Size(frame_out.cols, frame_out.rows), 0, 0, cv::INTER_NEAREST); + } + else + { + iFrameRgb.copyTo(iFrameResized); + } + cv::cvtColor(iFrameResized, frame_out, cv::COLOR_BGR2BGRA); return QImage((const unsigned char*) frame_out.data, @@ -66,20 +68,18 @@ QImage Preview::get_bitmap() QImage::Format_ARGB32); } -void Preview::draw_head_center(Coordinates::f x, Coordinates::f y) +void Preview::draw_head_center(numeric_types::f x, numeric_types::f y) { - auto [px_, py_] = Coordinates::to_pixel_pos(x, y, iFrameResized.cols, iFrameResized.rows); - - int px = iround(px_), py = iround(py_); + int px = iround(x), py = iround(y); constexpr int len = 9; static const cv::Scalar color(0, 255, 255); - cv::line(iFrameResized, + cv::line(iFrameRgb, cv::Point(px - len, py), cv::Point(px + len, py), color, 1); - cv::line(iFrameResized, + cv::line(iFrameRgb, cv::Point(px, py - len), cv::Point(px, py + len), color, 1); diff --git a/tracker-easy/frame.hpp b/tracker-easy/frame.hpp index ba5e45e3..8493b4e9 100644 --- a/tracker-easy/frame.hpp +++ b/tracker-easy/frame.hpp @@ -13,7 +13,7 @@ struct Preview Preview& operator=(const cv::Mat& frame); QImage get_bitmap(); - void draw_head_center(Coordinates::f x, Coordinates::f y); + void draw_head_center(numeric_types::f x, numeric_types::f y); operator cv::Mat&() { return iFrameResized; } operator cv::Mat const&() const { return iFrameResized; } diff --git a/tracker-easy/module.cpp b/tracker-easy/module.cpp index 86abffbc..d24a1336 100644 --- a/tracker-easy/module.cpp +++ b/tracker-easy/module.cpp @@ -4,7 +4,6 @@ #include "module.hpp" #include "frame.hpp" -#include "point_extractor.h" #include "cv-point-extractor.h" @@ -18,11 +17,11 @@ static const QString module_name = "tracker-easy"; namespace pt_module { -struct pt_module_traits final : pt_runtime_traits +struct pt_module_traits final : IEasyTrackerTraits { - pointer<pt_point_extractor> make_point_extractor() const override + pointer<IPointExtractor> make_point_extractor() const override { - return pointer<pt_point_extractor>(new CvPointExtractor(module_name)); + return pointer<IPointExtractor>(new CvPointExtractor(module_name)); } QString get_module_name() const override @@ -34,7 +33,7 @@ struct pt_module_traits final : pt_runtime_traits struct tracker_pt : EasyTracker { - tracker_pt() : EasyTracker(pointer<pt_runtime_traits>(new pt_module_traits)) + tracker_pt() : EasyTracker(pointer<IEasyTrackerTraits>(new pt_module_traits)) { } }; diff --git a/tracker-easy/point_extractor.cpp b/tracker-easy/point_extractor.cpp deleted file mode 100644 index 06bb6c9a..00000000 --- a/tracker-easy/point_extractor.cpp +++ /dev/null @@ -1,395 +0,0 @@ -/* Copyright (c) 2012 Patrick Ruoff - * Copyright (c) 2015-2017 Stanislaw Halik <sthalik@misaki.pl> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - */ - -#include "point_extractor.h" -#include "frame.hpp" - -#include "cv/numeric.hpp" -#include "compat/math.hpp" - -#undef PREVIEW -//#define PREVIEW - -#if defined PREVIEW -# include <opencv2/highgui.hpp> -#endif - -#include <cmath> -#include <algorithm> -#include <cinttypes> -#include <memory> - -#include <QDebug> - -using namespace numeric_types; - -// meanshift code written by Michael Welter - -/* -http://en.wikipedia.org/wiki/Mean-shift -In this application the idea, is to eliminate any bias of the point estimate -which is introduced by the rather arbitrary thresholded area. One must recognize -that the thresholded area can only move in one pixel increments since it is -binary. Thus, its center of mass might make "jumps" as pixels are added/removed -from the thresholded area. -With mean-shift, a moving "window" or kernel is multiplied with the gray-scale -image, and the COM is calculated of the result. This is iterated where the -kernel center is set the previously computed COM. Thus, peaks in the image intensity -distribution "pull" the kernel towards themselves. Eventually it stops moving, i.e. -then the computed COM coincides with the kernel center. We hope that the -corresponding location is a good candidate for the extracted point. -The idea similar to the window scaling suggested in Berglund et al. "Fast, bias-free -algorithm for tracking single particles with variable size and shape." (2008). -*/ -static vec2 MeanShiftIteration(const cv::Mat1b &frame_gray, const vec2 ¤t_center, f filter_width) -{ - const f s = 1 / filter_width; - - f m = 0; - vec2 com { 0, 0 }; - for (int i = 0; i < frame_gray.rows; i++) - { - uint8_t const* const __restrict frame_ptr = frame_gray.ptr(i); - for (int j = 0; j < frame_gray.cols; j++) - { - f val = frame_ptr[j]; - val = val * val; // taking the square weighs brighter parts of the image stronger. - f dx = (j - current_center[0])*s; - f dy = (i - current_center[1])*s; - f max = std::fmax(f(0), 1 - dx*dx - dy*dy); - val *= max; - m += val; - com[0] += j * val; - com[1] += i * val; - } - } - if (m > f(.1)) - { - com *= 1 / m; - return com; - } - else - return current_center; -} - -namespace pt_module { - -PointExtractor::PointExtractor(const QString& module_name) : s(module_name) -{ - blobs.reserve(max_blobs); -} - -void PointExtractor::ensure_channel_buffers(const cv::Mat& orig_frame) -{ - if (ch[0].rows != orig_frame.rows || ch[0].cols != orig_frame.cols) - for (cv::Mat1b& x : ch) - x = cv::Mat1b(orig_frame.rows, orig_frame.cols); -} - -void PointExtractor::ensure_buffers(const cv::Mat& frame) -{ - const int W = frame.cols, H = frame.rows; - - if (frame_gray.rows != W || frame_gray.cols != H) - { - frame_gray = cv::Mat1b(H, W); - frame_bin = cv::Mat1b(H, W); - frame_gray_unmasked = cv::Mat1b(H, W); - } -} - -void PointExtractor::extract_single_channel(const cv::Mat& orig_frame, int idx, cv::Mat1b& dest) -{ - ensure_channel_buffers(orig_frame); - - const int from_to[] = { - idx, 0, - }; - - cv::mixChannels(&orig_frame, 1, &dest, 1, from_to, 1); -} - -void PointExtractor::color_to_grayscale(const cv::Mat& frame, cv::Mat1b& output) -{ - switch (s.blob_color) - { - case pt_color_green_only: - { - extract_single_channel(frame, 1, output); - break; - } - case pt_color_blue_only: - { - extract_single_channel(frame, 0, output); - break; - } - case pt_color_red_only: - { - extract_single_channel(frame, 2, output); - break; - } - case pt_color_average: - { - const int W = frame.cols, H = frame.rows, sz = W*H; - cv::reduce(frame.reshape(1, sz), - output.reshape(1, sz), - 1, cv::REDUCE_AVG); - break; - } - default: - eval_once(qDebug() << "wrong pt_color_type enum value" << int(s.blob_color)); - [[fallthrough]]; - case pt_color_natural: - cv::cvtColor(frame, output, cv::COLOR_BGR2GRAY); - break; - } -} - -void PointExtractor::threshold_image(const cv::Mat& frame_gray, cv::Mat1b& output) -{ - const int threshold_slider_value = s.threshold_slider.to<int>(); - - if (!s.auto_threshold) - { - cv::threshold(frame_gray, output, threshold_slider_value, 255, cv::THRESH_BINARY); - } - else - { - const int hist_size = 256; - const float ranges_[] = { 0, 256 }; - float const* ranges = (const float*) ranges_; - - cv::calcHist(&frame_gray, - 1, - nullptr, - cv::noArray(), - hist, - 1, - &hist_size, - &ranges); - - const f radius = threshold_radius_value(frame_gray.cols, frame_gray.rows, threshold_slider_value); - - float const* const __restrict ptr = hist.ptr<float>(0); - const unsigned area = uround(3 * pi * radius*radius); - const unsigned sz = unsigned(hist.cols * hist.rows); - constexpr unsigned min_thres = 64; - unsigned thres = min_thres; - for (unsigned i = sz-1, cnt = 0; i > 32; i--) - { - cnt += (unsigned)ptr[i]; - if (cnt >= area) - break; - thres = i; - } - - cv::threshold(frame_gray, output, thres, 255, cv::THRESH_BINARY); - } -} - -static void draw_blobs(cv::Mat& preview_frame, const blob* blobs, unsigned nblobs, const cv::Size& size) -{ - for (unsigned k = 0; k < nblobs; k++) - { - const blob& b = blobs[k]; - - if (b.radius < 0) - continue; - - const f dpi = preview_frame.cols / f(320); - const f offx = 10 * dpi, offy = f(7.5) * dpi; - - const f cx = preview_frame.cols / f(size.width), - cy = preview_frame.rows / f(size.height), - c = std::fmax(f(1), cx+cy)/2; - - constexpr unsigned fract_bits = 8; - constexpr int c_fract(1 << fract_bits); - - cv::Point p(iround(b.pos[0] * cx * c_fract), iround(b.pos[1] * cy * c_fract)); - - auto circle_color = k >= KPointCount - ? cv::Scalar(192, 192, 192) - : cv::Scalar(255, 255, 0); - - const int overlay_size = iround(dpi); - - cv::circle(preview_frame, p, iround((b.radius + f(3.3) * c) * c_fract), - circle_color, overlay_size, - cv::LINE_AA, fract_bits); - - char buf[16]; - buf[sizeof(buf)-1] = '\0'; - std::snprintf(buf, sizeof(buf) - 1, "%.2fpx", (double)b.radius); - - auto text_color = k >= KPointCount - ? cv::Scalar(160, 160, 160) - : cv::Scalar(0, 0, 255); - - cv::Point pos(iround(b.pos[0]*cx+offx), iround(b.pos[1]*cy+offy)); - cv::putText(preview_frame, buf, pos, - cv::FONT_HERSHEY_PLAIN, overlay_size, text_color, - 1); - } -} - -void PointExtractor::extract_points(const cv::Mat& frame, cv::Mat& preview_frame_, std::vector<vec2>& points, std::vector<vec2>& imagePoints) -{ - - ensure_buffers(frame); - if (frame.channels() != 1) - { - color_to_grayscale(frame, frame_gray_unmasked); - } - else - { - frame_gray_unmasked = frame; - } - - -#if defined PREVIEW - cv::imshow("capture", frame_gray); - cv::waitKey(1); -#endif - - threshold_image(frame_gray_unmasked, frame_bin); - frame_gray_unmasked.copyTo(frame_gray, frame_bin); - - const f region_size_min = (f)s.min_point_size; - const f region_size_max = (f)s.max_point_size; - - unsigned idx = 0; - - blobs.clear(); - - for (int y=0; y < frame_bin.rows; y++) - { - const unsigned char* __restrict ptr_bin = frame_bin.ptr(y); - for (int x=0; x < frame_bin.cols; x++) - { - if (ptr_bin[x] != 255) - continue; - idx = blobs.size() + 1; - - cv::Rect rect; - cv::floodFill(frame_bin, - cv::Point(x,y), - cv::Scalar(idx), - &rect, - cv::Scalar(0), - cv::Scalar(0), - 4 | cv::FLOODFILL_FIXED_RANGE); - - unsigned cnt = 0; - unsigned norm = 0; - - const int ymax = rect.y+rect.height, - xmax = rect.x+rect.width; - - for (int i=rect.y; i < ymax; i++) - { - unsigned char const* const __restrict ptr_blobs = frame_bin.ptr(i); - unsigned char const* const __restrict ptr_gray = frame_gray.ptr(i); - for (int j=rect.x; j < xmax; j++) - { - if (ptr_blobs[j] != idx) - continue; - - //ptr_blobs[j] = 0; - norm += ptr_gray[j]; - cnt++; - } - } - - const f radius = std::sqrt(cnt / pi); - if (radius > region_size_max || radius < region_size_min) - continue; - - blobs.emplace_back(radius, - vec2(rect.width/f(2), rect.height/f(2)), - std::pow(f(norm), f(1.1))/cnt, - rect); - - if (idx >= max_blobs) - goto end; - - // XXX we could go to the next scanline unless the points are really small. - // i'd expect each point being present on at least one unique scanline - // but it turns out some people are using 2px points -sh 20180110 - //break; - } - } -end: - - const int W = frame_gray.cols; - const int H = frame_gray.rows; - - const unsigned sz = blobs.size(); - - std::sort(blobs.begin(), blobs.end(), [](const blob& b1, const blob& b2) { return b2.brightness < b1.brightness; }); - - for (idx = 0; idx < sz; ++idx) - { - blob& b = blobs[idx]; - cv::Rect rect = b.rect; - - rect.x -= rect.width / 2; - rect.y -= rect.height / 2; - rect.width *= 2; - rect.height *= 2; - rect &= cv::Rect(0, 0, W, H); // crop at frame boundaries - - cv::Mat frame_roi = frame_gray(rect); - - // smaller values mean more changes. 1 makes too many changes while 1.5 makes about .1 - static constexpr f radius_c = f(1.75); - - const f kernel_radius = b.radius * radius_c; - vec2 pos(rect.width/f(2), rect.height/f(2)); // position relative to ROI. - - for (int iter = 0; iter < 10; ++iter) - { - vec2 com_new = MeanShiftIteration(frame_roi, pos, kernel_radius); - vec2 delta = com_new - pos; - pos = com_new; - if (delta.dot(delta) < f(1e-3)) - break; - } - - b.pos[0] = pos[0] + rect.x; - b.pos[1] = pos[1] + rect.y; - } - - // TODO: Do not do that if no preview. Delay blob drawing until we know where are the points? - draw_blobs(preview_frame_, - blobs.data(), blobs.size(), - frame_gray.size()); - - - // End of mean shift code. At this point, blob positions are updated with hopefully less noisy less biased values. - points.reserve(max_blobs); - points.clear(); - - for (const auto& b : blobs) - { - // note: H/W is equal to fx/fy - - vec2 p; - std::tie(p[0], p[1]) = Coordinates::to_screen_pos(b.pos[0], b.pos[1], W, H); - points.push_back(p); - imagePoints.push_back(vec2(b.pos[0], b.pos[1])); - } -} - -blob::blob(f radius, const vec2& pos, f brightness, const cv::Rect& rect) : - radius(radius), brightness(brightness), pos(pos), rect(rect) -{ - //qDebug() << "radius" << radius << "pos" << pos[0] << pos[1]; -} - -} // ns pt_module diff --git a/tracker-easy/point_extractor.h b/tracker-easy/point_extractor.h deleted file mode 100644 index 41f74493..00000000 --- a/tracker-easy/point_extractor.h +++ /dev/null @@ -1,61 +0,0 @@ -/* Copyright (c) 2012 Patrick Ruoff - * Copyright (c) 2015-2016 Stanislaw Halik <sthalik@misaki.pl> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - */ - -#pragma once - -#include "tracker-easy-api.h" - -#include <vector> - -#include <opencv2/core.hpp> -#include <opencv2/imgproc.hpp> - -namespace pt_module { - -using namespace numeric_types; - -struct blob final -{ - f radius, brightness; - vec2 pos; - cv::Rect rect; - - blob(f radius, const vec2& pos, f brightness, const cv::Rect& rect); -}; - -class PointExtractor final : public pt_point_extractor -{ -public: - // extracts points from frame and draws some processing info into frame, if draw_output is set - // dt: time since last call in seconds - void extract_points(const cv::Mat& frame, cv::Mat& preview_frame, std::vector<vec2>& points, std::vector<vec2>& imagePoints) override; - PointExtractor(const QString& module_name); - -public: - std::vector<blob> blobs; - -private: - static constexpr int max_blobs = 16; - - pt_settings s; - - cv::Mat1b frame_gray_unmasked, frame_bin, frame_gray; - cv::Mat1f hist; - cv::Mat1b ch[3]; - - void ensure_channel_buffers(const cv::Mat& orig_frame); - void ensure_buffers(const cv::Mat& frame); - - void extract_single_channel(const cv::Mat& orig_frame, int idx, cv::Mat1b& dest); - - void color_to_grayscale(const cv::Mat& frame, cv::Mat1b& output); - void threshold_image(const cv::Mat& frame_gray, cv::Mat1b& output); -}; - -} // ns impl - diff --git a/tracker-easy/tracker-easy-api.cpp b/tracker-easy/tracker-easy-api.cpp index aaeb0631..2e3988a8 100644 --- a/tracker-easy/tracker-easy-api.cpp +++ b/tracker-easy/tracker-easy-api.cpp @@ -4,32 +4,7 @@ using namespace numeric_types; +IEasyTrackerTraits::IEasyTrackerTraits() = default; +IEasyTrackerTraits::~IEasyTrackerTraits() = default; -pt_runtime_traits::pt_runtime_traits() = default; -pt_runtime_traits::~pt_runtime_traits() = default; -pt_point_extractor::pt_point_extractor() = default; -pt_point_extractor::~pt_point_extractor() = default; - -f pt_point_extractor::threshold_radius_value(int w, int h, int threshold) -{ - f cx = w / f{640}, cy = h / f{480}; - - const f min_radius = f{1.75} * cx; - const f max_radius = f{15} * cy; - - const f radius = std::fmax(f{0}, (max_radius-min_radius) * threshold / f(255) + min_radius); - - return radius; -} - -std::tuple<f, f> Coordinates::to_pixel_pos(f x, f y, int w, int h) -{ - return std::make_tuple(w*(x+f{.5}), f{.5}*(h - 2*y*w)); -} - -std::tuple<f, f> Coordinates::to_screen_pos(f px, f py, int w, int h) -{ - px *= w/(w-f{1}); py *= h/(h-f{1}); - return std::make_tuple((px - w/f{2})/w, -(py - h/f{2})/w); -} diff --git a/tracker-easy/tracker-easy-api.h b/tracker-easy/tracker-easy-api.h index 40e472d4..e5627d11 100644 --- a/tracker-easy/tracker-easy-api.h +++ b/tracker-easy/tracker-easy-api.h @@ -22,43 +22,28 @@ const int KPointCount = 3; -/// -/// Utility class providing coordinates conversion functionalities -/// -struct Coordinates final -{ - using f = numeric_types::f; - - static std::tuple<f, f> to_pixel_pos(f x, f y, int w, int h); - static std::tuple<f, f> to_screen_pos(f px, f py, int w, int h); -}; - - -struct pt_point_extractor +class IPointExtractor { +public: using vec2 = numeric_types::vec2; using f = numeric_types::f; - pt_point_extractor(); - virtual ~pt_point_extractor(); - virtual void extract_points(const cv::Mat& image, cv::Mat& preview_frame, std::vector<vec2>& points, std::vector<vec2>& imagePoints) = 0; - - static f threshold_radius_value(int w, int h, int threshold); + virtual void extract_points(const cv::Mat& image, cv::Mat* aPreview, std::vector<vec2>& aPoints) = 0; }; -struct pt_runtime_traits +struct IEasyTrackerTraits { template<typename t> using pointer = std::shared_ptr<t>; - pt_runtime_traits(); - virtual ~pt_runtime_traits(); + IEasyTrackerTraits(); + virtual ~IEasyTrackerTraits(); - virtual pointer<pt_point_extractor> make_point_extractor() const = 0; + virtual pointer<IPointExtractor> make_point_extractor() const = 0; virtual QString get_module_name() const = 0; }; template<typename t> -using pt_pointer = typename pt_runtime_traits::pointer<t>; +using pt_pointer = typename IEasyTrackerTraits::pointer<t>; #ifdef __clang__ # pragma clang diagnostic pop diff --git a/tracker-easy/tracker-easy-dialog.cpp b/tracker-easy/tracker-easy-dialog.cpp index 6f7642ab..c0dd23dd 100644 --- a/tracker-easy/tracker-easy-dialog.cpp +++ b/tracker-easy/tracker-easy-dialog.cpp @@ -129,16 +129,8 @@ QString EasyTrackerDialog::threshold_display_text(int threshold_value) h = 480; } - //SL: sort this out - /* - if (tracker && tracker->get_cam_info(info) && info.res_x * info.res_y != 0) - { - w = info.res_x; - h = info.res_y; - } - */ - - double value = (double)pt_point_extractor::threshold_radius_value(w, h, threshold_value); + //SL: What are we suppose to do here? + double value = 0.0f; return tr("LED radius %1 pixels").arg(value, 0, 'f', 2); } diff --git a/tracker-easy/tracker-easy.cpp b/tracker-easy/tracker-easy.cpp index 425979ef..5fd1952c 100644 --- a/tracker-easy/tracker-easy.cpp +++ b/tracker-easy/tracker-easy.cpp @@ -27,7 +27,7 @@ using namespace options; -EasyTracker::EasyTracker(pointer<pt_runtime_traits> const& traits) : +EasyTracker::EasyTracker(pointer<IEasyTrackerTraits> const& traits) : traits { traits }, s { traits->get_module_name() }, point_extractor { traits->make_point_extractor() }, @@ -130,9 +130,9 @@ void EasyTracker::run() iPreview = iMatFrame; } - iImagePoints.clear(); - point_extractor->extract_points(iMatFrame, iPreview.iFrameRgb, points, iImagePoints); - point_count.store(points.size(), std::memory_order_relaxed); + iPoints.clear(); + point_extractor->extract_points(iMatFrame, (preview_visible?&iPreview.iFrameRgb:nullptr), iPoints); + point_count.store(iPoints.size(), std::memory_order_relaxed); if (preview_visible) @@ -146,7 +146,7 @@ void EasyTracker::run() cv::destroyWindow("Preview"); } - const bool success = points.size() >= KPointCount || iImagePoints.size() >= KPointCount; + const bool success = iPoints.size() >= KPointCount; int topPointIndex = -1; @@ -177,9 +177,9 @@ void EasyTracker::run() int minY = std::numeric_limits<int>::max(); for (int i = 0; i < 3; i++) { - if (iImagePoints[i][1]<minY) + if (iPoints[i][1]<minY) { - minY = iImagePoints[i][1]; + minY = iPoints[i][1]; topPointIndex = i; } } @@ -191,9 +191,9 @@ void EasyTracker::run() for (int i = 0; i < 3; i++) { // Excluding top most point - if (i!=topPointIndex && iImagePoints[i][0] > maxX) + if (i!=topPointIndex && iPoints[i][0] > maxX) { - maxX = iImagePoints[i][0]; + maxX = iPoints[i][0]; rightPointIndex = i; } } @@ -211,9 +211,9 @@ void EasyTracker::run() } // - trackedPoints.push_back(cv::Point2f(iImagePoints[rightPointIndex][0], iImagePoints[rightPointIndex][1])); - trackedPoints.push_back(cv::Point2f(iImagePoints[leftPointIndex][0], iImagePoints[leftPointIndex][1])); - trackedPoints.push_back(cv::Point2f(iImagePoints[topPointIndex][0], iImagePoints[topPointIndex][1])); + trackedPoints.push_back(cv::Point2f(iPoints[rightPointIndex][0], iPoints[rightPointIndex][1])); + trackedPoints.push_back(cv::Point2f(iPoints[leftPointIndex][0], iPoints[leftPointIndex][1])); + trackedPoints.push_back(cv::Point2f(iPoints[topPointIndex][0], iPoints[topPointIndex][1])); std::cout << "Object: " << objectPoints << "\n"; std::cout << "Points: " << trackedPoints << "\n"; @@ -304,10 +304,7 @@ void EasyTracker::run() if (topPointIndex != -1) { // Render a cross to indicate which point is the head - if (points.size() >= 3) - { - iPreview.draw_head_center(points[topPointIndex][0], points[topPointIndex][1]); - } + iPreview.draw_head_center(iPoints[topPointIndex][0], iPoints[topPointIndex][1]); } widget->update_image(iPreview.get_bitmap()); diff --git a/tracker-easy/tracker-easy.h b/tracker-easy/tracker-easy.h index 6dea5712..23c9252a 100644 --- a/tracker-easy/tracker-easy.h +++ b/tracker-easy/tracker-easy.h @@ -36,7 +36,7 @@ struct EasyTracker : QThread, ITracker template<typename t> using pointer = pt_pointer<t>; - explicit EasyTracker(pointer<pt_runtime_traits> const& pt_runtime_traits); + explicit EasyTracker(pointer<IEasyTrackerTraits> const& pt_runtime_traits); ~EasyTracker() override; module_status start_tracker(QFrame* parent_window) override; void data(double* data) override; @@ -50,7 +50,7 @@ private: bool maybe_reopen_camera(); void set_fov(int value); - pointer<pt_runtime_traits> traits; + pointer<IEasyTrackerTraits> traits; QMutex camera_mtx; @@ -58,12 +58,11 @@ private: pt_settings s; std::unique_ptr<QLayout> layout; - std::vector<vec2> points; - std::vector<vec2> iImagePoints; + std::vector<vec2> iPoints; int preview_width = 320, preview_height = 240; - pointer<pt_point_extractor> point_extractor; + pointer<IPointExtractor> point_extractor; std::unique_ptr<video::impl::camera> camera; video::impl::camera::info iCameraInfo; pointer<video_widget> widget; |