summaryrefslogtreecommitdiffhomepage
path: root/tracker-easy
diff options
context:
space:
mode:
Diffstat (limited to 'tracker-easy')
-rw-r--r--tracker-easy/cv-point-extractor.cpp32
-rw-r--r--tracker-easy/cv-point-extractor.h4
-rw-r--r--tracker-easy/frame.cpp30
-rw-r--r--tracker-easy/frame.hpp2
-rw-r--r--tracker-easy/module.cpp9
-rw-r--r--tracker-easy/point_extractor.cpp395
-rw-r--r--tracker-easy/point_extractor.h61
-rw-r--r--tracker-easy/tracker-easy-api.cpp29
-rw-r--r--tracker-easy/tracker-easy-api.h31
-rw-r--r--tracker-easy/tracker-easy-dialog.cpp12
-rw-r--r--tracker-easy/tracker-easy.cpp29
-rw-r--r--tracker-easy/tracker-easy.h9
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 &current_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;