summaryrefslogtreecommitdiffhomepage
path: root/tracker-easy
diff options
context:
space:
mode:
Diffstat (limited to 'tracker-easy')
-rw-r--r--tracker-easy/lang/nl_NL.ts98
-rw-r--r--tracker-easy/lang/ru_RU.ts143
-rw-r--r--tracker-easy/lang/stub.ts98
-rw-r--r--tracker-easy/lang/zh_CN.ts138
-rw-r--r--tracker-easy/module.cpp3
-rw-r--r--tracker-easy/point-extractor.cpp23
-rw-r--r--tracker-easy/point-extractor.h15
-rw-r--r--tracker-easy/preview.cpp10
-rw-r--r--tracker-easy/preview.h2
-rw-r--r--tracker-easy/settings.h30
-rw-r--r--tracker-easy/tracker-easy-dialog.cpp164
-rw-r--r--tracker-easy/tracker-easy-dialog.h9
-rw-r--r--tracker-easy/tracker-easy-settings.ui1261
-rw-r--r--tracker-easy/tracker-easy.cpp599
-rw-r--r--tracker-easy/tracker-easy.h38
15 files changed, 1190 insertions, 1441 deletions
diff --git a/tracker-easy/lang/nl_NL.ts b/tracker-easy/lang/nl_NL.ts
index 22a99106..9c4e1843 100644
--- a/tracker-easy/lang/nl_NL.ts
+++ b/tracker-easy/lang/nl_NL.ts
@@ -2,36 +2,9 @@
<!DOCTYPE TS>
<TS version="2.1" language="nl_NL">
<context>
- <name>EasyTracker::Dialog</name>
- <message>
- <source>%1 yaw samples. Yaw more to %2 samples for stable calibration.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source>%1 pitch samples. Pitch more to %2 samples for stable calibration.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source>%1 samples. Over %2, good!</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source>Stop calibration</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source>Start calibration</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source>Tracker offline</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
<name>EasyTracker::Metadata</name>
<message>
- <source>Easy Tracker 0.1</source>
+ <source>Easy Tracker 1.0</source>
<translation type="unfinished"></translation>
</message>
</context>
@@ -118,140 +91,139 @@
<translation type="unfinished"></translation>
</message>
<message>
- <source>Clip</source>
+ <source> mm</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Model Dimensions</source>
+ <source>About</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source> mm</source>
+ <source>Debug (full size preview)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Side</source>
+ <source>Deadzone</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Front</source>
+ <source>Size in pixels of half the edge defining deadzone squares around tracked points</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Cap</source>
+ <source>Perspective-N-Point solver</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Custom</source>
+ <source>Make sure you pick a solver supporting the number of marker you are using. For three points detection use either P3P or AP3P.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>z:</source>
+ <source>P3P</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>x:</source>
+ <source>ITERATIVE</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Location of the two remaining model points&lt;br/&gt;with respect to the reference point in default pose&lt;/p&gt;&lt;p&gt;Use any units you want, not necessarily centimeters.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <source>EPNP</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>y:</source>
+ <source>DLS</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:16pt;&quot;&gt;P&lt;/span&gt;&lt;span style=&quot; font-size:16pt; vertical-align:sub;&quot;&gt;3&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <source>UPNP</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:16pt;&quot;&gt;P&lt;/span&gt;&lt;span style=&quot; font-size:16pt; vertical-align:sub;&quot;&gt;2&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <source>AP3P</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Model position</source>
+ <source>Tracker</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Use only yaw and pitch while calibrating.
-Don&apos;t roll or change position.</source>
+ <source>Settings</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Start calibration</source>
+ <source>Top Right</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>About</source>
+ <source>Top</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Status</source>
+ <source>Top Left</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Extracted Points:</source>
+ <source>Left</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Camera Info:</source>
+ <source>Vertex count</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Debug (full size preview)</source>
+ <source>Three vertices</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Deadzone</source>
+ <source>Four vertices</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Easy Tracker&lt;br/&gt;Version 0.1&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;by Stéphane Lenclud&lt;/span&gt;&lt;/p&gt;&lt;p&gt;See &lt;a href=&quot;https://github.com/opentrack/opentrack/wiki/Easy-Tracker&quot;&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline; color:#9999AA;&quot;&gt;documentation on GitHub&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <source>Five vertices</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Size in pixels of half the edge defining deadzone squares around tracked points</source>
+ <source>Center</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Perspective-N-Point solver</source>
+ <source>Right</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Make sure you pick a solver supporting the number of marker you are using. For three points detection use either P3P or AP3P.</source>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;X&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>P3P</source>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Y&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>ITERATIVE</source>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Z&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>EPNP</source>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Easy Tracker&lt;br/&gt;Version 1.0&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;by Stéphane Lenclud&lt;/span&gt;&lt;/p&gt;&lt;p&gt;See &lt;a href=&quot;https://github.com/opentrack/opentrack/wiki/Easy-Tracker&quot;&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline; color:#9999aa;&quot;&gt;documentation on GitHub&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>DLS</source>
+ <source>Auto center</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>UPNP</source>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Use P3P or AP3P for three and four points setup. Use EPNP or ITERATIVE for five points setup. Inconsistent configuration will result in undefined behavior.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>AP3P</source>
+ <source>Auto center timeout</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Tracker</source>
+ <source>If no valid pose can be determined after that much time the center pose will be used.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Settings</source>
+ <source> ms</source>
<translation type="unfinished"></translation>
</message>
</context>
diff --git a/tracker-easy/lang/ru_RU.ts b/tracker-easy/lang/ru_RU.ts
index d45c89d1..6499415f 100644
--- a/tracker-easy/lang/ru_RU.ts
+++ b/tracker-easy/lang/ru_RU.ts
@@ -2,36 +2,9 @@
<!DOCTYPE TS>
<TS version="2.1" language="ru_RU">
<context>
- <name>EasyTracker::Dialog</name>
- <message>
- <source>%1 yaw samples. Yaw more to %2 samples for stable calibration.</source>
- <translation type="unfinished">По оси YAW выполнено: %1 замер(а/ов). Для стабильного результата необходимо не меньше %2</translation>
- </message>
- <message>
- <source>%1 pitch samples. Pitch more to %2 samples for stable calibration.</source>
- <translation type="unfinished">По оси Pitch выполнено: %1 замер(а/ов). Для стабильного результата необходимо не меньше %2</translation>
- </message>
- <message>
- <source>%1 samples. Over %2, good!</source>
- <translation type="unfinished">Получено %1 образца(-ов). Больше %2, отлично!!</translation>
- </message>
- <message>
- <source>Stop calibration</source>
- <translation type="unfinished">Остановить калибровку</translation>
- </message>
- <message>
- <source>Start calibration</source>
- <translation type="unfinished">Начать калибровку</translation>
- </message>
- <message>
- <source>Tracker offline</source>
- <translation type="unfinished">Отслеживание отключено</translation>
- </message>
-</context>
-<context>
<name>EasyTracker::Metadata</name>
<message>
- <source>Easy Tracker 0.1</source>
+ <source>Easy Tracker 1.0</source>
<translation type="unfinished"></translation>
</message>
</context>
@@ -118,145 +91,139 @@
<translation>Модель</translation>
</message>
<message>
- <source>Clip</source>
- <translation>Клипса</translation>
+ <source> mm</source>
+ <translation> мм</translation>
</message>
<message>
- <source>Model Dimensions</source>
- <translation>Размеры модели</translation>
+ <source>About</source>
+ <translation>О программе</translation>
</message>
<message>
- <source> mm</source>
- <translation> мм</translation>
+ <source>Debug (full size preview)</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>Side</source>
- <translation>Сбоку</translation>
+ <source>Deadzone</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>Front</source>
- <translation>Спереди</translation>
+ <source>Size in pixels of half the edge defining deadzone squares around tracked points</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>Cap</source>
- <translation>Кепка</translation>
+ <source>Perspective-N-Point solver</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>Custom</source>
- <translation>Свой</translation>
+ <source>Make sure you pick a solver supporting the number of marker you are using. For three points detection use either P3P or AP3P.</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>z:</source>
- <translation></translation>
+ <source>P3P</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>x:</source>
- <translation></translation>
+ <source>ITERATIVE</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Location of the two remaining model points&lt;br/&gt;with respect to the reference point in default pose&lt;/p&gt;&lt;p&gt;Use any units you want, not necessarily centimeters.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
- <translatorcomment>Расположение двух оставшихся точек модели относительно опорной точки в стандартной позе. Возможно исп-ть любые единицы измерения, не обязательно сантиметры.</translatorcomment>
- <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt; Расположение двух оставшихся точек модели&lt;br/&gt;относительно опорной точки в стандартной позе. &lt;/p&gt;&lt;p&gt;Возможно использовать любые единицы измерения.&lt;/p&gt;&lt;/body&gt;&lt;/html</translation>
+ <source>EPNP</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>y:</source>
- <translation></translation>
+ <source>DLS</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:16pt;&quot;&gt;P&lt;/span&gt;&lt;span style=&quot; font-size:16pt; vertical-align:sub;&quot;&gt;3&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
- <translation></translation>
+ <source>UPNP</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:16pt;&quot;&gt;P&lt;/span&gt;&lt;span style=&quot; font-size:16pt; vertical-align:sub;&quot;&gt;2&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
- <translation></translation>
+ <source>AP3P</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>Model position</source>
- <translation>Положение модели</translation>
+ <source>Tracker</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>Use only yaw and pitch while calibrating.
-Don&apos;t roll or change position.</source>
- <translation>Во время калибровки
-используйте только оси
-YAW и PITCH.
-Не используйте оси
-ROLL или X/Y-смещения.</translation>
+ <source>Settings</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>Start calibration</source>
- <translation>Начать калибровку</translation>
+ <source>Top Right</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>About</source>
- <translation>О программе</translation>
+ <source>Top</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>Status</source>
- <translation>Статус</translation>
+ <source>Top Left</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>Extracted Points:</source>
- <translation>Извлечено точек:</translation>
+ <source>Left</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>Camera Info:</source>
- <translation>Параметры камеры:</translation>
+ <source>Vertex count</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>Debug (full size preview)</source>
+ <source>Three vertices</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Deadzone</source>
+ <source>Four vertices</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Easy Tracker&lt;br/&gt;Version 0.1&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;by Stéphane Lenclud&lt;/span&gt;&lt;/p&gt;&lt;p&gt;See &lt;a href=&quot;https://github.com/opentrack/opentrack/wiki/Easy-Tracker&quot;&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline; color:#9999AA;&quot;&gt;documentation on GitHub&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <source>Five vertices</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Size in pixels of half the edge defining deadzone squares around tracked points</source>
+ <source>Center</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Perspective-N-Point solver</source>
+ <source>Right</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Make sure you pick a solver supporting the number of marker you are using. For three points detection use either P3P or AP3P.</source>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;X&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>P3P</source>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Y&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>ITERATIVE</source>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Z&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>EPNP</source>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Easy Tracker&lt;br/&gt;Version 1.0&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;by Stéphane Lenclud&lt;/span&gt;&lt;/p&gt;&lt;p&gt;See &lt;a href=&quot;https://github.com/opentrack/opentrack/wiki/Easy-Tracker&quot;&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline; color:#9999aa;&quot;&gt;documentation on GitHub&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>DLS</source>
+ <source>Auto center</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>UPNP</source>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Use P3P or AP3P for three and four points setup. Use EPNP or ITERATIVE for five points setup. Inconsistent configuration will result in undefined behavior.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>AP3P</source>
+ <source>Auto center timeout</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Tracker</source>
+ <source>If no valid pose can be determined after that much time the center pose will be used.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Settings</source>
+ <source> ms</source>
<translation type="unfinished"></translation>
</message>
</context>
diff --git a/tracker-easy/lang/stub.ts b/tracker-easy/lang/stub.ts
index 1b58a8f4..7b6facec 100644
--- a/tracker-easy/lang/stub.ts
+++ b/tracker-easy/lang/stub.ts
@@ -2,36 +2,9 @@
<!DOCTYPE TS>
<TS version="2.1">
<context>
- <name>EasyTracker::Dialog</name>
- <message>
- <source>%1 yaw samples. Yaw more to %2 samples for stable calibration.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source>%1 pitch samples. Pitch more to %2 samples for stable calibration.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source>%1 samples. Over %2, good!</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source>Stop calibration</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source>Start calibration</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source>Tracker offline</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
<name>EasyTracker::Metadata</name>
<message>
- <source>Easy Tracker 0.1</source>
+ <source>Easy Tracker 1.0</source>
<translation type="unfinished"></translation>
</message>
</context>
@@ -118,140 +91,139 @@
<translation type="unfinished"></translation>
</message>
<message>
- <source>Clip</source>
+ <source> mm</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Model Dimensions</source>
+ <source>About</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source> mm</source>
+ <source>Debug (full size preview)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Side</source>
+ <source>Deadzone</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Front</source>
+ <source>Size in pixels of half the edge defining deadzone squares around tracked points</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Cap</source>
+ <source>Perspective-N-Point solver</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Custom</source>
+ <source>Make sure you pick a solver supporting the number of marker you are using. For three points detection use either P3P or AP3P.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>z:</source>
+ <source>P3P</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>x:</source>
+ <source>ITERATIVE</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Location of the two remaining model points&lt;br/&gt;with respect to the reference point in default pose&lt;/p&gt;&lt;p&gt;Use any units you want, not necessarily centimeters.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <source>EPNP</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>y:</source>
+ <source>DLS</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:16pt;&quot;&gt;P&lt;/span&gt;&lt;span style=&quot; font-size:16pt; vertical-align:sub;&quot;&gt;3&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <source>UPNP</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:16pt;&quot;&gt;P&lt;/span&gt;&lt;span style=&quot; font-size:16pt; vertical-align:sub;&quot;&gt;2&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <source>AP3P</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Model position</source>
+ <source>Tracker</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Use only yaw and pitch while calibrating.
-Don&apos;t roll or change position.</source>
+ <source>Settings</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Start calibration</source>
+ <source>Top Right</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>About</source>
+ <source>Top</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Status</source>
+ <source>Top Left</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Extracted Points:</source>
+ <source>Left</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Camera Info:</source>
+ <source>Vertex count</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Debug (full size preview)</source>
+ <source>Three vertices</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Deadzone</source>
+ <source>Four vertices</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Easy Tracker&lt;br/&gt;Version 0.1&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;by Stéphane Lenclud&lt;/span&gt;&lt;/p&gt;&lt;p&gt;See &lt;a href=&quot;https://github.com/opentrack/opentrack/wiki/Easy-Tracker&quot;&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline; color:#9999AA;&quot;&gt;documentation on GitHub&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <source>Five vertices</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Size in pixels of half the edge defining deadzone squares around tracked points</source>
+ <source>Center</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Perspective-N-Point solver</source>
+ <source>Right</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Make sure you pick a solver supporting the number of marker you are using. For three points detection use either P3P or AP3P.</source>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;X&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>P3P</source>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Y&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>ITERATIVE</source>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Z&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>EPNP</source>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Easy Tracker&lt;br/&gt;Version 1.0&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;by Stéphane Lenclud&lt;/span&gt;&lt;/p&gt;&lt;p&gt;See &lt;a href=&quot;https://github.com/opentrack/opentrack/wiki/Easy-Tracker&quot;&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline; color:#9999aa;&quot;&gt;documentation on GitHub&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>DLS</source>
+ <source>Auto center</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>UPNP</source>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Use P3P or AP3P for three and four points setup. Use EPNP or ITERATIVE for five points setup. Inconsistent configuration will result in undefined behavior.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>AP3P</source>
+ <source>Auto center timeout</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Tracker</source>
+ <source>If no valid pose can be determined after that much time the center pose will be used.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Settings</source>
+ <source> ms</source>
<translation type="unfinished"></translation>
</message>
</context>
diff --git a/tracker-easy/lang/zh_CN.ts b/tracker-easy/lang/zh_CN.ts
index d524aaed..bbd8aff1 100644
--- a/tracker-easy/lang/zh_CN.ts
+++ b/tracker-easy/lang/zh_CN.ts
@@ -2,36 +2,9 @@
<!DOCTYPE TS>
<TS version="2.1" language="zh_CN">
<context>
- <name>EasyTracker::Dialog</name>
- <message>
- <source>%1 yaw samples. Yaw more to %2 samples for stable calibration.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source>%1 pitch samples. Pitch more to %2 samples for stable calibration.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source>%1 samples. Over %2, good!</source>
- <translation type="unfinished">%1 样本。%2 正常</translation>
- </message>
- <message>
- <source>Stop calibration</source>
- <translation type="unfinished">停止校准</translation>
- </message>
- <message>
- <source>Start calibration</source>
- <translation type="unfinished">开始校准</translation>
- </message>
- <message>
- <source>Tracker offline</source>
- <translation type="unfinished">跟踪器脱机</translation>
- </message>
-</context>
-<context>
<name>EasyTracker::Metadata</name>
<message>
- <source>Easy Tracker 0.1</source>
+ <source>Easy Tracker 1.0</source>
<translation type="unfinished"></translation>
</message>
</context>
@@ -118,140 +91,139 @@
<translation>点模式</translation>
</message>
<message>
- <source>Clip</source>
- <translation>夹子式</translation>
+ <source> mm</source>
+ <translation> 毫米</translation>
</message>
<message>
- <source>Model Dimensions</source>
- <translation>尺寸</translation>
+ <source>About</source>
+ <translation>关于</translation>
</message>
<message>
- <source> mm</source>
- <translation> 毫米</translation>
+ <source>Debug (full size preview)</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>Side</source>
- <translation>侧面</translation>
+ <source>Deadzone</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>Front</source>
- <translation>正面</translation>
+ <source>Size in pixels of half the edge defining deadzone squares around tracked points</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>Cap</source>
- <translation>帽子式</translation>
+ <source>Perspective-N-Point solver</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>Custom</source>
- <translation>自定义模式</translation>
+ <source>Make sure you pick a solver supporting the number of marker you are using. For three points detection use either P3P or AP3P.</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>z:</source>
- <translation>Z:</translation>
+ <source>P3P</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>x:</source>
- <translation>X:</translation>
+ <source>ITERATIVE</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Location of the two remaining model points&lt;br/&gt;with respect to the reference point in default pose&lt;/p&gt;&lt;p&gt;Use any units you want, not necessarily centimeters.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
- <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;三点中的两点位置是相对第一个点的&lt;/p&gt;&lt;p&gt;单位不一定要用厘米&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ <source>EPNP</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>y:</source>
- <translation>Y:</translation>
+ <source>DLS</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:16pt;&quot;&gt;P&lt;/span&gt;&lt;span style=&quot; font-size:16pt; vertical-align:sub;&quot;&gt;3&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
- <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:16pt;&quot;&gt;P&lt;/span&gt;&lt;span style=&quot; font-size:16pt; vertical-align:sub;&quot;&gt;3&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ <source>UPNP</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:16pt;&quot;&gt;P&lt;/span&gt;&lt;span style=&quot; font-size:16pt; vertical-align:sub;&quot;&gt;2&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
- <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:16pt;&quot;&gt;P&lt;/span&gt;&lt;span style=&quot; font-size:16pt; vertical-align:sub;&quot;&gt;2&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ <source>AP3P</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>Model position</source>
- <translation>姿态空间位置</translation>
+ <source>Tracker</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>Start calibration</source>
- <translation>开始校准</translation>
+ <source>Settings</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>About</source>
- <translation>关于</translation>
+ <source>Top Right</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>Status</source>
- <translation>状态</translation>
+ <source>Top</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>Extracted Points:</source>
- <translation>解析出的点:</translation>
+ <source>Top Left</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>Camera Info:</source>
- <translation>设备信息:</translation>
+ <source>Left</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>Use only yaw and pitch while calibrating.
-Don&apos;t roll or change position.</source>
- <translation>用pitch和yaw校准。不要roll或者变换位置</translation>
+ <source>Vertex count</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>Debug (full size preview)</source>
+ <source>Three vertices</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Deadzone</source>
+ <source>Four vertices</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Easy Tracker&lt;br/&gt;Version 0.1&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;by Stéphane Lenclud&lt;/span&gt;&lt;/p&gt;&lt;p&gt;See &lt;a href=&quot;https://github.com/opentrack/opentrack/wiki/Easy-Tracker&quot;&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline; color:#9999AA;&quot;&gt;documentation on GitHub&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <source>Five vertices</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Size in pixels of half the edge defining deadzone squares around tracked points</source>
+ <source>Center</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Perspective-N-Point solver</source>
+ <source>Right</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Make sure you pick a solver supporting the number of marker you are using. For three points detection use either P3P or AP3P.</source>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;X&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>P3P</source>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Y&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>ITERATIVE</source>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Z&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>EPNP</source>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Easy Tracker&lt;br/&gt;Version 1.0&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;by Stéphane Lenclud&lt;/span&gt;&lt;/p&gt;&lt;p&gt;See &lt;a href=&quot;https://github.com/opentrack/opentrack/wiki/Easy-Tracker&quot;&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline; color:#9999aa;&quot;&gt;documentation on GitHub&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>DLS</source>
+ <source>Auto center</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>UPNP</source>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Use P3P or AP3P for three and four points setup. Use EPNP or ITERATIVE for five points setup. Inconsistent configuration will result in undefined behavior.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>AP3P</source>
+ <source>Auto center timeout</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Tracker</source>
+ <source>If no valid pose can be determined after that much time the center pose will be used.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Settings</source>
+ <source> ms</source>
<translation type="unfinished"></translation>
</message>
</context>
diff --git a/tracker-easy/module.cpp b/tracker-easy/module.cpp
index 9f5461d5..3a9df22b 100644
--- a/tracker-easy/module.cpp
+++ b/tracker-easy/module.cpp
@@ -6,8 +6,7 @@
namespace EasyTracker
{
-
- QString Metadata::name() { return tr("Easy Tracker 0.1"); }
+ QString Metadata::name() { return tr("Easy Tracker 1.0"); }
QIcon Metadata::icon() { return QIcon(":/Resources/easy-tracker-logo.png"); }
}
diff --git a/tracker-easy/point-extractor.cpp b/tracker-easy/point-extractor.cpp
index f17fcde6..4b54fd25 100644
--- a/tracker-easy/point-extractor.cpp
+++ b/tracker-easy/point-extractor.cpp
@@ -29,13 +29,20 @@ using namespace numeric_types;
namespace EasyTracker
{
- PointExtractor::PointExtractor() : s(KModuleName)
+ PointExtractor::PointExtractor() : iSettings(KModuleName)
{
-
+ UpdateSettings();
}
+ ///
+ void PointExtractor::UpdateSettings()
+ {
+ iMinPointSize = iSettings.iMinBlobSize;
+ iMaxPointSize = iSettings.iMaxBlobSize;
+ }
- void PointExtractor::ExtractPoints(const cv::Mat& aFrame, cv::Mat* aPreview, std::vector<cv::Point>& aPoints)
+ ///
+ void PointExtractor::ExtractPoints(const cv::Mat& aFrame, cv::Mat* aPreview, int aNeededPointCount, std::vector<cv::Point>& aPoints)
{
//TODO: Assert if channel size is neither one nor two
// Make sure our frame channel is 8 bit
@@ -108,10 +115,10 @@ namespace EasyTracker
bBox = cv::boundingRect(iContours[i]);
// Make sure bounding box matches our criteria
- 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)
+ if (bBox.width >= iMinPointSize
+ && bBox.height >= iMinPointSize
+ && bBox.width <= iMaxPointSize
+ && bBox.height <= iMaxPointSize)
{
// Do a mean shift or cam shift, it's not bringing much though
//cv::CamShift(iFrameGray, bBox, cv::TermCriteria(cv::TermCriteria::EPS + cv::TermCriteria::MAX_ITER, 10, 1));
@@ -133,7 +140,7 @@ namespace EasyTracker
// Typically noise comming from zippers and metal parts on your clothing.
// With a cap tracker it also successfully discards noise from glasses.
// However it may not work as good with a clip user wearing glasses.
- while (aPoints.size() > KPointCount) // Until we have no more than three points
+ while (aPoints.size() > aNeededPointCount) // Until we have no more than three points
{
int maxY = 0;
unsigned index = (unsigned)-1;
diff --git a/tracker-easy/point-extractor.h b/tracker-easy/point-extractor.h
index 3c65b193..f275769d 100644
--- a/tracker-easy/point-extractor.h
+++ b/tracker-easy/point-extractor.h
@@ -17,19 +17,18 @@
namespace EasyTracker
{
-
- const int KPointCount = 3;
-
class PointExtractor
{
public:
PointExtractor();
// extracts points from frame and draws some processing info into frame, if draw_output is set
// dt: time since last call in seconds
- void ExtractPoints(const cv::Mat& aFrame, cv::Mat* aPreview, std::vector<cv::Point>& aPoints);
-
+ void ExtractPoints(const cv::Mat& aFrame, cv::Mat* aPreview, int aNeededPointCount, std::vector<cv::Point>& aPoints);
+
+ void UpdateSettings();
+
// Settings
- Settings s;
+ Settings iSettings;
// Our frame with a channel size of 8 bits
cv::Mat iFrameChannelSizeOne;
// Our frame with a single 8 bits channel
@@ -37,6 +36,10 @@ namespace EasyTracker
//
std::vector<std::vector<cv::Point> > iContours;
+ // Take a copy of settings to avoid dead lock
+ int iMinPointSize;
+ int iMaxPointSize;
+
};
}
diff --git a/tracker-easy/preview.cpp b/tracker-easy/preview.cpp
index 4d6b7c61..218fca43 100644
--- a/tracker-easy/preview.cpp
+++ b/tracker-easy/preview.cpp
@@ -105,19 +105,17 @@ namespace EasyTracker
cv::putText(iFrameRgb, aString, cv::Point(4,iFrameRgb.size().height-4), cv::FONT_HERSHEY_PLAIN, 2, cv::Scalar(0, 255, 0),2);
}
- void Preview::DrawCross(cv::Point aPoint)
+ void Preview::DrawCross(const cv::Point& aPoint, const cv::Scalar& aColor)
{
- constexpr int len = 9;
-
- static const cv::Scalar color(0, 255, 255);
+ constexpr int len = 9;
cv::line(iFrameRgb,
cv::Point(aPoint.x - len, aPoint.y),
cv::Point(aPoint.x + len, aPoint.y),
- color, 2);
+ aColor, 2);
cv::line(iFrameRgb,
cv::Point(aPoint.x, aPoint.y - len),
cv::Point(aPoint.x, aPoint.y + len),
- color, 2);
+ aColor, 2);
}
void Preview::ensure_size(cv::Mat& frame, int w, int h, int type)
diff --git a/tracker-easy/preview.h b/tracker-easy/preview.h
index 74ef89aa..d5cc8c30 100644
--- a/tracker-easy/preview.h
+++ b/tracker-easy/preview.h
@@ -21,7 +21,7 @@ namespace EasyTracker
Preview& operator=(const cv::Mat& frame);
QImage get_bitmap();
- void DrawCross(cv::Point aPoint);
+ void DrawCross(const cv::Point& aPoint, const cv::Scalar& aColor);
void DrawInfo(const std::string& aString);
operator cv::Mat&() { return iFrameResized; }
diff --git a/tracker-easy/settings.h b/tracker-easy/settings.h
index b4c14967..b0f14417 100644
--- a/tracker-easy/settings.h
+++ b/tracker-easy/settings.h
@@ -23,30 +23,30 @@ namespace EasyTracker {
value<int> cam_res_x{ b, "camera-res-width", 640 },
cam_res_y{ b, "camera-res-height", 480 },
cam_fps{ b, "camera-fps", 30 };
- value<double> min_point_size{ b, "min-point-size", 2.5 },
- max_point_size{ b, "max-point-size", 50 };
+ value<int> iMinBlobSize{ b, "iMinBlobSize", 4 }, iMaxBlobSize{ b, "iMaxBlobSize", 15 };
value<int> DeadzoneRectHalfEdgeSize { b, "deadzone-rect-half-edge-size", 1 };
- value<int> m01_x{ b, "m_01-x", 0 }, m01_y{ b, "m_01-y", 0 }, m01_z{ b, "m_01-z", 0 };
- value<int> m02_x{ b, "m_02-x", 0 }, m02_y{ b, "m_02-y", 0 }, m02_z{ b, "m_02-z", 0 };
+ // Type of custom model
+ value<bool> iCustomModelThree{ b, "iCustomModelThree", true };
+ value<bool> iCustomModelFour{ b, "iCustomModelFour", false };
+ value<bool> iCustomModelFive{ b, "iCustomModelFive", false };
- value<int> t_MH_x{ b, "model-centroid-x", 0 },
- t_MH_y{ b, "model-centroid-y", 0 },
- t_MH_z{ b, "model-centroid-z", 0 };
+ // Custom model vertices
+ value<int> iVertexTopX{ b, "iVertexTopX", 0 }, iVertexTopY{ b, "iVertexTopY", 0 }, iVertexTopZ{ b, "iVertexTopZ", 0 };
+ value<int> iVertexRightX{ b, "iVertexRightX", 0 }, iVertexRightY{ b, "iVertexRightY", 0 }, iVertexRightZ{ b, "iVertexRightZ", 0 };
+ value<int> iVertexLeftX{ b, "iVertexLeftX", 0 }, iVertexLeftY{ b, "iVertexLeftY", 0 }, iVertexLeftZ{ b, "iVertexLeftZ", 0 };
+ value<int> iVertexCenterX{ b, "iVertexCenterX", 0 }, iVertexCenterY{ b, "iVertexCenterY", 0 }, iVertexCenterZ{ b, "iVertexCenterZ", 0 };
+ value<int> iVertexTopRightX{ b, "iVertexTopRightX", 0 }, iVertexTopRightY{ b, "iVertexTopRightY", 0 }, iVertexTopRightZ{ b, "iVertexTopRightZ", 0 };
+ value<int> iVertexTopLeftX{ b, "iVertexTopLeftX", 0 }, iVertexTopLeftY{ b, "iVertexTopLeftY", 0 }, iVertexTopLeftZ{ b, "iVertexTopLeftZ", 0 };
- value<int> clip_ty{ b, "clip-ty", 40 },
- clip_tz{ b, "clip-tz", 30 },
- clip_by{ b, "clip-by", 70 },
- clip_bz{ b, "clip-bz", 80 };
- value<int> active_model_panel{ b, "active-model-panel", 0 },
- cap_x{ b, "cap-x", 35 },
- cap_y{ b, "cap-y", 55 },
- cap_z{ b, "cap-z", 100 };
value<int> fov{ b, "camera-fov", 56 };
value<bool> debug{ b, "debug", false };
+ value<bool> iAutoCenter{ b, "iAutoCenter", true };
+ value<int> iAutoCenterTimeout{ b, "iAutoCenterTimeout", 1000 };
+
value<int> PnpSolver{ b, "pnp-solver", cv::SOLVEPNP_P3P };
diff --git a/tracker-easy/tracker-easy-dialog.cpp b/tracker-easy/tracker-easy-dialog.cpp
index 411639d5..4a49e194 100644
--- a/tracker-easy/tracker-easy-dialog.cpp
+++ b/tracker-easy/tracker-easy-dialog.cpp
@@ -26,9 +26,7 @@ namespace EasyTracker
Dialog::Dialog() :
s(KModuleName),
- tracker(nullptr),
- timer(this),
- trans_calib(1, 2)
+ tracker(nullptr)
{
init_resources();
@@ -42,39 +40,41 @@ namespace EasyTracker
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.iMinBlobSize, ui.mindiam_spin);
+ tie_setting(s.iMaxBlobSize, ui.maxdiam_spin);
tie_setting(s.DeadzoneRectHalfEdgeSize, ui.spinDeadzone);
- 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.iVertexTopX, ui.iSpinVertexTopX);
+ tie_setting(s.iVertexTopY, ui.iSpinVertexTopY);
+ tie_setting(s.iVertexTopZ, ui.iSpinVertexTopZ);
- 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.iVertexRightX, ui.iSpinVertexRightX);
+ tie_setting(s.iVertexRightY, ui.iSpinVertexRightY);
+ tie_setting(s.iVertexRightZ, ui.iSpinVertexRightZ);
- 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.iVertexLeftX, ui.iSpinVertexLeftX);
+ tie_setting(s.iVertexLeftY, ui.iSpinVertexLeftY);
+ tie_setting(s.iVertexLeftZ, ui.iSpinVertexLeftZ);
- 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.iVertexCenterX, ui.iSpinVertexCenterX);
+ tie_setting(s.iVertexCenterY, ui.iSpinVertexCenterY);
+ tie_setting(s.iVertexCenterZ, ui.iSpinVertexCenterZ);
- 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.iVertexTopRightX, ui.iSpinVertexTopRightX);
+ tie_setting(s.iVertexTopRightY, ui.iSpinVertexTopRightY);
+ tie_setting(s.iVertexTopRightZ, ui.iSpinVertexTopRightZ);
- tie_setting(s.fov, ui.fov);
+ tie_setting(s.iVertexTopLeftX, ui.iSpinVertexTopLeftX);
+ tie_setting(s.iVertexTopLeftY, ui.iSpinVertexTopLeftY);
+ tie_setting(s.iVertexTopLeftZ, ui.iSpinVertexTopLeftZ);
- tie_setting(s.active_model_panel, ui.model_tabs);
+ tie_setting(s.fov, ui.fov);
tie_setting(s.debug, ui.debug);
+ tie_setting(s.iAutoCenter, ui.iCheckBoxAutoCenter);
+ tie_setting(s.iAutoCenterTimeout, ui.iSpinBoxAutoCenterTimeout);
- connect(ui.tcalib_button, SIGNAL(toggled(bool)), this, SLOT(startstop_trans_calib(bool)));
connect(ui.buttonBox, SIGNAL(accepted()), this, SLOT(doOK()));
connect(ui.buttonBox, SIGNAL(rejected()), this, SLOT(doCancel()));
@@ -83,102 +83,51 @@ namespace EasyTracker
set_camera_settings_available(ui.camdevice_combo->currentText());
connect(ui.camera_settings, &QPushButton::clicked, this, &Dialog::show_camera_settings);
- connect(&timer, &QTimer::timeout, this, &Dialog::poll_tracker_info_impl);
- timer.setInterval(250);
-
- connect(&calib_timer, &QTimer::timeout, this, &Dialog::trans_calib_step);
- calib_timer.setInterval(35);
+ // Radio Button
+ connect(ui.iRadioButtonCustomModelThree, &QRadioButton::clicked, this, &Dialog::UpdateCustomModelControls);
+ connect(ui.iRadioButtonCustomModelFour, &QRadioButton::clicked, this, &Dialog::UpdateCustomModelControls);
+ connect(ui.iRadioButtonCustomModelFive, &QRadioButton::clicked, this, &Dialog::UpdateCustomModelControls);
- poll_tracker_info_impl();
-
- connect(this, &Dialog::poll_tracker_info, this, &Dialog::poll_tracker_info_impl, Qt::DirectConnection);
+ tie_setting(s.iCustomModelThree, ui.iRadioButtonCustomModelThree);
+ tie_setting(s.iCustomModelFour, ui.iRadioButtonCustomModelFour);
+ tie_setting(s.iCustomModelFive, ui.iRadioButtonCustomModelFive);
for (unsigned k = 0; k < cv::SOLVEPNP_MAX_COUNT; k++)
+ {
ui.comboBoxSolvers->setItemData(k, k);
+ }
+
tie_setting(s.PnpSolver, ui.comboBoxSolvers);
+ UpdateCustomModelControls();
}
-
- void Dialog::startstop_trans_calib(bool start)
+ void Dialog::UpdateCustomModelControls()
{
- 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
+ if (ui.iRadioButtonCustomModelThree->isChecked())
{
- calib_timer.stop();
- qDebug() << "pt: stopping translation calibration";
- {
- 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.iGroupBoxCenter->hide();
+ ui.iGroupBoxTopRight->hide();
+ ui.iGroupBoxTopLeft->hide();
}
- 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 Dialog::poll_tracker_info_impl()
- {
- //SL: sort this out
- /*
- pt_camera_info info;
- if (tracker && tracker->get_cam_info(info))
+ else if (ui.iRadioButtonCustomModelFour->isChecked())
{
- 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));
+ ui.iGroupBoxCenter->show();
+ ui.iGroupBoxTopRight->hide();
+ ui.iGroupBoxTopLeft->hide();
}
- else
- */
+ else if (ui.iRadioButtonCustomModelFive->isChecked())
{
- ui.caminfo_label->setText(tr("Tracker offline"));
- ui.pointinfo_label->setText(QString());
+ ui.iGroupBoxCenter->hide();
+ ui.iGroupBoxTopRight->show();
+ ui.iGroupBoxTopLeft->show();
}
+
}
+
void Dialog::set_camera_settings_available(const QString& /* camera_name */)
{
ui.camera_settings->setEnabled(true);
@@ -195,12 +144,7 @@ namespace EasyTracker
(void)video::show_dialog(s.camera_name);
}
- void Dialog::trans_calib_step()
- {
- QMutexLocker l(&calibrator_mutex);
- // TODO: Do we still need that function
- }
-
+
void Dialog::save()
{
s.b->save();
@@ -220,16 +164,10 @@ namespace EasyTracker
void Dialog::register_tracker(ITracker *t)
{
tracker = static_cast<Tracker*>(t);
- ui.tcalib_button->setEnabled(true);
- poll_tracker_info();
- timer.start();
}
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 768eaa21..7eb1ffb1 100644
--- a/tracker-easy/tracker-easy-dialog.h
+++ b/tracker-easy/tracker-easy-dialog.h
@@ -26,13 +26,13 @@ namespace EasyTracker
void register_tracker(ITracker *tracker) override;
void unregister_tracker() override;
void save();
+ private:
+ void UpdateCustomModelControls();
+
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:
@@ -41,9 +41,6 @@ namespace EasyTracker
Settings s;
Tracker* tracker;
- QTimer timer, calib_timer;
- TranslationCalibrator trans_calib;
- QMutex calibrator_mutex;
Ui::UICPTClientControls ui;
};
diff --git a/tracker-easy/tracker-easy-settings.ui b/tracker-easy/tracker-easy-settings.ui
index 2ec56a04..451b3e54 100644
--- a/tracker-easy/tracker-easy-settings.ui
+++ b/tracker-easy/tracker-easy-settings.ui
@@ -9,8 +9,8 @@
<rect>
<x>0</x>
<y>0</y>
- <width>418</width>
- <height>724</height>
+ <width>465</width>
+ <height>764</height>
</rect>
</property>
<property name="sizePolicy">
@@ -36,71 +36,17 @@
<property name="sizeConstraint">
<enum>QLayout::SetFixedSize</enum>
</property>
- <item row="1" column="0" alignment="Qt::AlignVCenter">
- <widget class="QGroupBox" name="groupBox_5">
+ <item row="7" column="0">
+ <widget class="QDialogButtonBox" name="buttonBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
- <property name="title">
- <string>Status</string>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
- <layout class="QGridLayout" name="gridLayout_10">
- <item row="1" column="0">
- <widget class="QLabel" name="label_3">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="text">
- <string>Extracted Points:</string>
- </property>
- </widget>
- </item>
- <item row="0" column="0">
- <widget class="QLabel" name="label_38">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="text">
- <string>Camera Info:</string>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QLabel" name="pointinfo_label">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Minimum" vsizetype="Maximum">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QLabel" name="caminfo_label">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Minimum" vsizetype="Maximum">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
</widget>
</item>
<item row="0" column="0">
@@ -343,8 +289,21 @@
<property name="title">
<string>Settings</string>
</property>
- <layout class="QGridLayout" name="gridLayout_7">
- <item row="2" column="0">
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_5">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Debug (full size preview)</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0">
<widget class="QLabel" name="label_7">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
@@ -360,24 +319,24 @@
</property>
</widget>
</item>
- <item row="5" column="0">
- <widget class="QLabel" name="labelDeadzone">
+ <item row="5" column="2">
+ <widget class="QSpinBox" name="mindiam_spin">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
- <property name="text">
- <string>Deadzone</string>
+ <property name="toolTip">
+ <string>Minimum point diameter</string>
</property>
- <property name="buddy">
- <cstring>maxdiam_spin</cstring>
+ <property name="suffix">
+ <string> px</string>
</property>
</widget>
</item>
- <item row="3" column="0">
- <widget class="QLabel" name="label_8">
+ <item row="2" column="2">
+ <widget class="QCheckBox" name="iCheckBoxAutoCenter">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
@@ -385,15 +344,25 @@
</sizepolicy>
</property>
<property name="text">
- <string>Max size</string>
+ <string/>
</property>
- <property name="buddy">
- <cstring>maxdiam_spin</cstring>
+ </widget>
+ </item>
+ <item row="1" column="2">
+ <widget class="QCheckBox" name="debug">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string/>
</property>
</widget>
</item>
- <item row="0" column="0">
- <widget class="QLabel" name="label_5">
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_13">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Maximum">
<horstretch>0</horstretch>
@@ -401,12 +370,12 @@
</sizepolicy>
</property>
<property name="text">
- <string>Debug (full size preview)</string>
+ <string>Auto center</string>
</property>
</widget>
</item>
- <item row="0" column="1">
- <widget class="QCheckBox" name="debug">
+ <item row="6" column="0">
+ <widget class="QLabel" name="label_8">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
@@ -414,11 +383,27 @@
</sizepolicy>
</property>
<property name="text">
- <string/>
+ <string>Max size</string>
</property>
</widget>
</item>
- <item row="1" column="0">
+ <item row="7" column="2">
+ <widget class="QSpinBox" name="spinDeadzone">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="toolTip">
+ <string>Size in pixels of half the edge defining deadzone squares around tracked points</string>
+ </property>
+ <property name="suffix">
+ <string> px</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0">
<widget class="QLabel" name="label_12">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Maximum">
@@ -426,12 +411,15 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
+ <property name="toolTip">
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Use P3P or AP3P for three and four points setup. Use EPNP or ITERATIVE for five points setup. Inconsistent configuration will result in undefined behavior.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
<property name="text">
<string>Perspective-N-Point solver</string>
</property>
</widget>
</item>
- <item row="1" column="1">
+ <item row="4" column="2">
<widget class="QComboBox" name="comboBoxSolvers">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
@@ -477,30 +465,24 @@
</item>
</widget>
</item>
- <item row="2" column="1">
- <widget class="QDoubleSpinBox" name="mindiam_spin">
+ <item row="7" column="0">
+ <widget class="QLabel" name="labelDeadzone">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
- <property name="toolTip">
- <string>Minimum point diameter</string>
- </property>
- <property name="suffix">
- <string> px</string>
- </property>
- <property name="decimals">
- <number>1</number>
+ <property name="text">
+ <string>Deadzone</string>
</property>
- <property name="singleStep">
- <double>0.100000000000000</double>
+ <property name="buddy">
+ <cstring>maxdiam_spin</cstring>
</property>
</widget>
</item>
- <item row="3" column="1">
- <widget class="QDoubleSpinBox" name="maxdiam_spin">
+ <item row="6" column="2">
+ <widget class="QSpinBox" name="maxdiam_spin">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
@@ -513,16 +495,26 @@
<property name="suffix">
<string> px</string>
</property>
- <property name="decimals">
- <number>1</number>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="label_14">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
</property>
- <property name="singleStep">
- <double>0.100000000000000</double>
+ <property name="text">
+ <string>Auto center timeout</string>
+ </property>
+ <property name="buddy">
+ <cstring>mindiam_spin</cstring>
</property>
</widget>
</item>
- <item row="5" column="1">
- <widget class="QSpinBox" name="spinDeadzone">
+ <item row="3" column="2">
+ <widget class="QSpinBox" name="iSpinBoxAutoCenterTimeout">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
@@ -530,10 +522,16 @@
</sizepolicy>
</property>
<property name="toolTip">
- <string>Size in pixels of half the edge defining deadzone squares around tracked points</string>
+ <string>If no valid pose can be determined after that much time the center pose will be used.</string>
</property>
<property name="suffix">
- <string> px</string>
+ <string> ms</string>
+ </property>
+ <property name="maximum">
+ <number>3600000</number>
+ </property>
+ <property name="singleStep">
+ <number>500</number>
</property>
</widget>
</item>
@@ -546,705 +544,359 @@
<attribute name="title">
<string>Model</string>
</attribute>
- <layout class="QGridLayout" name="gridLayout_3">
- <item row="0" column="0">
- <widget class="QTabWidget" name="model_tabs">
- <property name="enabled">
- <bool>true</bool>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QGroupBox" name="groupBoxCustomModelType">
+ <property name="title">
+ <string>Vertex count</string>
</property>
- <property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QRadioButton" name="iRadioButtonCustomModelThree">
+ <property name="text">
+ <string>Three vertices</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QRadioButton" name="iRadioButtonCustomModelFour">
+ <property name="text">
+ <string>Four vertices</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QRadioButton" name="iRadioButtonCustomModelFive">
+ <property name="text">
+ <string>Five vertices</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string/>
</property>
- <property name="tabShape">
- <enum>QTabWidget::Rounded</enum>
+ <property name="flat">
+ <bool>false</bool>
</property>
- <property name="currentIndex">
- <number>2</number>
+ <layout class="QHBoxLayout" name="horizontalLayout_8">
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;X&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_6">
+ <property name="text">
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Y&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_11">
+ <property name="text">
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Z&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="iGroupBoxTop">
+ <property name="title">
+ <string>Top</string>
</property>
- <property name="usesScrollButtons">
- <bool>false</bool>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <property name="topMargin">
+ <number>9</number>
+ </property>
+ <item>
+ <widget class="QSpinBox" name="iSpinVertexTopX">
+ <property name="suffix">
+ <string> mm</string>
+ </property>
+ <property name="minimum">
+ <number>-65535</number>
+ </property>
+ <property name="maximum">
+ <number>65535</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="iSpinVertexTopY">
+ <property name="suffix">
+ <string> mm</string>
+ </property>
+ <property name="minimum">
+ <number>-65535</number>
+ </property>
+ <property name="maximum">
+ <number>65535</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="iSpinVertexTopZ">
+ <property name="suffix">
+ <string> mm</string>
+ </property>
+ <property name="minimum">
+ <number>-65535</number>
+ </property>
+ <property name="maximum">
+ <number>65535</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="iGroupBoxRight">
+ <property name="title">
+ <string>Right</string>
</property>
- <property name="documentMode">
- <bool>false</bool>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <widget class="QSpinBox" name="iSpinVertexRightX">
+ <property name="suffix">
+ <string> mm</string>
+ </property>
+ <property name="minimum">
+ <number>-65535</number>
+ </property>
+ <property name="maximum">
+ <number>65535</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="iSpinVertexRightY">
+ <property name="suffix">
+ <string> mm</string>
+ </property>
+ <property name="minimum">
+ <number>-65535</number>
+ </property>
+ <property name="maximum">
+ <number>65535</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="iSpinVertexRightZ">
+ <property name="suffix">
+ <string> mm</string>
+ </property>
+ <property name="minimum">
+ <number>-65535</number>
+ </property>
+ <property name="maximum">
+ <number>65535</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="iGroupBoxLeft">
+ <property name="title">
+ <string>Left</string>
</property>
- <property name="tabsClosable">
- <bool>false</bool>
+ <layout class="QHBoxLayout" name="horizontalLayout_4">
+ <item>
+ <widget class="QSpinBox" name="iSpinVertexLeftX">
+ <property name="suffix">
+ <string> mm</string>
+ </property>
+ <property name="minimum">
+ <number>-65535</number>
+ </property>
+ <property name="maximum">
+ <number>65535</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="iSpinVertexLeftY">
+ <property name="suffix">
+ <string> mm</string>
+ </property>
+ <property name="minimum">
+ <number>-65535</number>
+ </property>
+ <property name="maximum">
+ <number>65535</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="iSpinVertexLeftZ">
+ <property name="suffix">
+ <string> mm</string>
+ </property>
+ <property name="minimum">
+ <number>-65535</number>
+ </property>
+ <property name="maximum">
+ <number>65535</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="iGroupBoxCenter">
+ <property name="title">
+ <string>Center</string>
</property>
- <widget class="QWidget" name="tabClip">
- <property name="enabled">
- <bool>false</bool>
- </property>
- <attribute name="title">
- <string>Clip</string>
- </attribute>
- <layout class="QGridLayout" name="gridLayout_6">
- <item row="0" column="0">
- <widget class="QGroupBox" name="groupBox_8">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="minimumSize">
- <size>
- <width>331</width>
- <height>208</height>
- </size>
- </property>
- <property name="title">
- <string>Model Dimensions</string>
- </property>
- <widget class="QSpinBox" name="clip_tlength_spin">
- <property name="geometry">
- <rect>
- <x>70</x>
- <y>35</y>
- <width>100</width>
- <height>22</height>
- </rect>
- </property>
- <property name="suffix">
- <string> mm</string>
- </property>
- <property name="minimum">
- <number>-65535</number>
- </property>
- <property name="maximum">
- <number>65535</number>
- </property>
- </widget>
- <widget class="QSpinBox" name="clip_bheight_spin">
- <property name="geometry">
- <rect>
- <x>150</x>
- <y>130</y>
- <width>100</width>
- <height>22</height>
- </rect>
- </property>
- <property name="suffix">
- <string> mm</string>
- </property>
- <property name="minimum">
- <number>-65535</number>
- </property>
- <property name="maximum">
- <number>65535</number>
- </property>
- </widget>
- <widget class="QLabel" name="label_44">
- <property name="geometry">
- <rect>
- <x>65</x>
- <y>55</y>
- <width>71</width>
- <height>111</height>
- </rect>
- </property>
- <property name="text">
- <string/>
- </property>
- <property name="pixmap">
- <pixmap resource="tracker_easy.qrc">:/Resources/clip_side.png</pixmap>
- </property>
- </widget>
- <widget class="QLabel" name="label_50">
- <property name="geometry">
- <rect>
- <x>20</x>
- <y>40</y>
- <width>46</width>
- <height>13</height>
- </rect>
- </property>
- <property name="text">
- <string>Side</string>
- </property>
- </widget>
- <widget class="QSpinBox" name="clip_blength_spin">
- <property name="geometry">
- <rect>
- <x>50</x>
- <y>160</y>
- <width>100</width>
- <height>22</height>
- </rect>
- </property>
- <property name="suffix">
- <string> mm</string>
- </property>
- <property name="minimum">
- <number>-65535</number>
- </property>
- <property name="maximum">
- <number>65535</number>
- </property>
- </widget>
- <widget class="QSpinBox" name="clip_theight_spin">
- <property name="geometry">
- <rect>
- <x>150</x>
- <y>70</y>
- <width>100</width>
- <height>22</height>
- </rect>
- </property>
- <property name="suffix">
- <string> mm</string>
- </property>
- <property name="minimum">
- <number>-65535</number>
- </property>
- <property name="maximum">
- <number>65535</number>
- </property>
- </widget>
- <widget class="QLabel" name="label_51">
- <property name="geometry">
- <rect>
- <x>290</x>
- <y>40</y>
- <width>46</width>
- <height>13</height>
- </rect>
- </property>
- <property name="text">
- <string>Front</string>
- </property>
- </widget>
- <widget class="QLabel" name="label_45">
- <property name="geometry">
- <rect>
- <x>300</x>
- <y>70</y>
- <width>21</width>
- <height>111</height>
- </rect>
- </property>
- <property name="text">
- <string/>
- </property>
- <property name="pixmap">
- <pixmap resource="tracker_easy.qrc">:/Resources/clip_front.png</pixmap>
- </property>
- </widget>
- </widget>
- </item>
- </layout>
- </widget>
- <widget class="QWidget" name="tabCap">
- <attribute name="title">
- <string>Cap</string>
- </attribute>
- <layout class="QVBoxLayout" name="verticalLayout_14">
- <item>
- <widget class="QGroupBox" name="groupBox_9">
- <property name="minimumSize">
- <size>
- <width>331</width>
- <height>208</height>
- </size>
- </property>
- <property name="title">
- <string>Model Dimensions</string>
- </property>
- <widget class="QLabel" name="label_46">
- <property name="geometry">
- <rect>
- <x>100</x>
- <y>60</y>
- <width>111</width>
- <height>81</height>
- </rect>
- </property>
- <property name="text">
- <string/>
- </property>
- <property name="pixmap">
- <pixmap resource="tracker_easy.qrc">:/Resources/cap_side.png</pixmap>
- </property>
- </widget>
- <widget class="QLabel" name="label_48">
- <property name="geometry">
- <rect>
- <x>20</x>
- <y>40</y>
- <width>46</width>
- <height>13</height>
- </rect>
- </property>
- <property name="text">
- <string>Side</string>
- </property>
- </widget>
- <widget class="QSpinBox" name="cap_length_spin">
- <property name="geometry">
- <rect>
- <x>90</x>
- <y>40</y>
- <width>101</width>
- <height>22</height>
- </rect>
- </property>
- <property name="suffix">
- <string> mm</string>
- </property>
- <property name="minimum">
- <number>-65535</number>
- </property>
- <property name="maximum">
- <number>65535</number>
- </property>
- </widget>
- <widget class="QLabel" name="label_47">
- <property name="geometry">
- <rect>
- <x>220</x>
- <y>100</y>
- <width>81</width>
- <height>81</height>
- </rect>
- </property>
- <property name="text">
- <string/>
- </property>
- <property name="pixmap">
- <pixmap resource="tracker_easy.qrc">:/Resources/cap_front.png</pixmap>
- </property>
- </widget>
- <widget class="QSpinBox" name="cap_width_spin">
- <property name="geometry">
- <rect>
- <x>240</x>
- <y>70</y>
- <width>81</width>
- <height>22</height>
- </rect>
- </property>
- <property name="suffix">
- <string> mm</string>
- </property>
- <property name="minimum">
- <number>-65535</number>
- </property>
- <property name="maximum">
- <number>65535</number>
- </property>
- </widget>
- <widget class="QLabel" name="label_49">
- <property name="geometry">
- <rect>
- <x>240</x>
- <y>40</y>
- <width>46</width>
- <height>13</height>
- </rect>
- </property>
- <property name="text">
- <string>Front</string>
- </property>
- </widget>
- <widget class="QSpinBox" name="cap_height_spin">
- <property name="geometry">
- <rect>
- <x>20</x>
- <y>90</y>
- <width>81</width>
- <height>22</height>
- </rect>
- </property>
- <property name="suffix">
- <string> mm</string>
- </property>
- <property name="minimum">
- <number>-65535</number>
- </property>
- <property name="maximum">
- <number>65535</number>
- </property>
- </widget>
- </widget>
- </item>
- </layout>
- </widget>
- <widget class="QWidget" name="tabCustom">
- <property name="enabled">
- <bool>false</bool>
- </property>
- <attribute name="title">
- <string>Custom</string>
- </attribute>
- <layout class="QGridLayout" name="gridLayout">
- <item row="0" column="0">
- <widget class="QGroupBox" name="groupBox_7">
- <property name="title">
- <string>Model Dimensions</string>
- </property>
- <layout class="QGridLayout" name="gridLayout_5">
- <item row="3" column="1">
- <widget class="QLabel" name="label_57">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="text">
- <string>z:</string>
- </property>
- </widget>
- </item>
- <item row="2" column="5">
- <widget class="QSpinBox" name="m2y_spin">
- <property name="suffix">
- <string> mm</string>
- </property>
- <property name="minimum">
- <number>-65535</number>
- </property>
- <property name="maximum">
- <number>65535</number>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QLabel" name="label_63">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="text">
- <string>x:</string>
- </property>
- </widget>
- </item>
- <item row="1" column="2">
- <widget class="QSpinBox" name="m1x_spin">
- <property name="suffix">
- <string> mm</string>
- </property>
- <property name="minimum">
- <number>-65535</number>
- </property>
- <property name="maximum">
- <number>65535</number>
- </property>
- </widget>
- </item>
- <item row="2" column="2">
- <widget class="QSpinBox" name="m1y_spin">
- <property name="suffix">
- <string> mm</string>
- </property>
- <property name="minimum">
- <number>-65535</number>
- </property>
- <property name="maximum">
- <number>65535</number>
- </property>
- </widget>
- </item>
- <item row="3" column="5">
- <widget class="QSpinBox" name="m2z_spin">
- <property name="suffix">
- <string> mm</string>
- </property>
- <property name="minimum">
- <number>-65535</number>
- </property>
- <property name="maximum">
- <number>65535</number>
- </property>
- </widget>
- </item>
- <item row="1" column="5">
- <widget class="QSpinBox" name="m2x_spin">
- <property name="suffix">
- <string> mm</string>
- </property>
- <property name="minimum">
- <number>-65535</number>
- </property>
- <property name="maximum">
- <number>65535</number>
- </property>
- </widget>
- </item>
- <item row="0" column="0" colspan="6">
- <widget class="QLabel" name="label_56">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="text">
- <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Location of the two remaining model points&lt;br/&gt;with respect to the reference point in default pose&lt;/p&gt;&lt;p&gt;Use any units you want, not necessarily centimeters.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
- </property>
- </widget>
- </item>
- <item row="3" column="2">
- <widget class="QSpinBox" name="m1z_spin">
- <property name="suffix">
- <string> mm</string>
- </property>
- <property name="minimum">
- <number>-65535</number>
- </property>
- <property name="maximum">
- <number>65535</number>
- </property>
- </widget>
- </item>
- <item row="2" column="4">
- <widget class="QLabel" name="label_70">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="text">
- <string>y:</string>
- </property>
- </widget>
- </item>
- <item row="1" column="4">
- <widget class="QLabel" name="label_67">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="text">
- <string>x:</string>
- </property>
- </widget>
- </item>
- <item row="1" column="3">
- <widget class="QLabel" name="label_64">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="text">
- <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:16pt;&quot;&gt;P&lt;/span&gt;&lt;span style=&quot; font-size:16pt; vertical-align:sub;&quot;&gt;3&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="label_60">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="text">
- <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:16pt;&quot;&gt;P&lt;/span&gt;&lt;span style=&quot; font-size:16pt; vertical-align:sub;&quot;&gt;2&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
- </property>
- </widget>
- </item>
- <item row="3" column="4">
- <widget class="QLabel" name="label_69">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="text">
- <string>z:</string>
- </property>
- </widget>
- </item>
- <item row="2" column="1">
- <widget class="QLabel" name="label_58">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="text">
- <string>y:</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- </layout>
- </widget>
+ <layout class="QHBoxLayout" name="horizontalLayout_5">
+ <item>
+ <widget class="QSpinBox" name="iSpinVertexCenterX">
+ <property name="suffix">
+ <string> mm</string>
+ </property>
+ <property name="minimum">
+ <number>-65535</number>
+ </property>
+ <property name="maximum">
+ <number>65535</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="iSpinVertexCenterY">
+ <property name="suffix">
+ <string> mm</string>
+ </property>
+ <property name="minimum">
+ <number>-65535</number>
+ </property>
+ <property name="maximum">
+ <number>65535</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="iSpinVertexCenterZ">
+ <property name="suffix">
+ <string> mm</string>
+ </property>
+ <property name="minimum">
+ <number>-65535</number>
+ </property>
+ <property name="maximum">
+ <number>65535</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
</widget>
</item>
- <item row="1" column="0">
- <widget class="QGroupBox" name="groupBox_10">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
+ <item>
+ <widget class="QGroupBox" name="iGroupBoxTopRight">
+ <property name="title">
+ <string>Top Right</string>
</property>
+ <layout class="QHBoxLayout" name="horizontalLayout_6">
+ <item>
+ <widget class="QSpinBox" name="iSpinVertexTopRightX">
+ <property name="suffix">
+ <string> mm</string>
+ </property>
+ <property name="minimum">
+ <number>-65535</number>
+ </property>
+ <property name="maximum">
+ <number>65535</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="iSpinVertexTopRightY">
+ <property name="suffix">
+ <string> mm</string>
+ </property>
+ <property name="minimum">
+ <number>-65535</number>
+ </property>
+ <property name="maximum">
+ <number>65535</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="iSpinVertexTopRightZ">
+ <property name="suffix">
+ <string> mm</string>
+ </property>
+ <property name="minimum">
+ <number>-65535</number>
+ </property>
+ <property name="maximum">
+ <number>65535</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="iGroupBoxTopLeft">
<property name="title">
- <string>Model position</string>
+ <string>Top Left</string>
</property>
- <layout class="QGridLayout" name="gridLayout_4">
- <item row="0" column="0">
- <widget class="QFrame" name="frame_2">
- <property name="frameShape">
- <enum>QFrame::NoFrame</enum>
- </property>
- <property name="frameShadow">
- <enum>QFrame::Raised</enum>
- </property>
- <layout class="QGridLayout" name="gridLayout_11">
- <item row="1" column="1">
- <widget class="QSpinBox" name="ty_spin">
- <property name="suffix">
- <string> mm</string>
- </property>
- <property name="minimum">
- <number>-65535</number>
- </property>
- <property name="maximum">
- <number>65536</number>
- </property>
- </widget>
- </item>
- <item row="2" column="0">
- <widget class="QLabel" name="label_66">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="text">
- <string>z:</string>
- </property>
- </widget>
- </item>
- <item row="2" column="1">
- <widget class="QSpinBox" name="tz_spin">
- <property name="suffix">
- <string> mm</string>
- </property>
- <property name="minimum">
- <number>-65535</number>
- </property>
- <property name="maximum">
- <number>65536</number>
- </property>
- </widget>
- </item>
- <item row="0" column="0">
- <widget class="QLabel" name="label_61">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="text">
- <string>x:</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QSpinBox" name="tx_spin">
- <property name="suffix">
- <string> mm</string>
- </property>
- <property name="minimum">
- <number>-65535</number>
- </property>
- <property name="maximum">
- <number>65536</number>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="label_62">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="text">
- <string>y:</string>
- </property>
- </widget>
- </item>
- </layout>
+ <layout class="QHBoxLayout" name="horizontalLayout_7">
+ <item>
+ <widget class="QSpinBox" name="iSpinVertexTopLeftX">
+ <property name="suffix">
+ <string> mm</string>
+ </property>
+ <property name="minimum">
+ <number>-65535</number>
+ </property>
+ <property name="maximum">
+ <number>65535</number>
+ </property>
</widget>
</item>
- <item row="0" column="1">
- <widget class="QFrame" name="frame">
- <property name="frameShape">
- <enum>QFrame::NoFrame</enum>
- </property>
- <property name="frameShadow">
- <enum>QFrame::Raised</enum>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout_2">
- <item>
- <widget class="QLabel" name="label_59">
- <property name="text">
- <string>Use only yaw and pitch while calibrating.
-Don't roll or change position.</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignCenter</set>
- </property>
- <property name="wordWrap">
- <bool>true</bool>
- </property>
- <property name="openExternalLinks">
- <bool>false</bool>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QLabel" name="sample_count_display">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Minimum" vsizetype="Maximum">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="text">
- <string/>
- </property>
- <property name="wordWrap">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="tcalib_button">
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="text">
- <string>Start calibration</string>
- </property>
- <property name="checkable">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- </layout>
+ <item>
+ <widget class="QSpinBox" name="iSpinVertexTopLeftY">
+ <property name="suffix">
+ <string> mm</string>
+ </property>
+ <property name="minimum">
+ <number>-65535</number>
+ </property>
+ <property name="maximum">
+ <number>65535</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="iSpinVertexTopLeftZ">
+ <property name="suffix">
+ <string> mm</string>
+ </property>
+ <property name="minimum">
+ <number>-65535</number>
+ </property>
+ <property name="maximum">
+ <number>65535</number>
+ </property>
</widget>
</item>
</layout>
@@ -1260,7 +912,7 @@ Don't roll or change position.</string>
<item row="0" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
- <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Easy Tracker&lt;br/&gt;Version 0.1&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;by Stéphane Lenclud&lt;/span&gt;&lt;/p&gt;&lt;p&gt;See &lt;a href=&quot;https://github.com/opentrack/opentrack/wiki/Easy-Tracker&quot;&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline; color:#9999AA;&quot;&gt;documentation on GitHub&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Easy Tracker&lt;br/&gt;Version 1.0&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;by Stéphane Lenclud&lt;/span&gt;&lt;/p&gt;&lt;p&gt;See &lt;a href=&quot;https://github.com/opentrack/opentrack/wiki/Easy-Tracker&quot;&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline; color:#9999aa;&quot;&gt;documentation on GitHub&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
@@ -1287,19 +939,6 @@ Don't roll or change position.</string>
</widget>
</widget>
</item>
- <item row="2" column="0">
- <widget class="QDialogButtonBox" name="buttonBox">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="standardButtons">
- <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
- </property>
- </widget>
- </item>
</layout>
</widget>
<tabstops>
@@ -1310,24 +949,6 @@ Don't roll or change position.</string>
<tabstop>fps_spin</tabstop>
<tabstop>fov</tabstop>
<tabstop>camera_settings</tabstop>
- <tabstop>model_tabs</tabstop>
- <tabstop>clip_tlength_spin</tabstop>
- <tabstop>clip_theight_spin</tabstop>
- <tabstop>clip_bheight_spin</tabstop>
- <tabstop>clip_blength_spin</tabstop>
- <tabstop>cap_length_spin</tabstop>
- <tabstop>cap_height_spin</tabstop>
- <tabstop>cap_width_spin</tabstop>
- <tabstop>m1x_spin</tabstop>
- <tabstop>m1y_spin</tabstop>
- <tabstop>m1z_spin</tabstop>
- <tabstop>m2x_spin</tabstop>
- <tabstop>m2y_spin</tabstop>
- <tabstop>m2z_spin</tabstop>
- <tabstop>tx_spin</tabstop>
- <tabstop>ty_spin</tabstop>
- <tabstop>tz_spin</tabstop>
- <tabstop>tcalib_button</tabstop>
</tabstops>
<resources>
<include location="tracker_easy.qrc"/>
diff --git a/tracker-easy/tracker-easy.cpp b/tracker-easy/tracker-easy.cpp
index ebc6e128..e13bdf37 100644
--- a/tracker-easy/tracker-easy.cpp
+++ b/tracker-easy/tracker-easy.cpp
@@ -24,11 +24,14 @@
using namespace options;
// Disable debug
-#define dbgout if (true) {} else std::cout
+#define dbgout if (true) {} else std::cout << "\n" <<std::chrono::system_clock::now().time_since_epoch().count() << ": "
//#define infout if (true) {} else std::cout
// Enable debug
//#define dbgout if (false) {} else std::cout
-#define infout if (false) {} else std::cout
+#define infout if (false) {} else std::cout << "\n" << std::chrono::system_clock::now().time_since_epoch().count() << ": "
+
+// We need at least 3 vertices to be able to do anything
+const int KMinVertexCount = 3;
namespace EasyTracker
{
@@ -49,14 +52,35 @@ namespace EasyTracker
//connect(&iSettings.cam_fps, value_::value_changed<int>(), this, &Tracker::SetFps, Qt::DirectConnection);
// Make sure deadzones are updated whenever the settings are changed
- connect(&iSettings.DeadzoneRectHalfEdgeSize, value_::value_changed<int>(), this, &Tracker::UpdateDeadzones, Qt::DirectConnection);
- UpdateDeadzones(iSettings.DeadzoneRectHalfEdgeSize);
+ connect(&iSettings.DeadzoneRectHalfEdgeSize, value_::value_changed<int>(), this, &Tracker::UpdateSettings, Qt::DirectConnection);
+
+ // Update point extractor whenever some of the settings it needs are changed
+ connect(&iSettings.iMinBlobSize, value_::value_changed<int>(), this, &Tracker::UpdateSettings, Qt::DirectConnection);
+ connect(&iSettings.iMaxBlobSize, value_::value_changed<int>(), this, &Tracker::UpdateSettings, Qt::DirectConnection);
// Make sure solver is updated whenever the settings are changed
- connect(&iSettings.PnpSolver, value_::value_changed<int>(), this, &Tracker::UpdateSolver, Qt::DirectConnection);
- UpdateSolver(iSettings.PnpSolver);
+ connect(&iSettings.PnpSolver, value_::value_changed<int>(), this, &Tracker::UpdateSettings, Qt::DirectConnection);
+
+ // Debug
+ connect(&iSettings.debug, value_::value_changed<bool>(), this, &Tracker::UpdateSettings, Qt::DirectConnection);
+
+ // Make sure model is updated whenever it is changed
+ connect(&iSettings.iCustomModelThree, value_::value_changed<bool>(), this, &Tracker::UpdateModel, Qt::DirectConnection);
+ connect(&iSettings.iCustomModelFour, value_::value_changed<bool>(), this, &Tracker::UpdateModel, Qt::DirectConnection);
+ connect(&iSettings.iCustomModelFive, value_::value_changed<bool>(), this, &Tracker::UpdateModel, Qt::DirectConnection);
+
+ // Update model logic
+ #define UM(v) connect(&iSettings.v, value_::value_changed<int>(), this, &Tracker::UpdateModel, Qt::DirectConnection)
+ UM(iVertexTopX); UM(iVertexTopY); UM(iVertexTopZ);
+ UM(iVertexTopRightX); UM(iVertexTopRightY); UM(iVertexTopRightZ);
+ UM(iVertexTopLeftX); UM(iVertexTopLeftY); UM(iVertexTopLeftZ);
+ UM(iVertexRightX); UM(iVertexRightY); UM(iVertexRightZ);
+ UM(iVertexLeftX); UM(iVertexLeftY); UM(iVertexLeftZ);
+ UM(iVertexCenterX); UM(iVertexCenterY); UM(iVertexCenterZ);
+
+ UpdateModel();
- CreateModelFromSettings();
+ UpdateSettings();
}
Tracker::~Tracker()
@@ -77,7 +101,6 @@ namespace EasyTracker
// Compute Euler angles from rotation matrix
void getEulerAngles(cv::Mat &rotCamerMatrix, cv::Vec3d &eulerAngles)
{
-
cv::Mat cameraMatrix, rotMatrix, transVect, rotMatrixX, rotMatrixY, rotMatrixZ;
double* _r = rotCamerMatrix.ptr<double>();
double projMatrix[12] = { _r[0],_r[1],_r[2],0,
@@ -95,19 +118,6 @@ namespace EasyTracker
}
///
- void Tracker::CreateModelFromSettings()
- {
- // 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
- iModel.clear();
- iModel.push_back(cv::Point3f(iSettings.cap_x / 10.0, iSettings.cap_z / 10.0, -iSettings.cap_y / 10.0)); // Right
- iModel.push_back(cv::Point3f(-iSettings.cap_x / 10.0, iSettings.cap_z / 10.0, -iSettings.cap_y / 10.0)); // Left
- iModel.push_back(cv::Point3f(0, 0, 0)); // Top
- }
-
- ///
void Tracker::CreateCameraIntrinsicsMatrices()
{
// Create our camera matrix
@@ -132,11 +142,194 @@ namespace EasyTracker
iDistCoeffsMatrix.at<double>(7, 0) = iCameraInfo.radialDistortionSixthOrder; // Radial sixth order
}
+
+ void Tracker::MatchVertices(int& aTopIndex, int& aRightIndex, int& aLeftIndex, int& aCenterIndex, int& aTopRight, int& aTopLeft)
+ {
+ if (iModel.size() == 5)
+ {
+ MatchFiveVertices(aTopIndex, aRightIndex, aLeftIndex, aTopRight, aTopLeft);
+ }
+ else
+ {
+ MatchThreeOrFourVertices(aTopIndex, aRightIndex, aLeftIndex, aCenterIndex);
+ }
+ }
+
+
+ void Tracker::MatchFiveVertices(int& aTopIndex, int& aRightIndex, int& aLeftIndex, int& aTopRight, int& aTopLeft)
+ {
+ //Bitmap origin is top left
+ iTrackedPoints.clear();
+
+ int vertexIndices[] = { -1,-1,-1,-1,-1 };
+ std::vector<int> indices = { 0,1,2,3,4 };
+
+ // Tracked points must match the order of the object model points.
+ // 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 < iPoints.size(); i++)
+ {
+ if (iPoints[i].y < minY)
+ {
+ minY = iPoints[i].y;
+ vertexIndices[VertexPosition::Top] = i;
+ }
+ }
+ indices.erase(std::find(indices.begin(), indices.end(), vertexIndices[VertexPosition::Top]));
+
+ // Find right most point
+ int maxX = 0;
+ for (int i = 0; i < iPoints.size(); i++)
+ {
+ // Excluding top most point
+ if (i != vertexIndices[VertexPosition::Top] && iPoints[i].x > maxX)
+ {
+ maxX = iPoints[i].x;
+ vertexIndices[VertexPosition::Right] = i;
+ }
+ }
+ indices.erase(std::find(indices.begin(), indices.end(), vertexIndices[VertexPosition::Right]));
+
+ // Find left most point
+ int minX = std::numeric_limits<int>::max();
+ for (int i = 0; i < iPoints.size(); i++)
+ {
+ // Excluding top most point and right most point
+ if (i != vertexIndices[VertexPosition::Top] && i != vertexIndices[VertexPosition::Right] && iPoints[i].x < minX)
+ {
+ minX = iPoints[i].x;
+ vertexIndices[VertexPosition::Left] = i;
+ }
+ }
+ indices.erase(std::find(indices.begin(), indices.end(), vertexIndices[VertexPosition::Left]));
+
+ // Check which of our two remaining points is on the left
+ int leftIndex = -1;
+ int rightIndex = -1;
+ if (iPoints[indices[0]].x > iPoints[indices[1]].x)
+ {
+ leftIndex = indices[1];
+ rightIndex = indices[0];
+ }
+ else
+ {
+ leftIndex = indices[0];
+ rightIndex = indices[1];
+ }
+
+ // Check which of the left points is at the top
+ if (iPoints[vertexIndices[VertexPosition::Left]].y < iPoints[leftIndex].y)
+ {
+ vertexIndices[VertexPosition::TopLeft] = vertexIndices[VertexPosition::Left];
+ vertexIndices[VertexPosition::Left] = leftIndex;
+ }
+ else
+ {
+ vertexIndices[VertexPosition::TopLeft] = leftIndex;
+ }
+
+ // Check which of the right points is at the top
+ if (iPoints[vertexIndices[VertexPosition::Right]].y < iPoints[rightIndex].y)
+ {
+ vertexIndices[VertexPosition::TopRight] = vertexIndices[VertexPosition::Right];
+ vertexIndices[VertexPosition::Right] = rightIndex;
+ }
+ else
+ {
+ vertexIndices[VertexPosition::TopRight] = rightIndex;
+ }
+
+
+ // Order matters, see UpdateModel function
+ iTrackedPoints.push_back(iPoints[vertexIndices[VertexPosition::Top]]);
+ iTrackedPoints.push_back(iPoints[vertexIndices[VertexPosition::Right]]);
+ iTrackedPoints.push_back(iPoints[vertexIndices[VertexPosition::Left]]);
+ iTrackedPoints.push_back(iPoints[vertexIndices[VertexPosition::TopRight]]);
+ iTrackedPoints.push_back(iPoints[vertexIndices[VertexPosition::TopLeft]]);
+
+ //
+ aTopIndex = vertexIndices[VertexPosition::Top];
+ aRightIndex = vertexIndices[VertexPosition::Right];
+ aLeftIndex = vertexIndices[VertexPosition::Left];
+ aTopRight = vertexIndices[VertexPosition::TopRight];
+ aTopLeft = vertexIndices[VertexPosition::TopLeft];
+
+
+ }
+
+
+ void Tracker::MatchThreeOrFourVertices(int& aTopIndex, int& aRightIndex, int& aLeftIndex, int& aCenterIndex)
+ {
+ //Bitmap origin is top left
+ iTrackedPoints.clear();
+ // Tracked points must match the order of the object model points.
+ // 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 < iPoints.size(); i++)
+ {
+ if (iPoints[i].y < minY)
+ {
+ minY = iPoints[i].y;
+ aTopIndex = i;
+ }
+ }
+
+
+ int maxX = 0;
+
+ // Find right most point
+ for (int i = 0; i < iPoints.size(); i++)
+ {
+ // Excluding top most point
+ if (i != aTopIndex && iPoints[i].x > maxX)
+ {
+ maxX = iPoints[i].x;
+ aRightIndex = i;
+ }
+ }
+
+ // Find left most point
+ int minX = std::numeric_limits<int>::max();
+ for (int i = 0; i < iPoints.size(); i++)
+ {
+ // Excluding top most point and right most point
+ if (i != aTopIndex && i != aRightIndex && iPoints[i].x < minX)
+ {
+ aLeftIndex = i;
+ minX = iPoints[i].x;
+ }
+ }
+
+ // Find center point, the last one
+ for (int i = 0; i < iPoints.size(); i++)
+ {
+ // Excluding the three points we already have
+ if (i != aTopIndex && i != aRightIndex && i != aLeftIndex)
+ {
+ aCenterIndex = i;
+ }
+ }
+
+ // Order matters
+ iTrackedPoints.push_back(iPoints[aTopIndex]);
+ iTrackedPoints.push_back(iPoints[aRightIndex]);
+ iTrackedPoints.push_back(iPoints[aLeftIndex]);
+ if (iModel.size() > iTrackedPoints.size())
+ {
+ // We are tracking more than 3 points
+ iTrackedPoints.push_back(iPoints[aCenterIndex]);
+ }
+ }
+
+
+
///
///
///
void Tracker::ProcessFrame()
{
+ QMutexLocker l(&iProcessLock);
+
// Create OpenCV matrix from our frame
// TODO: Assert channel size is one or two
iMatFrame = cv::Mat(iFrame.height, iFrame.width, CV_MAKETYPE((iFrame.channelSize == 2 ? CV_16U : CV_8U), iFrame.channels), iFrame.data, iFrame.stride);
@@ -149,170 +342,208 @@ namespace EasyTracker
}
iPoints.clear();
- iPointExtractor.ExtractPoints(iMatFrame, (doPreview ? &iPreview.iFrameRgb : nullptr), iPoints);
+ iPointExtractor.ExtractPoints(iMatFrame, (doPreview ? &iPreview.iFrameRgb : nullptr), iModel.size(), iPoints);
- const bool success = iPoints.size() >= KPointCount;
+ const bool success = iPoints.size() >= iModel.size() && iModel.size() >= KMinVertexCount;
int topPointIndex = -1;
+ int rightPointIndex = -1;
+ int leftPointIndex = -1;
+ int centerPointIndex = -1;
+ int topRightPointIndex = -1;
+ int topLeftPointIndex = -1;
+ if (success)
{
- QMutexLocker l(&center_lock);
-
- if (success)
+ // Lets match our 3D vertices with our image 2D points
+ MatchVertices(topPointIndex, rightPointIndex, leftPointIndex, centerPointIndex, topRightPointIndex, topLeftPointIndex);
+
+ bool movedEnough = true;
+ // Check if we moved enough since last time we were here
+ // This is our deadzone management
+ if (iDeadzoneHalfEdge != 0 // Check if deazones are enabled
+ && iTrackedRects.size() == iTrackedPoints.size())
{
- ever_success.store(true, std::memory_order_relaxed);
-
- //Bitmap origin is top left
- iTrackedPoints.clear();
- // Tracked points must match the order of the object model points.
- // 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++)
+ movedEnough = false;
+ for (size_t i = 0; i < iTrackedPoints.size(); i++)
{
- if (iPoints[i].y < minY)
+ if (!iTrackedRects[i].contains(iTrackedPoints[i]))
{
- minY = iPoints[i].y;
- topPointIndex = i;
+ movedEnough = true;
+ break;
}
}
+ }
- int rightPointIndex = -1;
- int maxX = 0;
-
- // Find right most point
- for (int i = 0; i < 3; i++)
+ if (!movedEnough)
+ {
+ // We are in a dead zone
+ // However we still have tracking so make sure we don't auto center
+ QMutexLocker lock(&iDataLock);
+ iBestTime.start();
+ }
+ else
+ {
+ // Build deadzone rectangles if needed
+ iTrackedRects.clear();
+ if (iDeadzoneHalfEdge != 0) // Check if deazones are enabled
{
- // Excluding top most point
- if (i != topPointIndex && iPoints[i].x > maxX)
+ for (const cv::Point& pt : iTrackedPoints)
{
- maxX = iPoints[i].x;
- rightPointIndex = i;
+ cv::Rect rect(pt - cv::Point(iDeadzoneHalfEdge, iDeadzoneHalfEdge), cv::Size(iDeadzoneEdge, iDeadzoneEdge));
+ iTrackedRects.push_back(rect);
}
}
- // Find left most point
- int leftPointIndex = -1;
- for (int i = 0; i < 3; i++)
+ dbgout << "Object: " << iModel << "\n";
+ dbgout << "Points: " << iTrackedPoints << "\n";
+
+ iAngles.clear();
+ iBestSolutionIndex = -1;
+ // Solve P3P problem with OpenCV
+ int solutionCount = 0;
+ if (iModel.size() == 3)
{
- // Excluding top most point
- if (i != topPointIndex && i != rightPointIndex)
+ solutionCount = cv::solveP3P(iModel, iTrackedPoints, iCameraMatrix, iDistCoeffsMatrix, iRotations, iTranslations, iSolver);
+ }
+ else
+ {
+ //Guess extrinsic boolean is only for ITERATIVE method, it will be set to false for all other method
+ cv::Mat rotation, translation;
+ // Init only needed for iterative, it's also useless as it is
+ rotation = cv::Mat::zeros(3, 1, CV_64FC1);
+ translation = cv::Mat::zeros(3, 1, CV_64FC1);
+ rotation.setTo(cv::Scalar(0));
+ translation.setTo(cv::Scalar(0));
+ /////
+ iRotations.clear();
+ iTranslations.clear();
+ bool solved = cv::solvePnP(iModel, iTrackedPoints, iCameraMatrix, iDistCoeffsMatrix, rotation, translation, true, iSolver );
+ if (solved)
{
- leftPointIndex = i;
- break;
+ solutionCount = 1;
+ iRotations.push_back(rotation);
+ iTranslations.push_back(translation);
}
}
- //
- iTrackedPoints.push_back(iPoints[rightPointIndex]);
- iTrackedPoints.push_back(iPoints[leftPointIndex]);
- iTrackedPoints.push_back(iPoints[topPointIndex]);
+ // Reset best solution index
+ iBestSolutionIndex = -1;
- bool movedEnough = true;
- // Check if we moved enough since last time we were here
- // This is our deadzone management
- if (iSettings.DeadzoneRectHalfEdgeSize != 0 // Check if deazones are enabled
- && iTrackedRects.size() == iTrackedPoints.size())
+ if (solutionCount > 0)
{
- movedEnough = false;
- for (size_t i = 0; i < iTrackedPoints.size(); i++)
+ dbgout << "Solution count: " << solutionCount << "\n";
+ int minPitch = std::numeric_limits<int>::max();
+ // Find the solution we want amongst all possible ones
+ for (int i = 0; i < solutionCount; i++)
{
- if (!iTrackedRects[i].contains(iTrackedPoints[i]))
+ dbgout << "Translation:\n";
+ dbgout << iTranslations.at(i);
+ dbgout << "\n";
+ dbgout << "Rotation:\n";
+ //dbgout << 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)
{
- movedEnough = true;
- break;
+ // The solution with pitch closest to zero is the one we want
+ minPitch = absolutePitch;
+ iBestSolutionIndex = i;
}
+
+ dbgout << angles;
+ dbgout << "\n";
}
+
+ dbgout << "\n";
}
- if (movedEnough)
+ if (iBestSolutionIndex != -1)
{
- // Build deadzone rectangles if needed
- iTrackedRects.clear();
- if (iSettings.DeadzoneRectHalfEdgeSize != 0) // Check if deazones are enabled
- {
- for (const cv::Point& pt : iTrackedPoints)
- {
- cv::Rect rect(pt - cv::Point(iDeadzoneHalfEdge, iDeadzoneHalfEdge), cv::Size(iDeadzoneEdge, iDeadzoneEdge));
- iTrackedRects.push_back(rect);
- }
- }
+ // Best translation
+ cv::Vec3d translation = iTranslations[iBestSolutionIndex];
+ // Best angles
+ cv::Vec3d angles = iAngles[iBestSolutionIndex];
- dbgout << "Object: " << iModel << "\n";
- dbgout << "Points: " << iTrackedPoints << "\n";
+ // Pass solution through our kalman filter
+ iKf.Update(translation[0], translation[1], translation[2], angles[2], angles[0], angles[1]);
- iAngles.clear();
- iBestSolutionIndex = -1;
- // Solve P3P problem with OpenCV
- int solutionCount = cv::solveP3P(iModel, iTrackedPoints, iCameraMatrix, iDistCoeffsMatrix, iRotations, iTranslations, iSolver);
-
- if (solutionCount > 0)
+ // Check if our solution makes sense
+ // For now, just discard solutions with extrem pitch
+ if (std::abs(angles[0]) > 50) //TODO: Put that in settings
{
- dbgout << "Solution count: " << solutionCount << "\n";
- int minPitch = std::numeric_limits<int>::max();
- // Find the solution we want amongst all possible ones
- for (int i = 0; i < solutionCount; i++)
- {
- dbgout << "Translation:\n";
- dbgout << iTranslations.at(i);
- dbgout << "\n";
- dbgout << "Rotation:\n";
- //dbgout << 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)
- {
- // The solution with pitch closest to zero is the one we want
- minPitch = absolutePitch;
- iBestSolutionIndex = i;
- }
-
- dbgout << angles;
- dbgout << "\n";
- }
-
- dbgout << "\n";
+ infout << "WARNING: discarding solution!";
+ iBadSolutionCount++;
+ }
+ else
+ {
+ iGoodSolutionCount++;
+ // We succeded in finding a solution to our PNP problem
+ ever_success.store(true, std::memory_order_relaxed);
+
+ // Send solution data back to main thread
+ QMutexLocker l2(&iDataLock);
+ iBestAngles = angles;
+ iBestTranslation = translation;
+ iBestTime.start();
}
- }
- }
-
- if (iBestSolutionIndex != -1)
- {
- // Best translation
- cv::Vec3d translation = iTranslations[iBestSolutionIndex];
- // Best angles
- cv::Vec3d angles = iAngles[iBestSolutionIndex];
-
- // Pass solution through our kalman filter
- iKf.Update(translation[0], translation[1], translation[2], angles[2], angles[0], angles[1]);
-
- // Send solution data back to main thread
- QMutexLocker l2(&data_lock);
- iBestAngles = angles;
- iBestTranslation = translation;
+ }
}
-
}
if (doPreview)
{
+ double qualityIndex = 1 - (iGoodSolutionCount!=0?(double)iBadSolutionCount / (double)iGoodSolutionCount:0);
std::ostringstream ss;
- ss << "FPS: " << iFps << "/" << iSkippedFps;
+ ss << "FPS: " << iFps << "/" << iSkippedFps << " QI: " << qualityIndex;
iPreview.DrawInfo(ss.str());
- //
+ //Color is BGR
if (topPointIndex != -1)
{
// Render a cross to indicate which point is the head
- iPreview.DrawCross(iPoints[topPointIndex]);
+ static const cv::Scalar color(0, 255, 255); // Yellow
+ iPreview.DrawCross(iPoints[topPointIndex],color);
}
+ if (rightPointIndex != -1)
+ {
+ static const cv::Scalar color(255, 0, 255); // Pink
+ iPreview.DrawCross(iPoints[rightPointIndex], color);
+ }
+
+ if (leftPointIndex != -1)
+ {
+ static const cv::Scalar color(255, 0, 0); // Blue
+ iPreview.DrawCross(iPoints[leftPointIndex], color);
+ }
+
+ if (centerPointIndex != -1)
+ {
+ static const cv::Scalar color(0, 255, 0); // Green
+ iPreview.DrawCross(iPoints[centerPointIndex], color);
+ }
+
+ if (topRightPointIndex != -1)
+ {
+ static const cv::Scalar color(0, 0, 255); // Red
+ iPreview.DrawCross(iPoints[topRightPointIndex], color);
+ }
+
+ if (topLeftPointIndex != -1)
+ {
+ static const cv::Scalar color(255, 255, 0); // Cyan
+ iPreview.DrawCross(iPoints[topLeftPointIndex], color);
+ }
+
+
// Render our deadzone rects
for (const cv::Rect& rect : iTrackedRects)
{
@@ -320,7 +551,7 @@ namespace EasyTracker
}
// Show full size preview pop-up
- if (iSettings.debug)
+ if (iDebug)
{
cv::imshow("Preview", iPreview.iFrameRgb);
cv::waitKey(1);
@@ -340,7 +571,7 @@ namespace EasyTracker
else
{
// No preview, destroy preview pop-up
- if (iSettings.debug)
+ if (iDebug)
{
cv::destroyWindow("Preview");
}
@@ -442,27 +673,54 @@ namespace EasyTracker
iKf.Init(18, 6, 0, dt);
}
- void Tracker::UpdateDeadzones(int aHalfEdgeSize)
+
+ ///
+ /// Create our model from settings specifications
+ ///
+ void Tracker::UpdateModel()
{
- QMutexLocker l(&center_lock);
- iDeadzoneHalfEdge = aHalfEdgeSize;
- iDeadzoneEdge = iDeadzoneHalfEdge * 2;
- iTrackedRects.clear();
- }
+ infout << "Update model";
+ QMutexLocker lock(&iProcessLock);
+ // 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.
+ iModel.clear();
+ iModel.push_back(cv::Point3f(iSettings.iVertexTopX / 10.0, iSettings.iVertexTopY / 10.0, iSettings.iVertexTopZ / 10.0)); // Top
+ iModel.push_back(cv::Point3f(iSettings.iVertexRightX / 10.0, iSettings.iVertexRightY / 10.0, iSettings.iVertexRightZ / 10.0)); // Right
+ iModel.push_back(cv::Point3f(iSettings.iVertexLeftX / 10.0, iSettings.iVertexLeftY / 10.0, iSettings.iVertexLeftZ / 10.0)); // Left
- void Tracker::UpdateSolver(int aSolver)
- {
- QMutexLocker l(&center_lock);
- iSolver = aSolver;
+ if (iSettings.iCustomModelFour)
+ {
+ iModel.push_back(cv::Point3f(iSettings.iVertexCenterX / 10.0, iSettings.iVertexCenterY / 10.0, iSettings.iVertexCenterZ / 10.0)); // Center
+ }
+ else if (iSettings.iCustomModelFive)
+ {
+ iModel.push_back(cv::Point3f(iSettings.iVertexTopRightX / 10.0, iSettings.iVertexTopRightY / 10.0, iSettings.iVertexTopRightZ / 10.0)); // Top Right
+ iModel.push_back(cv::Point3f(iSettings.iVertexTopLeftX / 10.0, iSettings.iVertexTopLeftY / 10.0, iSettings.iVertexTopLeftZ / 10.0)); // Top Left
+ }
}
+ ///
+ /// Take a copy of the settings needed by our thread to avoid deadlocks
+ ///
+ void Tracker::UpdateSettings()
+ {
+ infout << "Update Setting";
+ QMutexLocker l(&iProcessLock);
+ iPointExtractor.UpdateSettings();
+ iSolver = iSettings.PnpSolver;
+ iDeadzoneHalfEdge = iSettings.DeadzoneRectHalfEdgeSize;
+ iDeadzoneEdge = iDeadzoneHalfEdge * 2;
+ iTrackedRects.clear();
+ iDebug = iSettings.debug;
+ }
-
+ ///
module_status Tracker::start_tracker(QFrame* video_frame)
{
// Check that we support that solver
- if (iSolver!=cv::SOLVEPNP_P3P && iSolver != cv::SOLVEPNP_AP3P)
+ if (iSolver!=cv::SOLVEPNP_P3P && iSolver != cv::SOLVEPNP_AP3P && iModel.size()==3)
{
return module_status("Error: Solver not supported use either P3P or AP3P.");
}
@@ -495,28 +753,47 @@ namespace EasyTracker
}
//
+ void FeedData(double* aData, const cv::Vec3d& aAngles, const cv::Vec3d& aTranslation)
+ {
+ aData[Yaw] = aAngles[1];
+ aData[Pitch] = aAngles[0];
+ aData[Roll] = aAngles[2];
+ aData[TX] = aTranslation[0];
+ aData[TY] = aTranslation[1];
+ aData[TZ] = aTranslation[2];
+ }
+
+ //
// That's called around 250 times per second.
// Therefore we better not do anything here other than provide current data.
//
- void Tracker::data(double *data)
+ void Tracker::data(double* aData)
{
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];
+ QMutexLocker l(&iDataLock);
+ // If there was no new data recently then we provide center data.
+ // Basically, if our user remove her hat, we will go back to center position until she puts it back on.
+ if (iSettings.iAutoCenter && iBestTime.elapsed_ms() > iSettings.iAutoCenterTimeout)
+ {
+ // Reset to center until we get new data
+ FeedData(aData, iCenterAngles, iCenterTranslation);
+ }
+ else
+ {
+ // We got valid data, provide it
+ FeedData(aData, iBestAngles, iBestTranslation);
+ }
}
}
bool Tracker::center()
{
- QMutexLocker l(&center_lock);
- //TODO: Do we need to do anything there?
+ QMutexLocker l(&iDataLock);
+ iCenterTranslation = iBestTranslation;
+ iCenterAngles = iBestAngles;
+ // Returning false tells the pipeline we want to use the default center behaviour
return false;
}
diff --git a/tracker-easy/tracker-easy.h b/tracker-easy/tracker-easy.h
index 41226d23..952f05a4 100644
--- a/tracker-easy/tracker-easy.h
+++ b/tracker-easy/tracker-easy.h
@@ -33,6 +33,19 @@
namespace EasyTracker
{
+ namespace VertexPosition
+ {
+ enum Type
+ {
+ Top = 0,
+ Right,
+ Left,
+ TopRight,
+ TopLeft,
+ Center
+ };
+ }
+
static const QString KModuleName = "tracker-easy";
class Dialog;
@@ -58,9 +71,13 @@ namespace EasyTracker
private:
- void CreateModelFromSettings();
+ void UpdateModel();
void CreateCameraIntrinsicsMatrices();
- void ProcessFrame();
+ void ProcessFrame();
+ void MatchVertices(int& aTopIndex, int& aRightIndex, int& aLeftIndex, int& aCenterIndex, int& aTopRight, int& aTopLeft);
+ void MatchThreeOrFourVertices(int& aTopIndex, int& aRightIndex, int& aLeftIndex, int& aCenterIndex);
+ void MatchFiveVertices(int& aTopIndex, int& aRightIndex, int& aLeftIndex, int& aTopRight, int& aTopLeft);
+
//
@@ -68,8 +85,7 @@ namespace EasyTracker
void set_fov(int value);
void SetFps(int aFps);
void DoSetFps(int aFps);
- void UpdateDeadzones(int aHalfEdgeSize);
- void UpdateSolver(int aSolver);
+ void UpdateSettings();
QMutex camera_mtx;
QThread iThread;
@@ -93,14 +109,16 @@ namespace EasyTracker
Preview iPreview;
std::atomic<bool> ever_success = false;
- mutable QMutex center_lock, data_lock;
+ mutable QMutex iProcessLock, iDataLock;
+ //// Copy the settings need by our thread to avoid dead locks
// Deadzone
int iDeadzoneEdge=0;
int iDeadzoneHalfEdge=0;
-
// Solver
int iSolver = cv::SOLVEPNP_P3P;
+ bool iDebug = false;
+ ////
// Statistics
Timer iTimer;
@@ -109,6 +127,8 @@ namespace EasyTracker
int iSkippedFrameCount = 0;
int iFps = 0;
int iSkippedFps = 0;
+ uint iBadSolutionCount = 0;
+ uint iGoodSolutionCount = 0;
//
KalmanFilterPose iKf;
@@ -136,6 +156,12 @@ namespace EasyTracker
cv::Vec3d iBestTranslation;
// Best angles
cv::Vec3d iBestAngles;
+ // Time at which we found our last best solution
+ Timer iBestTime;
+ // Center translation
+ cv::Vec3d iCenterTranslation = {0,0,0};
+ // Center angles
+ cv::Vec3d iCenterAngles = { 0,0,0 };
};
}