diff options
Diffstat (limited to 'tracker-pt/module')
-rw-r--r-- | tracker-pt/module/camera.cpp | 31 | ||||
-rw-r--r-- | tracker-pt/module/camera.h | 8 | ||||
-rw-r--r-- | tracker-pt/module/frame.cpp | 6 | ||||
-rw-r--r-- | tracker-pt/module/frame.hpp | 14 | ||||
-rw-r--r-- | tracker-pt/module/module.cpp | 16 | ||||
-rw-r--r-- | tracker-pt/module/module.hpp | 4 | ||||
-rw-r--r-- | tracker-pt/module/point_extractor.cpp | 156 | ||||
-rw-r--r-- | tracker-pt/module/point_extractor.h | 9 |
8 files changed, 136 insertions, 108 deletions
diff --git a/tracker-pt/module/camera.cpp b/tracker-pt/module/camera.cpp index e2edfcb6..1afecc92 100644 --- a/tracker-pt/module/camera.cpp +++ b/tracker-pt/module/camera.cpp @@ -18,7 +18,7 @@ #include <cstdlib> -using namespace pt_module; +namespace pt_module { Camera::Camera(const QString& module_name) : s { module_name } { @@ -56,16 +56,16 @@ Camera::result Camera::get_frame(pt_frame& frame_) { cv::Mat& frame = frame_.as<Frame>()->mat; - const bool new_frame = _get_frame(frame); + const bool new_frame = get_frame_(frame); if (new_frame) { - const double dt = t.elapsed_seconds(); + const f dt = (f)t.elapsed_seconds(); t.start(); // measure fps of valid frames - constexpr double RC = .1; // seconds - const double alpha = dt/(dt + RC); + constexpr f RC = f{1}/10; // seconds + const f alpha = dt/(dt + RC); if (dt_mean < dt_eps) dt_mean = dt; @@ -88,7 +88,7 @@ bool Camera::start(int idx, int fps, int res_x, int res_y) if (idx >= 0 && fps >= 0 && res_x >= 0 && res_y >= 0) { if (cam_desired.idx != idx || - cam_desired.fps != fps || + (int)cam_desired.fps != fps || cam_desired.res_x != res_x || cam_desired.res_y != res_y || !cap || !cap->isOpened() || !cap->grab()) @@ -104,10 +104,12 @@ bool Camera::start(int idx, int fps, int res_x, int res_y) cap = camera_ptr(new cv::VideoCapture(idx)); - if (cam_desired.res_x) + if (cam_desired.res_x > 0 && cam_desired.res_y > 0) + { cap->set(cv::CAP_PROP_FRAME_WIDTH, res_x); - if (cam_desired.res_y) cap->set(cv::CAP_PROP_FRAME_HEIGHT, res_y); + } + if (fps > 0) cap->set(cv::CAP_PROP_FPS, fps); @@ -120,7 +122,7 @@ bool Camera::start(int idx, int fps, int res_x, int res_y) cv::Mat tmp; - if (_get_frame(tmp)) + if (get_frame_(tmp)) { t.start(); return true; @@ -141,13 +143,13 @@ bool Camera::start(int idx, int fps, int res_x, int res_y) void Camera::stop() { cap = nullptr; - desired_name = QString(); - active_name = QString(); - cam_info = pt_camera_info(); - cam_desired = pt_camera_info(); + desired_name = QString{}; + active_name = QString{}; + cam_info = {}; + cam_desired = {}; } -bool Camera::_get_frame(cv::Mat& frame) +bool Camera::get_frame_(cv::Mat& frame) { if (cap && cap->isOpened()) { @@ -171,3 +173,4 @@ void Camera::camera_deleter::operator()(cv::VideoCapture* cap) } } +} // ns pt_module diff --git a/tracker-pt/module/camera.h b/tracker-pt/module/camera.h index f8f140de..2ea633d0 100644 --- a/tracker-pt/module/camera.h +++ b/tracker-pt/module/camera.h @@ -33,13 +33,13 @@ struct Camera final : pt_camera QString get_desired_name() const override; QString get_active_name() const override; - void set_fov(double value) override { fov = value; } + void set_fov(f value) override { fov = value; } void show_camera_settings() override; private: - [[nodiscard]] bool _get_frame(cv::Mat& Frame); + [[nodiscard]] bool get_frame_(cv::Mat& frame); - double dt_mean = 0, fov = 30; + f dt_mean = 0, fov = 30; Timer t; pt_camera_info cam_info; pt_camera_info cam_desired; @@ -56,7 +56,7 @@ private: pt_settings s; - static constexpr inline double dt_eps = 1./256; + static constexpr f dt_eps = f{1}/256; }; } // ns pt_module diff --git a/tracker-pt/module/frame.cpp b/tracker-pt/module/frame.cpp index 6734edf6..c88099f1 100644 --- a/tracker-pt/module/frame.cpp +++ b/tracker-pt/module/frame.cpp @@ -4,7 +4,7 @@ #include <opencv2/imgproc.hpp> -using namespace pt_module; +namespace pt_module { Preview& Preview::operator=(const pt_frame& frame_) { @@ -52,7 +52,7 @@ QImage Preview::get_bitmap() QImage::Format_ARGB32); } -void Preview::draw_head_center(double x, double y) +void Preview::draw_head_center(f x, f y) { auto [px_, py_] = to_pixel_pos(x, y, frame_copy.cols, frame_copy.rows); @@ -76,3 +76,5 @@ void Preview::ensure_size(cv::Mat& frame, int w, int h, int type) if (frame.cols != w || frame.rows != h) frame = cv::Mat(h, w, type); } + +} // ns pt_module diff --git a/tracker-pt/module/frame.hpp b/tracker-pt/module/frame.hpp index 49dde49e..89334599 100644 --- a/tracker-pt/module/frame.hpp +++ b/tracker-pt/module/frame.hpp @@ -5,6 +5,11 @@ #include <opencv2/core.hpp> #include <QImage> +#ifdef __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wweak-vtables" +#endif + namespace pt_module { struct Frame final : pt_frame @@ -21,7 +26,7 @@ struct Preview final : pt_preview Preview& operator=(const pt_frame& frame) override; QImage get_bitmap() override; - void draw_head_center(double x, double y) override; + void draw_head_center(f x, f y) override; operator cv::Mat&() { return frame_copy; } operator cv::Mat const&() const { return frame_copy; } @@ -29,8 +34,11 @@ struct Preview final : pt_preview private: static void ensure_size(cv::Mat& frame, int w, int h, int type); - bool fresh = true; - cv::Mat frame_copy, frame_color, frame_out, frame_out2; + cv::Mat frame_copy, frame_out; }; } // ns pt_module + +#ifdef __clang__ +# pragma clang diagnostic pop +#endif diff --git a/tracker-pt/module/module.cpp b/tracker-pt/module/module.cpp index 4731175a..f665face 100644 --- a/tracker-pt/module/module.cpp +++ b/tracker-pt/module/module.cpp @@ -12,7 +12,11 @@ static const QString module_name = "tracker-pt"; -using namespace pt_module; +#ifdef __clang__ +# pragma clang diagnostic ignored "-Wweak-vtables" +#endif + +namespace pt_module { struct pt_module_traits final : pt_runtime_traits { @@ -54,13 +58,15 @@ struct dialog_pt : TrackerDialog_PT dialog_pt(); }; -// ns pt_module - -using namespace pt_module; - dialog_pt::dialog_pt() : TrackerDialog_PT(module_name) {} QString metadata_pt::name() { return tr("PointTracker 1.1"); } QIcon metadata_pt::icon() { return QIcon(":/Resources/Logo_IR.png"); } +} + +// ns pt_module + +using namespace pt_module; + OPENTRACK_DECLARE_TRACKER(tracker_pt, dialog_pt, metadata_pt) diff --git a/tracker-pt/module/module.hpp b/tracker-pt/module/module.hpp index 3afe8bc9..0b3f12cf 100644 --- a/tracker-pt/module/module.hpp +++ b/tracker-pt/module/module.hpp @@ -13,8 +13,8 @@ class OTR_GENERIC_EXPORT metadata_pt : public Metadata { Q_OBJECT - QString name(); - QIcon icon(); + QString name() override; + QIcon icon() override; }; } // ns pt_module diff --git a/tracker-pt/module/point_extractor.cpp b/tracker-pt/module/point_extractor.cpp index a634768c..596b3d93 100644 --- a/tracker-pt/module/point_extractor.cpp +++ b/tracker-pt/module/point_extractor.cpp @@ -29,8 +29,7 @@ #include <QDebug> -using namespace types; -using namespace pt_module; +using namespace numeric_types; // meanshift code written by Michael Welter @@ -50,10 +49,10 @@ 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 cv::Vec2d MeanShiftIteration(const cv::Mat &frame_gray, const vec2 ¤t_center, f filter_width) +static vec2 MeanShiftIteration(const cv::Mat1b &frame_gray, const vec2 ¤t_center, f filter_width) { // Most amazingly this function runs faster with doubles than with floats. - const f s = 1.0 / filter_width; + const f s = 1 / filter_width; f m = 0; vec2 com { 0, 0 }; @@ -63,12 +62,12 @@ static cv::Vec2d MeanShiftIteration(const cv::Mat &frame_gray, const vec2 &curre for (int j = 0; j < frame_gray.cols; j++) { f val = frame_ptr[j]; - val = val * val; // taking the square wights brighter parts of the image stronger. + 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 f = std::fmax(0, 1 - dx*dx - dy*dy); - val *= f; + f max = std::fmax(f{0}, 1 - dx*dx - dy*dy); + val *= max; } m += val; com[0] += j * val; @@ -77,13 +76,15 @@ static cv::Vec2d MeanShiftIteration(const cv::Mat &frame_gray, const vec2 &curre } if (m > f(.1)) { - com *= f(1) / m; + 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); @@ -92,7 +93,7 @@ PointExtractor::PointExtractor(const QString& module_name) : s(module_name) void PointExtractor::ensure_channel_buffers(const cv::Mat& orig_frame) { if (ch[0].rows != orig_frame.rows || ch[0].cols != orig_frame.cols) - for (unsigned k = 0; k < 3; k++) + for (unsigned k = 0; k < 3; k++) // NOLINT(modernize-loop-convert) ch[k] = cv::Mat1b(orig_frame.rows, orig_frame.cols); } @@ -108,7 +109,7 @@ void PointExtractor::ensure_buffers(const cv::Mat& frame) } } -void PointExtractor::extract_single_channel(const cv::Mat& orig_frame, int idx, cv::Mat& dest) +void PointExtractor::extract_single_channel(const cv::Mat& orig_frame, int idx, cv::Mat1b& dest) { ensure_channel_buffers(orig_frame); @@ -119,13 +120,6 @@ void PointExtractor::extract_single_channel(const cv::Mat& orig_frame, int idx, cv::mixChannels(&orig_frame, 1, &dest, 1, from_to, 1); } -void PointExtractor::extract_channels(const cv::Mat& orig_frame, const int* order, int order_npairs) -{ - ensure_channel_buffers(orig_frame); - - cv::mixChannels(&orig_frame, 1, (cv::Mat*) ch, order_npairs, order, order_npairs); -} - void PointExtractor::color_to_grayscale(const cv::Mat& frame, cv::Mat1b& output) { switch (s.blob_color) @@ -147,15 +141,15 @@ void PointExtractor::color_to_grayscale(const cv::Mat& frame, cv::Mat1b& output) } case pt_color_average: { - const int W = frame.cols, H = frame.rows; - const cv::Mat tmp = frame.reshape(1, W * H); - cv::Mat output_ = output.reshape(1, W * H); - cv::reduce(tmp, output_, 1, cv::REDUCE_AVG); + 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*/ + [[fallthrough]]; case pt_color_natural: cv::cvtColor(frame, output, cv::COLOR_BGR2GRAY); break; @@ -182,31 +176,80 @@ void PointExtractor::threshold_image(const cv::Mat& frame_gray, cv::Mat1b& outpu cv::noArray(), hist, 1, - (int const*) &hist_size, + &hist_size, &ranges); const f radius = (f) 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 * M_PI * radius*radius); + const unsigned area = uround(3 * pi * radius*radius); const unsigned sz = unsigned(hist.cols * hist.rows); - unsigned thres = 32; + constexpr unsigned min_thres = 64; + unsigned thres = min_thres; for (unsigned i = sz-1, cnt = 0; i > 32; i--) { - cnt += ptr[i]; + cnt += (unsigned)ptr[i]; if (cnt >= area) break; thres = i; } + if (thres > min_thres) + thres = uround(thres * .8); + cv::threshold(frame_gray, output, thres, 255, cv::THRESH_BINARY); } } +static void draw_blobs(cv::Mat& preview_frame, const blob* blobs, unsigned nblobs, 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_ = (cx+cy)/2; + + static constexpr unsigned fract_bits = 16; + static constexpr double 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 >= PointModel::N_POINTS + ? cv::Scalar(192, 192, 192) + : cv::Scalar(255, 255, 0); + + const f overlay_size = dpi > 1.5 ? 2 : 1; + + cv::circle(preview_frame, p, iround((b.radius + 3.3) * c_ * c_fract), + circle_color, (int)overlay_size, + cv::LINE_AA, fract_bits); + + char buf[16]; + buf[sizeof(buf)-1] = '\0'; + std::snprintf(buf, sizeof(buf) - 1, "%.2fpx", b.radius); + + auto text_color = k >= PointModel::N_POINTS + ? 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 pt_frame& frame_, pt_preview& preview_frame_, std::vector<vec2>& points) { const cv::Mat& frame = frame_.as_const<Frame>()->mat; - cv::Mat& preview_frame = *preview_frame_.as<Preview>(); ensure_buffers(frame); color_to_grayscale(frame, frame_gray_unmasked); @@ -219,8 +262,8 @@ void PointExtractor::extract_points(const pt_frame& frame_, pt_preview& preview_ threshold_image(frame_gray_unmasked, frame_bin); frame_gray_unmasked.copyTo(frame_gray, frame_bin); - const f region_size_min = s.min_point_size; - const f region_size_max = s.max_point_size; + const f region_size_min = (f)s.min_point_size; + const f region_size_max = (f)s.max_point_size; unsigned idx = 0; @@ -265,12 +308,12 @@ void PointExtractor::extract_points(const pt_frame& frame_, pt_preview& preview_ } } - const double radius = std::sqrt(cnt / M_PI); + const double radius = std::sqrt(cnt / pi); if (radius > region_size_max || radius < region_size_min) continue; blobs.emplace_back(radius, - vec2(rect.width/2., rect.height/2.), + vec2(rect.width/f(2), rect.height/f(2)), std::pow(f(norm), f(1.1))/cnt, rect); @@ -280,9 +323,7 @@ void PointExtractor::extract_points(const pt_frame& frame_, pt_preview& preview_ // 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 -#if BROKEN && 0 - break; -#endif + //break; } } end: @@ -296,7 +337,7 @@ end: for (idx = 0; idx < sz; ++idx) { - blob &b = blobs[idx]; + blob& b = blobs[idx]; cv::Rect rect = b.rect; rect.x -= rect.width / 2; @@ -311,14 +352,14 @@ end: static constexpr f radius_c = f(1.75); const f kernel_radius = b.radius * radius_c; - vec2 pos(rect.width/2., rect.height/2.); // position relative to ROI. + 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) < 1e-2) + if (delta.dot(delta) < f(1e-3)) break; } @@ -326,43 +367,10 @@ end: b.pos[1] = pos[1] + rect.y; } - for (unsigned k = 0; k < blobs.size(); k++) - { - blob& b = blobs[k]; - - const f dpi = preview_frame.cols / f(320); - const f offx = 10 * dpi, offy = 7.5 * dpi; - - const f cx = preview_frame.cols / f(frame.cols), - cy = preview_frame.rows / f(frame.rows), - c_ = (cx+cy)/2; - - static constexpr unsigned fract_bits = 16; - static constexpr double 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 >= PointModel::N_POINTS - ? cv::Scalar(192, 192, 192) - : cv::Scalar(255, 255, 0); - - const f overlay_size = dpi > 1.5 ? 2 : 1; - - cv::circle(preview_frame, p, iround((b.radius + 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", b.radius); - - auto text_color = k >= PointModel::N_POINTS - ? cv::Scalar(160, 160, 160) - : cv::Scalar(0, 0, 255); + draw_blobs(preview_frame_.as<Frame>()->mat, + blobs.data(), blobs.size(), + frame_gray.size()); - 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); - } // End of mean shift code. At this point, blob positions are updated with hopefully less noisy less biased values. points.reserve(max_blobs); @@ -383,3 +391,5 @@ blob::blob(f radius, const vec2& pos, f brightness, const cv::Rect& rect) : { //qDebug() << "radius" << radius << "pos" << pos[0] << pos[1]; } + +} // ns pt_module diff --git a/tracker-pt/module/point_extractor.h b/tracker-pt/module/point_extractor.h index 2288f1a1..a6103667 100644 --- a/tracker-pt/module/point_extractor.h +++ b/tracker-pt/module/point_extractor.h @@ -17,9 +17,9 @@ namespace pt_module { -using namespace types; +using namespace numeric_types; -struct blob +struct blob final { f radius, brightness; vec2 pos; @@ -36,7 +36,7 @@ public: void extract_points(const pt_frame& frame, pt_preview& preview_frame, std::vector<vec2>& points) override; PointExtractor(const QString& module_name); private: - static constexpr inline int max_blobs = 16; + static constexpr int max_blobs = 16; pt_settings s; @@ -48,8 +48,7 @@ private: 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::Mat& dest); - void extract_channels(const cv::Mat& orig_frame, const int* order, int order_npairs); + 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); |