diff options
Diffstat (limited to 'tracker-pt')
-rw-r--r-- | tracker-pt/CMakeLists.txt | 2 | ||||
-rw-r--r-- | tracker-pt/ftnoir_tracker_pt.cpp | 126 | ||||
-rw-r--r-- | tracker-pt/ftnoir_tracker_pt.h | 16 | ||||
-rw-r--r-- | tracker-pt/ftnoir_tracker_pt_dialog.cpp | 14 | ||||
-rw-r--r-- | tracker-pt/ftnoir_tracker_pt_dialog.h | 2 | ||||
-rw-r--r-- | tracker-pt/lang/nl_NL.ts | 7 | ||||
-rw-r--r-- | tracker-pt/lang/ru_RU.ts | 7 | ||||
-rw-r--r-- | tracker-pt/lang/stub.ts | 7 | ||||
-rw-r--r-- | tracker-pt/lang/zh_CN.ts | 7 | ||||
-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 | ||||
-rw-r--r-- | tracker-pt/point_tracker.cpp | 174 | ||||
-rw-r--r-- | tracker-pt/point_tracker.h | 15 | ||||
-rw-r--r-- | tracker-pt/pt-api.cpp | 34 | ||||
-rw-r--r-- | tracker-pt/pt-api.hpp | 38 | ||||
-rw-r--r-- | tracker-pt/pt-settings.hpp | 10 |
22 files changed, 327 insertions, 376 deletions
diff --git a/tracker-pt/CMakeLists.txt b/tracker-pt/CMakeLists.txt index 4010b6c1..f12f530b 100644 --- a/tracker-pt/CMakeLists.txt +++ b/tracker-pt/CMakeLists.txt @@ -2,7 +2,7 @@ find_package(OpenCV QUIET) if(OpenCV_FOUND) otr_module(tracker-pt-base STATIC) target_include_directories(${self} SYSTEM PUBLIC ${OpenCV_INCLUDE_DIRS}) - target_link_libraries(${self} opentrack-cv opencv_core opencv_imgproc opencv_videoio) + target_link_libraries(${self} opencv_imgproc opentrack-cv opencv_core) set_property(TARGET ${self} PROPERTY OUTPUT_NAME "pt-base") endif() add_subdirectory(module) diff --git a/tracker-pt/ftnoir_tracker_pt.cpp b/tracker-pt/ftnoir_tracker_pt.cpp index 0d99ccd0..b717e4a1 100644 --- a/tracker-pt/ftnoir_tracker_pt.cpp +++ b/tracker-pt/ftnoir_tracker_pt.cpp @@ -7,14 +7,12 @@ */ #include "ftnoir_tracker_pt.h" -#include "cv/video-widget.hpp" +#include "video/video-widget.hpp" #include "compat/camera-names.hpp" #include "compat/math-imports.hpp" #include "pt-api.hpp" -#include <cmath> - #include <QHBoxLayout> #include <QDebug> #include <QFile> @@ -49,11 +47,7 @@ Tracker_PT::~Tracker_PT() void Tracker_PT::run() { -#ifdef PT_PERF_LOG - QFile log_file(OPENTRACK_BASE_PATH + "/PointTrackerPerformance.txt"); - if (!log_file.open(QIODevice::WriteOnly | QIODevice::Text)) return; - QTextStream log_stream(&log_file); -#endif + maybe_reopen_camera(); while(!isInterruptionRequested()) { @@ -69,58 +63,50 @@ void Tracker_PT::run() if (new_frame) { - while (center_flag.test_and_set()) - (void)0; - *preview_frame = *frame; point_extractor->extract_points(*frame, *preview_frame, points); point_count = points.size(); - const double fx = pt_camera_info::get_focal_length(info.fov, info.res_x, info.res_y); - + const f fx = pt_camera_info::get_focal_length(info.fov, info.res_x, info.res_y); const bool success = points.size() >= PointModel::N_POINTS; - if (success) - { - point_tracker.track(points, - PointModel(s), - info, - s.dynamic_pose ? s.init_phase_timeout : 0); - ever_success = true; - } + Affine X_CM; { - Affine X_CM; + QMutexLocker l(¢er_lock); + + if (success) { - QMutexLocker l(&data_mtx); - X_CM = point_tracker.pose(); + point_tracker.track(points, + PointModel(s), + info, + s.dynamic_pose ? s.init_phase_timeout : 0); + ever_success = true; } - // just copy pasted these lines from below - Affine X_MH(mat33::eye(), vec3(s.t_MH_x, s.t_MH_y, s.t_MH_z)); - Affine X_GH = X_CM * X_MH; - vec3 p = X_GH.t; // head (center?) position in global space - - preview_frame->draw_head_center((p[0] * fx) / p[2], (p[1] * fx) / p[2]); + QMutexLocker l2(&data_lock); + X_CM = point_tracker.pose(); } - video_widget->update_image(preview_frame->get_bitmap()); + Affine X_MH(mat33::eye(), vec3(s.t_MH_x, s.t_MH_y, s.t_MH_z)); + Affine X_GH = X_CM * X_MH; + vec3 p = X_GH.t; // head (center?) position in global space + + preview_frame->draw_head_center((p[0] * fx) / p[2], (p[1] * fx) / p[2]); + widget->update_image(preview_frame->get_bitmap()); { int w = -1, h = -1; - video_widget->get_preview_size(w, h); + widget->get_preview_size(w, h); if (w != preview_width || h != preview_height) { - preview_width = w, preview_height = h; + preview_width = w; preview_height = h; preview_frame = traits->make_preview(w, h); } } - - center_flag.clear(); } } - qDebug() << "pt: thread stopped"; } bool Tracker_PT::maybe_reopen_camera() @@ -141,17 +127,14 @@ module_status Tracker_PT::start_tracker(QFrame* video_frame) { //video_frame->setAttribute(Qt::WA_NativeWindow); - video_widget = std::make_unique<cv_video_widget>(video_frame); + widget = std::make_unique<video_widget>(video_frame); layout = std::make_unique<QHBoxLayout>(video_frame); layout->setContentsMargins(0, 0, 0, 0); - layout->addWidget(video_widget.get()); + layout->addWidget(widget.get()); video_frame->setLayout(layout.get()); //video_widget->resize(video_frame->width(), video_frame->height()); video_frame->show(); - if (!maybe_reopen_camera()) - return { tr("Can't open camera") }; - start(QThread::HighPriority); return {}; @@ -161,71 +144,70 @@ void Tracker_PT::data(double *data) { if (ever_success) { - Affine X_CM = pose(); + Affine X_CM; + { + QMutexLocker l(&data_lock); + X_CM = point_tracker.pose(); + } Affine X_MH(mat33::eye(), vec3(s.t_MH_x, s.t_MH_y, s.t_MH_z)); - Affine X_GH = X_CM * X_MH; + Affine X_GH(X_CM * X_MH); // translate rotation matrix from opengl (G) to roll-pitch-yaw (E) frame // -z -> x, y -> z, x -> -y mat33 R_EG(0, 0,-1, -1, 0, 0, 0, 1, 0); - mat33 R = R_EG * X_GH.R * R_EG.t(); + mat33 R(R_EG * X_GH.R * R_EG.t()); // get translation(s) const vec3& t = X_GH.t; // extract rotation angles - { - f alpha, beta, gamma; - beta = atan2( -R(2,0), sqrt(R(2,1)*R(2,1) + R(2,2)*R(2,2)) ); - alpha = atan2( R(1,0), R(0,0)); - gamma = atan2( R(2,1), R(2,2)); - - data[Yaw] = rad2deg * alpha; - data[Pitch] = -rad2deg * beta; - data[Roll] = rad2deg * gamma; - } + double alpha, beta, gamma; + beta = atan2( (double)-R(2,0), (double)sqrt(R(2,1)*R(2,1) + R(2,2)*R(2,2)) ); + alpha = atan2( (double)R(1,0), (double)R(0,0) ); + gamma = atan2( (double)R(2,1), (double)R(2,2) ); + + constexpr double rad2deg = 180/M_PI; + + data[Yaw] = rad2deg * alpha; + data[Pitch] = -rad2deg * beta; + data[Roll] = rad2deg * gamma; // convert to cm - data[TX] = t[0] / 10; - data[TY] = t[1] / 10; - data[TZ] = t[2] / 10; + data[TX] = (double)t[0] / 10; + data[TY] = (double)t[1] / 10; + data[TZ] = (double)t[2] / 10; } } bool Tracker_PT::center() { - while (center_flag.test_and_set()) - (void)0; + QMutexLocker l(¢er_lock); point_tracker.reset_state(); - - center_flag.clear(); - return false; } -Affine Tracker_PT::pose() -{ - QMutexLocker l(&data_mtx); - - return point_tracker.pose(); -} - int Tracker_PT::get_n_points() { return int(point_count); } -bool Tracker_PT::get_cam_info(pt_camera_info* info) +bool Tracker_PT::get_cam_info(pt_camera_info& info) { - QMutexLocker lock(&camera_mtx); + QMutexLocker l(&camera_mtx); bool ret; - std::tie(ret, *info) = camera->get_info(); + std::tie(ret, info) = camera->get_info(); return ret; } +Affine Tracker_PT::pose() const +{ + QMutexLocker l(&data_lock); + return point_tracker.pose(); +} + } // ns pt_module diff --git a/tracker-pt/ftnoir_tracker_pt.h b/tracker-pt/ftnoir_tracker_pt.h index 8cf609c3..77835602 100644 --- a/tracker-pt/ftnoir_tracker_pt.h +++ b/tracker-pt/ftnoir_tracker_pt.h @@ -24,11 +24,11 @@ #include <QLayout> class TrackerDialog_PT; -class cv_video_widget; +class video_widget; namespace pt_module { -using namespace types; +using namespace numeric_types; class Tracker_PT : public QThread, public ITracker { @@ -45,9 +45,9 @@ public: void data(double* data) override; bool center() override; - Affine pose(); int get_n_points(); - bool get_cam_info(pt_camera_info* info); + [[nodiscard]] bool get_cam_info(pt_camera_info& info); + Affine pose() const; public slots: bool maybe_reopen_camera(); void set_fov(int value); @@ -57,7 +57,6 @@ private: pointer<pt_runtime_traits> traits; QMutex camera_mtx; - QMutex data_mtx; PointTracker point_tracker; @@ -70,16 +69,13 @@ private: pointer<pt_point_extractor> point_extractor; pointer<pt_camera> camera; - pointer<cv_video_widget> video_widget; + pointer<video_widget> widget; pointer<pt_frame> frame; pointer<pt_preview> preview_frame; std::atomic<unsigned> point_count { 0 }; std::atomic<bool> ever_success { false }; - std::atomic_flag center_flag = ATOMIC_FLAG_INIT; - - static constexpr inline f rad2deg = f(180/M_PI); - //static constexpr float deg2rad = float(M_PI/180); + mutable QMutex center_lock, data_lock; }; } // ns pt_impl diff --git a/tracker-pt/ftnoir_tracker_pt_dialog.cpp b/tracker-pt/ftnoir_tracker_pt_dialog.cpp index 2a156cbc..87f4069f 100644 --- a/tracker-pt/ftnoir_tracker_pt_dialog.cpp +++ b/tracker-pt/ftnoir_tracker_pt_dialog.cpp @@ -123,10 +123,16 @@ QString TrackerDialog_PT::threshold_display_text(int threshold_value) int w = s.cam_res_x, h = s.cam_res_y; if (w * h <= 0) - w = 640, h = 480; + { + w = 640; + h = 480; + } - if (tracker && tracker->get_cam_info(&info) && info.res_x * info.res_y != 0) - w = info.res_x, h = info.res_y; + if (tracker && tracker->get_cam_info(info) && info.res_x * info.res_y != 0) + { + w = info.res_x; + h = info.res_y; + } double value = pt_point_extractor::threshold_radius_value(w, h, threshold_value); @@ -193,7 +199,7 @@ void TrackerDialog_PT::startstop_trans_calib(bool start) void TrackerDialog_PT::poll_tracker_info_impl() { pt_camera_info info; - if (tracker && tracker->get_cam_info(&info)) + if (tracker && tracker->get_cam_info(info)) { ui.caminfo_label->setText(tr("%1x%2 @ %3 FPS").arg(info.res_x).arg(info.res_y).arg(iround(info.fps))); diff --git a/tracker-pt/ftnoir_tracker_pt_dialog.h b/tracker-pt/ftnoir_tracker_pt_dialog.h index f36fe7b2..3bd1a561 100644 --- a/tracker-pt/ftnoir_tracker_pt_dialog.h +++ b/tracker-pt/ftnoir_tracker_pt_dialog.h @@ -12,7 +12,7 @@ #include "ftnoir_tracker_pt.h" #include "tracker-pt/ui_FTNoIR_PT_Controls.h" #include "cv/translation-calibrator.hpp" -#include "cv/video-widget.hpp" +#include "video/video-widget.hpp" #include <QTimer> #include <QMutex> diff --git a/tracker-pt/lang/nl_NL.ts b/tracker-pt/lang/nl_NL.ts index efa66875..c20f12d0 100644 --- a/tracker-pt/lang/nl_NL.ts +++ b/tracker-pt/lang/nl_NL.ts @@ -281,13 +281,6 @@ Don't roll or change position.</source> </message> </context> <context> - <name>pt_module::Tracker_PT</name> - <message> - <source>Can't open camera</source> - <translation type="unfinished"></translation> - </message> -</context> -<context> <name>pt_module::metadata_pt</name> <message> <source>PointTracker 1.1</source> diff --git a/tracker-pt/lang/ru_RU.ts b/tracker-pt/lang/ru_RU.ts index 44ccffc1..494a5a17 100644 --- a/tracker-pt/lang/ru_RU.ts +++ b/tracker-pt/lang/ru_RU.ts @@ -286,13 +286,6 @@ ROLL или X/Y-смещения.</translation> </message> </context> <context> - <name>pt_module::Tracker_PT</name> - <message> - <source>Can't open camera</source> - <translation type="unfinished"></translation> - </message> -</context> -<context> <name>pt_module::metadata_pt</name> <message> <source>PointTracker 1.1</source> diff --git a/tracker-pt/lang/stub.ts b/tracker-pt/lang/stub.ts index f5ebbb49..a1b9819f 100644 --- a/tracker-pt/lang/stub.ts +++ b/tracker-pt/lang/stub.ts @@ -281,13 +281,6 @@ Don't roll or change position.</source> </message> </context> <context> - <name>pt_module::Tracker_PT</name> - <message> - <source>Can't open camera</source> - <translation type="unfinished"></translation> - </message> -</context> -<context> <name>pt_module::metadata_pt</name> <message> <source>PointTracker 1.1</source> diff --git a/tracker-pt/lang/zh_CN.ts b/tracker-pt/lang/zh_CN.ts index c2f1d910..38fd40b1 100644 --- a/tracker-pt/lang/zh_CN.ts +++ b/tracker-pt/lang/zh_CN.ts @@ -281,13 +281,6 @@ Don't roll or change position.</source> </message> </context> <context> - <name>pt_module::Tracker_PT</name> - <message> - <source>Can't open camera</source> - <translation type="unfinished">无法打开摄像头</translation> - </message> -</context> -<context> <name>pt_module::metadata_pt</name> <message> <source>PointTracker 1.1</source> 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); diff --git a/tracker-pt/point_tracker.cpp b/tracker-pt/point_tracker.cpp index 63c6f47c..bda412e2 100644 --- a/tracker-pt/point_tracker.cpp +++ b/tracker-pt/point_tracker.cpp @@ -8,14 +8,16 @@ #include "point_tracker.h" #include "compat/math-imports.hpp" -using namespace types; - #include <vector> #include <algorithm> #include <cmath> #include <QDebug> +namespace pt_module { + +using namespace numeric_types; + static void get_row(const mat33& m, int i, vec3& v) { v[0] = m(i,0); @@ -48,6 +50,9 @@ void PointModel::set_model(const pt_settings& s) { switch (s.active_model_panel) { + default: + eval_once(qDebug() << "pt: wrong model type selected"); + [[fallthrough]]; case Clip: M01 = vec3(0, s.clip_ty, -s.clip_tz); M02 = vec3(0, -s.clip_by, -s.clip_bz); @@ -65,18 +70,19 @@ void PointModel::set_model(const pt_settings& s) void PointModel::get_d_order(const vec2* points, unsigned* d_order, const vec2& d) const { + constexpr unsigned cnt = PointModel::N_POINTS; // fit line to orthographically projected points using t = std::pair<f,unsigned>; - t d_vals[3]; + t d_vals[cnt]; // get sort indices with respect to d scalar product - for (unsigned i = 0; i < PointModel::N_POINTS; ++i) + for (unsigned i = 0; i < cnt; ++i) d_vals[i] = t(d.dot(points[i]), i); std::sort(d_vals, - d_vals + 3u, + d_vals + 3, [](const t& a, const t& b) { return a.first < b.first; }); - for (unsigned i = 0; i < PointModel::N_POINTS; ++i) + for (unsigned i = 0; i < cnt; ++i) d_order[i] = d_vals[i].second; } @@ -87,38 +93,34 @@ PointTracker::PointOrder PointTracker::find_correspondences_previous(const vec2* const PointModel& model, const pt_camera_info& info) { - const double fx = pt_camera_info::get_focal_length(info.fov, info.res_x, info.res_y); + const f fx = pt_camera_info::get_focal_length(info.fov, info.res_x, info.res_y); PointTracker::PointOrder p; p[0] = project(vec3(0,0,0), fx); p[1] = project(model.M01, fx); p[2] = project(model.M02, fx); - const int diagonal = int(std::sqrt(f(info.res_x*info.res_x + info.res_y*info.res_y))); - constexpr int div = 100; - const int max_dist = diagonal / div; // 8 pixels for 640x480 + constexpr unsigned sz = PointModel::N_POINTS; // set correspondences by minimum distance to projected model point - bool point_taken[PointModel::N_POINTS]; - for (unsigned i=0; i<PointModel::N_POINTS; ++i) + bool point_taken[sz]; + for (unsigned i=0; i < sz; ++i) // NOLINT(modernize-loop-convert) point_taken[i] = false; - for (unsigned i=0; i<PointModel::N_POINTS; ++i) + for (unsigned i=0; i < sz; ++i) { f min_sdist = 0; unsigned min_idx = 0; // find closest point to projected model point i - for (unsigned j=0; j<PointModel::N_POINTS; ++j) + for (unsigned j=0; j < sz; ++j) { vec2 d = p[i]-points[j]; f sdist = d.dot(d); - if (sdist < min_sdist || j==0) + if (sdist < min_sdist || j == 0) { min_idx = j; min_sdist = sdist; } } - if (min_sdist > max_dist) - return find_correspondences(points, model); // if one point is closest to more than one model point, fallback if (point_taken[min_idx]) @@ -133,119 +135,61 @@ PointTracker::PointOrder PointTracker::find_correspondences_previous(const vec2* return p; } -bool PointTracker::maybe_use_old_point_order(const PointOrder& order, const pt_camera_info& info) -{ - constexpr f std_width = 640, std_height = 480; - - PointOrder scaled_order; - - const f cx = std_width / info.res_x; - const f cy = std_height / info.res_y; - - for (unsigned k = 0; k < 3; k++) - { - // note, the .y component is actually scaled by width - scaled_order[k][0] = std_width * cx * order[k][0]; - scaled_order[k][1] = std_width * cy * order[k][1]; - } - - f sum = 0; - - for (unsigned k = 0; k < 3; k++) - { - vec2 tmp = prev_scaled_order[k] - scaled_order[k]; - sum += std::sqrt(tmp.dot(tmp)); - } - - // CAVEAT don't increase too much, it visibly loses precision - constexpr f max_dist = f(.13); - - const bool validp = sum < max_dist; - - prev_order_valid &= validp; - - if (!prev_order_valid) - { - prev_order = order; - prev_scaled_order = scaled_order; - } - -#if 0 - { - static Timer tt; - static int cnt1 = 0, cnt2 = 0; - if (tt.elapsed_ms() >= 1000) - { - tt.start(); - if (cnt1 + cnt2) - { - qDebug() << "old-order" << ((cnt1 * 100) / f(cnt1 + cnt2)) << "nsamples" << (cnt1 + cnt2); - cnt1 = 0, cnt2 = 0; - } - } - if (validp) - cnt1++; - else - cnt2++; - } -#endif - - prev_order_valid = validp; - - return validp; -} - void PointTracker::track(const std::vector<vec2>& points, const PointModel& model, const pt_camera_info& info, int init_phase_timeout) { - const double fx = pt_camera_info::get_focal_length(info.fov, info.res_x, info.res_y); + const f fx = pt_camera_info::get_focal_length(info.fov, info.res_x, info.res_y); PointOrder order; - if (init_phase_timeout > 0 && t.elapsed_ms() > init_phase_timeout) + if (init_phase_timeout <= 0 || t.elapsed_ms() > init_phase_timeout || init_phase) { - t.start(); init_phase = true; - } - - if (!(init_phase_timeout > 0 && !init_phase)) order = find_correspondences(points.data(), model); + } else order = find_correspondences_previous(points.data(), model, info); - if (maybe_use_old_point_order(order, info) || - POSIT(model, order, fx) != -1) + if (POSIT(model, order, fx) != -1) { init_phase = false; t.start(); } + else + reset_state(); } PointTracker::PointOrder PointTracker::find_correspondences(const vec2* points, const PointModel& model) { - static const Affine a(mat33::eye(), vec3(0, 0, 1)); + constexpr unsigned cnt = PointModel::N_POINTS; // We do a simple freetrack-like sorting in the init phase... - unsigned point_d_order[PointModel::N_POINTS]; - unsigned model_d_order[PointModel::N_POINTS]; - // sort points + unsigned point_d_order[cnt]; + unsigned model_d_order[cnt]; + // calculate d and d_order for simple freetrack-like point correspondence vec2 d(model.M01[0]-model.M02[0], model.M01[1]-model.M02[1]); + // sort points model.get_d_order(points, point_d_order, d); - // calculate d and d_order for simple freetrack-like point correspondence - vec2 pts[3] = { - vec2(0, 0), - vec2(model.M01[0], model.M01[1]), - vec2(model.M02[0], model.M02[1]) + vec2 pts[cnt] { + { 0, 0 }, + { model.M01[0], model.M01[1] }, + { model.M02[0], model.M02[1] }, }; model.get_d_order(pts, model_d_order, d); + // set correspondences PointOrder p; - for (unsigned i = 0; i < PointModel::N_POINTS; ++i) + for (unsigned i = 0; i < cnt; ++i) p[model_d_order[i]] = points[point_d_order[i]]; return p; } +#ifdef __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wfloat-equal" +#endif + int PointTracker::POSIT(const PointModel& model, const PointOrder& order, f focal_length) { // POSIT algorithm for coplanar points as presented in @@ -254,7 +198,7 @@ int PointTracker::POSIT(const PointModel& model, const PointOrder& order, f foca // The expected rotation used for resolving the ambiguity in POSIT: // In every iteration step the rotation closer to R_expected is taken - static const mat33 R_expected(X_CM.R); + const mat33& R_expected{X_CM_expected.R}; // initial pose = last (predicted) pose vec3 k; @@ -263,8 +207,7 @@ int PointTracker::POSIT(const PointModel& model, const PointOrder& order, f foca f old_epsilon_1 = 0; f old_epsilon_2 = 0; - f epsilon_1 = 1; - f epsilon_2 = 1; + f epsilon_1, epsilon_2; vec3 I0, J0; vec2 I0_coeff, J0_coeff; @@ -275,8 +218,8 @@ int PointTracker::POSIT(const PointModel& model, const PointOrder& order, f foca constexpr int max_iter = 100; - int i=1; - for (; i<max_iter; ++i) + int i; + for (i = 1; i < max_iter; ++i) { epsilon_1 = k.dot(model.M01)/Z0; epsilon_2 = k.dot(model.M02)/Z0; @@ -301,14 +244,14 @@ int PointTracker::POSIT(const PointModel& model, const PointOrder& order, f foca // CAVEAT don't change to comparison with an epsilon -sh 20160423 if (JJ0 == II0) { rho = sqrt(fabs(2*IJ0)); - theta = -M_PI/4; + theta = -pi/4; if (IJ0<0) theta *= -1; } else { rho = sqrt(sqrt( (JJ0-II0)*(JJ0-II0) + 4*IJ0*IJ0 )); theta = atan( -2*IJ0 / (JJ0-II0) ); // avoid branch misprediction - theta += (JJ0 - II0 < 0) * M_PI; + theta += (JJ0 - II0 < 0) * pi; theta *= f(.5); } @@ -319,7 +262,7 @@ int PointTracker::POSIT(const PointModel& model, const PointOrder& order, f foca J_1 = J0 + rho*sin(theta)*model.u; J_2 = J0 - rho*sin(theta)*model.u; - f norm_const = 1/cv::norm(I_1); // all have the same norm + f norm_const = (f)(1/cv::norm(I_1)); // all have the same norm // create rotation matrices I_1 *= norm_const; J_1 *= norm_const; @@ -338,8 +281,8 @@ int PointTracker::POSIT(const PointModel& model, const PointOrder& order, f foca // pick the rotation solution closer to the expected one // in simple metric d(A,B) = || I - A * B^T || - f R_1_deviation = cv::norm(mat33::eye() - R_expected * R_1.t()); - f R_2_deviation = cv::norm(mat33::eye() - R_expected * R_2.t()); + f R_1_deviation = (f)(cv::norm(mat33::eye() - R_expected * R_1.t())); + f R_2_deviation = (f)(cv::norm(mat33::eye() - R_expected * R_2.t())); if (R_1_deviation < R_2_deviation) R_current = &R_1; @@ -351,7 +294,7 @@ int PointTracker::POSIT(const PointModel& model, const PointOrder& order, f foca // check for convergence condition const f delta = fabs(epsilon_1 - old_epsilon_1) + fabs(epsilon_2 - old_epsilon_2); - if (!(delta > constants::eps)) + if (delta < eps) break; old_epsilon_1 = epsilon_1; @@ -371,17 +314,17 @@ int PointTracker::POSIT(const PointModel& model, const PointOrder& order, f foca int ret = std::fpclassify(r(i, j)); if (ret == FP_NAN || ret == FP_INFINITE) { - qDebug() << "posit nan -- R"; + qDebug() << "posit nan R"; return -1; } } - for (unsigned i = 0; i < 3; i++) + for (unsigned i = 0; i < 3; i++) // NOLINT(modernize-loop-convert) { int ret = std::fpclassify(t[i]); if (ret == FP_NAN || ret == FP_INFINITE) { - qDebug() << "posit nan -- T"; + qDebug() << "posit nan T"; return -1; } } @@ -392,11 +335,17 @@ int PointTracker::POSIT(const PointModel& model, const PointOrder& order, f foca X_CM.t[1] = t[1]; X_CM.t[2] = t[2]; + X_CM_expected = X_CM; + //qDebug() << "iter:" << i; return i; } +#ifdef __clang__ +# pragma clang diagnostic pop +#endif + vec2 PointTracker::project(const vec3& v_M, f focal_length) { return project(v_M, focal_length, X_CM); @@ -410,7 +359,8 @@ vec2 PointTracker::project(const vec3& v_M, f focal_length, const Affine& X_CM) void PointTracker::reset_state() { - prev_order_valid = false; init_phase = true; + X_CM_expected = {}; } +} // ns pt_module diff --git a/tracker-pt/point_tracker.h b/tracker-pt/point_tracker.h index 095b79d2..6f3e0cee 100644 --- a/tracker-pt/point_tracker.h +++ b/tracker-pt/point_tracker.h @@ -28,11 +28,11 @@ namespace pt_module { // nomenclature as in // [Denis Oberkampf, Daniel F. DeMenthon, Larry S. Davis: "Iterative Pose Estimation Using Coplanar Feature Points"] -using namespace types; +using namespace numeric_types; struct PointModel final { - static constexpr inline unsigned N_POINTS = 3; + static constexpr unsigned N_POINTS = 3; vec3 M01; // M01 in model frame vec3 M02; // M02 in model frame @@ -61,7 +61,7 @@ public: // f : (focal length)/(sensor width) // dt : time since last call void track(const std::vector<vec2>& projected_points, const PointModel& model, const pt_camera_info& info, int init_phase_timeout); - Affine pose() { return X_CM; } + Affine pose() const { return X_CM; } vec2 project(const vec3& v_M, f focal_length); vec2 project(const vec3& v_M, f focal_length, const Affine& X_CM); void reset_state(); @@ -70,17 +70,16 @@ private: // the points in model order using PointOrder = std::array<vec2, 3>; - bool maybe_use_old_point_order(const PointOrder& order, const pt_camera_info& info); - PointOrder find_correspondences(const vec2* projected_points, const PointModel &model); PointOrder find_correspondences_previous(const vec2* points, const PointModel &model, const pt_camera_info& info); // The POSIT algorithm, returns the number of iterations int POSIT(const PointModel& point_model, const PointOrder& order, f focal_length); - Affine X_CM; // transform from model to camera - PointOrder prev_order, prev_scaled_order; + Affine X_CM; // transform from model to camera + Affine X_CM_expected; + PointOrder prev_positions; Timer t; - bool init_phase = true, prev_order_valid = false; + bool init_phase = true; }; } // ns pt_module diff --git a/tracker-pt/pt-api.cpp b/tracker-pt/pt-api.cpp index d137a60a..f64d5c9a 100644 --- a/tracker-pt/pt-api.cpp +++ b/tracker-pt/pt-api.cpp @@ -1,19 +1,19 @@ #include "pt-api.hpp" #include "cv/numeric.hpp" -using namespace types; +using namespace numeric_types; pt_camera_info::pt_camera_info() = default; -double pt_camera_info::get_focal_length(f fov, int res_x, int res_y) +f pt_camera_info::get_focal_length(f fov, int res_x, int res_y) { - const double diag_len = std::sqrt(double(res_x*res_x + res_y*res_y)); - const double aspect_x = res_x / diag_len; + const f diag_len = std::sqrt(f(res_x*res_x + res_y*res_y)); + const f aspect_x = res_x / diag_len; //const double aspect_y = res_y / diag_len; - const double diag_fov = fov * M_PI/180; - const double fov_x = 2*std::atan(std::tan(diag_fov*.5) * aspect_x); + const f diag_fov = fov * pi/180; + const f fov_x = 2*std::atan(std::tan(diag_fov*f{.5}) * aspect_x); //const double fov_y = 2*atan(tan(diag_fov*.5) * aspect_y); - const double fx = .5 / std::tan(fov_x * .5); + const f fx = f{.5} / std::tan(fov_x * f{.5}); return fx; //fy = .5 / tan(fov_y * .5); //static bool once = false; if (!once) { once = true; qDebug() << "f" << ret << "fov" << (fov * 180/M_PI); } @@ -26,27 +26,27 @@ pt_runtime_traits::~pt_runtime_traits() = default; pt_point_extractor::pt_point_extractor() = default; pt_point_extractor::~pt_point_extractor() = default; -double pt_point_extractor::threshold_radius_value(int w, int h, int threshold) +f pt_point_extractor::threshold_radius_value(int w, int h, int threshold) { - double cx = w / 640., cy = h / 480.; + f cx = w / f{640}, cy = h / f{480}; - const double min_radius = 1.75 * cx; - const double max_radius = 15 * cy; + const f min_radius = f{1.75} * cx; + const f max_radius = f{15} * cy; - const double radius = std::fmax(0., (max_radius-min_radius) * threshold / f(255) + min_radius); + const f radius = std::fmax(f{0}, (max_radius-min_radius) * threshold / f(255) + min_radius); return radius; } -std::tuple<double, double> pt_pixel_pos_mixin::to_pixel_pos(double x, double y, int w, int h) +std::tuple<f, f> pt_pixel_pos_mixin::to_pixel_pos(f x, f y, int w, int h) { - return std::make_tuple(w*(x+.5), .5*(h - 2*y*w)); + return std::make_tuple(w*(x+f{.5}), f{.5}*(h - 2*y*w)); } -std::tuple<double, double> pt_pixel_pos_mixin::to_screen_pos(double px, double py, int w, int h) +std::tuple<f, f> pt_pixel_pos_mixin::to_screen_pos(f px, f py, int w, int h) { - px *= w/(w-1.), py *= h/(h-1.); - return std::make_tuple((px - w/2.)/w, -(py - h/2.)/w); + px *= w/(w-f{1}); py *= h/(h-f{1}); + return std::make_tuple((px - w/f{2})/w, -(py - h/f{2})/w); } pt_frame::pt_frame() = default; diff --git a/tracker-pt/pt-api.hpp b/tracker-pt/pt-api.hpp index 12085560..b44cfea2 100644 --- a/tracker-pt/pt-api.hpp +++ b/tracker-pt/pt-api.hpp @@ -13,15 +13,20 @@ #include <QImage> +#ifdef __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wweak-vtables" +#endif + struct pt_camera_info final { - using f = types::f; + using f = numeric_types::f; pt_camera_info(); - static double get_focal_length(f fov, int res_x, int res_y); + static f get_focal_length(f fov, int res_x, int res_y); - double fov = 0; - double fps = 0; + f fov = 0; + f fps = 0; int res_x = 0; int res_y = 0; @@ -30,8 +35,10 @@ struct pt_camera_info final struct pt_pixel_pos_mixin { - static std::tuple<double, double> to_pixel_pos(double x, double y, int w, int h); - static std::tuple<double, double> to_screen_pos(double px, double py, int w, int h); + 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_frame : pt_pixel_pos_mixin @@ -42,16 +49,13 @@ struct pt_frame : pt_pixel_pos_mixin template<typename t> t* as() & { - using u = remove_cvref_t<t>; - static_assert(std::is_convertible_v<u*, pt_frame*>, "must be derived from pt_frame"); - return static_cast<t*>(this); } template<typename t> t const* as_const() const& { - return const_cast<pt_frame*>(this)->as<const t>(); + return static_cast<t const*>(this); } }; @@ -59,12 +63,13 @@ struct pt_preview : pt_frame { virtual pt_preview& operator=(const pt_frame&) = 0; virtual QImage get_bitmap() = 0; - virtual void draw_head_center(double x, double y) = 0; + virtual void draw_head_center(f x, f y) = 0; }; struct pt_camera { using result = std::tuple<bool, pt_camera_info>; + using f = numeric_types::f; pt_camera(); virtual ~pt_camera(); @@ -79,19 +84,20 @@ struct pt_camera virtual QString get_desired_name() const = 0; virtual QString get_active_name() const = 0; - virtual void set_fov(double value) = 0; + virtual void set_fov(f value) = 0; virtual void show_camera_settings() = 0; }; struct pt_point_extractor : pt_pixel_pos_mixin { - using vec2 = types::vec2; + using vec2 = numeric_types::vec2; + using f = numeric_types::f; pt_point_extractor(); virtual ~pt_point_extractor(); virtual void extract_points(const pt_frame& image, pt_preview& preview_frame, std::vector<vec2>& points) = 0; - static double threshold_radius_value(int w, int h, int threshold); + static f threshold_radius_value(int w, int h, int threshold); }; struct pt_runtime_traits @@ -110,3 +116,7 @@ struct pt_runtime_traits template<typename t> using pt_pointer = typename pt_runtime_traits::pointer<t>; + +#ifdef __clang__ +# pragma clang diagnostic pop +#endif diff --git a/tracker-pt/pt-settings.hpp b/tracker-pt/pt-settings.hpp index 088dfe5a..df45b499 100644 --- a/tracker-pt/pt-settings.hpp +++ b/tracker-pt/pt-settings.hpp @@ -19,6 +19,11 @@ namespace pt_settings_detail { using namespace options; +#ifdef __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wweak-vtables" +#endif + struct pt_settings final : options::opts { using slider_value = options::slider_value; @@ -57,9 +62,12 @@ struct pt_settings final : options::opts value<slider_value> threshold_slider { b, "threshold-slider", { 128, 0, 255 } }; explicit pt_settings(const QString& name) : opts(name) {} - ~pt_settings() = default; }; +#ifdef __clang__ +# pragma clang diagnostic pop +#endif + } // ns pt_settings_detail using pt_settings = pt_settings_detail::pt_settings; |