diff options
Diffstat (limited to 'tracker-easy')
-rw-r--r-- | tracker-easy/lang/nl_NL.ts | 98 | ||||
-rw-r--r-- | tracker-easy/lang/ru_RU.ts | 143 | ||||
-rw-r--r-- | tracker-easy/lang/stub.ts | 98 | ||||
-rw-r--r-- | tracker-easy/lang/zh_CN.ts | 138 | ||||
-rw-r--r-- | tracker-easy/module.cpp | 3 | ||||
-rw-r--r-- | tracker-easy/point-extractor.cpp | 23 | ||||
-rw-r--r-- | tracker-easy/point-extractor.h | 15 | ||||
-rw-r--r-- | tracker-easy/preview.cpp | 10 | ||||
-rw-r--r-- | tracker-easy/preview.h | 2 | ||||
-rw-r--r-- | tracker-easy/settings.h | 30 | ||||
-rw-r--r-- | tracker-easy/tracker-easy-dialog.cpp | 164 | ||||
-rw-r--r-- | tracker-easy/tracker-easy-dialog.h | 9 | ||||
-rw-r--r-- | tracker-easy/tracker-easy-settings.ui | 1261 | ||||
-rw-r--r-- | tracker-easy/tracker-easy.cpp | 599 | ||||
-rw-r--r-- | tracker-easy/tracker-easy.h | 38 |
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><html><head/><body><p>Location of the two remaining model points<br/>with respect to the reference point in default pose</p><p>Use any units you want, not necessarily centimeters.</p></body></html></source> + <source>EPNP</source> <translation type="unfinished"></translation> </message> <message> - <source>y:</source> + <source>DLS</source> <translation type="unfinished"></translation> </message> <message> - <source><html><head/><body><p><span style=" font-size:16pt;">P</span><span style=" font-size:16pt; vertical-align:sub;">3</span></p></body></html></source> + <source>UPNP</source> <translation type="unfinished"></translation> </message> <message> - <source><html><head/><body><p><span style=" font-size:16pt;">P</span><span style=" font-size:16pt; vertical-align:sub;">2</span></p></body></html></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'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><html><head/><body><p><span style=" font-weight:600;">Easy Tracker<br/>Version 0.1</span></p><p><span style=" font-weight:600;">by Stéphane Lenclud</span></p><p>See <a href="https://github.com/opentrack/opentrack/wiki/Easy-Tracker"><span style=" font-weight:600; text-decoration: underline; color:#9999AA;">documentation on GitHub</span></a></p></body></html></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><html><head/><body><p><span style=" font-size:12pt;">X</span></p></body></html></source> <translation type="unfinished"></translation> </message> <message> - <source>P3P</source> + <source><html><head/><body><p><span style=" font-size:12pt;">Y</span></p></body></html></source> <translation type="unfinished"></translation> </message> <message> - <source>ITERATIVE</source> + <source><html><head/><body><p><span style=" font-size:12pt;">Z</span></p></body></html></source> <translation type="unfinished"></translation> </message> <message> - <source>EPNP</source> + <source><html><head/><body><p><span style=" font-weight:600;">Easy Tracker<br/>Version 1.0</span></p><p><span style=" font-weight:600;">by Stéphane Lenclud</span></p><p>See <a href="https://github.com/opentrack/opentrack/wiki/Easy-Tracker"><span style=" font-weight:600; text-decoration: underline; color:#9999aa;">documentation on GitHub</span></a></p></body></html></source> <translation type="unfinished"></translation> </message> <message> - <source>DLS</source> + <source>Auto center</source> <translation type="unfinished"></translation> </message> <message> - <source>UPNP</source> + <source><html><head/><body><p>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.</p></body></html></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><html><head/><body><p>Location of the two remaining model points<br/>with respect to the reference point in default pose</p><p>Use any units you want, not necessarily centimeters.</p></body></html></source> - <translatorcomment>Расположение двух оставшихся точек модели относительно опорной точки в стандартной позе. Возможно исп-ть любые единицы измерения, не обязательно сантиметры.</translatorcomment> - <translation><html><head/><body><p> Расположение двух оставшихся точек модели<br/>относительно опорной точки в стандартной позе. </p><p>Возможно использовать любые единицы измерения.</p></body></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><html><head/><body><p><span style=" font-size:16pt;">P</span><span style=" font-size:16pt; vertical-align:sub;">3</span></p></body></html></source> - <translation></translation> + <source>UPNP</source> + <translation type="unfinished"></translation> </message> <message> - <source><html><head/><body><p><span style=" font-size:16pt;">P</span><span style=" font-size:16pt; vertical-align:sub;">2</span></p></body></html></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'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><html><head/><body><p><span style=" font-weight:600;">Easy Tracker<br/>Version 0.1</span></p><p><span style=" font-weight:600;">by Stéphane Lenclud</span></p><p>See <a href="https://github.com/opentrack/opentrack/wiki/Easy-Tracker"><span style=" font-weight:600; text-decoration: underline; color:#9999AA;">documentation on GitHub</span></a></p></body></html></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><html><head/><body><p><span style=" font-size:12pt;">X</span></p></body></html></source> <translation type="unfinished"></translation> </message> <message> - <source>P3P</source> + <source><html><head/><body><p><span style=" font-size:12pt;">Y</span></p></body></html></source> <translation type="unfinished"></translation> </message> <message> - <source>ITERATIVE</source> + <source><html><head/><body><p><span style=" font-size:12pt;">Z</span></p></body></html></source> <translation type="unfinished"></translation> </message> <message> - <source>EPNP</source> + <source><html><head/><body><p><span style=" font-weight:600;">Easy Tracker<br/>Version 1.0</span></p><p><span style=" font-weight:600;">by Stéphane Lenclud</span></p><p>See <a href="https://github.com/opentrack/opentrack/wiki/Easy-Tracker"><span style=" font-weight:600; text-decoration: underline; color:#9999aa;">documentation on GitHub</span></a></p></body></html></source> <translation type="unfinished"></translation> </message> <message> - <source>DLS</source> + <source>Auto center</source> <translation type="unfinished"></translation> </message> <message> - <source>UPNP</source> + <source><html><head/><body><p>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.</p></body></html></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><html><head/><body><p>Location of the two remaining model points<br/>with respect to the reference point in default pose</p><p>Use any units you want, not necessarily centimeters.</p></body></html></source> + <source>EPNP</source> <translation type="unfinished"></translation> </message> <message> - <source>y:</source> + <source>DLS</source> <translation type="unfinished"></translation> </message> <message> - <source><html><head/><body><p><span style=" font-size:16pt;">P</span><span style=" font-size:16pt; vertical-align:sub;">3</span></p></body></html></source> + <source>UPNP</source> <translation type="unfinished"></translation> </message> <message> - <source><html><head/><body><p><span style=" font-size:16pt;">P</span><span style=" font-size:16pt; vertical-align:sub;">2</span></p></body></html></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'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><html><head/><body><p><span style=" font-weight:600;">Easy Tracker<br/>Version 0.1</span></p><p><span style=" font-weight:600;">by Stéphane Lenclud</span></p><p>See <a href="https://github.com/opentrack/opentrack/wiki/Easy-Tracker"><span style=" font-weight:600; text-decoration: underline; color:#9999AA;">documentation on GitHub</span></a></p></body></html></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><html><head/><body><p><span style=" font-size:12pt;">X</span></p></body></html></source> <translation type="unfinished"></translation> </message> <message> - <source>P3P</source> + <source><html><head/><body><p><span style=" font-size:12pt;">Y</span></p></body></html></source> <translation type="unfinished"></translation> </message> <message> - <source>ITERATIVE</source> + <source><html><head/><body><p><span style=" font-size:12pt;">Z</span></p></body></html></source> <translation type="unfinished"></translation> </message> <message> - <source>EPNP</source> + <source><html><head/><body><p><span style=" font-weight:600;">Easy Tracker<br/>Version 1.0</span></p><p><span style=" font-weight:600;">by Stéphane Lenclud</span></p><p>See <a href="https://github.com/opentrack/opentrack/wiki/Easy-Tracker"><span style=" font-weight:600; text-decoration: underline; color:#9999aa;">documentation on GitHub</span></a></p></body></html></source> <translation type="unfinished"></translation> </message> <message> - <source>DLS</source> + <source>Auto center</source> <translation type="unfinished"></translation> </message> <message> - <source>UPNP</source> + <source><html><head/><body><p>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.</p></body></html></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><html><head/><body><p>Location of the two remaining model points<br/>with respect to the reference point in default pose</p><p>Use any units you want, not necessarily centimeters.</p></body></html></source> - <translation><html><head/><body><p>三点中的两点位置是相对第一个点的</p><p>单位不一定要用厘米</p></body></html></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><html><head/><body><p><span style=" font-size:16pt;">P</span><span style=" font-size:16pt; vertical-align:sub;">3</span></p></body></html></source> - <translation><html><head/><body><p><span style=" font-size:16pt;">P</span><span style=" font-size:16pt; vertical-align:sub;">3</span></p></body></html></translation> + <source>UPNP</source> + <translation type="unfinished"></translation> </message> <message> - <source><html><head/><body><p><span style=" font-size:16pt;">P</span><span style=" font-size:16pt; vertical-align:sub;">2</span></p></body></html></source> - <translation><html><head/><body><p><span style=" font-size:16pt;">P</span><span style=" font-size:16pt; vertical-align:sub;">2</span></p></body></html></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'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><html><head/><body><p><span style=" font-weight:600;">Easy Tracker<br/>Version 0.1</span></p><p><span style=" font-weight:600;">by Stéphane Lenclud</span></p><p>See <a href="https://github.com/opentrack/opentrack/wiki/Easy-Tracker"><span style=" font-weight:600; text-decoration: underline; color:#9999AA;">documentation on GitHub</span></a></p></body></html></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><html><head/><body><p><span style=" font-size:12pt;">X</span></p></body></html></source> <translation type="unfinished"></translation> </message> <message> - <source>P3P</source> + <source><html><head/><body><p><span style=" font-size:12pt;">Y</span></p></body></html></source> <translation type="unfinished"></translation> </message> <message> - <source>ITERATIVE</source> + <source><html><head/><body><p><span style=" font-size:12pt;">Z</span></p></body></html></source> <translation type="unfinished"></translation> </message> <message> - <source>EPNP</source> + <source><html><head/><body><p><span style=" font-weight:600;">Easy Tracker<br/>Version 1.0</span></p><p><span style=" font-weight:600;">by Stéphane Lenclud</span></p><p>See <a href="https://github.com/opentrack/opentrack/wiki/Easy-Tracker"><span style=" font-weight:600; text-decoration: underline; color:#9999aa;">documentation on GitHub</span></a></p></body></html></source> <translation type="unfinished"></translation> </message> <message> - <source>DLS</source> + <source>Auto center</source> <translation type="unfinished"></translation> </message> <message> - <source>UPNP</source> + <source><html><head/><body><p>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.</p></body></html></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><html><head/><body><p>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.</p></body></html></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><html><head/><body><p><span style=" font-size:12pt;">X</span></p></body></html></string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_6"> + <property name="text"> + <string><html><head/><body><p><span style=" font-size:12pt;">Y</span></p></body></html></string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_11"> + <property name="text"> + <string><html><head/><body><p><span style=" font-size:12pt;">Z</span></p></body></html></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><html><head/><body><p>Location of the two remaining model points<br/>with respect to the reference point in default pose</p><p>Use any units you want, not necessarily centimeters.</p></body></html></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><html><head/><body><p><span style=" font-size:16pt;">P</span><span style=" font-size:16pt; vertical-align:sub;">3</span></p></body></html></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><html><head/><body><p><span style=" font-size:16pt;">P</span><span style=" font-size:16pt; vertical-align:sub;">2</span></p></body></html></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><html><head/><body><p><span style=" font-weight:600;">Easy Tracker<br/>Version 0.1</span></p><p><span style=" font-weight:600;">by Stéphane Lenclud</span></p><p>See <a href="https://github.com/opentrack/opentrack/wiki/Easy-Tracker"><span style=" font-weight:600; text-decoration: underline; color:#9999AA;">documentation on GitHub</span></a></p></body></html></string> + <string><html><head/><body><p><span style=" font-weight:600;">Easy Tracker<br/>Version 1.0</span></p><p><span style=" font-weight:600;">by Stéphane Lenclud</span></p><p>See <a href="https://github.com/opentrack/opentrack/wiki/Easy-Tracker"><span style=" font-weight:600; text-decoration: underline; color:#9999aa;">documentation on GitHub</span></a></p></body></html></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(¢er_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(¢er_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(¢er_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(¢er_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 }; }; } |