diff options
Diffstat (limited to 'tracker-pt')
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><html><head/><body><p>For LEDs, 'Natural' is the fastest grayscale mode thanks to optimized SIMD code. Color key allows to track regular pieces of colored paper.</p></body></html></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'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><html><head/><body><p>For LEDs, 'Natural' is the fastest grayscale mode thanks to optimized SIMD code. Color key allows to track regular pieces of colored paper.</p></body></html></source> + <translation><html><head/><body><p>‚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.</p></body></html></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><html><head/><body><p>Location of the two remaining model points<br/>with respect to the reference point in default pose</p><p>Use any units you want, not necessarily centimeters.</p></body></html></source> + <translation><html><head/><body><p>Ort der verbleibenden zwei Modellpunkte<br/>unter Berücksichtigung der Referenzpunkte der Standard-Pose</p><p>Dies können beliebige Einheiten sein, nicht zwingend Zentimeter.</p></body></html></translation> + </message> + <message> + <source>y:</source> + <translation>y:</translation> + </message> + <message> + <source><html><head/><body><p><span style=" font-size:16pt;">P</span><span style=" font-size:16pt; vertical-align:sub;">3</span></p></body></html></source> + <translation><html><head/><body><p><span style=" font-size:16pt;">P</span><span style=" font-size:16pt; vertical-align:sub;">3</span></p></body></html></translation> + </message> + <message> + <source><html><head/><body><p><span style=" font-size:16pt;">P</span><span style=" font-size:16pt; vertical-align:sub;">2</span></p></body></html></source> + <translation><html><head/><body><p><span style=" font-size:16pt;">P</span><span style=" font-size:16pt; vertical-align:sub;">2</span></p></body></html></translation> + </message> + <message> + <source>Model position</source> + <translation>Modell-Position</translation> + </message> + <message> + <source>Use only yaw and pitch while calibrating. +Don'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><html><head/><body><p><span style=" font-weight:600;">FTNoIR PointTracker Plugin<br/>Version 1.1</span></p><p><span style=" font-weight:600;">by Patrick Ruoff</span></p><p><a href="http://ftnoirpt.sourceforge.net/"><span style=" font-weight:600; text-decoration: underline; color:#0000ff;">Manual (external)</span></a></p></body></html></source> + <translation><html><head/><body><p><span style=" font-weight:600;">FTNoIR PointTracker Plugin<br/>Version 1.1</span></p><p><span style=" font-weight:600;">von Patrick Ruoff</span></p><p><a href="http://ftnoirpt.sourceforge.net/"><span style=" font-weight:600; text-decoration: underline; color:#0000ff;">Anleitung (extern)</span></a></p></body></html></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 '%1'</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'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'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><html><head/><body><p>For LEDs, 'Natural' is the fastest grayscale mode thanks to optimized SIMD code. Color key allows to track regular pieces of colored paper.</p></body></html></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't roll or change position.</source> </message> </context> <context> + <name>pt_impl::Tracker_PT</name> + <message> + <source>Failed to open camera '%1'</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'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><html><head/><body><p>For LEDs, 'Natural' is the fastest grayscale mode thanks to optimized SIMD code. Color key allows to track regular pieces of colored paper.</p></body></html></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 '%1'</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'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'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><html><head/><body><p>For LEDs, 'Natural' is the fastest grayscale mode thanks to optimized SIMD code. Color key allows to track regular pieces of colored paper.</p></body></html></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't roll or change position.</source> </message> </context> <context> + <name>pt_impl::Tracker_PT</name> + <message> + <source>Failed to open camera '%1'</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'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'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><html><head/><body><p>For LEDs, 'Natural' is the fastest grayscale mode thanks to optimized SIMD code. Color key allows to track regular pieces of colored paper.</p></body></html></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't roll or change position.</source> </message> </context> <context> + <name>pt_impl::Tracker_PT</name> + <message> + <source>Failed to open camera '%1'</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) {} }; |