summaryrefslogtreecommitdiffhomepage
path: root/tracker-pt
diff options
context:
space:
mode:
Diffstat (limited to 'tracker-pt')
-rw-r--r--tracker-pt/CMakeLists.txt2
-rw-r--r--tracker-pt/ftnoir_tracker_pt.cpp126
-rw-r--r--tracker-pt/ftnoir_tracker_pt.h16
-rw-r--r--tracker-pt/ftnoir_tracker_pt_dialog.cpp14
-rw-r--r--tracker-pt/ftnoir_tracker_pt_dialog.h2
-rw-r--r--tracker-pt/lang/nl_NL.ts7
-rw-r--r--tracker-pt/lang/ru_RU.ts7
-rw-r--r--tracker-pt/lang/stub.ts7
-rw-r--r--tracker-pt/lang/zh_CN.ts7
-rw-r--r--tracker-pt/module/camera.cpp31
-rw-r--r--tracker-pt/module/camera.h8
-rw-r--r--tracker-pt/module/frame.cpp6
-rw-r--r--tracker-pt/module/frame.hpp14
-rw-r--r--tracker-pt/module/module.cpp16
-rw-r--r--tracker-pt/module/module.hpp4
-rw-r--r--tracker-pt/module/point_extractor.cpp156
-rw-r--r--tracker-pt/module/point_extractor.h9
-rw-r--r--tracker-pt/point_tracker.cpp174
-rw-r--r--tracker-pt/point_tracker.h15
-rw-r--r--tracker-pt/pt-api.cpp34
-rw-r--r--tracker-pt/pt-api.hpp38
-rw-r--r--tracker-pt/pt-settings.hpp10
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(&center_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(&center_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&apos;t roll or change position.</source>
</message>
</context>
<context>
- <name>pt_module::Tracker_PT</name>
- <message>
- <source>Can&apos;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&apos;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&apos;t roll or change position.</source>
</message>
</context>
<context>
- <name>pt_module::Tracker_PT</name>
- <message>
- <source>Can&apos;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&apos;t roll or change position.</source>
</message>
</context>
<context>
- <name>pt_module::Tracker_PT</name>
- <message>
- <source>Can&apos;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 &current_center, f filter_width)
+static vec2 MeanShiftIteration(const cv::Mat1b &frame_gray, const vec2 &current_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;