summaryrefslogtreecommitdiffhomepage
path: root/tracker-pt
diff options
context:
space:
mode:
Diffstat (limited to 'tracker-pt')
-rw-r--r--tracker-pt/CMakeLists.txt5
-rw-r--r--tracker-pt/FTNoIR_PT_Controls.ui746
-rw-r--r--tracker-pt/ftnoir_tracker_pt.cpp96
-rw-r--r--tracker-pt/ftnoir_tracker_pt.h12
-rw-r--r--tracker-pt/ftnoir_tracker_pt_dialog.cpp72
-rw-r--r--tracker-pt/ftnoir_tracker_pt_dialog.h9
-rw-r--r--tracker-pt/lang/de_DE.ts378
-rw-r--r--tracker-pt/lang/nl_NL.ts79
-rw-r--r--tracker-pt/lang/ru_RU.ts79
-rw-r--r--tracker-pt/lang/stub.ts79
-rw-r--r--tracker-pt/lang/zh_CN.ts79
-rw-r--r--tracker-pt/module/CMakeLists.txt5
-rw-r--r--tracker-pt/module/camera.cpp21
-rw-r--r--tracker-pt/module/camera.h4
-rw-r--r--tracker-pt/module/frame.cpp53
-rw-r--r--tracker-pt/module/frame.hpp8
-rw-r--r--tracker-pt/module/lang/de_DE.ts11
-rw-r--r--tracker-pt/module/lang/zh_CN.ts2
-rw-r--r--tracker-pt/module/point_extractor.cpp157
-rw-r--r--tracker-pt/module/point_extractor.h18
-rw-r--r--tracker-pt/point-filter.cpp72
-rw-r--r--tracker-pt/point-filter.hpp32
-rw-r--r--tracker-pt/point_tracker.cpp24
-rw-r--r--tracker-pt/point_tracker.h17
-rw-r--r--tracker-pt/pt-api.cpp7
-rw-r--r--tracker-pt/pt-api.hpp28
-rw-r--r--tracker-pt/pt-settings.hpp14
27 files changed, 1668 insertions, 439 deletions
diff --git a/tracker-pt/CMakeLists.txt b/tracker-pt/CMakeLists.txt
index 078cd4bc..0c2e9ce3 100644
--- a/tracker-pt/CMakeLists.txt
+++ b/tracker-pt/CMakeLists.txt
@@ -1,9 +1,12 @@
include(opentrack-opencv)
find_package(OpenCV QUIET)
if(OpenCV_FOUND)
+ foreach(k core)
+ otr_install_lib("opencv_${k}" "${opentrack-libexec}")
+ endforeach()
otr_module(tracker-pt-base STATIC)
target_include_directories(${self} SYSTEM PUBLIC ${OpenCV_INCLUDE_DIRS})
- target_link_libraries(${self} opencv_imgproc opentrack-cv opencv_core opentrack-video)
+ target_link_libraries(${self} opentrack-cv opencv_core)
set_property(TARGET ${self} PROPERTY OUTPUT_NAME "pt-base")
endif()
add_subdirectory(module)
diff --git a/tracker-pt/FTNoIR_PT_Controls.ui b/tracker-pt/FTNoIR_PT_Controls.ui
index f683d7c3..53a29c1a 100644
--- a/tracker-pt/FTNoIR_PT_Controls.ui
+++ b/tracker-pt/FTNoIR_PT_Controls.ui
@@ -9,12 +9,12 @@
<rect>
<x>0</x>
<y>0</y>
- <width>418</width>
- <height>724</height>
+ <width>413</width>
+ <height>630</height>
</rect>
</property>
<property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
@@ -32,85 +32,24 @@
<property name="autoFillBackground">
<bool>false</bool>
</property>
- <layout class="QGridLayout" name="gridLayout_9">
- <property name="sizeConstraint">
- <enum>QLayout::SetFixedSize</enum>
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <property name="spacing">
+ <number>0</number>
</property>
- <item row="1" column="0" alignment="Qt::AlignVCenter">
- <widget class="QGroupBox" name="groupBox_5">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="title">
- <string>Status</string>
- </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">
+ <property name="leftMargin">
+ <number>4</number>
+ </property>
+ <property name="topMargin">
+ <number>4</number>
+ </property>
+ <property name="rightMargin">
+ <number>4</number>
+ </property>
+ <property name="bottomMargin">
+ <number>4</number>
+ </property>
+ <item>
<widget class="QTabWidget" name="tabWidget">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
<property name="locale">
<locale language="English" country="UnitedStates"/>
</property>
@@ -118,6 +57,12 @@
<number>0</number>
</property>
<widget class="QWidget" name="tab_2">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
<attribute name="title">
<string>Camera</string>
</attribute>
@@ -134,64 +79,100 @@
<string>Camera settings</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
- <item row="0" column="1">
- <widget class="QComboBox" name="camdevice_combo">
+ <item row="11" column="1">
+ <widget class="QCheckBox" name="chroma_key_overexposed">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0">
+ <widget class="QLabel" name="label_4">
<property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
+ <sizepolicy hsizetype="Minimum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
- <property name="minimumContentsLength">
- <number>10</number>
+ <property name="cursor">
+ <cursorShape>WhatsThisCursor</cursorShape>
+ </property>
+ <property name="toolTip">
+ <string>This should be 56° or 76° for the PS3 Eye, dependent upon the physical lens setting. It's only neccessary to get position correspond to real-world values.</string>
+ </property>
+ <property name="text">
+ <string>Diagonal field of view</string>
</property>
</widget>
</item>
- <item row="4" column="1">
- <widget class="QSpinBox" name="fov">
+ <item row="6" column="0">
+ <widget class="QLabel" name="label_5">
<property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
+ <sizepolicy hsizetype="Minimum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
- <property name="suffix">
- <string>°</string>
+ <property name="text">
+ <string>Dynamic pose (for caps only, never clips)</string>
</property>
- <property name="prefix">
- <string/>
+ </widget>
+ </item>
+ <item row="9" column="0">
+ <widget class="QLabel" name="label_12">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
</property>
- <property name="minimum">
- <number>10</number>
+ <property name="cursor">
+ <cursorShape>WhatsThisCursor</cursorShape>
</property>
- <property name="maximum">
- <number>90</number>
+ <property name="toolTip">
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;For LEDs, 'Natural' is the fastest grayscale mode thanks to optimized SIMD code. Color key allows to track regular pieces of colored paper.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ <property name="text">
+ <string>Color channels used</string>
</property>
</widget>
</item>
- <item row="4" column="0">
- <widget class="QLabel" name="label_4">
+ <item row="8" column="1">
+ <widget class="QPushButton" name="camera_settings">
<property name="sizePolicy">
- <sizepolicy hsizetype="Minimum" vsizetype="Maximum">
+ <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
- <string>Diagonal field of view</string>
+ <string>Open</string>
</property>
</widget>
</item>
- <item row="1" column="0">
- <widget class="QLabel" name="label_36">
+ <item row="4" column="1">
+ <widget class="QCheckBox" name="use_mjpeg">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0">
+ <widget class="QLabel" name="label_13">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
+ <property name="cursor">
+ <cursorShape>WhatsThisCursor</cursorShape>
+ </property>
+ <property name="toolTip">
+ <string>Enable MJPEG compression for high-speed cameras other than the PS3 Eye. Windows only.</string>
+ </property>
<property name="text">
- <string>Width</string>
+ <string>MJPEG compression</string>
</property>
</widget>
</item>
@@ -211,30 +192,28 @@
</property>
</widget>
</item>
- <item row="2" column="1">
- <widget class="QSpinBox" name="res_y_spin">
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_36">
<property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
+ <sizepolicy hsizetype="Minimum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
- <property name="toolTip">
- <string>Desired capture height</string>
- </property>
- <property name="suffix">
- <string> px</string>
- </property>
- <property name="maximum">
- <number>2000</number>
+ <property name="text">
+ <string>Width</string>
</property>
- <property name="singleStep">
- <number>10</number>
+ </widget>
+ </item>
+ <item row="11" column="0">
+ <widget class="QLabel" name="label_16">
+ <property name="text">
+ <string>Chroma key includes overexposed pixels</string>
</property>
</widget>
</item>
- <item row="6" column="0">
- <widget class="QLabel" name="label_6">
+ <item row="8" column="0">
+ <widget class="QLabel" name="label_9">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Maximum">
<horstretch>0</horstretch>
@@ -242,30 +221,30 @@
</sizepolicy>
</property>
<property name="text">
- <string>Dynamic pose timeout</string>
+ <string>Camera settings (when available)</string>
</property>
</widget>
</item>
- <item row="3" column="1">
- <widget class="QSpinBox" name="fps_spin">
+ <item row="7" column="1">
+ <widget class="QSpinBox" name="init_phase_timeout">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
- <property name="toolTip">
- <string>Desired capture framerate</string>
- </property>
<property name="suffix">
- <string> Hz</string>
+ <string> ms</string>
+ </property>
+ <property name="minimum">
+ <number>50</number>
</property>
<property name="maximum">
- <number>2000</number>
+ <number>5000</number>
</property>
</widget>
</item>
- <item row="5" column="1">
+ <item row="6" column="1">
<widget class="QCheckBox" name="dynamic_pose">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
@@ -300,8 +279,8 @@
</property>
</widget>
</item>
- <item row="2" column="0">
- <widget class="QLabel" name="label_41">
+ <item row="7" column="0">
+ <widget class="QLabel" name="label_6">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Maximum">
<horstretch>0</horstretch>
@@ -309,26 +288,20 @@
</sizepolicy>
</property>
<property name="text">
- <string>Height</string>
+ <string>Dynamic pose timeout</string>
</property>
</widget>
</item>
- <item row="6" column="1">
- <widget class="QSpinBox" name="init_phase_timeout">
+ <item row="0" column="1">
+ <widget class="QComboBox" name="camdevice_combo">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
- <property name="suffix">
- <string> ms</string>
- </property>
- <property name="minimum">
- <number>50</number>
- </property>
- <property name="maximum">
- <number>5000</number>
+ <property name="minimumContentsLength">
+ <number>10</number>
</property>
</widget>
</item>
@@ -348,46 +321,39 @@
</property>
</widget>
</item>
- <item row="7" column="1">
- <widget class="QPushButton" name="camera_settings">
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_41">
<property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
+ <sizepolicy hsizetype="Minimum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
- <string>Open</string>
+ <string>Height</string>
</property>
</widget>
</item>
- <item row="7" column="0">
- <widget class="QLabel" name="label_9">
+ <item row="3" column="1">
+ <widget class="QSpinBox" name="fps_spin">
<property name="sizePolicy">
- <sizepolicy hsizetype="Minimum" vsizetype="Maximum">
+ <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
- <property name="text">
- <string>Camera settings (when available)</string>
+ <property name="toolTip">
+ <string>Desired capture framerate</string>
</property>
- </widget>
- </item>
- <item row="8" column="0">
- <widget class="QLabel" name="label_12">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Minimum" vsizetype="Maximum">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
+ <property name="suffix">
+ <string> Hz</string>
</property>
- <property name="text">
- <string>Color channels used</string>
+ <property name="maximum">
+ <number>2000</number>
</property>
</widget>
</item>
- <item row="8" column="1">
+ <item row="9" column="1">
<widget class="QComboBox" name="blob_color">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
@@ -397,12 +363,12 @@
</property>
<item>
<property name="text">
- <string>Average</string>
+ <string>Grayscale BT.709</string>
</property>
</item>
<item>
<property name="text">
- <string>Natural</string>
+ <string>Grayscale (from hardware)</string>
</property>
</item>
<item>
@@ -452,19 +418,93 @@
</item>
</widget>
</item>
- <item row="5" column="0">
- <widget class="QLabel" name="label_5">
+ <item row="5" column="1">
+ <widget class="QSpinBox" name="fov">
<property name="sizePolicy">
- <sizepolicy hsizetype="Minimum" vsizetype="Maximum">
+ <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
+ <property name="suffix">
+ <string>°</string>
+ </property>
+ <property name="prefix">
+ <string/>
+ </property>
+ <property name="minimum">
+ <number>10</number>
+ </property>
+ <property name="maximum">
+ <number>90</number>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QSpinBox" name="res_y_spin">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="toolTip">
+ <string>Desired capture height</string>
+ </property>
+ <property name="suffix">
+ <string> px</string>
+ </property>
+ <property name="maximum">
+ <number>2000</number>
+ </property>
+ <property name="singleStep">
+ <number>10</number>
+ </property>
+ </widget>
+ </item>
+ <item row="10" column="0">
+ <widget class="QLabel" name="label_17">
<property name="text">
- <string>Dynamic pose (for caps only, never clips)</string>
+ <string>Chroma key strength</string>
</property>
</widget>
</item>
+ <item row="10" column="1">
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QSlider" name="chroma_key_strength_slider">
+ <property name="minimum">
+ <number>5</number>
+ </property>
+ <property name="maximum">
+ <number>40</number>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDoubleSpinBox" name="chroma_key_strength_label">
+ <property name="focusPolicy">
+ <enum>Qt::NoFocus</enum>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ <property name="buttonSymbols">
+ <enum>QAbstractSpinBox::NoButtons</enum>
+ </property>
+ <property name="minimum">
+ <double>0.500000000000000</double>
+ </property>
+ <property name="maximum">
+ <double>4.000000000000000</double>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
</layout>
</widget>
</item>
@@ -504,6 +544,12 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
+ <property name="cursor">
+ <cursorShape>WhatsThisCursor</cursorShape>
+ </property>
+ <property name="toolTip">
+ <string>Set minimum size to avoid small stray lights from being treated as points.</string>
+ </property>
<property name="text">
<string>Min size</string>
</property>
@@ -580,6 +626,12 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
+ <property name="cursor">
+ <cursorShape>WhatsThisCursor</cursorShape>
+ </property>
+ <property name="toolTip">
+ <string>Track dependent on point size and not absolute brightness. This may allow more stable tracking.</string>
+ </property>
<property name="text">
<string>Automatic threshold</string>
</property>
@@ -607,6 +659,26 @@
</property>
</widget>
</item>
+ <item row="2" column="1">
+ <widget class="QLabel" name="threshold_value_display">
+ <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="2" column="0">
+ <widget class="QLabel" name="label_14">
+ <property name="text">
+ <string>Value</string>
+ </property>
+ </widget>
+ </item>
<item row="3" column="1">
<widget class="QDoubleSpinBox" name="mindiam_spin">
<property name="sizePolicy">
@@ -629,29 +701,22 @@
</property>
</widget>
</item>
- <item row="2" column="1">
- <widget class="QLabel" name="threshold_value_display">
- <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="2" column="0">
- <widget class="QLabel" name="label_14">
- <property name="text">
- <string>Value</string>
- </property>
- </widget>
- </item>
</layout>
</widget>
</item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>1</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
</layout>
</widget>
<widget class="QWidget" name="tab_4">
@@ -1353,6 +1418,231 @@ Don't roll or change position.</string>
</layout>
</widget>
</item>
+ <item row="2" column="0">
+ <spacer name="verticalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>1</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="tab">
+ <attribute name="title">
+ <string>Filter</string>
+ </attribute>
+ <layout class="QGridLayout" name="gridLayout_9">
+ <item row="0" column="0">
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string>Point filter</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_12">
+ <item row="1" column="1">
+ <widget class="QSlider" name="point_filter_limit_slider">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimum">
+ <number>0</number>
+ </property>
+ <property name="maximum">
+ <number>99</number>
+ </property>
+ <property name="singleStep">
+ <number>1</number>
+ </property>
+ <property name="pageStep">
+ <number>10</number>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2">
+ <widget class="QDoubleSpinBox" name="point_filter_label">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
+ <horstretch>2</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="focusPolicy">
+ <enum>Qt::NoFocus</enum>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ <property name="buttonSymbols">
+ <enum>QAbstractSpinBox::NoButtons</enum>
+ </property>
+ <property name="maximum">
+ <double>999.990000000000009</double>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_15">
+ <property name="text">
+ <string>Limit</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="2">
+ <widget class="QDoubleSpinBox" name="point_filter_deadzone_label">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="focusPolicy">
+ <enum>Qt::NoFocus</enum>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ <property name="buttonSymbols">
+ <enum>QAbstractSpinBox::NoButtons</enum>
+ </property>
+ <property name="suffix">
+ <string> px</string>
+ </property>
+ <property name="maximum">
+ <double>1.000000000000000</double>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QSlider" name="point_filter_slider">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Maximum">
+ <horstretch>10</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimum">
+ <number>0</number>
+ </property>
+ <property name="maximum">
+ <number>400</number>
+ </property>
+ <property name="singleStep">
+ <number>1</number>
+ </property>
+ <property name="pageStep">
+ <number>10</number>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QSlider" name="point_filter_deadzone_slider">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimum">
+ <number>0</number>
+ </property>
+ <property name="maximum">
+ <number>100</number>
+ </property>
+ <property name="singleStep">
+ <number>1</number>
+ </property>
+ <property name="pageStep">
+ <number>3</number>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_30">
+ <property name="text">
+ <string>Deadzone</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="2">
+ <widget class="QDoubleSpinBox" name="point_filter_limit_label">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="focusPolicy">
+ <enum>Qt::NoFocus</enum>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ <property name="buttonSymbols">
+ <enum>QAbstractSpinBox::NoButtons</enum>
+ </property>
+ <property name="maximum">
+ <double>1.000000000000000</double>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QCheckBox" name="enable_point_filter">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="toolTip">
+ <string>Filter point centers prior to pose estimation.</string>
+ </property>
+ <property name="text">
+ <string>Enable</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <spacer name="verticalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
</layout>
</widget>
<widget class="QWidget" name="tab_3">
@@ -1390,7 +1680,74 @@ Don't roll or change position.</string>
</widget>
</widget>
</item>
- <item row="2" column="0">
+ <item>
+ <widget class="QGroupBox" name="groupBox_5">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Status</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_10">
+ <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>
+ <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>
+ </layout>
+ </widget>
+ </item>
+ <item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
@@ -1411,11 +1768,14 @@ Don't roll or change position.</string>
<tabstop>res_x_spin</tabstop>
<tabstop>res_y_spin</tabstop>
<tabstop>fps_spin</tabstop>
+ <tabstop>use_mjpeg</tabstop>
<tabstop>fov</tabstop>
<tabstop>dynamic_pose</tabstop>
<tabstop>init_phase_timeout</tabstop>
<tabstop>camera_settings</tabstop>
<tabstop>blob_color</tabstop>
+ <tabstop>chroma_key_strength_slider</tabstop>
+ <tabstop>chroma_key_overexposed</tabstop>
<tabstop>auto_threshold</tabstop>
<tabstop>threshold_slider</tabstop>
<tabstop>mindiam_spin</tabstop>
@@ -1426,8 +1786,8 @@ Don't roll or change position.</string>
<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>cap_height_spin</tabstop>
<tabstop>m1x_spin</tabstop>
<tabstop>m1y_spin</tabstop>
<tabstop>m1z_spin</tabstop>
@@ -1438,6 +1798,14 @@ Don't roll or change position.</string>
<tabstop>ty_spin</tabstop>
<tabstop>tz_spin</tabstop>
<tabstop>tcalib_button</tabstop>
+ <tabstop>enable_point_filter</tabstop>
+ <tabstop>point_filter_slider</tabstop>
+ <tabstop>point_filter_limit_slider</tabstop>
+ <tabstop>point_filter_deadzone_slider</tabstop>
+ <tabstop>maxdiam_spin</tabstop>
+ <tabstop>mindiam_spin</tabstop>
+ <tabstop>auto_threshold</tabstop>
+ <tabstop>threshold_slider</tabstop>
</tabstops>
<resources>
<include location="module/tracker_pt.qrc"/>
diff --git a/tracker-pt/ftnoir_tracker_pt.cpp b/tracker-pt/ftnoir_tracker_pt.cpp
index de95a0d4..0f8495d9 100644
--- a/tracker-pt/ftnoir_tracker_pt.cpp
+++ b/tracker-pt/ftnoir_tracker_pt.cpp
@@ -6,6 +6,7 @@
* copyright notice and this permission notice appear in all copies.
*/
+#undef NDEBUG
#include "ftnoir_tracker_pt.h"
#include "pt-api.hpp"
#include "cv/init.hpp"
@@ -13,7 +14,9 @@
#include "compat/math-imports.hpp"
#include "compat/check-visible.hpp"
#include "compat/thread-name.hpp"
+#include "compat/qt-dpi.hpp"
+#include <cassert>
#include <QHBoxLayout>
#include <QDebug>
#include <QFile>
@@ -27,17 +30,11 @@ Tracker_PT::Tracker_PT(pointer<pt_runtime_traits> const& traits) :
traits { traits },
s { traits->get_module_name() },
point_extractor { traits->make_point_extractor() },
- camera { traits->make_camera() },
- frame { traits->make_frame() },
- preview_frame { traits->make_preview(preview_width, preview_height) }
+ frame { traits->make_frame() }
{
opencv_init();
- connect(s.b.get(), &bundle_::saving, this, &Tracker_PT::maybe_reopen_camera, Qt::DirectConnection);
- connect(s.b.get(), &bundle_::reloading, this, &Tracker_PT::maybe_reopen_camera, Qt::DirectConnection);
-
- connect(&s.fov, value_::value_changed<int>(), this, &Tracker_PT::set_fov, Qt::DirectConnection);
- set_fov(s.fov);
+ connect(&*s.b, &bundle_::saving, this, [this]{ reopen_camera_flag = true; }, Qt::DirectConnection);
}
Tracker_PT::~Tracker_PT()
@@ -45,24 +42,41 @@ Tracker_PT::~Tracker_PT()
requestInterruption();
wait();
- QMutexLocker l(&camera_mtx);
- camera->stop();
+ if (camera)
+ camera->stop();
+}
+
+bool Tracker_PT::check_camera()
+{
+ if (reopen_camera_flag)
+ {
+ reopen_camera_flag = false;
+
+ camera = nullptr;
+ camera = traits->make_camera();
+ if (!camera || !camera->start(s))
+ return false;
+ }
+ assert(camera);
+ if (progn(bool x = true; return open_camera_dialog_flag.compare_exchange_strong(x, false);))
+ run_in_thread_sync(qApp->thread(), [this] { camera->show_camera_settings(); });
+ return true;
}
void Tracker_PT::run()
{
portable::set_curthread_name("tracker/pt");
- if (!maybe_reopen_camera())
- return;
-
while(!isInterruptionRequested())
{
+ if (!check_camera())
+ break;
+
pt_camera_info info;
bool new_frame = false;
{
- QMutexLocker l(&camera_mtx);
+ camera->set_fov(s.fov);
std::tie(new_frame, info) = camera->get_frame(*frame);
}
@@ -70,10 +84,10 @@ void Tracker_PT::run()
{
const bool preview_visible = check_is_visible();
- if (preview_visible)
- *preview_frame = *frame;
+ if (preview_visible && !widget->fresh())
+ preview_frame->set_last_frame(*frame);
- point_extractor->extract_points(*frame, *preview_frame, points);
+ point_extractor->extract_points(*frame, *preview_frame, preview_visible && !widget->fresh(), points);
point_count.store(points.size(), std::memory_order_relaxed);
const bool success = points.size() >= PointModel::N_POINTS;
@@ -87,10 +101,7 @@ void Tracker_PT::run()
{
int dynamic_pose_ms = s.dynamic_pose ? s.init_phase_timeout : 0;
- point_tracker.track(points,
- PointModel(s),
- info,
- dynamic_pose_ms);
+ point_tracker.track(points, PointModel(s), info, dynamic_pose_ms, filter, camera->deadzone_amount());
ever_success.store(true, std::memory_order_relaxed);
}
@@ -98,7 +109,7 @@ void Tracker_PT::run()
X_CM = point_tracker.pose();
}
- if (preview_visible)
+ if (preview_visible && !widget->fresh())
{
const f fx = pt_camera_info::get_focal_length(info.fov, info.res_x, info.res_y);
Affine X_MH(mat33::eye(), vec3(s.t_MH_x, s.t_MH_y, s.t_MH_z));
@@ -109,44 +120,31 @@ void Tracker_PT::run()
preview_frame->draw_head_center((p[0] * fx) / p[2], (p[1] * fx) / p[2]);
widget->update_image(preview_frame->get_bitmap());
-
- auto [ w, h ] = widget->preview_size();
- if (w != preview_width || h != preview_height)
- {
- preview_width = w; preview_height = h;
- preview_frame = traits->make_preview(w, h);
- }
}
}
}
}
-bool Tracker_PT::maybe_reopen_camera()
-{
- QMutexLocker l(&camera_mtx);
-
- return camera->start(s.camera_name,
- s.cam_fps, s.cam_res_x, s.cam_res_y);
-}
-
-void Tracker_PT::set_fov(int value)
-{
- QMutexLocker l(&camera_mtx);
- camera->set_fov(value);
-}
-
module_status Tracker_PT::start_tracker(QFrame* video_frame)
{
- //video_frame->setAttribute(Qt::WA_NativeWindow);
+ {
+ auto camera = traits->make_camera();
+ if (!camera || !camera->start(s))
+ return error(tr("Failed to open camera '%1'").arg(s.camera_name));
+ }
widget = std::make_unique<video_widget>(video_frame);
layout = std::make_unique<QHBoxLayout>(video_frame);
layout->setContentsMargins(0, 0, 0, 0);
- layout->addWidget(widget.get());
- video_frame->setLayout(layout.get());
+ layout->addWidget(&*widget);
+ video_frame->setLayout(&*layout);
//video_widget->resize(video_frame->width(), video_frame->height());
video_frame->show();
+ double dpi = screen_dpi(video_frame);
+ preview_frame = traits->make_preview(iround(preview_width * dpi),
+ iround(preview_height * dpi));
+
start(QThread::HighPriority);
return {};
@@ -212,10 +210,10 @@ int Tracker_PT::get_n_points()
bool Tracker_PT::get_cam_info(pt_camera_info& info)
{
- QMutexLocker l(&camera_mtx);
- bool ret;
+ bool ret = false;
- std::tie(ret, info) = camera->get_info();
+ if (camera)
+ std::tie(ret, info) = camera->get_info();
return ret;
}
diff --git a/tracker-pt/ftnoir_tracker_pt.h b/tracker-pt/ftnoir_tracker_pt.h
index 210c6a01..a793f94b 100644
--- a/tracker-pt/ftnoir_tracker_pt.h
+++ b/tracker-pt/ftnoir_tracker_pt.h
@@ -13,13 +13,12 @@
#include "point_tracker.h"
#include "cv/numeric.hpp"
#include "video/video-widget.hpp"
+#include "point-filter.hpp"
#include <atomic>
#include <memory>
#include <vector>
-#include <opencv2/core.hpp>
-
#include <QThread>
#include <QMutex>
#include <QLayout>
@@ -48,14 +47,10 @@ struct Tracker_PT : QThread, ITracker
private:
void run() override;
-
- bool maybe_reopen_camera();
- void set_fov(int value);
+ [[nodiscard]] bool check_camera();
pointer<pt_runtime_traits> traits;
- QMutex camera_mtx;
-
PointTracker point_tracker;
pt_settings s;
@@ -73,7 +68,10 @@ private:
std::atomic<unsigned> point_count { 0 };
std::atomic<bool> ever_success = false;
+ std::atomic<bool> reopen_camera_flag = true;
+ std::atomic<bool> open_camera_dialog_flag = false;
mutable QMutex center_lock, data_lock;
+ point_filter filter{s};
};
} // ns pt_impl
diff --git a/tracker-pt/ftnoir_tracker_pt_dialog.cpp b/tracker-pt/ftnoir_tracker_pt_dialog.cpp
index 32916cc5..d67f79a7 100644
--- a/tracker-pt/ftnoir_tracker_pt_dialog.cpp
+++ b/tracker-pt/ftnoir_tracker_pt_dialog.cpp
@@ -10,8 +10,6 @@
#include "compat/math.hpp"
#include "video/camera.hpp"
-#include <opencv2/core.hpp>
-
#include <QString>
#include <QtGlobal>
#include <QDebug>
@@ -39,6 +37,7 @@ TrackerDialog_PT::TrackerDialog_PT(const QString& module_name) :
tie_setting(s.cam_res_x, ui.res_x_spin);
tie_setting(s.cam_res_y, ui.res_y_spin);
tie_setting(s.cam_fps, ui.fps_spin);
+ tie_setting(s.use_mjpeg, ui.use_mjpeg);
tie_setting(s.threshold_slider, ui.threshold_slider);
@@ -92,11 +91,9 @@ TrackerDialog_PT::TrackerDialog_PT(const QString& module_name) :
poll_tracker_info_impl();
- connect(this, &TrackerDialog_PT::poll_tracker_info, this, &TrackerDialog_PT::poll_tracker_info_impl, Qt::DirectConnection);
-
constexpr pt_color_type color_types[] = {
- pt_color_average,
- pt_color_natural,
+ pt_color_bt709,
+ pt_color_hardware,
pt_color_red_only,
pt_color_green_only,
pt_color_blue_only,
@@ -113,14 +110,38 @@ TrackerDialog_PT::TrackerDialog_PT(const QString& module_name) :
tie_setting(s.blob_color, ui.blob_color);
+ tie_setting(s.chroma_key_strength, ui.chroma_key_strength_slider);
+ connect(&s.chroma_key_strength, value_::value_changed<slider_value>(), ui.chroma_key_strength_label,
+ [this] { ui.chroma_key_strength_label->setValue(*s.chroma_key_strength); });
+ ui.chroma_key_strength_label->setValue(*s.chroma_key_strength);
+
+ tie_setting(s.chroma_key_overexposed, ui.chroma_key_overexposed);
+ connect(ui.blob_color, &QComboBox::currentTextChanged, this, &TrackerDialog_PT::chroma_key_controls_enable);
+
+ chroma_key_controls_enable("");
+
tie_setting(s.threshold_slider, ui.threshold_value_display, [this](const slider_value& val) {
return threshold_display_text(int(val));
});
// refresh threshold display on auto-threshold checkbox state change
- tie_setting(s.auto_threshold,
- this,
- [this](bool) { s.threshold_slider.notify(); });
+ tie_setting(s.auto_threshold, this, [this](bool) { s.threshold_slider.notify_(); });
+
+ tie_setting(s.enable_point_filter, ui.enable_point_filter);
+ tie_setting(s.point_filter_coefficient, ui.point_filter_slider);
+ tie_setting(s.point_filter_limit, ui.point_filter_limit_slider);
+ connect(&s.point_filter_coefficient, value_::value_changed<slider_value>(),
+ ui.point_filter_label, [this] { ui.point_filter_label->setValue(*s.point_filter_coefficient); } );
+ connect(&s.point_filter_limit, value_::value_changed<slider_value>(), ui.point_filter_limit_label,
+ [this] { ui.point_filter_limit_label->setValue(*s.point_filter_limit); }, Qt::QueuedConnection);
+ ui.point_filter_label->setValue(*s.point_filter_coefficient);
+ ui.point_filter_limit_label->setValue(*s.point_filter_limit);
+
+ tie_setting(s.point_filter_deadzone, ui.point_filter_deadzone_slider);
+ ui.point_filter_deadzone_label->setValue(*s.point_filter_deadzone);
+
+ connect(&s.point_filter_deadzone, value_::value_changed<slider_value>(), ui.point_filter_deadzone_label,
+ [this] { ui.point_filter_deadzone_label->setValue(*s.point_filter_deadzone); }, Qt::QueuedConnection);
}
QString TrackerDialog_PT::threshold_display_text(int threshold_value)
@@ -232,14 +253,25 @@ void TrackerDialog_PT::set_camera_settings_available(const QString& /* camera_na
void TrackerDialog_PT::show_camera_settings()
{
if (tracker)
- {
- QMutexLocker l(&tracker->camera_mtx);
- tracker->camera->show_camera_settings();
- }
+ tracker->open_camera_dialog_flag = true;
else
(void)video::show_dialog(s.camera_name);
}
+void TrackerDialog_PT::chroma_key_controls_enable(const QString&)
+{
+ bool enabled = false;
+ QVariant data = ui.blob_color->currentData();
+ if (data.isValid())
+ {
+ pt_color_type blob_color = pt_color_type(data.toInt());
+ enabled = blob_color >= pt_color_red_chromakey && blob_color <= pt_color_magenta_chromakey;
+ }
+ ui.chroma_key_strength_slider->setEnabled(enabled);
+ ui.chroma_key_strength_label->setEnabled(enabled);
+ ui.chroma_key_overexposed->setEnabled(enabled);
+}
+
void TrackerDialog_PT::trans_calib_step()
{
QMutexLocker l(&calibrator_mutex);
@@ -273,7 +305,7 @@ void TrackerDialog_PT::register_tracker(ITracker *t)
{
tracker = static_cast<Tracker_PT*>(t);
ui.tcalib_button->setEnabled(true);
- poll_tracker_info();
+ poll_tracker_info_impl();
timer.start();
}
@@ -281,8 +313,18 @@ void TrackerDialog_PT::unregister_tracker()
{
tracker = nullptr;
ui.tcalib_button->setEnabled(false);
- poll_tracker_info();
+ poll_tracker_info_impl();
timer.stop();
}
+void TrackerDialog_PT::set_buttons_visible(bool x)
+{
+ ui.buttonBox->setVisible(x);
+}
+
+void TrackerDialog_PT::reload()
+{
+ s.b->reload();
+}
+
} // ns pt_impl
diff --git a/tracker-pt/ftnoir_tracker_pt_dialog.h b/tracker-pt/ftnoir_tracker_pt_dialog.h
index 66981ee6..79cd91bd 100644
--- a/tracker-pt/ftnoir_tracker_pt_dialog.h
+++ b/tracker-pt/ftnoir_tracker_pt_dialog.h
@@ -26,7 +26,10 @@ public:
TrackerDialog_PT(const QString& module_name);
void register_tracker(ITracker *tracker) override;
void unregister_tracker() override;
- void save();
+ bool embeddable() noexcept override { return true; }
+ void set_buttons_visible(bool x) override;
+ void save() override;
+ void reload() override;
public slots:
void doOK();
void doCancel();
@@ -36,8 +39,8 @@ public slots:
void poll_tracker_info_impl();
void set_camera_settings_available(const QString& camera_name);
void show_camera_settings();
-signals:
- void poll_tracker_info();
+ void chroma_key_controls_enable(const QString&);
+
protected:
QString threshold_display_text(int threshold_value);
diff --git a/tracker-pt/lang/de_DE.ts b/tracker-pt/lang/de_DE.ts
new file mode 100644
index 00000000..30ab42c2
--- /dev/null
+++ b/tracker-pt/lang/de_DE.ts
@@ -0,0 +1,378 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="de_DE">
+<context>
+ <name>UICPTClientControls</name>
+ <message>
+ <source>PointTracker Settings</source>
+ <translation>PointTracker-Einstellungen</translation>
+ </message>
+ <message>
+ <source>Camera</source>
+ <translation>Kamera</translation>
+ </message>
+ <message>
+ <source>Camera settings</source>
+ <translation>Kamera-Einstellungen</translation>
+ </message>
+ <message>
+ <source>This should be 56° or 76° for the PS3 Eye, dependent upon the physical lens setting. It&apos;s only neccessary to get position correspond to real-world values.</source>
+ <translation>Für die PS3 Eye sollte dies 56° oder 76° sein, abhängig von der Einstellung der physikalischen Linse. Dies wird nur benutzt, um die Position aus den Welt-Koordinaten zur ermitteln.</translation>
+ </message>
+ <message>
+ <source>Diagonal field of view</source>
+ <translation>Diagonales Sichtfeld</translation>
+ </message>
+ <message>
+ <source>Dynamic pose (for caps only, never clips)</source>
+ <translation>Dynamische Pose (nur für Hüte, niemals Sticker)</translation>
+ </message>
+ <message>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;For LEDs, &apos;Natural&apos; is the fastest grayscale mode thanks to optimized SIMD code. Color key allows to track regular pieces of colored paper.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;‚Natürlich‘ ist, dank des optimierten SIMD-Codes, die schnellste Methode für LEDs. Mit dem Farbschlüssel kann man normale farbige Papierstücke tracken.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <source>Color channels used</source>
+ <translation>Benutzte Farbkanäle</translation>
+ </message>
+ <message>
+ <source>Open</source>
+ <translation>Öffnen</translation>
+ </message>
+ <message>
+ <source>Enable MJPEG compression for high-speed cameras other than the PS3 Eye. Windows only.</source>
+ <translation>Aktiviert MJPEG-Kompression für Hochgeschwindigkeitskameras, PS3 Eye ausgenommen. Nur für Windows.</translation>
+ </message>
+ <message>
+ <source>MJPEG compression</source>
+ <translation>MJPEG-Kompression</translation>
+ </message>
+ <message>
+ <source>FPS</source>
+ <translation>FPS</translation>
+ </message>
+ <message>
+ <source>Width</source>
+ <translation>Breite</translation>
+ </message>
+ <message>
+ <source>Chroma key includes overexposed pixels</source>
+ <translation>Chroma-Key enthält überbelichtete Pixel</translation>
+ </message>
+ <message>
+ <source>Camera settings (when available)</source>
+ <translation>Kamera-Einstellungen (falls verfügbar)</translation>
+ </message>
+ <message>
+ <source> ms</source>
+ <translation> ms</translation>
+ </message>
+ <message>
+ <source>Desired capture width</source>
+ <translation>Angestrebte Aufnahmebreite</translation>
+ </message>
+ <message>
+ <source> px</source>
+ <translation> px</translation>
+ </message>
+ <message>
+ <source>Dynamic pose timeout</source>
+ <translation>Dynamisches Pose-Timeout</translation>
+ </message>
+ <message>
+ <source>Device</source>
+ <translation>Gerät</translation>
+ </message>
+ <message>
+ <source>Height</source>
+ <translation>Höhe</translation>
+ </message>
+ <message>
+ <source>Desired capture framerate</source>
+ <translation>Angestrebte Aufnahme-Bildrate</translation>
+ </message>
+ <message>
+ <source> Hz</source>
+ <translation> Hz</translation>
+ </message>
+ <message>
+ <source>Grayscale BT.709</source>
+ <translation>Graustufen BT.709</translation>
+ </message>
+ <message>
+ <source>Grayscale (from hardware)</source>
+ <translation>Graustufen (gemäß Hardware)</translation>
+ </message>
+ <message>
+ <source>Red only</source>
+ <translation>nur Rot</translation>
+ </message>
+ <message>
+ <source>Green only</source>
+ <translation>nur Grün</translation>
+ </message>
+ <message>
+ <source>Blue only</source>
+ <translation>nur Blau</translation>
+ </message>
+ <message>
+ <source>Red chroma key</source>
+ <translation>Roter Chroma-Key</translation>
+ </message>
+ <message>
+ <source>Green chroma key</source>
+ <translation>Grüner Chroma-Key</translation>
+ </message>
+ <message>
+ <source>Blue chroma key</source>
+ <translation>Blauer Chroma-Key</translation>
+ </message>
+ <message>
+ <source>Cyan chroma key</source>
+ <translation>Cyan-Chroma-Key</translation>
+ </message>
+ <message>
+ <source>Yellow chroma key</source>
+ <translation>Gelber Chroma-Key</translation>
+ </message>
+ <message>
+ <source>Magenta chroma key</source>
+ <translation>Magenta-Chroma-Key</translation>
+ </message>
+ <message>
+ <source>°</source>
+ <translation>°</translation>
+ </message>
+ <message>
+ <source>Desired capture height</source>
+ <translation>Angestrebte Aufnahmehöhe</translation>
+ </message>
+ <message>
+ <source>Chroma key strength</source>
+ <translation>Chroma-Key-Stärke</translation>
+ </message>
+ <message>
+ <source>Point extraction</source>
+ <translation>Punktextraktion</translation>
+ </message>
+ <message>
+ <source>Threshold</source>
+ <translation>Schwelle</translation>
+ </message>
+ <message>
+ <source>Set minimum size to avoid small stray lights from being treated as points.</source>
+ <translation>Setzt die Mindestgröße, um zu verhindern, dass kleine Streulichter als Punkte erkannt werden.</translation>
+ </message>
+ <message>
+ <source>Min size</source>
+ <translation>Mindestgröße</translation>
+ </message>
+ <message>
+ <source>Max size</source>
+ <translation>Maximale Größe</translation>
+ </message>
+ <message>
+ <source>Intensity threshold for point extraction</source>
+ <translation>Intensitätsschwelle für die Punktextraktion</translation>
+ </message>
+ <message>
+ <source>Enable, slider sets point size</source>
+ <translation>Aktivieren, Regler setzt die Punktgröße</translation>
+ </message>
+ <message>
+ <source>Track dependent on point size and not absolute brightness. This may allow more stable tracking.</source>
+ <translation>Tracking abhängig von der Punktgröße anstelle der absoluten Helligkeit durchführen. Dies kann stabileres Tracking ermöglichen.</translation>
+ </message>
+ <message>
+ <source>Automatic threshold</source>
+ <translation>Automatische Schwelle</translation>
+ </message>
+ <message>
+ <source>Maximum point diameter</source>
+ <translation>Maximaler Punktdurchmesser</translation>
+ </message>
+ <message>
+ <source>Value</source>
+ <translation>Wert</translation>
+ </message>
+ <message>
+ <source>Minimum point diameter</source>
+ <translation>Minimaler Punktdurchmesser</translation>
+ </message>
+ <message>
+ <source>Model</source>
+ <translation>Modell</translation>
+ </message>
+ <message>
+ <source>Clip</source>
+ <translation>Sticker</translation>
+ </message>
+ <message>
+ <source>Model Dimensions</source>
+ <translation>Modellabmessungen</translation>
+ </message>
+ <message>
+ <source> mm</source>
+ <translation> mm</translation>
+ </message>
+ <message>
+ <source>Side</source>
+ <translation>Seitlich</translation>
+ </message>
+ <message>
+ <source>Front</source>
+ <translation>Vorne</translation>
+ </message>
+ <message>
+ <source>Cap</source>
+ <translation>Hut</translation>
+ </message>
+ <message>
+ <source>Custom</source>
+ <translation>Benutzerdefiniert</translation>
+ </message>
+ <message>
+ <source>z:</source>
+ <translation>z:</translation>
+ </message>
+ <message>
+ <source>x:</source>
+ <translation>x:</translation>
+ </message>
+ <message>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Location of the two remaining model points&lt;br/&gt;with respect to the reference point in default pose&lt;/p&gt;&lt;p&gt;Use any units you want, not necessarily centimeters.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Ort der verbleibenden zwei Modellpunkte&lt;br/&gt;unter Berücksichtigung der Referenzpunkte der Standard-Pose&lt;/p&gt;&lt;p&gt;Dies können beliebige Einheiten sein, nicht zwingend Zentimeter.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <source>y:</source>
+ <translation>y:</translation>
+ </message>
+ <message>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:16pt;&quot;&gt;P&lt;/span&gt;&lt;span style=&quot; font-size:16pt; vertical-align:sub;&quot;&gt;3&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:16pt;&quot;&gt;P&lt;/span&gt;&lt;span style=&quot; font-size:16pt; vertical-align:sub;&quot;&gt;3&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:16pt;&quot;&gt;P&lt;/span&gt;&lt;span style=&quot; font-size:16pt; vertical-align:sub;&quot;&gt;2&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:16pt;&quot;&gt;P&lt;/span&gt;&lt;span style=&quot; font-size:16pt; vertical-align:sub;&quot;&gt;2&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <source>Model position</source>
+ <translation>Modell-Position</translation>
+ </message>
+ <message>
+ <source>Use only yaw and pitch while calibrating.
+Don&apos;t roll or change position.</source>
+ <translation>Bitte nur gieren oder nicken während der Kalibrierung.
+Bitte nicht rollen oder die Position ändern.</translation>
+ </message>
+ <message>
+ <source>Start calibration</source>
+ <translation>Kalibrierung starten</translation>
+ </message>
+ <message>
+ <source>Filter</source>
+ <translation>Filter</translation>
+ </message>
+ <message>
+ <source>Point filter</source>
+ <translation>Punktfilter</translation>
+ </message>
+ <message>
+ <source>Limit</source>
+ <translation>Grenze</translation>
+ </message>
+ <message>
+ <source>Deadzone</source>
+ <translation>Totbereich</translation>
+ </message>
+ <message>
+ <source>Filter point centers prior to pose estimation.</source>
+ <translation>Punktmitten vor der Posen-Abschätzung filtern.</translation>
+ </message>
+ <message>
+ <source>Enable</source>
+ <translation>Einschalten</translation>
+ </message>
+ <message>
+ <source>About</source>
+ <translation>Über</translation>
+ </message>
+ <message>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;FTNoIR PointTracker Plugin&lt;br/&gt;Version 1.1&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;by Patrick Ruoff&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://ftnoirpt.sourceforge.net/&quot;&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline; color:#0000ff;&quot;&gt;Manual (external)&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;FTNoIR PointTracker Plugin&lt;br/&gt;Version 1.1&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;von Patrick Ruoff&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://ftnoirpt.sourceforge.net/&quot;&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline; color:#0000ff;&quot;&gt;Anleitung (extern)&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <source>Status</source>
+ <translation>Status</translation>
+ </message>
+ <message>
+ <source>Extracted Points:</source>
+ <translation>Extrahierte Punkte:</translation>
+ </message>
+ <message>
+ <source>Camera Info:</source>
+ <translation>Kamera-Info:</translation>
+ </message>
+</context>
+<context>
+ <name>pt_impl::TrackerDialog_PT</name>
+ <message>
+ <source>Brightness %1/255</source>
+ <translation>Helligkeit %1/255</translation>
+ </message>
+ <message>
+ <source>LED radius %1 pixels</source>
+ <translation>LED-Radius %1 Pixel</translation>
+ </message>
+ <message>
+ <source>%1 yaw samples. Yaw more to %2 samples for stable calibration.</source>
+ <translation>%1 Gieren-Proben. Weiterhin gieren bis %2 Proben für eine stabile Kalibrierung.</translation>
+ </message>
+ <message>
+ <source>%1 pitch samples. Pitch more to %2 samples for stable calibration.</source>
+ <translation>%1 Nicken-Proben. Weiterhin nicken bis %2 Proben für eine stabile Kalibrierung.</translation>
+ </message>
+ <message>
+ <source>%1 samples. Over %2, good!</source>
+ <translation>%1 Proben. Mehr als %2, gut!</translation>
+ </message>
+ <message>
+ <source>Stop calibration</source>
+ <translation>Kalibrierung stoppen</translation>
+ </message>
+ <message>
+ <source>Start calibration</source>
+ <translation>Kalibrierung starten</translation>
+ </message>
+ <message>
+ <source>%1x%2 @ %3 FPS</source>
+ <translation>%1x%2 @ %3 FPS</translation>
+ </message>
+ <message>
+ <source>%1 OK!</source>
+ <translation>%1 OKAY!</translation>
+ </message>
+ <message>
+ <source>%1 BAD!</source>
+ <translation>%1 SCHLECHT!</translation>
+ </message>
+ <message>
+ <source>Tracker offline</source>
+ <translation>Tracker offline</translation>
+ </message>
+</context>
+<context>
+ <name>pt_impl::Tracker_PT</name>
+ <message>
+ <source>Failed to open camera &apos;%1&apos;</source>
+ <translation>Öffnen der Kamera ‚%1‘ fehlgeschlagen</translation>
+ </message>
+</context>
+<context>
+ <name>pt_module::metadata_pt</name>
+ <message>
+ <source>PointTracker 1.1</source>
+ <translation>PointTracker 1.1</translation>
+ </message>
+</context>
+</TS>
diff --git a/tracker-pt/lang/nl_NL.ts b/tracker-pt/lang/nl_NL.ts
index 3d12a7ea..fc44b0f1 100644
--- a/tracker-pt/lang/nl_NL.ts
+++ b/tracker-pt/lang/nl_NL.ts
@@ -108,14 +108,6 @@
<translation type="unfinished"></translation>
</message>
<message>
- <source>Average</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source>Natural</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
<source>Red only</source>
<translation type="unfinished"></translation>
</message>
@@ -256,6 +248,70 @@ Don&apos;t roll or change position.</source>
<source>Magenta chroma key</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>This should be 56° or 76° for the PS3 Eye, dependent upon the physical lens setting. It&apos;s only neccessary to get position correspond to real-world values.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Enable MJPEG compression for high-speed cameras other than the PS3 Eye. Windows only.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Set minimum size to avoid small stray lights from being treated as points.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Track dependent on point size and not absolute brightness. This may allow more stable tracking.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;For LEDs, &apos;Natural&apos; is the fastest grayscale mode thanks to optimized SIMD code. Color key allows to track regular pieces of colored paper.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>MJPEG compression</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Point filter</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Filter point centers prior to pose estimation.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Enable</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Limit</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Grayscale BT.709</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Grayscale (from hardware)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Deadzone</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Filter</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Chroma key includes overexposed pixels</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Chroma key strength</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>pt_impl::TrackerDialog_PT</name>
@@ -305,6 +361,13 @@ Don&apos;t roll or change position.</source>
</message>
</context>
<context>
+ <name>pt_impl::Tracker_PT</name>
+ <message>
+ <source>Failed to open camera &apos;%1&apos;</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
<name>pt_module::metadata_pt</name>
<message>
<source>PointTracker 1.1</source>
diff --git a/tracker-pt/lang/ru_RU.ts b/tracker-pt/lang/ru_RU.ts
index 0315d493..7ff4657e 100644
--- a/tracker-pt/lang/ru_RU.ts
+++ b/tracker-pt/lang/ru_RU.ts
@@ -112,14 +112,6 @@
<translation type="unfinished"></translation>
</message>
<message>
- <source>Average</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source>Natural</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
<source>Red only</source>
<translation type="unfinished"></translation>
</message>
@@ -261,6 +253,70 @@ ROLL или X/Y-смещения.</translation>
<source>Magenta chroma key</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>This should be 56° or 76° for the PS3 Eye, dependent upon the physical lens setting. It&apos;s only neccessary to get position correspond to real-world values.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Enable MJPEG compression for high-speed cameras other than the PS3 Eye. Windows only.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Set minimum size to avoid small stray lights from being treated as points.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Track dependent on point size and not absolute brightness. This may allow more stable tracking.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;For LEDs, &apos;Natural&apos; is the fastest grayscale mode thanks to optimized SIMD code. Color key allows to track regular pieces of colored paper.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>MJPEG compression</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Point filter</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Filter point centers prior to pose estimation.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Enable</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Limit</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Grayscale BT.709</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Grayscale (from hardware)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Deadzone</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Filter</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Chroma key includes overexposed pixels</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Chroma key strength</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>pt_impl::TrackerDialog_PT</name>
@@ -310,6 +366,13 @@ ROLL или X/Y-смещения.</translation>
</message>
</context>
<context>
+ <name>pt_impl::Tracker_PT</name>
+ <message>
+ <source>Failed to open camera &apos;%1&apos;</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
<name>pt_module::metadata_pt</name>
<message>
<source>PointTracker 1.1</source>
diff --git a/tracker-pt/lang/stub.ts b/tracker-pt/lang/stub.ts
index 4c8c4f82..3dbe208d 100644
--- a/tracker-pt/lang/stub.ts
+++ b/tracker-pt/lang/stub.ts
@@ -108,14 +108,6 @@
<translation type="unfinished"></translation>
</message>
<message>
- <source>Average</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source>Natural</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
<source>Red only</source>
<translation type="unfinished"></translation>
</message>
@@ -256,6 +248,70 @@ Don&apos;t roll or change position.</source>
<source>Magenta chroma key</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>This should be 56° or 76° for the PS3 Eye, dependent upon the physical lens setting. It&apos;s only neccessary to get position correspond to real-world values.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Enable MJPEG compression for high-speed cameras other than the PS3 Eye. Windows only.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Set minimum size to avoid small stray lights from being treated as points.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Track dependent on point size and not absolute brightness. This may allow more stable tracking.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;For LEDs, &apos;Natural&apos; is the fastest grayscale mode thanks to optimized SIMD code. Color key allows to track regular pieces of colored paper.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>MJPEG compression</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Point filter</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Filter point centers prior to pose estimation.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Enable</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Limit</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Grayscale BT.709</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Grayscale (from hardware)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Deadzone</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Filter</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Chroma key includes overexposed pixels</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Chroma key strength</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>pt_impl::TrackerDialog_PT</name>
@@ -305,6 +361,13 @@ Don&apos;t roll or change position.</source>
</message>
</context>
<context>
+ <name>pt_impl::Tracker_PT</name>
+ <message>
+ <source>Failed to open camera &apos;%1&apos;</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
<name>pt_module::metadata_pt</name>
<message>
<source>PointTracker 1.1</source>
diff --git a/tracker-pt/lang/zh_CN.ts b/tracker-pt/lang/zh_CN.ts
index bbbc7f8d..3519d719 100644
--- a/tracker-pt/lang/zh_CN.ts
+++ b/tracker-pt/lang/zh_CN.ts
@@ -200,14 +200,6 @@
<translation type="unfinished"></translation>
</message>
<message>
- <source>Average</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source>Natural</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
<source>Red only</source>
<translation type="unfinished"></translation>
</message>
@@ -256,6 +248,70 @@ Don&apos;t roll or change position.</source>
<source>Magenta chroma key</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>This should be 56° or 76° for the PS3 Eye, dependent upon the physical lens setting. It&apos;s only neccessary to get position correspond to real-world values.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Enable MJPEG compression for high-speed cameras other than the PS3 Eye. Windows only.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Set minimum size to avoid small stray lights from being treated as points.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Track dependent on point size and not absolute brightness. This may allow more stable tracking.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;For LEDs, &apos;Natural&apos; is the fastest grayscale mode thanks to optimized SIMD code. Color key allows to track regular pieces of colored paper.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>MJPEG compression</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Point filter</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Filter point centers prior to pose estimation.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Enable</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Limit</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Grayscale BT.709</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Grayscale (from hardware)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Deadzone</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Filter</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Chroma key includes overexposed pixels</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Chroma key strength</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>pt_impl::TrackerDialog_PT</name>
@@ -305,6 +361,13 @@ Don&apos;t roll or change position.</source>
</message>
</context>
<context>
+ <name>pt_impl::Tracker_PT</name>
+ <message>
+ <source>Failed to open camera &apos;%1&apos;</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
<name>pt_module::metadata_pt</name>
<message>
<source>PointTracker 1.1</source>
diff --git a/tracker-pt/module/CMakeLists.txt b/tracker-pt/module/CMakeLists.txt
index f7a6cc7f..b7fc974f 100644
--- a/tracker-pt/module/CMakeLists.txt
+++ b/tracker-pt/module/CMakeLists.txt
@@ -1,7 +1,10 @@
include(opentrack-opencv)
find_package(OpenCV QUIET)
if(OpenCV_FOUND)
+ foreach(k core imgproc)
+ otr_install_lib("opencv_${k}" "${opentrack-libexec}")
+ endforeach()
otr_module(tracker-pt)
- target_link_libraries(${self} opentrack-tracker-pt-base)
+ target_link_libraries(${self} opentrack-video opencv_imgproc opentrack-tracker-pt-base)
target_include_directories(${self} PUBLIC "${CMAKE_SOURCE_DIR}/tracker-pt")
endif()
diff --git a/tracker-pt/module/camera.cpp b/tracker-pt/module/camera.cpp
index a70698de..1beba474 100644
--- a/tracker-pt/module/camera.cpp
+++ b/tracker-pt/module/camera.cpp
@@ -7,10 +7,7 @@
#include "camera.h"
#include "frame.hpp"
-
-#include "compat/math-imports.hpp"
-
-#include <opencv2/core.hpp>
+#include <opencv2/core/mat.hpp>
namespace pt_module {
@@ -73,23 +70,29 @@ Camera::result Camera::get_frame(pt_frame& frame_)
return { false, {} };
}
-bool Camera::start(const QString& name, int fps, int res_x, int res_y)
+bool Camera::start(const pt_settings& s)
{
+ int fps = s.cam_fps, res_x = s.cam_res_x, res_y = s.cam_res_y;
+ QString name = s.camera_name;
+ bool use_mjpeg = s.use_mjpeg;
+
if (fps >= 0 && res_x >= 0 && res_y >= 0)
{
if (cam_desired.name != name ||
(int)cam_desired.fps != fps ||
cam_desired.res_x != res_x ||
cam_desired.res_y != res_y ||
+ cam_desired.use_mjpeg != use_mjpeg ||
!cap || !cap->is_open())
{
stop();
cam_desired.name = name;
- cam_desired.fps = fps;
+ cam_desired.fps = (f)fps;
cam_desired.res_x = res_x;
cam_desired.res_y = res_y;
cam_desired.fov = fov;
+ cam_desired.use_mjpeg = use_mjpeg;
cap = video::make_camera(name);
@@ -100,12 +103,16 @@ bool Camera::start(const QString& name, int fps, int res_x, int res_y)
info.fps = fps;
info.width = res_x;
info.height = res_y;
+ info.use_mjpeg = use_mjpeg;
+ info.num_channels = s.blob_color == pt_color_hardware ? 1 : 3;
if (!cap->start(info))
goto fail;
cam_info = pt_camera_info();
cam_info.name = name;
+ cam_info.use_mjpeg = use_mjpeg;
+ cam_info.fov = (f)s.fov;
dt_mean = 0;
cv::Mat tmp;
@@ -141,7 +148,7 @@ bool Camera::get_frame_(cv::Mat& img)
int stride = frame.stride;
if (stride == 0)
stride = cv::Mat::AUTO_STEP;
- img = cv::Mat(frame.height, frame.width, CV_8UC(frame.channels), (void*)frame.data, stride);
+ img = cv::Mat(frame.height, frame.width, CV_8UC(frame.channels), (void*)frame.data, (size_t)stride);
return true;
}
}
diff --git a/tracker-pt/module/camera.h b/tracker-pt/module/camera.h
index e2ba159f..e4772178 100644
--- a/tracker-pt/module/camera.h
+++ b/tracker-pt/module/camera.h
@@ -13,8 +13,6 @@
#include <memory>
-#include <opencv2/core.hpp>
-
#include <QString>
namespace pt_module {
@@ -23,7 +21,7 @@ struct Camera final : pt_camera
{
Camera(const QString& module_name);
- bool start(const QString& name, int fps, int res_x, int res_y) override;
+ bool start(const pt_settings& s) override;
void stop() override;
result get_frame(pt_frame& Frame) override;
diff --git a/tracker-pt/module/frame.cpp b/tracker-pt/module/frame.cpp
index ab110871..1a276f16 100644
--- a/tracker-pt/module/frame.cpp
+++ b/tracker-pt/module/frame.cpp
@@ -1,43 +1,52 @@
#include "frame.hpp"
-
#include "compat/math.hpp"
-
#include <opencv2/imgproc.hpp>
namespace pt_module {
-Preview& Preview::operator=(const pt_frame& frame_)
+void Preview::set_last_frame(const pt_frame& frame_)
{
const cv::Mat& frame = frame_.as_const<const Frame>()->mat;
+ const bool need_resize = frame.size != frame_copy.size;
- if (frame.channels() != 3)
+ if (frame.channels() == 1)
{
- eval_once(qDebug() << "tracker/pt: camera frame depth: 3 !=" << frame.channels());
- return *this;
+ if (need_resize)
+ {
+ frame_tmp.create(frame.size(), CV_8UC3);
+ cv::cvtColor(frame, frame_tmp, cv::COLOR_GRAY2BGR);
+ cv::resize(frame_tmp, frame_copy, frame_copy.size(), 0, 0, cv::INTER_NEAREST);
+ }
+ else
+ cv::cvtColor(frame, frame_copy, cv::COLOR_GRAY2BGR);
+ }
+ else if (frame.channels() == 3)
+ {
+ if (need_resize)
+ cv::resize(frame, frame_copy, frame_copy.size(), 0, 0, cv::INTER_NEAREST);
+ else
+ frame.copyTo(frame_copy);
}
-
- const bool need_resize = frame.cols != frame_out.cols || frame.rows != frame_out.rows;
- if (need_resize)
- cv::resize(frame, frame_copy, cv::Size(frame_out.cols, frame_out.rows), 0, 0, cv::INTER_NEAREST);
else
- frame.copyTo(frame_copy);
-
- return *this;
+ {
+ eval_once(qDebug() << "tracker/pt: camera frame depth" << frame.channels() << "!= 3");
+ frame_copy.create(frame_copy.size(), CV_8UC3);
+ frame_copy.setTo({0});
+ }
}
Preview::Preview(int w, int h)
{
- ensure_size(frame_out, w, h, CV_8UC4);
- ensure_size(frame_copy, w, h, CV_8UC3);
-
- frame_copy.setTo(cv::Scalar(0, 0, 0));
+ frame_out.create(h, w, CV_8UC4);
+ frame_copy.create(h, w, CV_8UC3);
+ frame_copy.setTo({0});
}
QImage Preview::get_bitmap()
{
- int stride = frame_out.step.p[0];
+ int stride = (int)frame_out.step.p[0];
- if (stride < 64 || stride < frame_out.cols * 4)
+ if (stride < frame_out.cols * 4)
{
eval_once(qDebug() << "bad stride" << stride
<< "for bitmap size" << frame_copy.cols << frame_copy.rows);
@@ -71,10 +80,4 @@ void Preview::draw_head_center(f x, f y)
color, 1);
}
-void Preview::ensure_size(cv::Mat& frame, int w, int h, int type)
-{
- if (frame.cols != w || frame.rows != h || frame.type() != type)
- frame = cv::Mat(h, w, type);
-}
-
} // ns pt_module
diff --git a/tracker-pt/module/frame.hpp b/tracker-pt/module/frame.hpp
index 89334599..0569a323 100644
--- a/tracker-pt/module/frame.hpp
+++ b/tracker-pt/module/frame.hpp
@@ -2,7 +2,7 @@
#include "pt-api.hpp"
-#include <opencv2/core.hpp>
+#include <opencv2/core/mat.hpp>
#include <QImage>
#ifdef __clang__
@@ -24,7 +24,7 @@ struct Preview final : pt_preview
{
Preview(int w, int h);
- Preview& operator=(const pt_frame& frame) override;
+ void set_last_frame(const pt_frame& frame) override;
QImage get_bitmap() override;
void draw_head_center(f x, f y) override;
@@ -32,9 +32,7 @@ struct Preview final : pt_preview
operator cv::Mat const&() const { return frame_copy; }
private:
- static void ensure_size(cv::Mat& frame, int w, int h, int type);
-
- cv::Mat frame_copy, frame_out;
+ cv::Mat frame_copy, frame_out, frame_tmp;
};
} // ns pt_module
diff --git a/tracker-pt/module/lang/de_DE.ts b/tracker-pt/module/lang/de_DE.ts
new file mode 100644
index 00000000..6c548aba
--- /dev/null
+++ b/tracker-pt/module/lang/de_DE.ts
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="de_DE">
+<context>
+ <name>pt_module::metadata_pt</name>
+ <message>
+ <source>PointTracker 1.1</source>
+ <translation>PointTracker 1.1</translation>
+ </message>
+</context>
+</TS>
diff --git a/tracker-pt/module/lang/zh_CN.ts b/tracker-pt/module/lang/zh_CN.ts
index 03d19f4e..c39728a1 100644
--- a/tracker-pt/module/lang/zh_CN.ts
+++ b/tracker-pt/module/lang/zh_CN.ts
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
-<TS version="2.1">
+<TS version="2.1" language="zh_CN">
<context>
<name>pt_module::metadata_pt</name>
<message>
diff --git a/tracker-pt/module/point_extractor.cpp b/tracker-pt/module/point_extractor.cpp
index a92c87c9..3329fafc 100644
--- a/tracker-pt/module/point_extractor.cpp
+++ b/tracker-pt/module/point_extractor.cpp
@@ -9,9 +9,11 @@
#include "point_extractor.h"
#include "point_tracker.h"
#include "frame.hpp"
-
#include "cv/numeric.hpp"
#include "compat/math.hpp"
+#include "compat/math-imports.hpp"
+
+#include <opencv2/imgproc.hpp>
#undef PREVIEW
//#define PREVIEW
@@ -87,21 +89,16 @@ PointExtractor::PointExtractor(const QString& module_name) : s(module_name)
void PointExtractor::ensure_channel_buffers(const cv::Mat& orig_frame)
{
- if (ch[0].rows != orig_frame.rows || ch[0].cols != orig_frame.cols)
- for (cv::Mat1b& x : ch)
- x = cv::Mat1b(orig_frame.rows, orig_frame.cols);
+ for (cv::Mat1b& x : ch)
+ x.create(orig_frame.rows, orig_frame.cols);
}
void PointExtractor::ensure_buffers(const cv::Mat& frame)
{
const int W = frame.cols, H = frame.rows;
- if (frame_gray.rows != W || frame_gray.cols != H)
- {
- frame_gray = cv::Mat1b(H, W);
- frame_bin = cv::Mat1b(H, W);
- frame_gray_unmasked = cv::Mat1b(H, W);
- }
+ frame_gray.create(H, W);
+ frame_bin.create(H, W);
}
void PointExtractor::extract_single_channel(const cv::Mat& orig_frame, int idx, cv::Mat1b& dest)
@@ -115,15 +112,43 @@ void PointExtractor::extract_single_channel(const cv::Mat& orig_frame, int idx,
cv::mixChannels(&orig_frame, 1, &dest, 1, from_to, 1);
}
-void PointExtractor::filter_single_channel(const cv::Mat& orig_frame, float r, float g, float b, cv::Mat1b& dest)
+void PointExtractor::filter_single_channel(const cv::Mat& orig_frame, float r, float g, float b, bool overexp, cv::Mat1b& dest)
{
ensure_channel_buffers(orig_frame);
- cv::transform(orig_frame, dest, cv::Mat(cv::Matx13f(b, g, r)));
+ // just filter for colour or also include overexposed regions?
+ if (!overexp)
+ cv::transform(orig_frame, dest, cv::Mat(cv::Matx13f(b, g, r)));
+ else
+ {
+ for (int i = 0; i < orig_frame.rows; i++)
+ {
+ cv::Vec3b const* const __restrict orig_ptr = orig_frame.ptr<cv::Vec3b>(i);
+ uint8_t* const __restrict dest_ptr = dest.ptr(i);
+ for (int j = 0; j < orig_frame.cols; j++)
+ {
+ // get the intensity of the key color (i.e. +ve coefficients)
+ uchar blue = orig_ptr[j][0], green = orig_ptr[j][1], red = orig_ptr[j][2];
+ float key = std::max(b, 0.0f) * blue + std::max(g, 0.0f) * green + std::max(r, 0.0f) * red;
+ // get the intensity of the non-key color (i.e. -ve coefficients)
+ float nonkey = std::max(-b, 0.0f) * blue + std::max(-g, 0.0f) * green + std::max(-r, 0.0f) * red;
+ // the result is key color minus non-key color inversely weighted by key colour intensity
+ dest_ptr[j] = std::max(0.0f, std::min(255.0f, key - (255.0f - key) / 255.0f * nonkey));
+ }
+ }
+ }
}
void PointExtractor::color_to_grayscale(const cv::Mat& frame, cv::Mat1b& output)
{
+ if (frame.channels() == 1)
+ {
+ output.create(frame.rows, frame.cols);
+ frame.copyTo(output);
+ return;
+ }
+
+ const float half_chr_key_str = *s.chroma_key_strength * 0.5;
switch (s.blob_color)
{
case pt_color_green_only:
@@ -143,46 +168,42 @@ void PointExtractor::color_to_grayscale(const cv::Mat& frame, cv::Mat1b& output)
}
case pt_color_red_chromakey:
{
- filter_single_channel(frame, 1, -0.5, -0.5, output);
+ filter_single_channel(frame, 1, -half_chr_key_str, -half_chr_key_str, s.chroma_key_overexposed, output);
break;
}
case pt_color_green_chromakey:
{
- filter_single_channel(frame, -0.5, 1, -0.5, output);
+ filter_single_channel(frame, -half_chr_key_str, 1, -half_chr_key_str, s.chroma_key_overexposed, output);
break;
}
case pt_color_blue_chromakey:
{
- filter_single_channel(frame, -0.5, -0.5, 1, output);
+ filter_single_channel(frame, -half_chr_key_str, -half_chr_key_str, 1, s.chroma_key_overexposed, output);
break;
}
case pt_color_cyan_chromakey:
{
- filter_single_channel(frame, -1, 0.5, 0.5, output);
+ filter_single_channel(frame, -*s.chroma_key_strength, 0.5, 0.5, s.chroma_key_overexposed, output);
break;
}
case pt_color_yellow_chromakey:
{
- filter_single_channel(frame, 0.5, 0.5, -1, output);
+ filter_single_channel(frame, 0.5, 0.5, -*s.chroma_key_strength, s.chroma_key_overexposed, output);
break;
}
case pt_color_magenta_chromakey:
{
- filter_single_channel(frame, 0.5, -1, 0.5, output);
- break;
- }
- case pt_color_average:
- {
- const int W = frame.cols, H = frame.rows, sz = W*H;
- cv::reduce(frame.reshape(1, sz),
- output.reshape(1, sz),
- 1, cv::REDUCE_AVG);
+ filter_single_channel(frame, 0.5, -*s.chroma_key_strength, 0.5, s.chroma_key_overexposed, output);
break;
}
+ case pt_color_hardware:
+ eval_once(qDebug() << "camera driver doesn't support grayscale");
+ goto do_grayscale;
default:
eval_once(qDebug() << "wrong pt_color_type enum value" << int(s.blob_color));
[[fallthrough]];
- case pt_color_natural:
+ case pt_color_bt709:
+do_grayscale:
cv::cvtColor(frame, output, cv::COLOR_BGR2GRAY);
break;
}
@@ -214,11 +235,10 @@ void PointExtractor::threshold_image(const cv::Mat& frame_gray, cv::Mat1b& outpu
const f radius = threshold_radius_value(frame_gray.cols, frame_gray.rows, threshold_slider_value);
float const* const __restrict ptr = hist.ptr<float>(0);
- const unsigned area = uround(3 * pi * radius*radius);
+ const unsigned area = unsigned(iround(3 * pi * radius*radius));
const unsigned sz = unsigned(hist.cols * hist.rows);
- constexpr unsigned min_thres = 64;
- unsigned thres = min_thres;
- for (unsigned i = sz-1, cnt = 0; i > 32; i--)
+ unsigned thres = 1;
+ for (unsigned i = sz-1, cnt = 0; i > 1; i--)
{
cnt += (unsigned)ptr[i];
if (cnt >= area)
@@ -246,20 +266,15 @@ static void draw_blobs(cv::Mat& preview_frame, const blob* blobs, unsigned nblob
cy = preview_frame.rows / f(size.height),
c = std::fmax(f(1), cx+cy)/2;
- constexpr unsigned fract_bits = 8;
- constexpr int c_fract(1 << fract_bits);
-
- cv::Point p(iround(b.pos[0] * cx * c_fract), iround(b.pos[1] * cy * c_fract));
-
- auto circle_color = k >= PointModel::N_POINTS
- ? cv::Scalar(192, 192, 192)
- : cv::Scalar(255, 255, 0);
+ cv::Point p(iround(b.pos[0] * cx), iround(b.pos[1] * cy));
- const int overlay_size = iround(dpi);
+ auto outline_color = k >= PointModel::N_POINTS
+ ? cv::Scalar(192, 192, 192)
+ : cv::Scalar(255, 255, 0);
- cv::circle(preview_frame, p, iround((b.radius + f(3.3) * c) * c_fract),
- circle_color, overlay_size,
- cv::LINE_AA, fract_bits);
+ cv::ellipse(preview_frame, p,
+ {iround(b.rect.width/(f)2+2*c), iround(b.rect.height/(f)2+2*c)},
+ 0, 0, 360, outline_color, iround(dpi), cv::LINE_AA);
char buf[16];
std::snprintf(buf, sizeof(buf), "%.2fpx", (double)b.radius);
@@ -270,25 +285,51 @@ static void draw_blobs(cv::Mat& preview_frame, const blob* blobs, unsigned nblob
cv::Point pos(iround(b.pos[0]*cx+offx), iround(b.pos[1]*cy+offy));
cv::putText(preview_frame, buf, pos,
- cv::FONT_HERSHEY_PLAIN, overlay_size, text_color,
+ cv::FONT_HERSHEY_PLAIN, iround(dpi), text_color,
1);
}
}
-void PointExtractor::extract_points(const pt_frame& frame_, pt_preview& preview_frame_, std::vector<vec2>& points)
+static vec2 meanshift_initial_guess(const cv::Rect rect, cv::Mat& frame_roi)
+{
+ vec2 ret = {rect.width/(f)2, rect.height/(f)2};
+
+ // compute center initial guess
+ double ynorm = 0, xnorm = 0, y = 0, x = 0;
+ for (int j = 0; j < rect.height; j++)
+ {
+ const unsigned char* __restrict ptr = frame_roi.ptr<unsigned char>(j);
+ for (int i = 0; i < rect.width; i++)
+ {
+ double val = ptr[i] * 1./255;
+ x += i * val;
+ y += j * val;
+ xnorm += val;
+ ynorm += val;
+ }
+ }
+ constexpr double eps = 1e-4;
+ if (xnorm > eps && ynorm > eps)
+ ret = { (f)(x / xnorm), (f)(y / ynorm) };
+ return ret;
+}
+
+void PointExtractor::extract_points(const pt_frame& frame_,
+ pt_preview& preview_frame_,
+ bool preview_visible,
+ std::vector<vec2>& points)
{
const cv::Mat& frame = frame_.as_const<Frame>()->mat;
ensure_buffers(frame);
- color_to_grayscale(frame, frame_gray_unmasked);
+ color_to_grayscale(frame, frame_gray);
#if defined PREVIEW
cv::imshow("capture", frame_gray);
cv::waitKey(1);
#endif
- threshold_image(frame_gray_unmasked, frame_bin);
- frame_gray_unmasked.copyTo(frame_gray, frame_bin);
+ threshold_image(frame_gray, frame_bin);
const f region_size_min = (f)s.min_point_size;
const f region_size_max = (f)s.max_point_size;
@@ -336,7 +377,7 @@ void PointExtractor::extract_points(const pt_frame& frame_, pt_preview& preview_
}
}
- const f radius = std::sqrt(cnt / pi);
+ const f radius = std::sqrt((f)cnt) / std::sqrt(pi);
if (radius > region_size_max || radius < region_size_min)
continue;
@@ -366,21 +407,14 @@ end:
for (idx = 0; idx < sz; ++idx)
{
blob& b = blobs[idx];
- cv::Rect rect = b.rect;
-
- rect.x -= rect.width / 2;
- rect.y -= rect.height / 2;
- rect.width *= 2;
- rect.height *= 2;
- rect &= cv::Rect(0, 0, W, H); // crop at frame boundaries
-
+ cv::Rect rect = b.rect & cv::Rect(0, 0, W, H); // crop at frame boundaries
cv::Mat frame_roi = frame_gray(rect);
// smaller values mean more changes. 1 makes too many changes while 1.5 makes about .1
static constexpr f radius_c = f(1.75);
const f kernel_radius = b.radius * radius_c;
- vec2 pos(rect.width/f(2), rect.height/f(2)); // position relative to ROI.
+ vec2 pos = meanshift_initial_guess(rect, frame_roi); // position relative to ROI.
for (int iter = 0; iter < 10; ++iter)
{
@@ -395,9 +429,10 @@ end:
b.pos[1] = pos[1] + rect.y;
}
- draw_blobs(preview_frame_.as<Frame>()->mat,
- blobs.data(), blobs.size(),
- frame_gray.size());
+ if (preview_visible)
+ draw_blobs(preview_frame_.as<Frame>()->mat,
+ blobs.data(), blobs.size(),
+ frame_gray.size());
// End of mean shift code. At this point, blob positions are updated with hopefully less noisy less biased values.
diff --git a/tracker-pt/module/point_extractor.h b/tracker-pt/module/point_extractor.h
index 9c97b6ce..fbfdbb0b 100644
--- a/tracker-pt/module/point_extractor.h
+++ b/tracker-pt/module/point_extractor.h
@@ -9,12 +9,10 @@
#pragma once
#include "pt-api.hpp"
-
+#include <opencv2/core/mat.hpp>
+#include <opencv2/core/types.hpp>
#include <vector>
-#include <opencv2/core.hpp>
-#include <opencv2/imgproc.hpp>
-
namespace pt_module {
using namespace numeric_types;
@@ -33,14 +31,18 @@ class PointExtractor final : public pt_point_extractor
public:
// extracts points from frame and draws some processing info into frame, if draw_output is set
// dt: time since last call in seconds
- void extract_points(const pt_frame& frame, pt_preview& preview_frame, std::vector<vec2>& points) override;
- PointExtractor(const QString& module_name);
+ void extract_points(const pt_frame& frame,
+ pt_preview& preview_frame, bool preview_visible,
+ std::vector<vec2>& points) override;
+
+ explicit PointExtractor(const QString& module_name);
+
private:
static constexpr int max_blobs = 16;
pt_settings s;
- cv::Mat1b frame_gray_unmasked, frame_bin, frame_gray;
+ cv::Mat1b frame_bin, frame_gray;
cv::Mat1f hist;
std::vector<blob> blobs;
cv::Mat1b ch[3];
@@ -49,7 +51,7 @@ private:
void ensure_buffers(const cv::Mat& frame);
void extract_single_channel(const cv::Mat& orig_frame, int idx, cv::Mat1b& dest);
- void filter_single_channel(const cv::Mat& orig_frame, float r, float g, float b, cv::Mat1b& dest);
+ void filter_single_channel(const cv::Mat& orig_frame, float r, float g, float b, bool overexp, cv::Mat1b& dest);
void color_to_grayscale(const cv::Mat& frame, cv::Mat1b& output);
void threshold_image(const cv::Mat& frame_gray, cv::Mat1b& output);
diff --git a/tracker-pt/point-filter.cpp b/tracker-pt/point-filter.cpp
new file mode 100644
index 00000000..10448fe2
--- /dev/null
+++ b/tracker-pt/point-filter.cpp
@@ -0,0 +1,72 @@
+#include "point-filter.hpp"
+#include <algorithm>
+#include <cmath>
+#include <QDebug>
+
+namespace pt_point_filter_impl {
+
+void point_filter::reset()
+{
+ t = std::nullopt;
+}
+
+const PointOrder& point_filter::operator()(const PointOrder& input, f deadzone_amount)
+{
+ using std::fmod;
+ using std::sqrt;
+ using std::pow;
+ using std::clamp;
+
+ if (!s.enable_point_filter)
+ {
+ t = std::nullopt;
+ state_ = input;
+ return state_;
+ }
+
+ if (!t)
+ {
+ t.emplace();
+ state_ = input;
+ return state_;
+ }
+
+ constexpr auto E = (f)1.75;
+ const f limit = (f)*s.point_filter_limit;
+ const f C = progn(
+ constexpr int A = 1'000'000;
+ double K = *s.point_filter_coefficient;
+ f log10_pos = -2 + (int)K, rest = (f)(.999-fmod(K, 1.)*.9);
+ return A * pow((f)10, (f)-log10_pos) * rest;
+ );
+
+ f dist = 0, dz = deadzone_amount * (f)s.point_filter_deadzone / 800; // sqrt(640^2 + 480^2)
+
+ for (unsigned i = 0; i < 3; i++)
+ {
+ vec2 tmp = input[i] - state_[i];
+ f x = sqrt(tmp.dot(tmp));
+ x = std::max((f)0, x - dz);
+ dist = std::max(dist, x);
+ }
+
+ if (dist < (f)1e-6)
+ return state_;
+
+ f dt = (f)t->elapsed_seconds(); t->start();
+ f delta = pow(dist, E) * C * dt; // gain
+
+ //qDebug() << "gain" << std::min((f)1, delta);
+
+ for (unsigned i = 0; i < 3; i++)
+ {
+ f x = clamp(delta, (f)0, limit);
+ state_[i] += x*(input[i] - state_[i]);
+ }
+
+ return state_;
+}
+
+point_filter::point_filter(const pt_settings& s) : s{s} {}
+
+} // ns pt_point_filter_impl
diff --git a/tracker-pt/point-filter.hpp b/tracker-pt/point-filter.hpp
new file mode 100644
index 00000000..c3c045dd
--- /dev/null
+++ b/tracker-pt/point-filter.hpp
@@ -0,0 +1,32 @@
+#pragma once
+
+#include "cv/numeric.hpp"
+#include "compat/timer.hpp"
+#include "pt-settings.hpp"
+#include <optional>
+#include <array>
+
+namespace pt_point_filter_impl {
+
+using namespace numeric_types;
+using PointOrder = std::array<numeric_types::vec2, 3>;
+
+class point_filter final
+{
+ PointOrder state_;
+ std::optional<Timer> t;
+ const pt_settings& s;
+
+public:
+ void reset();
+ const PointOrder& operator()(const PointOrder& input, f deadzone_amount);
+
+ explicit point_filter(const pt_settings& s);
+ ~point_filter() = default;
+
+ OTR_DISABLE_MOVE_COPY(point_filter);
+};
+
+} // ns pt_point_filter_impl
+
+using point_filter = pt_point_filter_impl::point_filter;
diff --git a/tracker-pt/point_tracker.cpp b/tracker-pt/point_tracker.cpp
index e209938f..39e96038 100644
--- a/tracker-pt/point_tracker.cpp
+++ b/tracker-pt/point_tracker.cpp
@@ -68,7 +68,7 @@ void PointModel::set_model(const pt_settings& s)
}
}
-void PointModel::get_d_order(const vec2* points, unsigned* d_order, const vec2& d) const
+void PointModel::get_d_order(const vec2* points, unsigned* d_order, const vec2& d)
{
constexpr unsigned cnt = PointModel::N_POINTS;
// fit line to orthographically projected points
@@ -76,11 +76,10 @@ void PointModel::get_d_order(const vec2* points, unsigned* d_order, const vec2&
t d_vals[cnt];
// get sort indices with respect to d scalar product
for (unsigned i = 0; i < cnt; ++i)
- d_vals[i] = t(d.dot(points[i]), i);
+ d_vals[i] = {d.dot(points[i]), i};
- std::sort(d_vals,
- d_vals + 3,
- [](const t& a, const t& b) { return a.first < b.first; });
+ std::sort(std::begin(d_vals), std::end(d_vals),
+ [](t a, t b) { return a.first < b.first; });
for (unsigned i = 0; i < cnt; ++i)
d_order[i] = d_vals[i].second;
@@ -94,10 +93,11 @@ PointTracker::PointOrder PointTracker::find_correspondences_previous(const vec2*
const pt_camera_info& info)
{
const f fx = pt_camera_info::get_focal_length(info.fov, info.res_x, info.res_y);
- PointTracker::PointOrder p;
- p[0] = project(vec3(0,0,0), fx);
- p[1] = project(model.M01, fx);
- p[2] = project(model.M02, fx);
+ PointTracker::PointOrder p {
+ project(vec3(0,0,0), fx),
+ project(model.M01, fx),
+ project(model.M02, fx)
+ };
constexpr unsigned sz = PointModel::N_POINTS;
@@ -136,7 +136,9 @@ PointTracker::PointOrder PointTracker::find_correspondences_previous(const vec2*
void PointTracker::track(const std::vector<vec2>& points,
const PointModel& model,
const pt_camera_info& info,
- int init_phase_timeout)
+ int init_phase_timeout,
+ point_filter& filter,
+ f deadzone_amount)
{
const f fx = pt_camera_info::get_focal_length(info.fov, info.res_x, info.res_y);
PointOrder order;
@@ -149,7 +151,7 @@ void PointTracker::track(const std::vector<vec2>& points,
else
order = find_correspondences_previous(points.data(), model, info);
- if (POSIT(model, order, fx) != -1)
+ if (POSIT(model, filter(order, deadzone_amount), fx) != -1)
{
init_phase = false;
t.start();
diff --git a/tracker-pt/point_tracker.h b/tracker-pt/point_tracker.h
index 70c7a9fc..7492b4eb 100644
--- a/tracker-pt/point_tracker.h
+++ b/tracker-pt/point_tracker.h
@@ -11,14 +11,11 @@
#include "cv/affine.hpp"
#include "cv/numeric.hpp"
#include "pt-api.hpp"
+#include "point-filter.hpp"
-#include <cstddef>
-#include <memory>
#include <vector>
#include <array>
-#include <opencv2/core.hpp>
-
#include <QObject>
namespace pt_impl {
@@ -46,7 +43,7 @@ struct PointModel final
explicit PointModel(const pt_settings& s);
void set_model(const pt_settings& s);
- void get_d_order(const vec2* points, unsigned* d_order, const vec2& d) const;
+ static void get_d_order(const vec2* points, unsigned* d_order, const vec2& d);
};
// ----------------------------------------------------------------------------
@@ -60,7 +57,12 @@ public:
// track the pose using the set of normalized point coordinates (x pos in range -0.5:0.5)
// f : (focal length)/(sensor width)
// dt : time since last call
- void track(const std::vector<vec2>& projected_points, const PointModel& model, const pt_camera_info& info, int init_phase_timeout);
+ void track(const std::vector<vec2>& projected_points,
+ const PointModel& model,
+ const pt_camera_info& info,
+ int init_phase_timeout,
+ point_filter& filter,
+ f deadzone_amount);
Affine pose() const { return X_CM; }
vec2 project(const vec3& v_M, f focal_length);
vec2 project(const vec3& v_M, f focal_length, const Affine& X_CM);
@@ -70,14 +72,13 @@ private:
// the points in model order
using PointOrder = std::array<vec2, 3>;
- PointOrder find_correspondences(const vec2* projected_points, const PointModel &model);
+ static PointOrder find_correspondences(const vec2* projected_points, const PointModel &model);
PointOrder find_correspondences_previous(const vec2* points, const PointModel &model, const pt_camera_info& info);
// The POSIT algorithm, returns the number of iterations
int POSIT(const PointModel& point_model, const PointOrder& order, f focal_length);
Affine X_CM; // transform from model to camera
Affine X_CM_expected;
- PointOrder prev_positions;
Timer t;
bool init_phase = true;
};
diff --git a/tracker-pt/pt-api.cpp b/tracker-pt/pt-api.cpp
index f64d5c9a..d71c6e13 100644
--- a/tracker-pt/pt-api.cpp
+++ b/tracker-pt/pt-api.cpp
@@ -31,7 +31,7 @@ f pt_point_extractor::threshold_radius_value(int w, int h, int threshold)
f cx = w / f{640}, cy = h / f{480};
const f min_radius = f{1.75} * cx;
- const f max_radius = f{15} * cy;
+ const f max_radius = f{30} * cy;
const f radius = std::fmax(f{0}, (max_radius-min_radius) * threshold / f(255) + min_radius);
@@ -40,15 +40,14 @@ f pt_point_extractor::threshold_radius_value(int w, int h, int threshold)
std::tuple<f, f> pt_pixel_pos_mixin::to_pixel_pos(f x, f y, int w, int h)
{
- return std::make_tuple(w*(x+f{.5}), f{.5}*(h - 2*y*w));
+ return { w*(x+f{.5}), f{.5}*(h - 2*y*w) };
}
std::tuple<f, f> pt_pixel_pos_mixin::to_screen_pos(f px, f py, int w, int h)
{
px *= w/(w-f{1}); py *= h/(h-f{1});
- return std::make_tuple((px - w/f{2})/w, -(py - h/f{2})/w);
+ return { (px - w/f{2})/w, -(py - h/f{2})/w };
}
pt_frame::pt_frame() = default;
-
pt_frame::~pt_frame() = default;
diff --git a/tracker-pt/pt-api.hpp b/tracker-pt/pt-api.hpp
index 741576a1..15021ff3 100644
--- a/tracker-pt/pt-api.hpp
+++ b/tracker-pt/pt-api.hpp
@@ -6,11 +6,9 @@
#include "options/options.hpp"
#include <tuple>
-#include <type_traits>
+#include <vector>
#include <memory>
-#include <opencv2/core.hpp>
-
#include <QImage>
#include <QString>
@@ -32,6 +30,7 @@ struct pt_camera_info final
int res_x = 0;
int res_y = 0;
QString name;
+ bool use_mjpeg = false;
};
struct pt_pixel_pos_mixin
@@ -58,11 +57,21 @@ struct pt_frame : pt_pixel_pos_mixin
{
return static_cast<t const*>(this);
}
+
+protected:
+ pt_frame(const pt_frame&) = default;
+ pt_frame(pt_frame&&) = default;
+ pt_frame& operator=(const pt_frame&) = default;
+ pt_frame& operator=(pt_frame&&) = default;
};
struct pt_preview : pt_frame
{
- virtual pt_preview& operator=(const pt_frame&) = 0;
+ pt_preview() = default;
+
+ OTR_DISABLE_MOVE_COPY(pt_preview);
+
+ virtual void set_last_frame(const pt_frame&) = 0;
virtual QImage get_bitmap() = 0;
virtual void draw_head_center(f x, f y) = 0;
};
@@ -75,7 +84,9 @@ struct pt_camera
pt_camera();
virtual ~pt_camera();
- [[nodiscard]] virtual bool start(const QString& name, int fps, int res_x, int res_y) = 0;
+ OTR_DISABLE_MOVE_COPY(pt_camera);
+
+ [[nodiscard]] virtual bool start(const pt_settings& s) = 0;
virtual void stop() = 0;
virtual result get_frame(pt_frame& frame) = 0;
@@ -87,6 +98,7 @@ struct pt_camera
virtual void set_fov(f value) = 0;
virtual void show_camera_settings() = 0;
+ virtual f deadzone_amount() const { return 1; }
};
struct pt_point_extractor : pt_pixel_pos_mixin
@@ -94,9 +106,11 @@ struct pt_point_extractor : pt_pixel_pos_mixin
using vec2 = numeric_types::vec2;
using f = numeric_types::f;
+ OTR_DISABLE_MOVE_COPY(pt_point_extractor);
+
pt_point_extractor();
virtual ~pt_point_extractor();
- virtual void extract_points(const pt_frame& image, pt_preview& preview_frame, std::vector<vec2>& points) = 0;
+ virtual void extract_points(const pt_frame& image, pt_preview& preview_frame, bool preview_visible, std::vector<vec2>& points) = 0;
static f threshold_radius_value(int w, int h, int threshold);
};
@@ -105,6 +119,8 @@ struct pt_runtime_traits
{
template<typename t> using pointer = std::shared_ptr<t>;
+ OTR_DISABLE_MOVE_COPY(pt_runtime_traits);
+
pt_runtime_traits();
virtual ~pt_runtime_traits();
diff --git a/tracker-pt/pt-settings.hpp b/tracker-pt/pt-settings.hpp
index ed13a1ec..5d16d973 100644
--- a/tracker-pt/pt-settings.hpp
+++ b/tracker-pt/pt-settings.hpp
@@ -8,9 +8,9 @@ enum pt_color_type
{
// explicit values, gotta preserve the numbering in .ini
// don't reuse when removing some of the modes
- pt_color_natural = 2,
+ pt_color_bt709 = 2,
+ pt_color_hardware = 14,
pt_color_red_only = 3,
- pt_color_average = 5,
pt_color_blue_only = 6,
pt_color_green_only = 7,
pt_color_red_chromakey = 8,
@@ -63,10 +63,18 @@ struct pt_settings final : options::opts
value<bool> dynamic_pose { b, "dynamic-pose-resolution", false };
value<int> init_phase_timeout { b, "init-phase-timeout", 250 };
value<bool> auto_threshold { b, "automatic-threshold", true };
- value<pt_color_type> blob_color { b, "blob-color", pt_color_natural };
+ value<pt_color_type> blob_color { b, "blob-color", pt_color_bt709 };
+ value<bool> use_mjpeg { b, "use-mjpeg", false };
+ value<slider_value> chroma_key_strength{ b, "chroma-key-strength", { 1.0, 0.5, 4. } };
+ value<bool> chroma_key_overexposed{ b, "chroma-key-overexposed", false };
value<slider_value> threshold_slider { b, "threshold-slider", { 128, 0, 255 } };
+ value<bool> enable_point_filter{ b, "enable-point-filter", false };
+ value<slider_value> point_filter_coefficient { b, "point-filter-coefficient", { 1.0, 0, 4 } };
+ value<slider_value> point_filter_limit { b, "point-filter-limit", { 0.1, 0.01, 1 }};
+ value<slider_value> point_filter_deadzone { b, "point-filter-deadzone", {0, 0, 1} };
+
explicit pt_settings(const QString& name) : opts(name) {}
};