summaryrefslogtreecommitdiffhomepage
path: root/tracker-easy
diff options
context:
space:
mode:
authorStéphane Lenclud <github@lenclud.com>2019-04-13 12:59:22 +0200
committerStéphane Lenclud <github@lenclud.com>2019-04-24 18:46:12 +0200
commitabaf23d7043c42a07e0d71fc0a17a8264c828d48 (patch)
treeb5e8f14e4730bb45d26d2858a26ac2c6cbfc23a8 /tracker-easy
parentac8f7a3e7b29a5ce60ae751ee3a97e3b344c8f3f (diff)
EasyTracker: Adding namespace. Reducing number of classes.
Diffstat (limited to 'tracker-easy')
-rw-r--r--tracker-easy/cv-point-extractor.cpp120
-rw-r--r--tracker-easy/cv-point-extractor.h21
-rw-r--r--tracker-easy/lang/nl_NL.ts16
-rw-r--r--tracker-easy/lang/ru_RU.ts16
-rw-r--r--tracker-easy/lang/stub.ts16
-rw-r--r--tracker-easy/lang/zh_CN.ts16
-rw-r--r--tracker-easy/module.cpp43
-rw-r--r--tracker-easy/module.hpp14
-rw-r--r--tracker-easy/preview.cpp142
-rw-r--r--tracker-easy/preview.h30
-rw-r--r--tracker-easy/tracker-easy-api.cpp10
-rw-r--r--tracker-easy/tracker-easy-dialog.cpp384
-rw-r--r--tracker-easy/tracker-easy-dialog.h64
-rw-r--r--tracker-easy/tracker-easy.cpp564
-rw-r--r--tracker-easy/tracker-easy.h94
15 files changed, 765 insertions, 785 deletions
diff --git a/tracker-easy/cv-point-extractor.cpp b/tracker-easy/cv-point-extractor.cpp
index 56de4c0b..9720eb63 100644
--- a/tracker-easy/cv-point-extractor.cpp
+++ b/tracker-easy/cv-point-extractor.cpp
@@ -8,6 +8,7 @@
#include "cv-point-extractor.h"
#include "preview.h"
+#include "tracker-easy.h"
#include "cv/numeric.hpp"
#include "compat/math.hpp"
@@ -22,87 +23,86 @@
using namespace numeric_types;
-
-
-CvPointExtractor::CvPointExtractor(const QString& module_name) : s(module_name)
+namespace EasyTracker
{
+
+ CvPointExtractor::CvPointExtractor() : s(KModuleName)
+ {
-}
+ }
-void CvPointExtractor::extract_points(const cv::Mat& frame, cv::Mat* aPreview, std::vector<vec2>& aPoints)
-{
+ void CvPointExtractor::extract_points(const cv::Mat& frame, cv::Mat* aPreview, std::vector<vec2>& aPoints)
+ {
- // Contours detection
- std::vector<std::vector<cv::Point> > contours;
- cv::findContours(frame, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
+ // Contours detection
+ std::vector<std::vector<cv::Point> > contours;
+ cv::findContours(frame, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
- // Workout which countours are valid points
- for (size_t i = 0; i < contours.size(); i++)
- {
- if (aPreview)
+ // Workout which countours are valid points
+ for (size_t i = 0; i < contours.size(); i++)
{
- cv::drawContours(*aPreview, contours, i, CV_RGB(255, 0, 0), 2);
- }
+ if (aPreview)
+ {
+ cv::drawContours(*aPreview, contours, i, CV_RGB(255, 0, 0), 2);
+ }
- cv::Rect bBox;
- bBox = cv::boundingRect(contours[i]);
+ cv::Rect bBox;
+ bBox = cv::boundingRect(contours[i]);
- float ratio = (float)bBox.width / (float)bBox.height;
- if (ratio > 1.0f)
- ratio = 1.0f / ratio;
+ float ratio = (float)bBox.width / (float)bBox.height;
+ if (ratio > 1.0f)
+ ratio = 1.0f / ratio;
- // Searching for a bBox almost square
- float minArea = s.min_point_size*s.min_point_size;
- float maxArea = s.max_point_size*s.max_point_size;
- if (bBox.width >= s.min_point_size
- && bBox.height >= s.min_point_size
- && bBox.width <= s.max_point_size
- && bBox.height <= s.max_point_size
- && bBox.area() >= minArea
- && bBox.area() <= maxArea
- /*&& ratio > 0.75 &&*/)
- {
- vec2 center;
- center[0] = bBox.x + bBox.width / 2;
- center[1] = bBox.y + bBox.height / 2;
- aPoints.push_back(vec2(center));
-
- if (aPreview)
+ // Searching for a bBox almost square
+ float minArea = s.min_point_size*s.min_point_size;
+ float maxArea = s.max_point_size*s.max_point_size;
+ if (bBox.width >= s.min_point_size
+ && bBox.height >= s.min_point_size
+ && bBox.width <= s.max_point_size
+ && bBox.height <= s.max_point_size
+ && bBox.area() >= minArea
+ && bBox.area() <= maxArea
+ /*&& ratio > 0.75 &&*/)
{
- cv::rectangle(*aPreview, bBox, CV_RGB(0, 255, 0), 2);
+ vec2 center;
+ center[0] = bBox.x + bBox.width / 2;
+ center[1] = bBox.y + bBox.height / 2;
+ aPoints.push_back(vec2(center));
+
+ if (aPreview)
+ {
+ cv::rectangle(*aPreview, bBox, CV_RGB(0, 255, 0), 2);
+ }
}
}
- }
-
- // Keep the three points which are highest, i.e. with lowest Y coordinates
- // That's most usefull to discard noise from features below your cap/head.
- // Typically noise comming from zippers and metal parts on your clothing.
- // With a cap tracker it also successfully discards noise glasses.
- // However it may not work as good with a clip user wearing glasses.
- while (aPoints.size() > 3) // Until we have no more than three points
- {
- int maxY = 0;
- int index = -1;
- // Search for the point with highest Y coordinate
- for (size_t i = 0; i < aPoints.size(); i++)
+ // Keep the three points which are highest, i.e. with lowest Y coordinates
+ // That's most usefull to discard noise from features below your cap/head.
+ // Typically noise comming from zippers and metal parts on your clothing.
+ // With a cap tracker it also successfully discards noise glasses.
+ // However it may not work as good with a clip user wearing glasses.
+ while (aPoints.size() > 3) // Until we have no more than three points
{
- if (aPoints[i][1] > maxY)
+ int maxY = 0;
+ int index = -1;
+
+ // Search for the point with highest Y coordinate
+ for (size_t i = 0; i < aPoints.size(); i++)
{
- maxY = aPoints[i][1];
- index = i;
+ if (aPoints[i][1] > maxY)
+ {
+ maxY = aPoints[i][1];
+ index = i;
+ }
}
- }
- // Discard it
- aPoints.erase(aPoints.begin() + index);
+ // Discard it
+ aPoints.erase(aPoints.begin() + index);
+ }
}
-
}
-
-
diff --git a/tracker-easy/cv-point-extractor.h b/tracker-easy/cv-point-extractor.h
index 405ca052..18229d4a 100644
--- a/tracker-easy/cv-point-extractor.h
+++ b/tracker-easy/cv-point-extractor.h
@@ -18,17 +18,20 @@
using namespace numeric_types;
-
-class CvPointExtractor final : public IPointExtractor
+namespace EasyTracker
{
-public:
- // extracts points from frame and draws some processing info into frame, if draw_output is set
- // dt: time since last call in seconds
- void extract_points(const cv::Mat& frame, cv::Mat* aPreview, std::vector<vec2>& aPoints) override;
- CvPointExtractor(const QString& module_name);
- pt_settings s;
-};
+ class CvPointExtractor final : public IPointExtractor
+ {
+ public:
+ // extracts points from frame and draws some processing info into frame, if draw_output is set
+ // dt: time since last call in seconds
+ void extract_points(const cv::Mat& frame, cv::Mat* aPreview, std::vector<vec2>& aPoints) override;
+ CvPointExtractor();
+
+ pt_settings s;
+ };
+}
diff --git a/tracker-easy/lang/nl_NL.ts b/tracker-easy/lang/nl_NL.ts
index 86022183..b10c7e14 100644
--- a/tracker-easy/lang/nl_NL.ts
+++ b/tracker-easy/lang/nl_NL.ts
@@ -2,7 +2,7 @@
<!DOCTYPE TS>
<TS version="2.1" language="nl_NL">
<context>
- <name>EasyTrackerDialog</name>
+ <name>EasyTracker::Dialog</name>
<message>
<source>Brightness %1/255</source>
<translation type="unfinished"></translation>
@@ -37,6 +37,13 @@
</message>
</context>
<context>
+ <name>EasyTracker::Metadata</name>
+ <message>
+ <source>Easy Tracker 0.1</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
<name>UICPTClientControls</name>
<message>
<source>PointTracker Settings</source>
@@ -268,11 +275,4 @@ Don&apos;t roll or change position.</source>
<translation type="unfinished"></translation>
</message>
</context>
-<context>
- <name>pt_module::metadata_pt</name>
- <message>
- <source>Easy Tracker 0.1</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
</TS>
diff --git a/tracker-easy/lang/ru_RU.ts b/tracker-easy/lang/ru_RU.ts
index 8ed38fac..7f5df2e2 100644
--- a/tracker-easy/lang/ru_RU.ts
+++ b/tracker-easy/lang/ru_RU.ts
@@ -2,7 +2,7 @@
<!DOCTYPE TS>
<TS version="2.1" language="ru_RU">
<context>
- <name>EasyTrackerDialog</name>
+ <name>EasyTracker::Dialog</name>
<message>
<source>Brightness %1/255</source>
<translation type="unfinished"></translation>
@@ -37,6 +37,13 @@
</message>
</context>
<context>
+ <name>EasyTracker::Metadata</name>
+ <message>
+ <source>Easy Tracker 0.1</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
<name>UICPTClientControls</name>
<message>
<source>PointTracker Settings</source>
@@ -273,11 +280,4 @@ ROLL или X/Y-смещения.</translation>
<translation type="unfinished"></translation>
</message>
</context>
-<context>
- <name>pt_module::metadata_pt</name>
- <message>
- <source>Easy Tracker 0.1</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
</TS>
diff --git a/tracker-easy/lang/stub.ts b/tracker-easy/lang/stub.ts
index 98e2e0f8..144b8e76 100644
--- a/tracker-easy/lang/stub.ts
+++ b/tracker-easy/lang/stub.ts
@@ -2,7 +2,7 @@
<!DOCTYPE TS>
<TS version="2.1">
<context>
- <name>EasyTrackerDialog</name>
+ <name>EasyTracker::Dialog</name>
<message>
<source>Brightness %1/255</source>
<translation type="unfinished"></translation>
@@ -37,6 +37,13 @@
</message>
</context>
<context>
+ <name>EasyTracker::Metadata</name>
+ <message>
+ <source>Easy Tracker 0.1</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
<name>UICPTClientControls</name>
<message>
<source>PointTracker Settings</source>
@@ -268,11 +275,4 @@ Don&apos;t roll or change position.</source>
<translation type="unfinished"></translation>
</message>
</context>
-<context>
- <name>pt_module::metadata_pt</name>
- <message>
- <source>Easy Tracker 0.1</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
</TS>
diff --git a/tracker-easy/lang/zh_CN.ts b/tracker-easy/lang/zh_CN.ts
index c2c3024a..43e121ac 100644
--- a/tracker-easy/lang/zh_CN.ts
+++ b/tracker-easy/lang/zh_CN.ts
@@ -2,7 +2,7 @@
<!DOCTYPE TS>
<TS version="2.1" language="zh_CN">
<context>
- <name>EasyTrackerDialog</name>
+ <name>EasyTracker::Dialog</name>
<message>
<source>Brightness %1/255</source>
<translation type="unfinished">亮度 %1/255</translation>
@@ -37,6 +37,13 @@
</message>
</context>
<context>
+ <name>EasyTracker::Metadata</name>
+ <message>
+ <source>Easy Tracker 0.1</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
<name>UICPTClientControls</name>
<message>
<source>PointTracker Settings</source>
@@ -268,11 +275,4 @@ Don&apos;t roll or change position.</source>
<translation type="unfinished"></translation>
</message>
</context>
-<context>
- <name>pt_module::metadata_pt</name>
- <message>
- <source>Easy Tracker 0.1</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
</TS>
diff --git a/tracker-easy/module.cpp b/tracker-easy/module.cpp
index 0c360e80..c5751e6e 100644
--- a/tracker-easy/module.cpp
+++ b/tracker-easy/module.cpp
@@ -4,52 +4,17 @@
#include "module.hpp"
#include "cv-point-extractor.h"
-
#include <memory>
-static const QString module_name = "tracker-easy";
-
-#ifdef __clang__
-# pragma clang diagnostic ignored "-Wweak-vtables"
-#endif
-
-namespace pt_module {
-
-struct pt_module_traits final : IEasyTrackerTraits
-{
- pointer<IPointExtractor> make_point_extractor() const override
- {
- return pointer<IPointExtractor>(new CvPointExtractor(module_name));
- }
-
- QString get_module_name() const override
- {
- return module_name;
- }
-
-};
-struct tracker_pt : EasyTracker
-{
- tracker_pt() : EasyTracker(pointer<IEasyTrackerTraits>(new pt_module_traits))
- {
- }
-};
-struct dialog_pt : EasyTrackerDialog
+namespace EasyTracker
{
- dialog_pt();
-};
-dialog_pt::dialog_pt() : EasyTrackerDialog(module_name) {}
-
-QString metadata_pt::name() { return tr("Easy Tracker 0.1"); }
-QIcon metadata_pt::icon() { return QIcon(":/Resources/Logo_IR.png"); }
+ QString Metadata::name() { return tr("Easy Tracker 0.1"); }
+ QIcon Metadata::icon() { return QIcon(":/Resources/Logo_IR.png"); }
}
-// ns pt_module
-
-using namespace pt_module;
-OPENTRACK_DECLARE_TRACKER(tracker_pt, dialog_pt, metadata_pt)
+OPENTRACK_DECLARE_TRACKER(EasyTracker::Tracker, EasyTracker::Dialog, EasyTracker::Metadata)
diff --git a/tracker-easy/module.hpp b/tracker-easy/module.hpp
index 0b3f12cf..8a4e3920 100644
--- a/tracker-easy/module.hpp
+++ b/tracker-easy/module.hpp
@@ -6,15 +6,15 @@
#include "compat/linkage-macros.hpp"
-namespace pt_module
+namespace EasyTracker
{
-class OTR_GENERIC_EXPORT metadata_pt : public Metadata
-{
- Q_OBJECT
+ class OTR_GENERIC_EXPORT Metadata : public ::Metadata
+ {
+ Q_OBJECT
- QString name() override;
- QIcon icon() override;
-};
+ QString name() override;
+ QIcon icon() override;
+ };
} // ns pt_module
diff --git a/tracker-easy/preview.cpp b/tracker-easy/preview.cpp
index 33758cfa..404ad299 100644
--- a/tracker-easy/preview.cpp
+++ b/tracker-easy/preview.cpp
@@ -13,88 +13,94 @@
#include <opencv2/imgproc.hpp>
-Preview& Preview::operator=(const cv::Mat& aFrame)
+namespace EasyTracker
{
- // Make sure our frame is RGB
- // Make an extra copy if needed
- int channelCount = aFrame.channels();
- if (channelCount == 1)
- {
- // Convert to RGB
- cv::cvtColor(aFrame, iFrameRgb, cv::COLOR_GRAY2BGR);
- }
- else if (channelCount == 3)
- {
- iFrameRgb = aFrame;
- }
- else
- {
- eval_once(qDebug() << "tracker/easy: camera frame depth not supported" << aFrame.channels());
- return *this;
- }
-
- return *this;
-}
+ Preview& Preview::operator=(const cv::Mat& aFrame)
+ {
-Preview::Preview(int w, int h)
-{
- ensure_size(frame_out, w, h, CV_8UC4);
- ensure_size(iFrameResized, w, h, CV_8UC3);
+ // Make sure our frame is RGB
+ // Make an extra copy if needed
+ int channelCount = aFrame.channels();
+ if (channelCount == 1)
+ {
+ // Convert to RGB
+ cv::cvtColor(aFrame, iFrameRgb, cv::COLOR_GRAY2BGR);
+ }
+ else if (channelCount == 3)
+ {
+ iFrameRgb = aFrame;
+ }
+ else
+ {
+ eval_once(qDebug() << "tracker/easy: camera frame depth not supported" << aFrame.channels());
+ return *this;
+ }
- iFrameResized.setTo(cv::Scalar(0, 0, 0));
-}
-QImage Preview::get_bitmap()
-{
- int stride = frame_out.step.p[0];
+ return *this;
+ }
- if (stride < 64 || stride < frame_out.cols * 4)
+ Preview::Preview(int w, int h)
{
- eval_once(qDebug() << "bad stride" << stride
- << "for bitmap size" << iFrameResized.cols << iFrameResized.rows);
- return QImage();
+ ensure_size(frame_out, w, h, CV_8UC4);
+ ensure_size(iFrameResized, w, h, CV_8UC3);
+
+ iFrameResized.setTo(cv::Scalar(0, 0, 0));
}
- // Resize if needed
- const bool need_resize = iFrameRgb.cols != frame_out.cols || iFrameRgb.rows != frame_out.rows;
- if (need_resize)
+ QImage Preview::get_bitmap()
{
- cv::resize(iFrameRgb, iFrameResized, cv::Size(frame_out.cols, frame_out.rows), 0, 0, cv::INTER_NEAREST);
+ int stride = frame_out.step.p[0];
+
+ if (stride < 64 || stride < frame_out.cols * 4)
+ {
+ eval_once(qDebug() << "bad stride" << stride
+ << "for bitmap size" << iFrameResized.cols << iFrameResized.rows);
+ return QImage();
+ }
+
+ // Resize if needed
+ const bool need_resize = iFrameRgb.cols != frame_out.cols || iFrameRgb.rows != frame_out.rows;
+ if (need_resize)
+ {
+ cv::resize(iFrameRgb, iFrameResized, cv::Size(frame_out.cols, frame_out.rows), 0, 0, cv::INTER_NEAREST);
+ }
+ else
+ {
+ iFrameRgb.copyTo(iFrameResized);
+ }
+
+ cv::cvtColor(iFrameResized, frame_out, cv::COLOR_BGR2BGRA);
+
+ return QImage((const unsigned char*)frame_out.data,
+ frame_out.cols, frame_out.rows,
+ stride,
+ QImage::Format_ARGB32);
}
- else
+
+ void Preview::draw_head_center(numeric_types::f x, numeric_types::f y)
{
- iFrameRgb.copyTo(iFrameResized);
+ int px = iround(x), py = iround(y);
+
+ constexpr int len = 9;
+
+ static const cv::Scalar color(0, 255, 255);
+ cv::line(iFrameRgb,
+ cv::Point(px - len, py),
+ cv::Point(px + len, py),
+ color, 1);
+ cv::line(iFrameRgb,
+ cv::Point(px, py - len),
+ cv::Point(px, py + len),
+ color, 1);
}
- cv::cvtColor(iFrameResized, frame_out, cv::COLOR_BGR2BGRA);
-
- return QImage((const unsigned char*) frame_out.data,
- frame_out.cols, frame_out.rows,
- stride,
- QImage::Format_ARGB32);
-}
-
-void Preview::draw_head_center(numeric_types::f x, numeric_types::f y)
-{
- int px = iround(x), py = iround(y);
-
- constexpr int len = 9;
-
- static const cv::Scalar color(0, 255, 255);
- cv::line(iFrameRgb,
- cv::Point(px - len, py),
- cv::Point(px + len, py),
- color, 1);
- cv::line(iFrameRgb,
- cv::Point(px, py - len),
- cv::Point(px, py + len),
- color, 1);
-}
+ 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);
+ }
-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);
}
diff --git a/tracker-easy/preview.h b/tracker-easy/preview.h
index fc7ec9c9..c3ed9f6b 100644
--- a/tracker-easy/preview.h
+++ b/tracker-easy/preview.h
@@ -14,23 +14,27 @@
#include <opencv2/core.hpp>
#include <QImage>
-struct Preview
+namespace EasyTracker
{
- Preview(int w, int h);
- Preview& operator=(const cv::Mat& frame);
- QImage get_bitmap();
- void draw_head_center(numeric_types::f x, numeric_types::f y);
+ struct Preview
+ {
+ Preview(int w, int h);
- operator cv::Mat&() { return iFrameResized; }
- operator cv::Mat const&() const { return iFrameResized; }
+ Preview& operator=(const cv::Mat& frame);
+ QImage get_bitmap();
+ void draw_head_center(numeric_types::f x, numeric_types::f y);
-private:
- static void ensure_size(cv::Mat& frame, int w, int h, int type);
+ operator cv::Mat&() { return iFrameResized; }
+ operator cv::Mat const&() const { return iFrameResized; }
-public:
- cv::Mat iFrameResized, frame_out;
- cv::Mat iFrameRgb;
-};
+ private:
+ static void ensure_size(cv::Mat& frame, int w, int h, int type);
+ public:
+ cv::Mat iFrameResized, frame_out;
+ cv::Mat iFrameRgb;
+ };
+
+}
diff --git a/tracker-easy/tracker-easy-api.cpp b/tracker-easy/tracker-easy-api.cpp
deleted file mode 100644
index 2e3988a8..00000000
--- a/tracker-easy/tracker-easy-api.cpp
+++ /dev/null
@@ -1,10 +0,0 @@
-#include "tracker-easy-api.h"
-#include "cv/numeric.hpp"
-
-using namespace numeric_types;
-
-
-IEasyTrackerTraits::IEasyTrackerTraits() = default;
-IEasyTrackerTraits::~IEasyTrackerTraits() = default;
-
-
diff --git a/tracker-easy/tracker-easy-dialog.cpp b/tracker-easy/tracker-easy-dialog.cpp
index c0dd23dd..0b0dd61d 100644
--- a/tracker-easy/tracker-easy-dialog.cpp
+++ b/tracker-easy/tracker-easy-dialog.cpp
@@ -20,249 +20,253 @@ using namespace options;
static void init_resources() { Q_INIT_RESOURCE(tracker_easy); }
-EasyTrackerDialog::EasyTrackerDialog(const QString& module_name) :
- s(module_name),
- tracker(nullptr),
- timer(this),
- trans_calib(1, 2)
+namespace EasyTracker
{
- init_resources();
- ui.setupUi(this);
+ Dialog::Dialog() :
+ s(KModuleName),
+ tracker(nullptr),
+ timer(this),
+ trans_calib(1, 2)
+ {
+ init_resources();
- for (const QString& str : video::camera_names())
- ui.camdevice_combo->addItem(str);
+ ui.setupUi(this);
- tie_setting(s.camera_name, ui.camdevice_combo);
- tie_setting(s.cam_res_x, ui.res_x_spin);
- tie_setting(s.cam_res_y, ui.res_y_spin);
- tie_setting(s.cam_fps, ui.fps_spin);
+ for (const QString& str : video::camera_names())
+ ui.camdevice_combo->addItem(str);
- tie_setting(s.threshold_slider, ui.threshold_slider);
+ tie_setting(s.camera_name, ui.camdevice_combo);
+ tie_setting(s.cam_res_x, ui.res_x_spin);
+ tie_setting(s.cam_res_y, ui.res_y_spin);
+ tie_setting(s.cam_fps, ui.fps_spin);
- tie_setting(s.min_point_size, ui.mindiam_spin);
- tie_setting(s.max_point_size, ui.maxdiam_spin);
+ tie_setting(s.threshold_slider, ui.threshold_slider);
- tie_setting(s.clip_by, ui.clip_bheight_spin);
- tie_setting(s.clip_bz, ui.clip_blength_spin);
- tie_setting(s.clip_ty, ui.clip_theight_spin);
- tie_setting(s.clip_tz, ui.clip_tlength_spin);
+ tie_setting(s.min_point_size, ui.mindiam_spin);
+ tie_setting(s.max_point_size, ui.maxdiam_spin);
- tie_setting(s.cap_x, ui.cap_width_spin);
- tie_setting(s.cap_y, ui.cap_height_spin);
- tie_setting(s.cap_z, ui.cap_length_spin);
+ tie_setting(s.clip_by, ui.clip_bheight_spin);
+ tie_setting(s.clip_bz, ui.clip_blength_spin);
+ tie_setting(s.clip_ty, ui.clip_theight_spin);
+ tie_setting(s.clip_tz, ui.clip_tlength_spin);
- tie_setting(s.m01_x, ui.m1x_spin);
- tie_setting(s.m01_y, ui.m1y_spin);
- tie_setting(s.m01_z, ui.m1z_spin);
+ tie_setting(s.cap_x, ui.cap_width_spin);
+ tie_setting(s.cap_y, ui.cap_height_spin);
+ tie_setting(s.cap_z, ui.cap_length_spin);
- tie_setting(s.m02_x, ui.m2x_spin);
- tie_setting(s.m02_y, ui.m2y_spin);
- tie_setting(s.m02_z, ui.m2z_spin);
+ tie_setting(s.m01_x, ui.m1x_spin);
+ tie_setting(s.m01_y, ui.m1y_spin);
+ tie_setting(s.m01_z, ui.m1z_spin);
- tie_setting(s.t_MH_x, ui.tx_spin);
- tie_setting(s.t_MH_y, ui.ty_spin);
- tie_setting(s.t_MH_z, ui.tz_spin);
+ tie_setting(s.m02_x, ui.m2x_spin);
+ tie_setting(s.m02_y, ui.m2y_spin);
+ tie_setting(s.m02_z, ui.m2z_spin);
- tie_setting(s.fov, ui.fov);
+ tie_setting(s.t_MH_x, ui.tx_spin);
+ tie_setting(s.t_MH_y, ui.ty_spin);
+ tie_setting(s.t_MH_z, ui.tz_spin);
- tie_setting(s.active_model_panel, ui.model_tabs);
+ tie_setting(s.fov, ui.fov);
- tie_setting(s.dynamic_pose, ui.dynamic_pose);
- tie_setting(s.init_phase_timeout, ui.init_phase_timeout);
+ tie_setting(s.active_model_panel, ui.model_tabs);
- tie_setting(s.auto_threshold, ui.auto_threshold);
+ tie_setting(s.dynamic_pose, ui.dynamic_pose);
+ tie_setting(s.init_phase_timeout, ui.init_phase_timeout);
- connect(ui.tcalib_button,SIGNAL(toggled(bool)), this, SLOT(startstop_trans_calib(bool)));
+ tie_setting(s.auto_threshold, ui.auto_threshold);
- connect(ui.buttonBox, SIGNAL(accepted()), this, SLOT(doOK()));
- connect(ui.buttonBox, SIGNAL(rejected()), this, SLOT(doCancel()));
+ connect(ui.tcalib_button, SIGNAL(toggled(bool)), this, SLOT(startstop_trans_calib(bool)));
- connect(ui.camdevice_combo, &QComboBox::currentTextChanged, this, &EasyTrackerDialog::set_camera_settings_available);
- set_camera_settings_available(ui.camdevice_combo->currentText());
- connect(ui.camera_settings, &QPushButton::clicked, this, &EasyTrackerDialog::show_camera_settings);
+ connect(ui.buttonBox, SIGNAL(accepted()), this, SLOT(doOK()));
+ connect(ui.buttonBox, SIGNAL(rejected()), this, SLOT(doCancel()));
- connect(&timer, &QTimer::timeout, this, &EasyTrackerDialog::poll_tracker_info_impl);
- timer.setInterval(250);
+ connect(ui.camdevice_combo, &QComboBox::currentTextChanged, this, &Dialog::set_camera_settings_available);
+ set_camera_settings_available(ui.camdevice_combo->currentText());
+ connect(ui.camera_settings, &QPushButton::clicked, this, &Dialog::show_camera_settings);
- connect(&calib_timer, &QTimer::timeout, this, &EasyTrackerDialog::trans_calib_step);
- calib_timer.setInterval(35);
+ connect(&timer, &QTimer::timeout, this, &Dialog::poll_tracker_info_impl);
+ timer.setInterval(250);
- poll_tracker_info_impl();
+ connect(&calib_timer, &QTimer::timeout, this, &Dialog::trans_calib_step);
+ calib_timer.setInterval(35);
- connect(this, &EasyTrackerDialog::poll_tracker_info, this, &EasyTrackerDialog::poll_tracker_info_impl, Qt::DirectConnection);
+ poll_tracker_info_impl();
- constexpr pt_color_type color_types[] = {
- pt_color_average,
- pt_color_natural,
- pt_color_red_only,
- pt_color_green_only,
- pt_color_blue_only,
- };
+ connect(this, &Dialog::poll_tracker_info, this, &Dialog::poll_tracker_info_impl, Qt::DirectConnection);
- for (unsigned k = 0; k < std::size(color_types); k++)
- ui.blob_color->setItemData(k, int(color_types[k]));
+ constexpr pt_color_type color_types[] = {
+ pt_color_average,
+ pt_color_natural,
+ pt_color_red_only,
+ pt_color_green_only,
+ pt_color_blue_only,
+ };
- tie_setting(s.blob_color, ui.blob_color);
+ for (unsigned k = 0; k < std::size(color_types); k++)
+ ui.blob_color->setItemData(k, int(color_types[k]));
- tie_setting(s.threshold_slider, ui.threshold_value_display, [this](const slider_value& val) {
- return threshold_display_text(int(val));
- });
+ tie_setting(s.blob_color, ui.blob_color);
- // refresh threshold display on auto-threshold checkbox state change
- tie_setting(s.auto_threshold,
- this,
- [this](bool) { s.threshold_slider.notify(); });
-}
+ tie_setting(s.threshold_slider, ui.threshold_value_display, [this](const slider_value& val) {
+ return threshold_display_text(int(val));
+ });
-QString EasyTrackerDialog::threshold_display_text(int threshold_value)
-{
- if (!s.auto_threshold)
- return tr("Brightness %1/255").arg(threshold_value);
- else
- {
- int w = s.cam_res_x, h = s.cam_res_y;
+ // refresh threshold display on auto-threshold checkbox state change
+ tie_setting(s.auto_threshold,
+ this,
+ [this](bool) { s.threshold_slider.notify(); });
+ }
- if (w * h <= 0)
+ QString Dialog::threshold_display_text(int threshold_value)
+ {
+ if (!s.auto_threshold)
+ return tr("Brightness %1/255").arg(threshold_value);
+ else
{
- w = 640;
- h = 480;
- }
-
- //SL: What are we suppose to do here?
- double value = 0.0f;
+ int w = s.cam_res_x, h = s.cam_res_y;
- return tr("LED radius %1 pixels").arg(value, 0, 'f', 2);
- }
-}
+ if (w * h <= 0)
+ {
+ w = 640;
+ h = 480;
+ }
-void EasyTrackerDialog::startstop_trans_calib(bool start)
-{
- QMutexLocker l(&calibrator_mutex);
+ //SL: What are we suppose to do here?
+ double value = 0.0f;
- if (start)
- {
- qDebug() << "pt: starting translation calibration";
- calib_timer.start();
- trans_calib.reset();
- s.t_MH_x = 0;
- s.t_MH_y = 0;
- s.t_MH_z = 0;
-
- ui.sample_count_display->setText(QString());
+ return tr("LED radius %1 pixels").arg(value, 0, 'f', 2);
+ }
}
- else
+
+ void Dialog::startstop_trans_calib(bool start)
{
- calib_timer.stop();
- qDebug() << "pt: stopping translation calibration";
+ QMutexLocker l(&calibrator_mutex);
+
+ if (start)
+ {
+ qDebug() << "pt: starting translation calibration";
+ calib_timer.start();
+ trans_calib.reset();
+ s.t_MH_x = 0;
+ s.t_MH_y = 0;
+ s.t_MH_z = 0;
+
+ ui.sample_count_display->setText(QString());
+ }
+ else
{
- auto [tmp, nsamples] = trans_calib.get_estimate();
- s.t_MH_x = int(tmp[0]);
- s.t_MH_y = int(tmp[1]);
- s.t_MH_z = int(tmp[2]);
-
- constexpr int min_yaw_samples = 15;
- constexpr int min_pitch_samples = 15;
- constexpr int min_samples = min_yaw_samples+min_pitch_samples;
-
- // Don't bother counting roll samples. Roll calibration is hard enough
- // that it's a hidden unsupported feature anyway.
-
- QString sample_feedback;
- if (nsamples[0] < min_yaw_samples)
- sample_feedback = tr("%1 yaw samples. Yaw more to %2 samples for stable calibration.").arg(nsamples[0]).arg(min_yaw_samples);
- else if (nsamples[1] < min_pitch_samples)
- sample_feedback = tr("%1 pitch samples. Pitch more to %2 samples for stable calibration.").arg(nsamples[1]).arg(min_pitch_samples);
- else
+ calib_timer.stop();
+ qDebug() << "pt: stopping translation calibration";
{
- const int nsamples_total = nsamples[0] + nsamples[1];
- sample_feedback = tr("%1 samples. Over %2, good!").arg(nsamples_total).arg(min_samples);
+ auto[tmp, nsamples] = trans_calib.get_estimate();
+ s.t_MH_x = int(tmp[0]);
+ s.t_MH_y = int(tmp[1]);
+ s.t_MH_z = int(tmp[2]);
+
+ constexpr int min_yaw_samples = 15;
+ constexpr int min_pitch_samples = 15;
+ constexpr int min_samples = min_yaw_samples + min_pitch_samples;
+
+ // Don't bother counting roll samples. Roll calibration is hard enough
+ // that it's a hidden unsupported feature anyway.
+
+ QString sample_feedback;
+ if (nsamples[0] < min_yaw_samples)
+ sample_feedback = tr("%1 yaw samples. Yaw more to %2 samples for stable calibration.").arg(nsamples[0]).arg(min_yaw_samples);
+ else if (nsamples[1] < min_pitch_samples)
+ sample_feedback = tr("%1 pitch samples. Pitch more to %2 samples for stable calibration.").arg(nsamples[1]).arg(min_pitch_samples);
+ else
+ {
+ const int nsamples_total = nsamples[0] + nsamples[1];
+ sample_feedback = tr("%1 samples. Over %2, good!").arg(nsamples_total).arg(min_samples);
+ }
+
+ ui.sample_count_display->setText(sample_feedback);
}
-
- ui.sample_count_display->setText(sample_feedback);
}
+ ui.tx_spin->setEnabled(!start);
+ ui.ty_spin->setEnabled(!start);
+ ui.tz_spin->setEnabled(!start);
+
+ if (start)
+ ui.tcalib_button->setText(tr("Stop calibration"));
+ else
+ ui.tcalib_button->setText(tr("Start calibration"));
}
- ui.tx_spin->setEnabled(!start);
- ui.ty_spin->setEnabled(!start);
- ui.tz_spin->setEnabled(!start);
-
- if (start)
- ui.tcalib_button->setText(tr("Stop calibration"));
- else
- ui.tcalib_button->setText(tr("Start calibration"));
-}
-void EasyTrackerDialog::poll_tracker_info_impl()
-{
- //SL: sort this out
- /*
- pt_camera_info info;
- if (tracker && tracker->get_cam_info(info))
+ void Dialog::poll_tracker_info_impl()
{
- ui.caminfo_label->setText(tr("%1x%2 @ %3 FPS").arg(info.res_x).arg(info.res_y).arg(iround(info.fps)));
+ //SL: sort this out
+ /*
+ pt_camera_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)));
- // display point info
- const int n_points = tracker->get_n_points();
- ui.pointinfo_label->setText((n_points == 3 ? tr("%1 OK!") : tr("%1 BAD!")).arg(n_points));
+ // display point info
+ const int n_points = tracker->get_n_points();
+ ui.pointinfo_label->setText((n_points == 3 ? tr("%1 OK!") : tr("%1 BAD!")).arg(n_points));
+ }
+ else
+ */
+ {
+ ui.caminfo_label->setText(tr("Tracker offline"));
+ ui.pointinfo_label->setText(QString());
+ }
}
- else
- */
+
+ void Dialog::set_camera_settings_available(const QString& /* camera_name */)
{
- ui.caminfo_label->setText(tr("Tracker offline"));
- ui.pointinfo_label->setText(QString());
+ ui.camera_settings->setEnabled(true);
}
-}
-
-void EasyTrackerDialog::set_camera_settings_available(const QString& /* camera_name */)
-{
- ui.camera_settings->setEnabled(true);
-}
-void EasyTrackerDialog::show_camera_settings()
-{
- if (tracker)
+ void Dialog::show_camera_settings()
{
- QMutexLocker l(&tracker->camera_mtx);
- tracker->camera->show_dialog();
+ if (tracker)
+ {
+ QMutexLocker l(&tracker->camera_mtx);
+ tracker->camera->show_dialog();
+ }
+ else
+ (void)video::show_dialog(s.camera_name);
}
- else
- (void)video::show_dialog(s.camera_name);
-}
-void EasyTrackerDialog::trans_calib_step()
-{
- QMutexLocker l(&calibrator_mutex);
- // TODO: Do we still need that function
-}
+ void Dialog::trans_calib_step()
+ {
+ QMutexLocker l(&calibrator_mutex);
+ // TODO: Do we still need that function
+ }
-void EasyTrackerDialog::save()
-{
- s.b->save();
-}
+ void Dialog::save()
+ {
+ s.b->save();
+ }
-void EasyTrackerDialog::doOK()
-{
- save();
- close();
-}
+ void Dialog::doOK()
+ {
+ save();
+ close();
+ }
-void EasyTrackerDialog::doCancel()
-{
- close();
-}
+ void Dialog::doCancel()
+ {
+ close();
+ }
-void EasyTrackerDialog::register_tracker(ITracker *t)
-{
- tracker = static_cast<EasyTracker*>(t);
- ui.tcalib_button->setEnabled(true);
- poll_tracker_info();
- timer.start();
-}
+ void Dialog::register_tracker(ITracker *t)
+ {
+ tracker = static_cast<Tracker*>(t);
+ ui.tcalib_button->setEnabled(true);
+ poll_tracker_info();
+ timer.start();
+ }
-void EasyTrackerDialog::unregister_tracker()
-{
- tracker = nullptr;
- ui.tcalib_button->setEnabled(false);
- poll_tracker_info();
- timer.stop();
+ void Dialog::unregister_tracker()
+ {
+ tracker = nullptr;
+ ui.tcalib_button->setEnabled(false);
+ poll_tracker_info();
+ timer.stop();
+ }
}
diff --git a/tracker-easy/tracker-easy-dialog.h b/tracker-easy/tracker-easy-dialog.h
index 1f21f92b..8d4cffbd 100644
--- a/tracker-easy/tracker-easy-dialog.h
+++ b/tracker-easy/tracker-easy-dialog.h
@@ -17,35 +17,37 @@
#include <QTimer>
#include <QMutex>
-
-class EasyTrackerDialog : public ITrackerDialog
+namespace EasyTracker
{
- Q_OBJECT
-public:
- EasyTrackerDialog(const QString& module_name);
- void register_tracker(ITracker *tracker) override;
- void unregister_tracker() override;
- void save();
-public slots:
- void doOK();
- void doCancel();
-
- void startstop_trans_calib(bool start);
- void trans_calib_step();
- void poll_tracker_info_impl();
- void set_camera_settings_available(const QString& camera_name);
- void show_camera_settings();
-signals:
- void poll_tracker_info();
-protected:
- QString threshold_display_text(int threshold_value);
-
- pt_settings s;
- EasyTracker* tracker;
- QTimer timer, calib_timer;
- TranslationCalibrator trans_calib;
- QMutex calibrator_mutex;
-
- Ui::UICPTClientControls ui;
-};
-
+ class Dialog : public ITrackerDialog
+ {
+ Q_OBJECT
+ public:
+ Dialog();
+ void register_tracker(ITracker *tracker) override;
+ void unregister_tracker() override;
+ void save();
+ public slots:
+ void doOK();
+ void doCancel();
+
+ void startstop_trans_calib(bool start);
+ void trans_calib_step();
+ void poll_tracker_info_impl();
+ void set_camera_settings_available(const QString& camera_name);
+ void show_camera_settings();
+ signals:
+ void poll_tracker_info();
+ protected:
+ QString threshold_display_text(int threshold_value);
+
+ pt_settings s;
+ Tracker* tracker;
+ QTimer timer, calib_timer;
+ TranslationCalibrator trans_calib;
+ QMutex calibrator_mutex;
+
+ Ui::UICPTClientControls ui;
+ };
+
+}
diff --git a/tracker-easy/tracker-easy.cpp b/tracker-easy/tracker-easy.cpp
index 5fd1952c..5fe93b0e 100644
--- a/tracker-easy/tracker-easy.cpp
+++ b/tracker-easy/tracker-easy.cpp
@@ -11,7 +11,7 @@
#include "video/video-widget.hpp"
#include "compat/math-imports.hpp"
#include "compat/check-visible.hpp"
-
+#include "cv-point-extractor.h"
#include "tracker-easy-api.h"
#include <QHBoxLayout>
@@ -26,358 +26,360 @@
using namespace options;
-
-EasyTracker::EasyTracker(pointer<IEasyTrackerTraits> const& traits) :
- traits { traits },
- s { traits->get_module_name() },
- point_extractor { traits->make_point_extractor() },
- iPreview{ preview_width, preview_height }
+namespace EasyTracker
{
- cv::setBreakOnError(true);
- cv::setNumThreads(1);
- connect(s.b.get(), &bundle_::saving, this, &EasyTracker::maybe_reopen_camera, Qt::DirectConnection);
- connect(s.b.get(), &bundle_::reloading, this, &EasyTracker::maybe_reopen_camera, Qt::DirectConnection);
-
- connect(&s.fov, value_::value_changed<int>(), this, &EasyTracker::set_fov, Qt::DirectConnection);
- set_fov(s.fov);
-}
-
-EasyTracker::~EasyTracker()
-{
- //
- cv::destroyWindow("Preview");
+ Tracker::Tracker() :
+ s{ KModuleName },
+ point_extractor{ std::make_unique<CvPointExtractor>() },
+ iPreview{ preview_width, preview_height }
+ {
+ cv::setBreakOnError(true);
+ cv::setNumThreads(1);
- requestInterruption();
- wait();
+ connect(s.b.get(), &bundle_::saving, this, &Tracker::maybe_reopen_camera, Qt::DirectConnection);
+ connect(s.b.get(), &bundle_::reloading, this, &Tracker::maybe_reopen_camera, Qt::DirectConnection);
- QMutexLocker l(&camera_mtx);
- camera->stop();
-}
+ connect(&s.fov, value_::value_changed<int>(), this, &Tracker::set_fov, Qt::DirectConnection);
+ set_fov(s.fov);
+ }
+ Tracker::~Tracker()
+ {
+ //
+ cv::destroyWindow("Preview");
-// Compute Euler angles from ratation matrix
-cv::Vec3f EulerAngles(cv::Mat &R)
-{
+ requestInterruption();
+ wait();
- float sy = sqrt(R.at<double>(0, 0) * R.at<double>(0, 0) + R.at<double>(1, 0) * R.at<double>(1, 0));
+ QMutexLocker l(&camera_mtx);
+ camera->stop();
+ }
- bool singular = sy < 1e-6; // If
- float x, y, z;
- if (!singular)
- {
- x = atan2(R.at<double>(2, 1), R.at<double>(2, 2));
- y = atan2(-R.at<double>(2, 0), sy);
- z = atan2(R.at<double>(1, 0), R.at<double>(0, 0));
- }
- else
+ // Compute Euler angles from ratation matrix
+ cv::Vec3f EulerAngles(cv::Mat &R)
{
- x = atan2(-R.at<double>(1, 2), R.at<double>(1, 1));
- y = atan2(-R.at<double>(2, 0), sy);
- z = 0;
- }
- // Convert to degrees
- return cv::Vec3f(x* 180 / CV_PI, y* 180 / CV_PI, z* 180 / CV_PI);
-}
+ float sy = sqrt(R.at<double>(0, 0) * R.at<double>(0, 0) + R.at<double>(1, 0) * R.at<double>(1, 0));
+ bool singular = sy < 1e-6; // If
-void getEulerAngles(cv::Mat &rotCamerMatrix, cv::Vec3d &eulerAngles)
-{
+ float x, y, z;
+ if (!singular)
+ {
+ x = atan2(R.at<double>(2, 1), R.at<double>(2, 2));
+ y = atan2(-R.at<double>(2, 0), sy);
+ z = atan2(R.at<double>(1, 0), R.at<double>(0, 0));
+ }
+ else
+ {
+ x = atan2(-R.at<double>(1, 2), R.at<double>(1, 1));
+ y = atan2(-R.at<double>(2, 0), sy);
+ z = 0;
+ }
- cv::Mat cameraMatrix, rotMatrix, transVect, rotMatrixX, rotMatrixY, rotMatrixZ;
- double* _r = rotCamerMatrix.ptr<double>();
- double projMatrix[12] = { _r[0],_r[1],_r[2],0,
- _r[3],_r[4],_r[5],0,
- _r[6],_r[7],_r[8],0 };
-
- cv::decomposeProjectionMatrix(cv::Mat(3, 4, CV_64FC1, projMatrix),
- cameraMatrix,
- rotMatrix,
- transVect,
- rotMatrixX,
- rotMatrixY,
- rotMatrixZ,
- eulerAngles);
-}
+ // Convert to degrees
+ return cv::Vec3f(x * 180 / CV_PI, y * 180 / CV_PI, z * 180 / CV_PI);
+ }
-void EasyTracker::run()
-{
- maybe_reopen_camera();
+ void getEulerAngles(cv::Mat &rotCamerMatrix, cv::Vec3d &eulerAngles)
+ {
- while(!isInterruptionRequested())
- {
- bool new_frame = false;
+ cv::Mat cameraMatrix, rotMatrix, transVect, rotMatrixX, rotMatrixY, rotMatrixZ;
+ double* _r = rotCamerMatrix.ptr<double>();
+ double projMatrix[12] = { _r[0],_r[1],_r[2],0,
+ _r[3],_r[4],_r[5],0,
+ _r[6],_r[7],_r[8],0 };
+
+ cv::decomposeProjectionMatrix(cv::Mat(3, 4, CV_64FC1, projMatrix),
+ cameraMatrix,
+ rotMatrix,
+ transVect,
+ rotMatrixX,
+ rotMatrixY,
+ rotMatrixZ,
+ eulerAngles);
+ }
- {
- QMutexLocker l(&camera_mtx);
- if (camera)
- std::tie(iFrame, new_frame) = camera->get_frame();
- }
+ void Tracker::run()
+ {
+ maybe_reopen_camera();
- if (new_frame)
+ while (!isInterruptionRequested())
{
- //TODO: We should not assume channel size of 1 byte
- iMatFrame = cv::Mat(iFrame.height, iFrame.width, CV_MAKETYPE(CV_8U,iFrame.channels), iFrame.data, iFrame.stride);
+ bool new_frame = false;
-
- const bool preview_visible = check_is_visible();
- if (preview_visible)
{
- iPreview = iMatFrame;
- }
+ QMutexLocker l(&camera_mtx);
- iPoints.clear();
- point_extractor->extract_points(iMatFrame, (preview_visible?&iPreview.iFrameRgb:nullptr), iPoints);
- point_count.store(iPoints.size(), std::memory_order_relaxed);
-
-
- if (preview_visible)
- {
- //iPreview = iMatFrame;
- cv::imshow("Preview", iPreview.iFrameRgb);
- cv::waitKey(1);
+ if (camera)
+ std::tie(iFrame, new_frame) = camera->get_frame();
}
- else
+
+ if (new_frame)
{
- cv::destroyWindow("Preview");
- }
+ //TODO: We should not assume channel size of 1 byte
+ iMatFrame = cv::Mat(iFrame.height, iFrame.width, CV_MAKETYPE(CV_8U, iFrame.channels), iFrame.data, iFrame.stride);
+
+
+ const bool preview_visible = check_is_visible();
+ if (preview_visible)
+ {
+ iPreview = iMatFrame;
+ }
- const bool success = iPoints.size() >= KPointCount;
+ iPoints.clear();
+ point_extractor->extract_points(iMatFrame, (preview_visible ? &iPreview.iFrameRgb : nullptr), iPoints);
+ point_count.store(iPoints.size(), std::memory_order_relaxed);
- int topPointIndex = -1;
- {
- QMutexLocker l(&center_lock);
+ if (preview_visible)
+ {
+ //iPreview = iMatFrame;
+ cv::imshow("Preview", iPreview.iFrameRgb);
+ cv::waitKey(1);
+ }
+ else
+ {
+ cv::destroyWindow("Preview");
+ }
+
+ const bool success = iPoints.size() >= KPointCount;
+
+ int topPointIndex = -1;
- if (success)
{
- ever_success.store(true, std::memory_order_relaxed);
-
- // Solve P3P problem with OpenCV
-
- // Construct the points defining the object we want to detect based on settings.
- // We are converting them from millimeters to centimeters.
- // TODO: Need to support clip too. That's cap only for now.
- // s.active_model_panel != PointModel::Clip
-
- std::vector<cv::Point3f> objectPoints;
- objectPoints.push_back(cv::Point3f(s.cap_x/10.0, s.cap_z / 10.0, -s.cap_y / 10.0)); // Right
- objectPoints.push_back(cv::Point3f(-s.cap_x/10.0, s.cap_z / 10.0, -s.cap_y / 10.0)); // Left
- objectPoints.push_back(cv::Point3f(0, 0, 0)); // Top
-
- //Bitmap origin is top left
- std::vector<cv::Point2f> trackedPoints;
- // Stuff bitmap point in there making sure they match the order of the object point
- // Find top most point, that's the one with min Y as we assume our guy's head is not up side down
-
- int minY = std::numeric_limits<int>::max();
- for (int i = 0; i < 3; i++)
+ QMutexLocker l(&center_lock);
+
+ if (success)
{
- if (iPoints[i][1]<minY)
+ ever_success.store(true, std::memory_order_relaxed);
+
+ // Solve P3P problem with OpenCV
+
+ // Construct the points defining the object we want to detect based on settings.
+ // We are converting them from millimeters to centimeters.
+ // TODO: Need to support clip too. That's cap only for now.
+ // s.active_model_panel != PointModel::Clip
+
+ std::vector<cv::Point3f> objectPoints;
+ objectPoints.push_back(cv::Point3f(s.cap_x / 10.0, s.cap_z / 10.0, -s.cap_y / 10.0)); // Right
+ objectPoints.push_back(cv::Point3f(-s.cap_x / 10.0, s.cap_z / 10.0, -s.cap_y / 10.0)); // Left
+ objectPoints.push_back(cv::Point3f(0, 0, 0)); // Top
+
+ //Bitmap origin is top left
+ std::vector<cv::Point2f> trackedPoints;
+ // Stuff bitmap point in there making sure they match the order of the object point
+ // Find top most point, that's the one with min Y as we assume our guy's head is not up side down
+
+ int minY = std::numeric_limits<int>::max();
+ for (int i = 0; i < 3; i++)
{
- minY = iPoints[i][1];
- topPointIndex = i;
+ if (iPoints[i][1] < minY)
+ {
+ minY = iPoints[i][1];
+ topPointIndex = i;
+ }
}
- }
- int rightPointIndex = -1;
- int maxX = 0;
+ int rightPointIndex = -1;
+ int maxX = 0;
- // Find right most point
- for (int i = 0; i < 3; i++)
- {
- // Excluding top most point
- if (i!=topPointIndex && iPoints[i][0] > maxX)
+ // Find right most point
+ for (int i = 0; i < 3; i++)
{
- maxX = iPoints[i][0];
- rightPointIndex = i;
+ // Excluding top most point
+ if (i != topPointIndex && iPoints[i][0] > maxX)
+ {
+ maxX = iPoints[i][0];
+ rightPointIndex = i;
+ }
}
- }
- // Find left most point
- int leftPointIndex = -1;
- for (int i = 0; i < 3; i++)
- {
- // Excluding top most point
- if (i != topPointIndex && i != rightPointIndex)
+ // Find left most point
+ int leftPointIndex = -1;
+ for (int i = 0; i < 3; i++)
{
- leftPointIndex = i;
- break;
+ // Excluding top most point
+ if (i != topPointIndex && i != rightPointIndex)
+ {
+ leftPointIndex = i;
+ break;
+ }
}
- }
- //
- trackedPoints.push_back(cv::Point2f(iPoints[rightPointIndex][0], iPoints[rightPointIndex][1]));
- trackedPoints.push_back(cv::Point2f(iPoints[leftPointIndex][0], iPoints[leftPointIndex][1]));
- trackedPoints.push_back(cv::Point2f(iPoints[topPointIndex][0], iPoints[topPointIndex][1]));
-
- std::cout << "Object: " << objectPoints << "\n";
- std::cout << "Points: " << trackedPoints << "\n";
-
-
- // Create our camera matrix
- // TODO: Just do that once, use data member instead
- // Double or Float?
- cv::Mat cameraMatrix;
- cameraMatrix.create(3, 3, CV_64FC1);
- cameraMatrix.setTo(cv::Scalar(0));
- cameraMatrix.at<double>(0, 0) = iCameraInfo.focalLengthX;
- cameraMatrix.at<double>(1, 1) = iCameraInfo.focalLengthY;
- cameraMatrix.at<double>(0, 2) = iCameraInfo.principalPointX;
- cameraMatrix.at<double>(1, 2) = iCameraInfo.principalPointY;
- cameraMatrix.at<double>(2, 2) = 1;
-
- // Create distortion cooefficients
- cv::Mat distCoeffs = cv::Mat::zeros(8, 1, CV_64FC1);
- // As per OpenCV docs they should be thus: k1, k2, p1, p2, k3, k4, k5, k6
- distCoeffs.at<double>(0, 0) = 0; // Radial first order
- distCoeffs.at<double>(1, 0) = iCameraInfo.radialDistortionSecondOrder; // Radial second order
- distCoeffs.at<double>(2, 0) = 0; // Tangential first order
- distCoeffs.at<double>(3, 0) = 0; // Tangential second order
- distCoeffs.at<double>(4, 0) = 0; // Radial third order
- distCoeffs.at<double>(5, 0) = iCameraInfo.radialDistortionFourthOrder; // Radial fourth order
- distCoeffs.at<double>(6, 0) = 0; // Radial fith order
- distCoeffs.at<double>(7, 0) = iCameraInfo.radialDistortionSixthOrder; // Radial sixth order
-
- // Define our solution arrays
- // They will receive up to 4 solutions for our P3P problem
-
-
- // TODO: try SOLVEPNP_AP3P too
- iAngles.clear();
- iBestSolutionIndex = -1;
- int solutionCount = cv::solveP3P(objectPoints, trackedPoints, cameraMatrix, distCoeffs, iRotations, iTranslations, cv::SOLVEPNP_P3P);
-
- if (solutionCount > 0)
- {
- std::cout << "Solution count: " << solutionCount << "\n";
- int minPitch = std::numeric_limits<int>::max();
- // Find the solution we want
- for (int i = 0; i < solutionCount; i++)
+ //
+ trackedPoints.push_back(cv::Point2f(iPoints[rightPointIndex][0], iPoints[rightPointIndex][1]));
+ trackedPoints.push_back(cv::Point2f(iPoints[leftPointIndex][0], iPoints[leftPointIndex][1]));
+ trackedPoints.push_back(cv::Point2f(iPoints[topPointIndex][0], iPoints[topPointIndex][1]));
+
+ std::cout << "Object: " << objectPoints << "\n";
+ std::cout << "Points: " << trackedPoints << "\n";
+
+
+ // Create our camera matrix
+ // TODO: Just do that once, use data member instead
+ // Double or Float?
+ cv::Mat cameraMatrix;
+ cameraMatrix.create(3, 3, CV_64FC1);
+ cameraMatrix.setTo(cv::Scalar(0));
+ cameraMatrix.at<double>(0, 0) = iCameraInfo.focalLengthX;
+ cameraMatrix.at<double>(1, 1) = iCameraInfo.focalLengthY;
+ cameraMatrix.at<double>(0, 2) = iCameraInfo.principalPointX;
+ cameraMatrix.at<double>(1, 2) = iCameraInfo.principalPointY;
+ cameraMatrix.at<double>(2, 2) = 1;
+
+ // Create distortion cooefficients
+ cv::Mat distCoeffs = cv::Mat::zeros(8, 1, CV_64FC1);
+ // As per OpenCV docs they should be thus: k1, k2, p1, p2, k3, k4, k5, k6
+ distCoeffs.at<double>(0, 0) = 0; // Radial first order
+ distCoeffs.at<double>(1, 0) = iCameraInfo.radialDistortionSecondOrder; // Radial second order
+ distCoeffs.at<double>(2, 0) = 0; // Tangential first order
+ distCoeffs.at<double>(3, 0) = 0; // Tangential second order
+ distCoeffs.at<double>(4, 0) = 0; // Radial third order
+ distCoeffs.at<double>(5, 0) = iCameraInfo.radialDistortionFourthOrder; // Radial fourth order
+ distCoeffs.at<double>(6, 0) = 0; // Radial fith order
+ distCoeffs.at<double>(7, 0) = iCameraInfo.radialDistortionSixthOrder; // Radial sixth order
+
+ // Define our solution arrays
+ // They will receive up to 4 solutions for our P3P problem
+
+
+ // TODO: try SOLVEPNP_AP3P too
+ iAngles.clear();
+ iBestSolutionIndex = -1;
+ int solutionCount = cv::solveP3P(objectPoints, trackedPoints, cameraMatrix, distCoeffs, iRotations, iTranslations, cv::SOLVEPNP_P3P);
+
+ if (solutionCount > 0)
{
- std::cout << "Translation:\n";
- std::cout << iTranslations.at(i);
- std::cout << "\n";
- std::cout << "Rotation:\n";
- //std::cout << rvecs.at(i);
- cv::Mat rotationCameraMatrix;
- cv::Rodrigues(iRotations[i], rotationCameraMatrix);
- cv::Vec3d angles;
- getEulerAngles(rotationCameraMatrix,angles);
- iAngles.push_back(angles);
-
- // Check if pitch is closest to zero
- int absolutePitch = std::abs(angles[0]);
- if (minPitch > absolutePitch)
+ std::cout << "Solution count: " << solutionCount << "\n";
+ int minPitch = std::numeric_limits<int>::max();
+ // Find the solution we want
+ for (int i = 0; i < solutionCount; i++)
{
- minPitch = absolutePitch;
- iBestSolutionIndex = i;
+ std::cout << "Translation:\n";
+ std::cout << iTranslations.at(i);
+ std::cout << "\n";
+ std::cout << "Rotation:\n";
+ //std::cout << rvecs.at(i);
+ cv::Mat rotationCameraMatrix;
+ cv::Rodrigues(iRotations[i], rotationCameraMatrix);
+ cv::Vec3d angles;
+ getEulerAngles(rotationCameraMatrix, angles);
+ iAngles.push_back(angles);
+
+ // Check if pitch is closest to zero
+ int absolutePitch = std::abs(angles[0]);
+ if (minPitch > absolutePitch)
+ {
+ minPitch = absolutePitch;
+ iBestSolutionIndex = i;
+ }
+
+ //cv::Vec3f angles=EulerAngles(quaternion);
+ std::cout << angles;
+ std::cout << "\n";
}
- //cv::Vec3f angles=EulerAngles(quaternion);
- std::cout << angles;
std::cout << "\n";
+
}
- std::cout << "\n";
-
}
- }
+ // Send solution data back to main thread
+ QMutexLocker l2(&data_lock);
+ if (iBestSolutionIndex != -1)
+ {
+ iBestAngles = iAngles[iBestSolutionIndex];
+ iBestTranslation = iTranslations[iBestSolutionIndex];
+ }
- // Send solution data back to main thread
- QMutexLocker l2(&data_lock);
- if (iBestSolutionIndex != -1)
- {
- iBestAngles = iAngles[iBestSolutionIndex];
- iBestTranslation = iTranslations[iBestSolutionIndex];
}
- }
-
- if (preview_visible)
- {
- if (topPointIndex != -1)
+ if (preview_visible)
{
- // Render a cross to indicate which point is the head
- iPreview.draw_head_center(iPoints[topPointIndex][0], iPoints[topPointIndex][1]);
- }
-
- widget->update_image(iPreview.get_bitmap());
+ if (topPointIndex != -1)
+ {
+ // Render a cross to indicate which point is the head
+ iPreview.draw_head_center(iPoints[topPointIndex][0], iPoints[topPointIndex][1]);
+ }
- auto [ w, h ] = widget->preview_size();
- if (w != preview_width || h != preview_height)
- {
- // Resize preivew if widget size has changed
- preview_width = w; preview_height = h;
- iPreview = Preview(w, h);
+ widget->update_image(iPreview.get_bitmap());
+
+ auto[w, h] = widget->preview_size();
+ if (w != preview_width || h != preview_height)
+ {
+ // Resize preivew if widget size has changed
+ preview_width = w; preview_height = h;
+ iPreview = Preview(w, h);
+ }
}
}
}
}
-}
-bool EasyTracker::maybe_reopen_camera()
-{
- QMutexLocker l(&camera_mtx);
+ bool Tracker::maybe_reopen_camera()
+ {
+ QMutexLocker l(&camera_mtx);
- return camera->start(iCameraInfo);
-}
+ return camera->start(iCameraInfo);
+ }
-void EasyTracker::set_fov(int value)
-{
- QMutexLocker l(&camera_mtx);
+ void Tracker::set_fov(int value)
+ {
+ QMutexLocker l(&camera_mtx);
-}
+ }
-module_status EasyTracker::start_tracker(QFrame* video_frame)
-{
- //video_frame->setAttribute(Qt::WA_NativeWindow);
+ module_status Tracker::start_tracker(QFrame* video_frame)
+ {
+ //video_frame->setAttribute(Qt::WA_NativeWindow);
- widget = std::make_unique<video_widget>(video_frame);
- layout = std::make_unique<QHBoxLayout>(video_frame);
- layout->setContentsMargins(0, 0, 0, 0);
- layout->addWidget(widget.get());
- video_frame->setLayout(layout.get());
- //video_widget->resize(video_frame->width(), video_frame->height());
- video_frame->show();
+ widget = std::make_unique<video_widget>(video_frame);
+ layout = std::make_unique<QHBoxLayout>(video_frame);
+ layout->setContentsMargins(0, 0, 0, 0);
+ layout->addWidget(widget.get());
+ video_frame->setLayout(layout.get());
+ //video_widget->resize(video_frame->width(), video_frame->height());
+ video_frame->show();
- // Create our camera
- camera = video::make_camera(s.camera_name);
+ // Create our camera
+ camera = video::make_camera(s.camera_name);
- start(QThread::HighPriority);
+ start(QThread::HighPriority);
- return {};
-}
+ return {};
+ }
-void EasyTracker::data(double *data)
-{
- if (ever_success.load(std::memory_order_relaxed))
+ void Tracker::data(double *data)
{
- // Get data back from tracker thread
- QMutexLocker l(&data_lock);
- data[Yaw] = iBestAngles[1];
- data[Pitch] = iBestAngles[0];
- data[Roll] = iBestAngles[2];
- data[TX] = iBestTranslation[0];
- data[TY] = iBestTranslation[1];
- data[TZ] = iBestTranslation[2];
+ if (ever_success.load(std::memory_order_relaxed))
+ {
+ // Get data back from tracker thread
+ QMutexLocker l(&data_lock);
+ data[Yaw] = iBestAngles[1];
+ data[Pitch] = iBestAngles[0];
+ data[Roll] = iBestAngles[2];
+ data[TX] = iBestTranslation[0];
+ data[TY] = iBestTranslation[1];
+ data[TZ] = iBestTranslation[2];
+ }
}
-}
-bool EasyTracker::center()
-{
- QMutexLocker l(&center_lock);
- //TODO: Do we need to do anything there?
- return false;
-}
+ bool Tracker::center()
+ {
+ QMutexLocker l(&center_lock);
+ //TODO: Do we need to do anything there?
+ return false;
+ }
-int EasyTracker::get_n_points()
-{
- return (int)point_count.load(std::memory_order_relaxed);
-}
+ int Tracker::get_n_points()
+ {
+ return (int)point_count.load(std::memory_order_relaxed);
+ }
+}
diff --git a/tracker-easy/tracker-easy.h b/tracker-easy/tracker-easy.h
index 3055299b..341d676b 100644
--- a/tracker-easy/tracker-easy.h
+++ b/tracker-easy/tracker-easy.h
@@ -25,66 +25,70 @@
#include <QMutex>
#include <QLayout>
+namespace EasyTracker
+{
-class EasyTrackerDialog;
+ static const QString KModuleName = "tracker-easy";
-using namespace numeric_types;
+ class Dialog;
-struct EasyTracker : QThread, ITracker
-{
- friend class EasyTrackerDialog;
+ using namespace numeric_types;
+
+ struct Tracker : QThread, ITracker
+ {
+ friend class Dialog;
- template<typename t> using pointer = pt_pointer<t>;
+ template<typename t> using pointer = pt_pointer<t>;
- explicit EasyTracker(pointer<IEasyTrackerTraits> const& pt_runtime_traits);
- ~EasyTracker() override;
- module_status start_tracker(QFrame* parent_window) override;
- void data(double* data) override;
- bool center() override;
+ explicit Tracker();
+ ~Tracker() override;
+ module_status start_tracker(QFrame* parent_window) override;
+ void data(double* data) override;
+ bool center() override;
- int get_n_points();
+ int get_n_points();
-private:
- void run() override;
+ private:
+ void run() override;
- bool maybe_reopen_camera();
- void set_fov(int value);
+ bool maybe_reopen_camera();
+ void set_fov(int value);
- pointer<IEasyTrackerTraits> traits;
+ QMutex camera_mtx;
- QMutex camera_mtx;
+ pt_settings s;
- pt_settings s;
+ std::unique_ptr<QLayout> layout;
+ std::vector<vec2> iPoints;
- std::unique_ptr<QLayout> layout;
- std::vector<vec2> iPoints;
+ int preview_width = 320, preview_height = 240;
- int preview_width = 320, preview_height = 240;
+ std::unique_ptr<IPointExtractor> point_extractor;
+ std::unique_ptr<video::impl::camera> camera;
+ video::impl::camera::info iCameraInfo;
+ pointer<video_widget> widget;
- pointer<IPointExtractor> point_extractor;
- std::unique_ptr<video::impl::camera> camera;
- video::impl::camera::info iCameraInfo;
- pointer<video_widget> widget;
+ video::frame iFrame;
+ cv::Mat iMatFrame;
+ Preview iPreview;
- video::frame iFrame;
- cv::Mat iMatFrame;
- Preview iPreview;
+ std::atomic<unsigned> point_count{ 0 };
+ std::atomic<bool> ever_success = false;
+ mutable QMutex center_lock, data_lock;
- std::atomic<unsigned> point_count { 0 };
- std::atomic<bool> ever_success = false;
- mutable QMutex center_lock, data_lock;
+ // Translation solutions
+ std::vector<cv::Mat> iTranslations;
+ // Rotation solutions
+ std::vector<cv::Mat> iRotations;
+ // Angle solutions, pitch, yaw, roll, in this order
+ std::vector<cv::Vec3d> iAngles;
+ // The index of our best solution in the above arrays
+ int iBestSolutionIndex = -1;
+ // Best translation
+ cv::Vec3d iBestTranslation;
+ // Best angles
+ cv::Vec3d iBestAngles;
+ };
- // Translation solutions
- std::vector<cv::Mat> iTranslations;
- // Rotation solutions
- std::vector<cv::Mat> iRotations;
- // Angle solutions, pitch, yaw, roll, in this order
- std::vector<cv::Vec3d> iAngles;
- // The index of our best solution in the above arrays
- int iBestSolutionIndex = -1;
- // Best translation
- cv::Vec3d iBestTranslation;
- // Best angles
- cv::Vec3d iBestAngles;
-};
+}