diff options
30 files changed, 4065 insertions, 4065 deletions
diff --git a/ftnoir_tracker_pt/FTNoIR_PT_Controls.ui b/ftnoir_tracker_pt/FTNoIR_PT_Controls.ui index 44dfc060..a2d5c47c 100644 --- a/ftnoir_tracker_pt/FTNoIR_PT_Controls.ui +++ b/ftnoir_tracker_pt/FTNoIR_PT_Controls.ui @@ -1,1545 +1,1545 @@ -<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>UICPTClientControls</class>
- <widget class="QWidget" name="UICPTClientControls">
- <property name="windowModality">
- <enum>Qt::NonModal</enum>
- </property>
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>459</width>
- <height>621</height>
- </rect>
- </property>
- <property name="sizePolicy">
- <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="windowTitle">
- <string>PointTracker Settings</string>
- </property>
- <property name="windowIcon">
- <iconset resource="ftnoir_tracker_pt.qrc">
- <normaloff>:/Resources/Logo_IR.png</normaloff>:/Resources/Logo_IR.png</iconset>
- </property>
- <property name="layoutDirection">
- <enum>Qt::LeftToRight</enum>
- </property>
- <property name="autoFillBackground">
- <bool>false</bool>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout_2">
- <property name="sizeConstraint">
- <enum>QLayout::SetFixedSize</enum>
- </property>
- <item>
- <widget class="QTabWidget" name="tabWidget">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="minimumSize">
- <size>
- <width>0</width>
- <height>0</height>
- </size>
- </property>
- <property name="locale">
- <locale language="English" country="UnitedStates"/>
- </property>
- <property name="currentIndex">
- <number>0</number>
- </property>
- <widget class="QWidget" name="tab">
- <attribute name="title">
- <string>General</string>
- </attribute>
- <layout class="QVBoxLayout" name="verticalLayout_3">
- <item>
- <widget class="QGroupBox" name="groupBox_6">
- <property name="title">
- <string>Tracker Thread</string>
- </property>
- <layout class="QGridLayout" name="gridLayout">
- <item row="0" column="0">
- <widget class="QLabel" name="label_43">
- <property name="text">
- <string>Auto-reset time</string>
- </property>
- <property name="buddy">
- <cstring>reset_spin</cstring>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QSpinBox" name="reset_spin">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Expanding" vsizetype="Minimum">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="toolTip">
- <string>Time until automatic reset of tracker's internal state when no valid tracking result is found</string>
- </property>
- <property name="suffix">
- <string>ms</string>
- </property>
- <property name="maximum">
- <number>9999</number>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="label_17">
- <property name="text">
- <string>Dynamic Pose Resolution</string>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QCheckBox" name="dynpose_check">
- <property name="toolTip">
- <string/>
- </property>
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- <item row="2" column="1">
- <widget class="QPushButton" name="reset_button">
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="toolTip">
- <string>Reset the tracker's internal state</string>
- </property>
- <property name="text">
- <string>Reset</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>20</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
- <widget class="QWidget" name="tab_2">
- <attribute name="title">
- <string>Camera</string>
- </attribute>
- <layout class="QVBoxLayout" name="verticalLayout_7">
- <item>
- <widget class="QGroupBox" name="groupBox">
- <property name="toolTip">
- <string>The camera device used as input</string>
- </property>
- <property name="title">
- <string>Camera Settings</string>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout">
- <item>
- <layout class="QHBoxLayout" name="horizontalLayout_3">
- <item>
- <widget class="QLabel" name="label_2">
- <property name="minimumSize">
- <size>
- <width>55</width>
- <height>0</height>
- </size>
- </property>
- <property name="text">
- <string>Device</string>
- </property>
- <property name="buddy">
- <cstring>camdevice_combo</cstring>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QComboBox" name="camdevice_combo">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="toolTip">
- <string>Camera device used as input</string>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <layout class="QHBoxLayout" name="horizontalLayout_8">
- <item>
- <layout class="QGridLayout" name="gridLayout_8">
- <item row="0" column="0">
- <widget class="QLabel" name="label_36">
- <property name="minimumSize">
- <size>
- <width>55</width>
- <height>0</height>
- </size>
- </property>
- <property name="text">
- <string>Resolution</string>
- </property>
- </widget>
- </item>
- <item row="0" column="5">
- <widget class="QLabel" name="label_37">
- <property name="text">
- <string>FPS</string>
- </property>
- <property name="buddy">
- <cstring>fps_spin</cstring>
- </property>
- </widget>
- </item>
- <item row="0" column="6">
- <widget class="QSpinBox" name="fps_spin">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="toolTip">
- <string>Desired capture framerate</string>
- </property>
- <property name="maximum">
- <number>999</number>
- </property>
- </widget>
- </item>
- <item row="0" column="2">
- <widget class="QLabel" name="label_41">
- <property name="text">
- <string>x</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QSpinBox" name="res_x_spin">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="toolTip">
- <string>Desired capture width</string>
- </property>
- <property name="maximum">
- <number>2000</number>
- </property>
- <property name="singleStep">
- <number>10</number>
- </property>
- </widget>
- </item>
- <item row="0" column="3">
- <widget class="QSpinBox" name="res_y_spin">
- <property name="toolTip">
- <string>Desired capture height</string>
- </property>
- <property name="maximum">
- <number>2000</number>
- </property>
- <property name="singleStep">
- <number>10</number>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="label_34">
- <property name="text">
- <string>F/W</string>
- </property>
- <property name="buddy">
- <cstring>f_dspin</cstring>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QDoubleSpinBox" name="f_dspin">
- <property name="toolTip">
- <string>The camera's focal length devided by its sensor width</string>
- </property>
- <property name="decimals">
- <number>2</number>
- </property>
- <property name="singleStep">
- <double>0.100000000000000</double>
- </property>
- </widget>
- </item>
- <item row="0" column="4">
- <spacer name="horizontalSpacer_2">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="0" column="7">
- <spacer name="horizontalSpacer_9">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>0</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </item>
- </layout>
- </item>
- <item>
- <layout class="QHBoxLayout" name="horizontalLayout_7"/>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <widget class="QGroupBox" name="groupBox_4">
- <property name="title">
- <string>Camera Orientation</string>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout_8">
- <item>
- <layout class="QHBoxLayout" name="horizontalLayout_6">
- <item>
- <layout class="QGridLayout" name="gridLayout_3">
- <item row="1" column="0">
- <widget class="QLabel" name="label_4">
- <property name="text">
- <string>Pitch</string>
- </property>
- <property name="buddy">
- <cstring>campitch_spin</cstring>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QSpinBox" name="campitch_spin">
- <property name="contextMenuPolicy">
- <enum>Qt::DefaultContextMenu</enum>
- </property>
- <property name="toolTip">
- <string>The angle the camera is facing upwards</string>
- </property>
- <property name="minimum">
- <number>-99</number>
- </property>
- </widget>
- </item>
- <item row="2" column="0">
- <widget class="QLabel" name="label_20">
- <property name="text">
- <string>Yaw</string>
- </property>
- <property name="buddy">
- <cstring>camyaw_spin</cstring>
- </property>
- </widget>
- </item>
- <item row="2" column="1">
- <widget class="QSpinBox" name="camyaw_spin">
- <property name="contextMenuPolicy">
- <enum>Qt::DefaultContextMenu</enum>
- </property>
- <property name="toolTip">
- <string>The angle the camera is facing leftwards</string>
- </property>
- <property name="minimum">
- <number>-99</number>
- </property>
- </widget>
- </item>
- <item row="2" column="2">
- <widget class="QLabel" name="label_21">
- <property name="text">
- <string>deg (positve = leftwards)</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QComboBox" name="camroll_combo">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="minimumSize">
- <size>
- <width>0</width>
- <height>0</height>
- </size>
- </property>
- <property name="toolTip">
- <string>Rotation of the camera image</string>
- </property>
- </widget>
- </item>
- <item row="1" column="2">
- <widget class="QLabel" name="label_5">
- <property name="text">
- <string>deg (positive = upwards)</string>
- </property>
- </widget>
- </item>
- <item row="0" column="2">
- <widget class="QLabel" name="label_19">
- <property name="text">
- <string>deg</string>
- </property>
- </widget>
- </item>
- <item row="0" column="0">
- <widget class="QLabel" name="label_18">
- <property name="text">
- <string>Roll</string>
- </property>
- <property name="buddy">
- <cstring>camroll_combo</cstring>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <spacer name="horizontalSpacer_10">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>0</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <spacer name="verticalSpacer_2">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>0</height>
- </size>
- </property>
- </spacer>
- </item>
- <item>
- <widget class="QGroupBox" name="groupBox_2">
- <property name="title">
- <string>Point Extraction</string>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout_4">
- <item>
- <layout class="QHBoxLayout" name="horizontalLayout">
- <item>
- <widget class="QLabel" name="label">
- <property name="text">
- <string>Threshold</string>
- </property>
- <property name="buddy">
- <cstring>threshold_slider</cstring>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QSlider" name="threshold_slider">
- <property name="toolTip">
- <string>Intensity threshold for point extraction</string>
- </property>
- <property name="maximum">
- <number>255</number>
- </property>
- <property name="value">
- <number>127</number>
- </property>
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <layout class="QHBoxLayout" name="horizontalLayout_secondary">
- <item>
- <widget class="QLabel" name="label_secondary">
- <property name="text">
- <string>Hysteresis</string>
- </property>
- <property name="buddy">
- <cstring>threshold_secondary_slider</cstring>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QSlider" name="threshold_secondary_slider">
- <property name="toolTip">
- <string>Per pixel hysteresis width (leave left if there is little difference between dot and non-dot, move right for increased stability against pixel noise)</string>
- </property>
- <property name="maximum">
- <number>255</number>
- </property>
- <property name="pageStep">
- <number>1</number>
- </property>
- <property name="value">
- <number>100</number>
- </property>
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <layout class="QHBoxLayout" name="horizontalLayout_2">
- <item>
- <widget class="QLabel" name="label_7">
- <property name="text">
- <string>Min Diameter</string>
- </property>
- <property name="buddy">
- <cstring>mindiam_spin</cstring>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QSpinBox" name="mindiam_spin">
- <property name="toolTip">
- <string>Minimum point diameter</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QLabel" name="label_12">
- <property name="text">
- <string>px</string>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="horizontalSpacer">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item>
- <widget class="QLabel" name="label_8">
- <property name="text">
- <string>Max Diameter</string>
- </property>
- <property name="buddy">
- <cstring>maxdiam_spin</cstring>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QSpinBox" name="maxdiam_spin">
- <property name="toolTip">
- <string>Maximum point diameter</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QLabel" name="label_13">
- <property name="text">
- <string>px</string>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- </layout>
- </widget>
- </item>
- </layout>
- </widget>
- <widget class="QWidget" name="tab_4">
- <attribute name="title">
- <string>Model</string>
- </attribute>
- <layout class="QVBoxLayout" name="verticalLayout_16">
- <item>
- <widget class="QTabWidget" name="model_tabs">
- <property name="tabShape">
- <enum>QTabWidget::Rounded</enum>
- </property>
- <property name="currentIndex">
- <number>2</number>
- </property>
- <property name="usesScrollButtons">
- <bool>false</bool>
- </property>
- <property name="documentMode">
- <bool>false</bool>
- </property>
- <property name="tabsClosable">
- <bool>false</bool>
- </property>
- <widget class="QWidget" name="tab_5">
- <attribute name="title">
- <string>Clip</string>
- </attribute>
- <layout class="QVBoxLayout" name="verticalLayout_13">
- <item>
- <widget class="QGroupBox" name="groupBox_8">
- <property name="title">
- <string>Model Dimensions (mm)</string>
- </property>
- <layout class="QHBoxLayout" name="horizontalLayout_16">
- <item>
- <widget class="QWidget" name="widget_4" native="true">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="minimumSize">
- <size>
- <width>150</width>
- <height>160</height>
- </size>
- </property>
- <widget class="QLabel" name="label_44">
- <property name="geometry">
- <rect>
- <x>30</x>
- <y>30</y>
- <width>71</width>
- <height>111</height>
- </rect>
- </property>
- <property name="text">
- <string/>
- </property>
- <property name="pixmap">
- <pixmap resource="ftnoir_tracker_pt.qrc">:/Resources/clip_side.png</pixmap>
- </property>
- </widget>
- <widget class="QSpinBox" name="clip_theight_spin">
- <property name="geometry">
- <rect>
- <x>100</x>
- <y>50</y>
- <width>46</width>
- <height>22</height>
- </rect>
- </property>
- <property name="maximum">
- <number>999</number>
- </property>
- </widget>
- <widget class="QSpinBox" name="clip_tlength_spin">
- <property name="geometry">
- <rect>
- <x>60</x>
- <y>10</y>
- <width>46</width>
- <height>22</height>
- </rect>
- </property>
- <property name="maximum">
- <number>999</number>
- </property>
- </widget>
- <widget class="QSpinBox" name="clip_bheight_spin">
- <property name="geometry">
- <rect>
- <x>100</x>
- <y>90</y>
- <width>46</width>
- <height>22</height>
- </rect>
- </property>
- <property name="maximum">
- <number>999</number>
- </property>
- </widget>
- <widget class="QLabel" name="label_50">
- <property name="geometry">
- <rect>
- <x>10</x>
- <y>10</y>
- <width>46</width>
- <height>13</height>
- </rect>
- </property>
- <property name="text">
- <string>Side</string>
- </property>
- </widget>
- <widget class="QSpinBox" name="clip_blength_spin">
- <property name="geometry">
- <rect>
- <x>40</x>
- <y>140</y>
- <width>46</width>
- <height>22</height>
- </rect>
- </property>
- <property name="maximum">
- <number>999</number>
- </property>
- </widget>
- <widget class="QLabel" name="label_52">
- <property name="geometry">
- <rect>
- <x>70</x>
- <y>70</y>
- <width>16</width>
- <height>16</height>
- </rect>
- </property>
- <property name="text">
- <string>R</string>
- </property>
- </widget>
- </widget>
- </item>
- <item>
- <widget class="QWidget" name="widget_3" native="true">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="minimumSize">
- <size>
- <width>100</width>
- <height>140</height>
- </size>
- </property>
- <widget class="QLabel" name="label_51">
- <property name="geometry">
- <rect>
- <x>10</x>
- <y>10</y>
- <width>46</width>
- <height>13</height>
- </rect>
- </property>
- <property name="text">
- <string>Front</string>
- </property>
- </widget>
- <widget class="QLabel" name="label_45">
- <property name="geometry">
- <rect>
- <x>40</x>
- <y>30</y>
- <width>21</width>
- <height>111</height>
- </rect>
- </property>
- <property name="text">
- <string/>
- </property>
- <property name="pixmap">
- <pixmap resource="ftnoir_tracker_pt.qrc">:/Resources/clip_front.png</pixmap>
- </property>
- </widget>
- <widget class="QLabel" name="label_53">
- <property name="geometry">
- <rect>
- <x>60</x>
- <y>70</y>
- <width>16</width>
- <height>16</height>
- </rect>
- </property>
- <property name="text">
- <string>R</string>
- </property>
- </widget>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- </layout>
- </widget>
- <widget class="QWidget" name="tab_6">
- <attribute name="title">
- <string>Cap</string>
- </attribute>
- <layout class="QVBoxLayout" name="verticalLayout_14">
- <item>
- <widget class="QGroupBox" name="groupBox_9">
- <property name="title">
- <string>Model Dimensions (mm)</string>
- </property>
- <layout class="QHBoxLayout" name="horizontalLayout_15">
- <item>
- <widget class="QWidget" name="widget" native="true">
- <property name="minimumSize">
- <size>
- <width>140</width>
- <height>130</height>
- </size>
- </property>
- <widget class="QLabel" name="label_46">
- <property name="geometry">
- <rect>
- <x>20</x>
- <y>50</y>
- <width>111</width>
- <height>81</height>
- </rect>
- </property>
- <property name="text">
- <string/>
- </property>
- <property name="pixmap">
- <pixmap resource="ftnoir_tracker_pt.qrc">:/Resources/cap_side.png</pixmap>
- </property>
- </widget>
- <widget class="QSpinBox" name="cap_height_spin">
- <property name="geometry">
- <rect>
- <x>30</x>
- <y>80</y>
- <width>46</width>
- <height>22</height>
- </rect>
- </property>
- <property name="maximum">
- <number>999</number>
- </property>
- </widget>
- <widget class="QLabel" name="label_54">
- <property name="geometry">
- <rect>
- <x>130</x>
- <y>50</y>
- <width>16</width>
- <height>16</height>
- </rect>
- </property>
- <property name="text">
- <string>R</string>
- </property>
- </widget>
- <widget class="QLabel" name="label_48">
- <property name="geometry">
- <rect>
- <x>10</x>
- <y>10</y>
- <width>46</width>
- <height>13</height>
- </rect>
- </property>
- <property name="text">
- <string>Side</string>
- </property>
- </widget>
- <widget class="QSpinBox" name="cap_length_spin">
- <property name="geometry">
- <rect>
- <x>50</x>
- <y>40</y>
- <width>46</width>
- <height>22</height>
- </rect>
- </property>
- <property name="maximum">
- <number>999</number>
- </property>
- </widget>
- </widget>
- </item>
- <item>
- <widget class="QWidget" name="widget_2" native="true">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="minimumSize">
- <size>
- <width>100</width>
- <height>130</height>
- </size>
- </property>
- <widget class="QLabel" name="label_49">
- <property name="geometry">
- <rect>
- <x>10</x>
- <y>10</y>
- <width>46</width>
- <height>13</height>
- </rect>
- </property>
- <property name="text">
- <string>Front</string>
- </property>
- </widget>
- <widget class="QLabel" name="label_55">
- <property name="geometry">
- <rect>
- <x>30</x>
- <y>50</y>
- <width>16</width>
- <height>16</height>
- </rect>
- </property>
- <property name="text">
- <string>R</string>
- </property>
- </widget>
- <widget class="QLabel" name="label_47">
- <property name="geometry">
- <rect>
- <x>10</x>
- <y>50</y>
- <width>81</width>
- <height>81</height>
- </rect>
- </property>
- <property name="text">
- <string/>
- </property>
- <property name="pixmap">
- <pixmap resource="ftnoir_tracker_pt.qrc">:/Resources/cap_front.png</pixmap>
- </property>
- </widget>
- <widget class="QSpinBox" name="cap_width_spin">
- <property name="geometry">
- <rect>
- <x>50</x>
- <y>30</y>
- <width>46</width>
- <height>22</height>
- </rect>
- </property>
- <property name="maximum">
- <number>999</number>
- </property>
- </widget>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- </layout>
- </widget>
- <widget class="QWidget" name="tab_7">
- <attribute name="title">
- <string>Custom</string>
- </attribute>
- <layout class="QVBoxLayout" name="verticalLayout_15">
- <item>
- <widget class="QGroupBox" name="groupBox_7">
- <property name="title">
- <string>Model Dimensions (mm)</string>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout_12">
- <item>
- <widget class="QLabel" name="label_56">
- <property name="text">
- <string><html><head/><body><p>Location of the two remaining model points<br/>with respect to the reference point in default pose</p></body></html></string>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="verticalSpacer_4">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>0</height>
- </size>
- </property>
- </spacer>
- </item>
- <item>
- <layout class="QHBoxLayout" name="horizontalLayout_14">
- <item>
- <spacer name="horizontalSpacer_14">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>10</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item>
- <layout class="QGridLayout" name="gridLayout_4">
- <item row="3" column="2">
- <widget class="QSpinBox" name="m1z_spin">
- <property name="minimum">
- <number>-999</number>
- </property>
- <property name="maximum">
- <number>999</number>
- </property>
- </widget>
- </item>
- <item row="2" column="1">
- <widget class="QLabel" name="label_58">
- <property name="text">
- <string>y:</string>
- </property>
- </widget>
- </item>
- <item row="2" column="2">
- <widget class="QSpinBox" name="m1y_spin">
- <property name="minimum">
- <number>-999</number>
- </property>
- <property name="maximum">
- <number>999</number>
- </property>
- </widget>
- </item>
- <item row="3" column="1">
- <widget class="QLabel" name="label_57">
- <property name="text">
- <string>z:</string>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="label_60">
- <property name="text">
- <string>M1:</string>
- </property>
- </widget>
- </item>
- <item row="1" column="2">
- <widget class="QSpinBox" name="m1x_spin">
- <property name="minimum">
- <number>-999</number>
- </property>
- <property name="maximum">
- <number>999</number>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QLabel" name="label_63">
- <property name="text">
- <string>x:</string>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <spacer name="horizontalSpacer_15">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item>
- <layout class="QGridLayout" name="gridLayout_5">
- <item row="1" column="2">
- <widget class="QSpinBox" name="m2x_spin">
- <property name="minimum">
- <number>-999</number>
- </property>
- <property name="maximum">
- <number>999</number>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QLabel" name="label_67">
- <property name="text">
- <string>x:</string>
- </property>
- </widget>
- </item>
- <item row="3" column="1">
- <widget class="QLabel" name="label_69">
- <property name="text">
- <string>z:</string>
- </property>
- </widget>
- </item>
- <item row="2" column="2">
- <widget class="QSpinBox" name="m2y_spin">
- <property name="minimum">
- <number>-999</number>
- </property>
- <property name="maximum">
- <number>999</number>
- </property>
- </widget>
- </item>
- <item row="2" column="1">
- <widget class="QLabel" name="label_70">
- <property name="text">
- <string>y:</string>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="label_64">
- <property name="text">
- <string>M2:</string>
- </property>
- </widget>
- </item>
- <item row="3" column="2">
- <widget class="QSpinBox" name="m2z_spin">
- <property name="suffix">
- <string/>
- </property>
- <property name="minimum">
- <number>-999</number>
- </property>
- <property name="maximum">
- <number>999</number>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <spacer name="horizontalSpacer_16">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>10</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </item>
- <item>
- <spacer name="verticalSpacer_3">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>0</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
- </item>
- </layout>
- </widget>
- </widget>
- </item>
- <item>
- <widget class="QGroupBox" name="groupBox_10">
- <property name="title">
- <string>Model Position (mm)</string>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout_11">
- <item>
- <widget class="QLabel" name="label_59">
- <property name="text">
- <string><html><head/><body><p>Translation from head center to model reference point<br/> in default pose</p></body></html></string>
- </property>
- </widget>
- </item>
- <item>
- <layout class="QHBoxLayout" name="horizontalLayout_17">
- <item>
- <spacer name="horizontalSpacer_17">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>10</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item>
- <layout class="QGridLayout" name="gridLayout_6">
- <item row="3" column="1">
- <widget class="QSpinBox" name="tz_spin">
- <property name="suffix">
- <string/>
- </property>
- <property name="minimum">
- <number>-999</number>
- </property>
- <property name="maximum">
- <number>999</number>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="label_61">
- <property name="text">
- <string>x:</string>
- </property>
- </widget>
- </item>
- <item row="2" column="0">
- <widget class="QLabel" name="label_62">
- <property name="text">
- <string>y:</string>
- </property>
- </widget>
- </item>
- <item row="3" column="0">
- <widget class="QLabel" name="label_66">
- <property name="text">
- <string>z:</string>
- </property>
- </widget>
- </item>
- <item row="2" column="1">
- <widget class="QSpinBox" name="ty_spin">
- <property name="minimum">
- <number>-999</number>
- </property>
- <property name="maximum">
- <number>999</number>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QSpinBox" name="tx_spin">
- <property name="minimum">
- <number>-999</number>
- </property>
- <property name="maximum">
- <number>999</number>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <spacer name="horizontalSpacer_18">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item>
- <widget class="QPushButton" name="tcalib_button">
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="text">
- <string>Calibrate</string>
- </property>
- <property name="checkable">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="horizontalSpacer_19">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>10</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </item>
- </layout>
- </widget>
- </item>
- </layout>
- </widget>
- <widget class="QWidget" name="tab_3">
- <attribute name="title">
- <string>About</string>
- </attribute>
- <widget class="QLabel" name="label_10">
- <property name="geometry">
- <rect>
- <x>30</x>
- <y>30</y>
- <width>161</width>
- <height>111</height>
- </rect>
- </property>
- <property name="text">
- <string><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></string>
- </property>
- <property name="openExternalLinks">
- <bool>true</bool>
- </property>
- </widget>
- <widget class="QLabel" name="label_35">
- <property name="geometry">
- <rect>
- <x>200</x>
- <y>30</y>
- <width>141</width>
- <height>141</height>
- </rect>
- </property>
- <property name="text">
- <string/>
- </property>
- <property name="pixmap">
- <pixmap resource="ftnoir_tracker_pt.qrc">:/Resources/Logo_IR.png</pixmap>
- </property>
- </widget>
- </widget>
- </widget>
- </item>
- <item>
- <widget class="QGroupBox" name="groupBox_5">
- <property name="title">
- <string>Status</string>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout_5">
- <item>
- <layout class="QFormLayout" name="formLayout">
- <property name="fieldGrowthPolicy">
- <enum>QFormLayout::AllNonFixedFieldsGrow</enum>
- </property>
- <item row="0" column="0">
- <widget class="QLabel" name="label_38">
- <property name="text">
- <string>Camera Info:</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QLabel" name="caminfo_label">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="minimumSize">
- <size>
- <width>120</width>
- <height>0</height>
- </size>
- </property>
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="label_3">
- <property name="text">
- <string>Extracted Points:</string>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QLabel" name="pointinfo_label">
- <property name="minimumSize">
- <size>
- <width>50</width>
- <height>0</height>
- </size>
- </property>
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <layout class="QHBoxLayout" name="horizontalLayout_4">
- <item>
- <widget class="QPushButton" name="btnApply">
- <property name="text">
- <string>Save</string>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="horizontalSpacer_6">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item>
- <widget class="QPushButton" name="ok_button">
- <property name="locale">
- <locale language="English" country="UnitedStates"/>
- </property>
- <property name="text">
- <string>Ok</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="cancel_button">
- <property name="locale">
- <locale language="English" country="UnitedStates"/>
- </property>
- <property name="text">
- <string>Cancel</string>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- </layout>
- </widget>
- <tabstops>
- <tabstop>tabWidget</tabstop>
- <tabstop>reset_spin</tabstop>
- <tabstop>camdevice_combo</tabstop>
- <tabstop>res_x_spin</tabstop>
- <tabstop>res_y_spin</tabstop>
- <tabstop>fps_spin</tabstop>
- <tabstop>f_dspin</tabstop>
- <tabstop>camroll_combo</tabstop>
- <tabstop>campitch_spin</tabstop>
- <tabstop>camyaw_spin</tabstop>
- <tabstop>threshold_slider</tabstop>
- <tabstop>mindiam_spin</tabstop>
- <tabstop>maxdiam_spin</tabstop>
- <tabstop>model_tabs</tabstop>
- <tabstop>clip_tlength_spin</tabstop>
- <tabstop>clip_theight_spin</tabstop>
- <tabstop>clip_bheight_spin</tabstop>
- <tabstop>clip_blength_spin</tabstop>
- <tabstop>cap_length_spin</tabstop>
- <tabstop>cap_height_spin</tabstop>
- <tabstop>cap_width_spin</tabstop>
- <tabstop>m1x_spin</tabstop>
- <tabstop>m1y_spin</tabstop>
- <tabstop>m1z_spin</tabstop>
- <tabstop>m2x_spin</tabstop>
- <tabstop>m2y_spin</tabstop>
- <tabstop>m2z_spin</tabstop>
- <tabstop>tx_spin</tabstop>
- <tabstop>ty_spin</tabstop>
- <tabstop>tz_spin</tabstop>
- <tabstop>tcalib_button</tabstop>
- <tabstop>ok_button</tabstop>
- <tabstop>cancel_button</tabstop>
- </tabstops>
- <resources>
- <include location="ftnoir_tracker_pt.qrc"/>
- </resources>
- <connections>
- <connection>
- <sender>dynpose_check</sender>
- <signal>toggled(bool)</signal>
- <receiver>reset_spin</receiver>
- <slot>setEnabled(bool)</slot>
- <hints>
- <hint type="sourcelabel">
- <x>172</x>
- <y>110</y>
- </hint>
- <hint type="destinationlabel">
- <x>351</x>
- <y>112</y>
- </hint>
- </hints>
- </connection>
- </connections>
- <slots>
- <slot>startEngineClicked()</slot>
- <slot>stopEngineClicked()</slot>
- <slot>cameraSettingsClicked()</slot>
- </slots>
-</ui>
+<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>UICPTClientControls</class> + <widget class="QWidget" name="UICPTClientControls"> + <property name="windowModality"> + <enum>Qt::NonModal</enum> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>459</width> + <height>621</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="windowTitle"> + <string>PointTracker Settings</string> + </property> + <property name="windowIcon"> + <iconset resource="ftnoir_tracker_pt.qrc"> + <normaloff>:/Resources/Logo_IR.png</normaloff>:/Resources/Logo_IR.png</iconset> + </property> + <property name="layoutDirection"> + <enum>Qt::LeftToRight</enum> + </property> + <property name="autoFillBackground"> + <bool>false</bool> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <property name="sizeConstraint"> + <enum>QLayout::SetFixedSize</enum> + </property> + <item> + <widget class="QTabWidget" name="tabWidget"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + <property name="locale"> + <locale language="English" country="UnitedStates"/> + </property> + <property name="currentIndex"> + <number>0</number> + </property> + <widget class="QWidget" name="tab"> + <attribute name="title"> + <string>General</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <item> + <widget class="QGroupBox" name="groupBox_6"> + <property name="title"> + <string>Tracker Thread</string> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <widget class="QLabel" name="label_43"> + <property name="text"> + <string>Auto-reset time</string> + </property> + <property name="buddy"> + <cstring>reset_spin</cstring> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QSpinBox" name="reset_spin"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Time until automatic reset of tracker's internal state when no valid tracking result is found</string> + </property> + <property name="suffix"> + <string>ms</string> + </property> + <property name="maximum"> + <number>9999</number> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_17"> + <property name="text"> + <string>Dynamic Pose Resolution</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QCheckBox" name="dynpose_check"> + <property name="toolTip"> + <string/> + </property> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QPushButton" name="reset_button"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="toolTip"> + <string>Reset the tracker's internal state</string> + </property> + <property name="text"> + <string>Reset</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>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <widget class="QWidget" name="tab_2"> + <attribute name="title"> + <string>Camera</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_7"> + <item> + <widget class="QGroupBox" name="groupBox"> + <property name="toolTip"> + <string>The camera device used as input</string> + </property> + <property name="title"> + <string>Camera Settings</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_3"> + <item> + <widget class="QLabel" name="label_2"> + <property name="minimumSize"> + <size> + <width>55</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string>Device</string> + </property> + <property name="buddy"> + <cstring>camdevice_combo</cstring> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="camdevice_combo"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Camera device used as input</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_8"> + <item> + <layout class="QGridLayout" name="gridLayout_8"> + <item row="0" column="0"> + <widget class="QLabel" name="label_36"> + <property name="minimumSize"> + <size> + <width>55</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string>Resolution</string> + </property> + </widget> + </item> + <item row="0" column="5"> + <widget class="QLabel" name="label_37"> + <property name="text"> + <string>FPS</string> + </property> + <property name="buddy"> + <cstring>fps_spin</cstring> + </property> + </widget> + </item> + <item row="0" column="6"> + <widget class="QSpinBox" name="fps_spin"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Desired capture framerate</string> + </property> + <property name="maximum"> + <number>999</number> + </property> + </widget> + </item> + <item row="0" column="2"> + <widget class="QLabel" name="label_41"> + <property name="text"> + <string>x</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QSpinBox" name="res_x_spin"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Desired capture width</string> + </property> + <property name="maximum"> + <number>2000</number> + </property> + <property name="singleStep"> + <number>10</number> + </property> + </widget> + </item> + <item row="0" column="3"> + <widget class="QSpinBox" name="res_y_spin"> + <property name="toolTip"> + <string>Desired capture height</string> + </property> + <property name="maximum"> + <number>2000</number> + </property> + <property name="singleStep"> + <number>10</number> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_34"> + <property name="text"> + <string>F/W</string> + </property> + <property name="buddy"> + <cstring>f_dspin</cstring> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QDoubleSpinBox" name="f_dspin"> + <property name="toolTip"> + <string>The camera's focal length devided by its sensor width</string> + </property> + <property name="decimals"> + <number>2</number> + </property> + <property name="singleStep"> + <double>0.100000000000000</double> + </property> + </widget> + </item> + <item row="0" column="4"> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="0" column="7"> + <spacer name="horizontalSpacer_9"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_7"/> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="groupBox_4"> + <property name="title"> + <string>Camera Orientation</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_8"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_6"> + <item> + <layout class="QGridLayout" name="gridLayout_3"> + <item row="1" column="0"> + <widget class="QLabel" name="label_4"> + <property name="text"> + <string>Pitch</string> + </property> + <property name="buddy"> + <cstring>campitch_spin</cstring> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QSpinBox" name="campitch_spin"> + <property name="contextMenuPolicy"> + <enum>Qt::DefaultContextMenu</enum> + </property> + <property name="toolTip"> + <string>The angle the camera is facing upwards</string> + </property> + <property name="minimum"> + <number>-99</number> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label_20"> + <property name="text"> + <string>Yaw</string> + </property> + <property name="buddy"> + <cstring>camyaw_spin</cstring> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QSpinBox" name="camyaw_spin"> + <property name="contextMenuPolicy"> + <enum>Qt::DefaultContextMenu</enum> + </property> + <property name="toolTip"> + <string>The angle the camera is facing leftwards</string> + </property> + <property name="minimum"> + <number>-99</number> + </property> + </widget> + </item> + <item row="2" column="2"> + <widget class="QLabel" name="label_21"> + <property name="text"> + <string>deg (positve = leftwards)</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QComboBox" name="camroll_combo"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + <property name="toolTip"> + <string>Rotation of the camera image</string> + </property> + </widget> + </item> + <item row="1" column="2"> + <widget class="QLabel" name="label_5"> + <property name="text"> + <string>deg (positive = upwards)</string> + </property> + </widget> + </item> + <item row="0" column="2"> + <widget class="QLabel" name="label_19"> + <property name="text"> + <string>deg</string> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="label_18"> + <property name="text"> + <string>Roll</string> + </property> + <property name="buddy"> + <cstring>camroll_combo</cstring> + </property> + </widget> + </item> + </layout> + </item> + <item> + <spacer name="horizontalSpacer_10"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item> + <spacer name="verticalSpacer_2"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QGroupBox" name="groupBox_2"> + <property name="title"> + <string>Point Extraction</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_4"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Threshold</string> + </property> + <property name="buddy"> + <cstring>threshold_slider</cstring> + </property> + </widget> + </item> + <item> + <widget class="QSlider" name="threshold_slider"> + <property name="toolTip"> + <string>Intensity threshold for point extraction</string> + </property> + <property name="maximum"> + <number>255</number> + </property> + <property name="value"> + <number>127</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_secondary"> + <item> + <widget class="QLabel" name="label_secondary"> + <property name="text"> + <string>Hysteresis</string> + </property> + <property name="buddy"> + <cstring>threshold_secondary_slider</cstring> + </property> + </widget> + </item> + <item> + <widget class="QSlider" name="threshold_secondary_slider"> + <property name="toolTip"> + <string>Per pixel hysteresis width (leave left if there is little difference between dot and non-dot, move right for increased stability against pixel noise)</string> + </property> + <property name="maximum"> + <number>255</number> + </property> + <property name="pageStep"> + <number>1</number> + </property> + <property name="value"> + <number>100</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QLabel" name="label_7"> + <property name="text"> + <string>Min Diameter</string> + </property> + <property name="buddy"> + <cstring>mindiam_spin</cstring> + </property> + </widget> + </item> + <item> + <widget class="QSpinBox" name="mindiam_spin"> + <property name="toolTip"> + <string>Minimum point diameter</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_12"> + <property name="text"> + <string>px</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="label_8"> + <property name="text"> + <string>Max Diameter</string> + </property> + <property name="buddy"> + <cstring>maxdiam_spin</cstring> + </property> + </widget> + </item> + <item> + <widget class="QSpinBox" name="maxdiam_spin"> + <property name="toolTip"> + <string>Maximum point diameter</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_13"> + <property name="text"> + <string>px</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="tab_4"> + <attribute name="title"> + <string>Model</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_16"> + <item> + <widget class="QTabWidget" name="model_tabs"> + <property name="tabShape"> + <enum>QTabWidget::Rounded</enum> + </property> + <property name="currentIndex"> + <number>2</number> + </property> + <property name="usesScrollButtons"> + <bool>false</bool> + </property> + <property name="documentMode"> + <bool>false</bool> + </property> + <property name="tabsClosable"> + <bool>false</bool> + </property> + <widget class="QWidget" name="tab_5"> + <attribute name="title"> + <string>Clip</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_13"> + <item> + <widget class="QGroupBox" name="groupBox_8"> + <property name="title"> + <string>Model Dimensions (mm)</string> + </property> + <layout class="QHBoxLayout" name="horizontalLayout_16"> + <item> + <widget class="QWidget" name="widget_4" native="true"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>150</width> + <height>160</height> + </size> + </property> + <widget class="QLabel" name="label_44"> + <property name="geometry"> + <rect> + <x>30</x> + <y>30</y> + <width>71</width> + <height>111</height> + </rect> + </property> + <property name="text"> + <string/> + </property> + <property name="pixmap"> + <pixmap resource="ftnoir_tracker_pt.qrc">:/Resources/clip_side.png</pixmap> + </property> + </widget> + <widget class="QSpinBox" name="clip_theight_spin"> + <property name="geometry"> + <rect> + <x>100</x> + <y>50</y> + <width>46</width> + <height>22</height> + </rect> + </property> + <property name="maximum"> + <number>999</number> + </property> + </widget> + <widget class="QSpinBox" name="clip_tlength_spin"> + <property name="geometry"> + <rect> + <x>60</x> + <y>10</y> + <width>46</width> + <height>22</height> + </rect> + </property> + <property name="maximum"> + <number>999</number> + </property> + </widget> + <widget class="QSpinBox" name="clip_bheight_spin"> + <property name="geometry"> + <rect> + <x>100</x> + <y>90</y> + <width>46</width> + <height>22</height> + </rect> + </property> + <property name="maximum"> + <number>999</number> + </property> + </widget> + <widget class="QLabel" name="label_50"> + <property name="geometry"> + <rect> + <x>10</x> + <y>10</y> + <width>46</width> + <height>13</height> + </rect> + </property> + <property name="text"> + <string>Side</string> + </property> + </widget> + <widget class="QSpinBox" name="clip_blength_spin"> + <property name="geometry"> + <rect> + <x>40</x> + <y>140</y> + <width>46</width> + <height>22</height> + </rect> + </property> + <property name="maximum"> + <number>999</number> + </property> + </widget> + <widget class="QLabel" name="label_52"> + <property name="geometry"> + <rect> + <x>70</x> + <y>70</y> + <width>16</width> + <height>16</height> + </rect> + </property> + <property name="text"> + <string>R</string> + </property> + </widget> + </widget> + </item> + <item> + <widget class="QWidget" name="widget_3" native="true"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>100</width> + <height>140</height> + </size> + </property> + <widget class="QLabel" name="label_51"> + <property name="geometry"> + <rect> + <x>10</x> + <y>10</y> + <width>46</width> + <height>13</height> + </rect> + </property> + <property name="text"> + <string>Front</string> + </property> + </widget> + <widget class="QLabel" name="label_45"> + <property name="geometry"> + <rect> + <x>40</x> + <y>30</y> + <width>21</width> + <height>111</height> + </rect> + </property> + <property name="text"> + <string/> + </property> + <property name="pixmap"> + <pixmap resource="ftnoir_tracker_pt.qrc">:/Resources/clip_front.png</pixmap> + </property> + </widget> + <widget class="QLabel" name="label_53"> + <property name="geometry"> + <rect> + <x>60</x> + <y>70</y> + <width>16</width> + <height>16</height> + </rect> + </property> + <property name="text"> + <string>R</string> + </property> + </widget> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="tab_6"> + <attribute name="title"> + <string>Cap</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_14"> + <item> + <widget class="QGroupBox" name="groupBox_9"> + <property name="title"> + <string>Model Dimensions (mm)</string> + </property> + <layout class="QHBoxLayout" name="horizontalLayout_15"> + <item> + <widget class="QWidget" name="widget" native="true"> + <property name="minimumSize"> + <size> + <width>140</width> + <height>130</height> + </size> + </property> + <widget class="QLabel" name="label_46"> + <property name="geometry"> + <rect> + <x>20</x> + <y>50</y> + <width>111</width> + <height>81</height> + </rect> + </property> + <property name="text"> + <string/> + </property> + <property name="pixmap"> + <pixmap resource="ftnoir_tracker_pt.qrc">:/Resources/cap_side.png</pixmap> + </property> + </widget> + <widget class="QSpinBox" name="cap_height_spin"> + <property name="geometry"> + <rect> + <x>30</x> + <y>80</y> + <width>46</width> + <height>22</height> + </rect> + </property> + <property name="maximum"> + <number>999</number> + </property> + </widget> + <widget class="QLabel" name="label_54"> + <property name="geometry"> + <rect> + <x>130</x> + <y>50</y> + <width>16</width> + <height>16</height> + </rect> + </property> + <property name="text"> + <string>R</string> + </property> + </widget> + <widget class="QLabel" name="label_48"> + <property name="geometry"> + <rect> + <x>10</x> + <y>10</y> + <width>46</width> + <height>13</height> + </rect> + </property> + <property name="text"> + <string>Side</string> + </property> + </widget> + <widget class="QSpinBox" name="cap_length_spin"> + <property name="geometry"> + <rect> + <x>50</x> + <y>40</y> + <width>46</width> + <height>22</height> + </rect> + </property> + <property name="maximum"> + <number>999</number> + </property> + </widget> + </widget> + </item> + <item> + <widget class="QWidget" name="widget_2" native="true"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>100</width> + <height>130</height> + </size> + </property> + <widget class="QLabel" name="label_49"> + <property name="geometry"> + <rect> + <x>10</x> + <y>10</y> + <width>46</width> + <height>13</height> + </rect> + </property> + <property name="text"> + <string>Front</string> + </property> + </widget> + <widget class="QLabel" name="label_55"> + <property name="geometry"> + <rect> + <x>30</x> + <y>50</y> + <width>16</width> + <height>16</height> + </rect> + </property> + <property name="text"> + <string>R</string> + </property> + </widget> + <widget class="QLabel" name="label_47"> + <property name="geometry"> + <rect> + <x>10</x> + <y>50</y> + <width>81</width> + <height>81</height> + </rect> + </property> + <property name="text"> + <string/> + </property> + <property name="pixmap"> + <pixmap resource="ftnoir_tracker_pt.qrc">:/Resources/cap_front.png</pixmap> + </property> + </widget> + <widget class="QSpinBox" name="cap_width_spin"> + <property name="geometry"> + <rect> + <x>50</x> + <y>30</y> + <width>46</width> + <height>22</height> + </rect> + </property> + <property name="maximum"> + <number>999</number> + </property> + </widget> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="tab_7"> + <attribute name="title"> + <string>Custom</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_15"> + <item> + <widget class="QGroupBox" name="groupBox_7"> + <property name="title"> + <string>Model Dimensions (mm)</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_12"> + <item> + <widget class="QLabel" name="label_56"> + <property name="text"> + <string><html><head/><body><p>Location of the two remaining model points<br/>with respect to the reference point in default pose</p></body></html></string> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer_4"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_14"> + <item> + <spacer name="horizontalSpacer_14"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>10</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <layout class="QGridLayout" name="gridLayout_4"> + <item row="3" column="2"> + <widget class="QSpinBox" name="m1z_spin"> + <property name="minimum"> + <number>-999</number> + </property> + <property name="maximum"> + <number>999</number> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QLabel" name="label_58"> + <property name="text"> + <string>y:</string> + </property> + </widget> + </item> + <item row="2" column="2"> + <widget class="QSpinBox" name="m1y_spin"> + <property name="minimum"> + <number>-999</number> + </property> + <property name="maximum"> + <number>999</number> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="QLabel" name="label_57"> + <property name="text"> + <string>z:</string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_60"> + <property name="text"> + <string>M1:</string> + </property> + </widget> + </item> + <item row="1" column="2"> + <widget class="QSpinBox" name="m1x_spin"> + <property name="minimum"> + <number>-999</number> + </property> + <property name="maximum"> + <number>999</number> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLabel" name="label_63"> + <property name="text"> + <string>x:</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <spacer name="horizontalSpacer_15"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <layout class="QGridLayout" name="gridLayout_5"> + <item row="1" column="2"> + <widget class="QSpinBox" name="m2x_spin"> + <property name="minimum"> + <number>-999</number> + </property> + <property name="maximum"> + <number>999</number> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLabel" name="label_67"> + <property name="text"> + <string>x:</string> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="QLabel" name="label_69"> + <property name="text"> + <string>z:</string> + </property> + </widget> + </item> + <item row="2" column="2"> + <widget class="QSpinBox" name="m2y_spin"> + <property name="minimum"> + <number>-999</number> + </property> + <property name="maximum"> + <number>999</number> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QLabel" name="label_70"> + <property name="text"> + <string>y:</string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_64"> + <property name="text"> + <string>M2:</string> + </property> + </widget> + </item> + <item row="3" column="2"> + <widget class="QSpinBox" name="m2z_spin"> + <property name="suffix"> + <string/> + </property> + <property name="minimum"> + <number>-999</number> + </property> + <property name="maximum"> + <number>999</number> + </property> + </widget> + </item> + </layout> + </item> + <item> + <spacer name="horizontalSpacer_16"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>10</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item> + <spacer name="verticalSpacer_3"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + </widget> + </item> + <item> + <widget class="QGroupBox" name="groupBox_10"> + <property name="title"> + <string>Model Position (mm)</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_11"> + <item> + <widget class="QLabel" name="label_59"> + <property name="text"> + <string><html><head/><body><p>Translation from head center to model reference point<br/> in default pose</p></body></html></string> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_17"> + <item> + <spacer name="horizontalSpacer_17"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>10</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <layout class="QGridLayout" name="gridLayout_6"> + <item row="3" column="1"> + <widget class="QSpinBox" name="tz_spin"> + <property name="suffix"> + <string/> + </property> + <property name="minimum"> + <number>-999</number> + </property> + <property name="maximum"> + <number>999</number> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_61"> + <property name="text"> + <string>x:</string> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label_62"> + <property name="text"> + <string>y:</string> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="label_66"> + <property name="text"> + <string>z:</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QSpinBox" name="ty_spin"> + <property name="minimum"> + <number>-999</number> + </property> + <property name="maximum"> + <number>999</number> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QSpinBox" name="tx_spin"> + <property name="minimum"> + <number>-999</number> + </property> + <property name="maximum"> + <number>999</number> + </property> + </widget> + </item> + </layout> + </item> + <item> + <spacer name="horizontalSpacer_18"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="tcalib_button"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Calibrate</string> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_19"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>10</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="tab_3"> + <attribute name="title"> + <string>About</string> + </attribute> + <widget class="QLabel" name="label_10"> + <property name="geometry"> + <rect> + <x>30</x> + <y>30</y> + <width>161</width> + <height>111</height> + </rect> + </property> + <property name="text"> + <string><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></string> + </property> + <property name="openExternalLinks"> + <bool>true</bool> + </property> + </widget> + <widget class="QLabel" name="label_35"> + <property name="geometry"> + <rect> + <x>200</x> + <y>30</y> + <width>141</width> + <height>141</height> + </rect> + </property> + <property name="text"> + <string/> + </property> + <property name="pixmap"> + <pixmap resource="ftnoir_tracker_pt.qrc">:/Resources/Logo_IR.png</pixmap> + </property> + </widget> + </widget> + </widget> + </item> + <item> + <widget class="QGroupBox" name="groupBox_5"> + <property name="title"> + <string>Status</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_5"> + <item> + <layout class="QFormLayout" name="formLayout"> + <property name="fieldGrowthPolicy"> + <enum>QFormLayout::AllNonFixedFieldsGrow</enum> + </property> + <item row="0" column="0"> + <widget class="QLabel" name="label_38"> + <property name="text"> + <string>Camera Info:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLabel" name="caminfo_label"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>120</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Extracted Points:</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLabel" name="pointinfo_label"> + <property name="minimumSize"> + <size> + <width>50</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string/> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_4"> + <item> + <widget class="QPushButton" name="btnApply"> + <property name="text"> + <string>Save</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_6"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="ok_button"> + <property name="locale"> + <locale language="English" country="UnitedStates"/> + </property> + <property name="text"> + <string>Ok</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="cancel_button"> + <property name="locale"> + <locale language="English" country="UnitedStates"/> + </property> + <property name="text"> + <string>Cancel</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <tabstops> + <tabstop>tabWidget</tabstop> + <tabstop>reset_spin</tabstop> + <tabstop>camdevice_combo</tabstop> + <tabstop>res_x_spin</tabstop> + <tabstop>res_y_spin</tabstop> + <tabstop>fps_spin</tabstop> + <tabstop>f_dspin</tabstop> + <tabstop>camroll_combo</tabstop> + <tabstop>campitch_spin</tabstop> + <tabstop>camyaw_spin</tabstop> + <tabstop>threshold_slider</tabstop> + <tabstop>mindiam_spin</tabstop> + <tabstop>maxdiam_spin</tabstop> + <tabstop>model_tabs</tabstop> + <tabstop>clip_tlength_spin</tabstop> + <tabstop>clip_theight_spin</tabstop> + <tabstop>clip_bheight_spin</tabstop> + <tabstop>clip_blength_spin</tabstop> + <tabstop>cap_length_spin</tabstop> + <tabstop>cap_height_spin</tabstop> + <tabstop>cap_width_spin</tabstop> + <tabstop>m1x_spin</tabstop> + <tabstop>m1y_spin</tabstop> + <tabstop>m1z_spin</tabstop> + <tabstop>m2x_spin</tabstop> + <tabstop>m2y_spin</tabstop> + <tabstop>m2z_spin</tabstop> + <tabstop>tx_spin</tabstop> + <tabstop>ty_spin</tabstop> + <tabstop>tz_spin</tabstop> + <tabstop>tcalib_button</tabstop> + <tabstop>ok_button</tabstop> + <tabstop>cancel_button</tabstop> + </tabstops> + <resources> + <include location="ftnoir_tracker_pt.qrc"/> + </resources> + <connections> + <connection> + <sender>dynpose_check</sender> + <signal>toggled(bool)</signal> + <receiver>reset_spin</receiver> + <slot>setEnabled(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>172</x> + <y>110</y> + </hint> + <hint type="destinationlabel"> + <x>351</x> + <y>112</y> + </hint> + </hints> + </connection> + </connections> + <slots> + <slot>startEngineClicked()</slot> + <slot>stopEngineClicked()</slot> + <slot>cameraSettingsClicked()</slot> + </slots> +</ui> diff --git a/ftnoir_tracker_pt/Resources/Logo_IR.png b/ftnoir_tracker_pt/Resources/Logo_IR.png Binary files differindex 95032a25..85590691 100644 --- a/ftnoir_tracker_pt/Resources/Logo_IR.png +++ b/ftnoir_tracker_pt/Resources/Logo_IR.png diff --git a/ftnoir_tracker_pt/Resources/cap_front.png b/ftnoir_tracker_pt/Resources/cap_front.png Binary files differindex 14207a67..cbee28c9 100644 --- a/ftnoir_tracker_pt/Resources/cap_front.png +++ b/ftnoir_tracker_pt/Resources/cap_front.png diff --git a/ftnoir_tracker_pt/Resources/cap_side.png b/ftnoir_tracker_pt/Resources/cap_side.png Binary files differindex 5ad4ee65..27c28341 100644 --- a/ftnoir_tracker_pt/Resources/cap_side.png +++ b/ftnoir_tracker_pt/Resources/cap_side.png diff --git a/ftnoir_tracker_pt/Resources/clip_front.png b/ftnoir_tracker_pt/Resources/clip_front.png Binary files differindex 04880138..63fd70eb 100644 --- a/ftnoir_tracker_pt/Resources/clip_front.png +++ b/ftnoir_tracker_pt/Resources/clip_front.png diff --git a/ftnoir_tracker_pt/Resources/clip_side.png b/ftnoir_tracker_pt/Resources/clip_side.png Binary files differindex 72667ac7..1c295506 100644 --- a/ftnoir_tracker_pt/Resources/clip_side.png +++ b/ftnoir_tracker_pt/Resources/clip_side.png diff --git a/ftnoir_tracker_pt/camera.cpp b/ftnoir_tracker_pt/camera.cpp index 33e0ef2a..686e1b9b 100644 --- a/ftnoir_tracker_pt/camera.cpp +++ b/ftnoir_tracker_pt/camera.cpp @@ -1,346 +1,346 @@ -/* Copyright (c) 2012 Patrick Ruoff
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- */
-
- #if defined(OPENTRACK_API) && defined(_WIN32)
-#include <windows.h>
-#include <dshow.h>
-#endif
-
-#include "camera.h"
-#include <string>
-#include <QDebug>
-
-using namespace cv;
-
-#if defined(OPENTRACK_API) && (defined(__unix) || defined(__linux) || defined(__APPLE__))
-#include <unistd.h>
-#endif
-
-#ifdef OPENTRACK_API
-void get_camera_device_names(std::vector<std::string>& device_names) {
-# if defined(_WIN32)
- // Create the System Device Enumerator.
- HRESULT hr;
- ICreateDevEnum *pSysDevEnum = NULL;
- hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void **)&pSysDevEnum);
- if (FAILED(hr))
- {
- return;
- }
- // Obtain a class enumerator for the video compressor category.
- IEnumMoniker *pEnumCat = NULL;
- hr = pSysDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnumCat, 0);
-
- if (hr == S_OK) {
- // Enumerate the monikers.
- IMoniker *pMoniker = NULL;
- ULONG cFetched;
- while (pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK) {
- IPropertyBag *pPropBag;
- hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pPropBag);
- if (SUCCEEDED(hr)) {
- // To retrieve the filter's friendly name, do the following:
- VARIANT varName;
- VariantInit(&varName);
- hr = pPropBag->Read(L"FriendlyName", &varName, 0);
- if (SUCCEEDED(hr))
- {
- auto wstr = std::wstring(varName.bstrVal);
- auto str = std::string(wstr.begin(), wstr.end());
- device_names.push_back(str);
- }
- VariantClear(&varName);
-
- ////// To create an instance of the filter, do the following:
- ////IBaseFilter *pFilter;
- ////hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter,
- //// (void**)&pFilter);
- // Now add the filter to the graph.
- //Remember to release pFilter later.
- pPropBag->Release();
- }
- pMoniker->Release();
- }
- pEnumCat->Release();
- }
- pSysDevEnum->Release();
-# else
- for (int i = 0; i < 16; i++) {
- char buf[128];
- sprintf(buf, "/dev/video%d", i);
- if (access(buf, R_OK | W_OK) == 0) {
- device_names.push_back(std::string(buf));
- }
- }
-# endif
-}
-#else
-// ----------------------------------------------------------------------------
-void get_camera_device_names(std::vector<std::string>& device_names)
-{
- videoInput VI;
- VI.listDevices();
- std::string device_name;
- for(int index = 0; ; ++index) {
- device_name = VI.getDeviceName(index);
- if (device_name.empty()) break;
- device_names.push_back(device_name);
- }
-}
-#endif
-
-// ----------------------------------------------------------------------------
-void Camera::set_device_index(int index)
-{
- if (desired_index != index)
- {
- desired_index = index;
- _set_device_index();
-
- // reset fps
- dt_valid = 0;
- dt_mean = 0;
- active_index = index;
- }
-}
-
-void Camera::set_f(float f)
-{
- if (cam_desired.f != f)
- {
- cam_desired.f = f;
- _set_f();
- }
-}
-void Camera::set_fps(int fps)
-{
- if (cam_desired.fps != fps)
- {
- cam_desired.fps = fps;
- _set_fps();
- }
-}
-
-void Camera::set_res(int x_res, int y_res)
-{
- if (cam_desired.res_x != x_res || cam_desired.res_y != y_res)
- {
- cam_desired.res_x = x_res;
- cam_desired.res_y = y_res;
- _set_res();
- _set_fps();
- }
-}
-
-bool Camera::get_frame(float dt, cv::Mat* frame)
-{
- bool new_frame = _get_frame(frame);
- // measure fps of valid frames
- const float dt_smoothing_const = 0.9;
- dt_valid += dt;
- if (new_frame)
- {
- dt_mean = dt_smoothing_const * dt_mean + (1.0 - dt_smoothing_const) * dt_valid;
- cam_info.fps = 1.0 / dt_mean;
- dt_valid = 0;
- }
- return new_frame;
-}
-
-// ----------------------------------------------------------------------------
-#ifdef OPENTRACK_API
-void CVCamera::start()
-{
- cap = new VideoCapture(desired_index);
- // extract camera info
- if (cap->isOpened())
- {
- active = true;
- active_index = desired_index;
- cam_info.res_x = cap->get(CV_CAP_PROP_FRAME_WIDTH);
- cam_info.res_y = cap->get(CV_CAP_PROP_FRAME_HEIGHT);
- } else {
- delete cap;
- cap = nullptr;
- }
-}
-
-void CVCamera::stop()
-{
- if (cap)
- {
- cap->release();
- delete cap;
- }
- active = false;
-}
-
-bool CVCamera::_get_frame(Mat* frame)
-{
- if (cap && cap->isOpened())
- {
- Mat img;
- for (int i = 0; i < 100 && !cap->read(img); i++)
- ;;
-
- if (img.empty())
- return false;
-
- *frame = img;
- return true;
- }
- return false;
-}
-
-void CVCamera::_set_index()
-{
- if (active) restart();
-}
-
-void CVCamera::_set_f()
-{
- cam_info.f = cam_desired.f;
-}
-
-void CVCamera::_set_fps()
-{
- if (cap) cap->set(CV_CAP_PROP_FPS, cam_desired.fps);
-}
-
-void CVCamera::_set_res()
-{
- if (cap)
- {
- cap->set(CV_CAP_PROP_FRAME_WIDTH, cam_desired.res_x);
- cap->set(CV_CAP_PROP_FRAME_HEIGHT, cam_desired.res_y);
- cam_info.res_x = cap->get(CV_CAP_PROP_FRAME_WIDTH);
- cam_info.res_y = cap->get(CV_CAP_PROP_FRAME_HEIGHT);
- }
-}
-void CVCamera::_set_device_index()
-{
- if (cap)
- {
- cap->release();
- delete cap;
- }
- cap = new VideoCapture(desired_index);
-}
-
-#else
-// ----------------------------------------------------------------------------
-VICamera::VICamera() : frame_buffer(NULL)
-{
- VI.listDevices();
-}
-
-void VICamera::start()
-{
- if (desired_index >= 0)
- {
- if (cam_desired.res_x == 0 || cam_desired.res_y == 0)
- VI.setupDevice(desired_index);
- else
- VI.setupDevice(desired_index, cam_desired.res_x, cam_desired.res_y);
-
- active = true;
- active_index = desired_index;
-
- cam_info.res_x = VI.getWidth(active_index);
- cam_info.res_y = VI.getHeight(active_index);
- new_frame = cv::Mat(cam_info.res_y, cam_info.res_x, CV_8UC3);
- // If matrix is not continuous we have to copy manually via frame_buffer
- if (!new_frame.isContinuous()) {
- unsigned int size = VI.getSize(active_index);
- frame_buffer = new unsigned char[size];
- }
- }
-}
-
-void VICamera::stop()
-{
- if (active)
- {
- VI.stopDevice(active_index);
- }
- if (frame_buffer)
- {
- delete[] frame_buffer;
- frame_buffer = NULL;
- }
- active = false;
-}
-
-bool VICamera::_get_frame(Mat* frame)
-{
- if (active && VI.isFrameNew(active_index))
- {
- if (new_frame.isContinuous())
- {
- VI.getPixels(active_index, new_frame.data, false, true);
- }
- else
- {
- // If matrix is not continuous we have to copy manually via frame_buffer
- VI.getPixels(active_index, frame_buffer, false, true);
- new_frame = cv::Mat(cam_info.res_y, cam_info.res_x, CV_8UC3, frame_buffer).clone();
- }
- *frame = new_frame;
- return true;
- }
- return false;
-}
-
-void VICamera::_set_device_index()
-{
- if (active) restart();
-}
-
-void VICamera::_set_f()
-{
- cam_info.f = cam_desired.f;
-}
-
-void VICamera::_set_fps()
-{
- bool was_active = active;
- if (active) stop();
- VI.setIdealFramerate(desired_index, cam_desired.fps);
- if (was_active) start();
-}
-
-void VICamera::_set_res()
-{
- if (active) restart();
-}
-#endif
-
-// ----------------------------------------------------------------------------
-Mat FrameRotation::rotate_frame(Mat frame)
-{
- switch (rotation)
- {
- case CLOCKWISE:
- {
- Mat dst;
- transpose(frame, dst);
- flip(dst, dst, 1);
- return dst;
- }
-
- case COUNTER_CLOCKWISE:
- {
- Mat dst;
- transpose(frame, dst);
- flip(dst, dst, 0);
- return dst;
- }
-
- default:
- return frame;
- }
-}
+/* Copyright (c) 2012 Patrick Ruoff + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + */ + + #if defined(OPENTRACK_API) && defined(_WIN32) +#include <windows.h> +#include <dshow.h> +#endif + +#include "camera.h" +#include <string> +#include <QDebug> + +using namespace cv; + +#if defined(OPENTRACK_API) && (defined(__unix) || defined(__linux) || defined(__APPLE__)) +#include <unistd.h> +#endif + +#ifdef OPENTRACK_API +void get_camera_device_names(std::vector<std::string>& device_names) { +# if defined(_WIN32) + // Create the System Device Enumerator. + HRESULT hr; + ICreateDevEnum *pSysDevEnum = NULL; + hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void **)&pSysDevEnum); + if (FAILED(hr)) + { + return; + } + // Obtain a class enumerator for the video compressor category. + IEnumMoniker *pEnumCat = NULL; + hr = pSysDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnumCat, 0); + + if (hr == S_OK) { + // Enumerate the monikers. + IMoniker *pMoniker = NULL; + ULONG cFetched; + while (pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK) { + IPropertyBag *pPropBag; + hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pPropBag); + if (SUCCEEDED(hr)) { + // To retrieve the filter's friendly name, do the following: + VARIANT varName; + VariantInit(&varName); + hr = pPropBag->Read(L"FriendlyName", &varName, 0); + if (SUCCEEDED(hr)) + { + auto wstr = std::wstring(varName.bstrVal); + auto str = std::string(wstr.begin(), wstr.end()); + device_names.push_back(str); + } + VariantClear(&varName); + + ////// To create an instance of the filter, do the following: + ////IBaseFilter *pFilter; + ////hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter, + //// (void**)&pFilter); + // Now add the filter to the graph. + //Remember to release pFilter later. + pPropBag->Release(); + } + pMoniker->Release(); + } + pEnumCat->Release(); + } + pSysDevEnum->Release(); +# else + for (int i = 0; i < 16; i++) { + char buf[128]; + sprintf(buf, "/dev/video%d", i); + if (access(buf, R_OK | W_OK) == 0) { + device_names.push_back(std::string(buf)); + } + } +# endif +} +#else +// ---------------------------------------------------------------------------- +void get_camera_device_names(std::vector<std::string>& device_names) +{ + videoInput VI; + VI.listDevices(); + std::string device_name; + for(int index = 0; ; ++index) { + device_name = VI.getDeviceName(index); + if (device_name.empty()) break; + device_names.push_back(device_name); + } +} +#endif + +// ---------------------------------------------------------------------------- +void Camera::set_device_index(int index) +{ + if (desired_index != index) + { + desired_index = index; + _set_device_index(); + + // reset fps + dt_valid = 0; + dt_mean = 0; + active_index = index; + } +} + +void Camera::set_f(float f) +{ + if (cam_desired.f != f) + { + cam_desired.f = f; + _set_f(); + } +} +void Camera::set_fps(int fps) +{ + if (cam_desired.fps != fps) + { + cam_desired.fps = fps; + _set_fps(); + } +} + +void Camera::set_res(int x_res, int y_res) +{ + if (cam_desired.res_x != x_res || cam_desired.res_y != y_res) + { + cam_desired.res_x = x_res; + cam_desired.res_y = y_res; + _set_res(); + _set_fps(); + } +} + +bool Camera::get_frame(float dt, cv::Mat* frame) +{ + bool new_frame = _get_frame(frame); + // measure fps of valid frames + const float dt_smoothing_const = 0.9; + dt_valid += dt; + if (new_frame) + { + dt_mean = dt_smoothing_const * dt_mean + (1.0 - dt_smoothing_const) * dt_valid; + cam_info.fps = 1.0 / dt_mean; + dt_valid = 0; + } + return new_frame; +} + +// ---------------------------------------------------------------------------- +#ifdef OPENTRACK_API +void CVCamera::start() +{ + cap = new VideoCapture(desired_index); + // extract camera info + if (cap->isOpened()) + { + active = true; + active_index = desired_index; + cam_info.res_x = cap->get(CV_CAP_PROP_FRAME_WIDTH); + cam_info.res_y = cap->get(CV_CAP_PROP_FRAME_HEIGHT); + } else { + delete cap; + cap = nullptr; + } +} + +void CVCamera::stop() +{ + if (cap) + { + cap->release(); + delete cap; + } + active = false; +} + +bool CVCamera::_get_frame(Mat* frame) +{ + if (cap && cap->isOpened()) + { + Mat img; + for (int i = 0; i < 100 && !cap->read(img); i++) + ;; + + if (img.empty()) + return false; + + *frame = img; + return true; + } + return false; +} + +void CVCamera::_set_index() +{ + if (active) restart(); +} + +void CVCamera::_set_f() +{ + cam_info.f = cam_desired.f; +} + +void CVCamera::_set_fps() +{ + if (cap) cap->set(CV_CAP_PROP_FPS, cam_desired.fps); +} + +void CVCamera::_set_res() +{ + if (cap) + { + cap->set(CV_CAP_PROP_FRAME_WIDTH, cam_desired.res_x); + cap->set(CV_CAP_PROP_FRAME_HEIGHT, cam_desired.res_y); + cam_info.res_x = cap->get(CV_CAP_PROP_FRAME_WIDTH); + cam_info.res_y = cap->get(CV_CAP_PROP_FRAME_HEIGHT); + } +} +void CVCamera::_set_device_index() +{ + if (cap) + { + cap->release(); + delete cap; + } + cap = new VideoCapture(desired_index); +} + +#else +// ---------------------------------------------------------------------------- +VICamera::VICamera() : frame_buffer(NULL) +{ + VI.listDevices(); +} + +void VICamera::start() +{ + if (desired_index >= 0) + { + if (cam_desired.res_x == 0 || cam_desired.res_y == 0) + VI.setupDevice(desired_index); + else + VI.setupDevice(desired_index, cam_desired.res_x, cam_desired.res_y); + + active = true; + active_index = desired_index; + + cam_info.res_x = VI.getWidth(active_index); + cam_info.res_y = VI.getHeight(active_index); + new_frame = cv::Mat(cam_info.res_y, cam_info.res_x, CV_8UC3); + // If matrix is not continuous we have to copy manually via frame_buffer + if (!new_frame.isContinuous()) { + unsigned int size = VI.getSize(active_index); + frame_buffer = new unsigned char[size]; + } + } +} + +void VICamera::stop() +{ + if (active) + { + VI.stopDevice(active_index); + } + if (frame_buffer) + { + delete[] frame_buffer; + frame_buffer = NULL; + } + active = false; +} + +bool VICamera::_get_frame(Mat* frame) +{ + if (active && VI.isFrameNew(active_index)) + { + if (new_frame.isContinuous()) + { + VI.getPixels(active_index, new_frame.data, false, true); + } + else + { + // If matrix is not continuous we have to copy manually via frame_buffer + VI.getPixels(active_index, frame_buffer, false, true); + new_frame = cv::Mat(cam_info.res_y, cam_info.res_x, CV_8UC3, frame_buffer).clone(); + } + *frame = new_frame; + return true; + } + return false; +} + +void VICamera::_set_device_index() +{ + if (active) restart(); +} + +void VICamera::_set_f() +{ + cam_info.f = cam_desired.f; +} + +void VICamera::_set_fps() +{ + bool was_active = active; + if (active) stop(); + VI.setIdealFramerate(desired_index, cam_desired.fps); + if (was_active) start(); +} + +void VICamera::_set_res() +{ + if (active) restart(); +} +#endif + +// ---------------------------------------------------------------------------- +Mat FrameRotation::rotate_frame(Mat frame) +{ + switch (rotation) + { + case CLOCKWISE: + { + Mat dst; + transpose(frame, dst); + flip(dst, dst, 1); + return dst; + } + + case COUNTER_CLOCKWISE: + { + Mat dst; + transpose(frame, dst); + flip(dst, dst, 0); + return dst; + } + + default: + return frame; + } +} diff --git a/ftnoir_tracker_pt/camera.h b/ftnoir_tracker_pt/camera.h index a9f60841..733cc61f 100644 --- a/ftnoir_tracker_pt/camera.h +++ b/ftnoir_tracker_pt/camera.h @@ -1,145 +1,145 @@ -/* Copyright (c) 2012 Patrick Ruoff
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- */
-
-#ifndef CAMERA_H
-#define CAMERA_H
-
-#include <opencv2/opencv.hpp>
-#ifndef OPENTRACK_API
-# include <boost/shared_ptr.hpp>
-#else
+/* Copyright (c) 2012 Patrick Ruoff + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + */ + +#ifndef CAMERA_H +#define CAMERA_H + +#include <opencv2/opencv.hpp> +#ifndef OPENTRACK_API +# include <boost/shared_ptr.hpp> +#else # include <memory> -# include <opencv2/highgui/highgui.hpp>
-# include <opencv2/highgui/highgui_c.h>
-#endif
-#include <string>
-
-// ----------------------------------------------------------------------------
-void get_camera_device_names(std::vector<std::string>& device_names);
-
-
-// ----------------------------------------------------------------------------
-struct CamInfo
-{
- CamInfo() : res_x(0), res_y(0), fps(0), f(1) {}
-
- int res_x;
- int res_y;
- int fps;
- float f; // (focal length) / (sensor width)
-};
-
-// ----------------------------------------------------------------------------
-// Base class for cameras, calculates the frame rate
-class Camera
-{
-public:
- Camera() : dt_valid(0), dt_mean(0), desired_index(0), active_index(-1), active(false) {}
- virtual ~Camera() {}
-
- // start/stop capturing
- virtual void start() = 0;
- virtual void stop() = 0;
- void restart() { stop(); start(); }
-
- // calls corresponding template methods and reinitializes frame rate calculation
- void set_device_index(int index);
- void set_f(float f);
- void set_fps(int fps);
- void set_res(int x_res, int y_res);
-
- // gets a frame from the camera, dt: time since last call in seconds
- bool get_frame(float dt, cv::Mat* frame);
-
- // WARNING: returned references are valid as long as object
- const CamInfo& get_info() const { return cam_info; }
- const CamInfo& get_desired() const { return cam_desired; }
-
-protected:
- // get a frame from the camera
- virtual bool _get_frame(cv::Mat* frame) = 0;
-
- // update the camera using cam_desired, write res and f to cam_info if successful
- virtual void _set_device_index() = 0;
- virtual void _set_f() = 0;
- virtual void _set_fps() = 0;
- virtual void _set_res() = 0;
-
- float dt_valid;
- float dt_mean;
- int desired_index;
- int active_index;
- bool active;
- CamInfo cam_info;
- CamInfo cam_desired;
-};
-
-
-// ----------------------------------------------------------------------------
-// camera based on OpenCV's videoCapture
-#ifdef OPENTRACK_API
-class CVCamera : public Camera
-{
-public:
- CVCamera() : cap(NULL) {}
- ~CVCamera() { stop(); }
-
- virtual void start();
- virtual void stop();
-
-protected:
- virtual bool _get_frame(cv::Mat* frame);
- virtual void _set_index();
- virtual void _set_f();
- virtual void _set_fps();
- virtual void _set_res();
- virtual void _set_device_index();
-
- cv::VideoCapture* cap;
-};
-#else
-// ----------------------------------------------------------------------------
-// Camera based on the videoInput library
-class VICamera : public Camera
-{
-public:
- VICamera();
- ~VICamera() { stop(); }
-
- virtual void start();
- virtual void stop();
-
-protected:
- virtual bool _get_frame(cv::Mat* frame);
- virtual void _set_device_index();
- virtual void _set_f();
- virtual void _set_fps();
- virtual void _set_res();
-
- videoInput VI;
- cv::Mat new_frame;
- unsigned char* frame_buffer;
-};
-#endif
-
-enum RotationType
-{
- CLOCKWISE = 0,
- ZERO = 1,
- COUNTER_CLOCKWISE = 2
-};
-
-// ----------------------------------------------------------------------------
-class FrameRotation
-{
-public:
- RotationType rotation;
-
- cv::Mat rotate_frame(cv::Mat frame);
-};
-
-#endif //CAMERA_H
+# include <opencv2/highgui/highgui.hpp> +# include <opencv2/highgui/highgui_c.h> +#endif +#include <string> + +// ---------------------------------------------------------------------------- +void get_camera_device_names(std::vector<std::string>& device_names); + + +// ---------------------------------------------------------------------------- +struct CamInfo +{ + CamInfo() : res_x(0), res_y(0), fps(0), f(1) {} + + int res_x; + int res_y; + int fps; + float f; // (focal length) / (sensor width) +}; + +// ---------------------------------------------------------------------------- +// Base class for cameras, calculates the frame rate +class Camera +{ +public: + Camera() : dt_valid(0), dt_mean(0), desired_index(0), active_index(-1), active(false) {} + virtual ~Camera() {} + + // start/stop capturing + virtual void start() = 0; + virtual void stop() = 0; + void restart() { stop(); start(); } + + // calls corresponding template methods and reinitializes frame rate calculation + void set_device_index(int index); + void set_f(float f); + void set_fps(int fps); + void set_res(int x_res, int y_res); + + // gets a frame from the camera, dt: time since last call in seconds + bool get_frame(float dt, cv::Mat* frame); + + // WARNING: returned references are valid as long as object + const CamInfo& get_info() const { return cam_info; } + const CamInfo& get_desired() const { return cam_desired; } + +protected: + // get a frame from the camera + virtual bool _get_frame(cv::Mat* frame) = 0; + + // update the camera using cam_desired, write res and f to cam_info if successful + virtual void _set_device_index() = 0; + virtual void _set_f() = 0; + virtual void _set_fps() = 0; + virtual void _set_res() = 0; + + float dt_valid; + float dt_mean; + int desired_index; + int active_index; + bool active; + CamInfo cam_info; + CamInfo cam_desired; +}; + + +// ---------------------------------------------------------------------------- +// camera based on OpenCV's videoCapture +#ifdef OPENTRACK_API +class CVCamera : public Camera +{ +public: + CVCamera() : cap(NULL) {} + ~CVCamera() { stop(); } + + virtual void start(); + virtual void stop(); + +protected: + virtual bool _get_frame(cv::Mat* frame); + virtual void _set_index(); + virtual void _set_f(); + virtual void _set_fps(); + virtual void _set_res(); + virtual void _set_device_index(); + + cv::VideoCapture* cap; +}; +#else +// ---------------------------------------------------------------------------- +// Camera based on the videoInput library +class VICamera : public Camera +{ +public: + VICamera(); + ~VICamera() { stop(); } + + virtual void start(); + virtual void stop(); + +protected: + virtual bool _get_frame(cv::Mat* frame); + virtual void _set_device_index(); + virtual void _set_f(); + virtual void _set_fps(); + virtual void _set_res(); + + videoInput VI; + cv::Mat new_frame; + unsigned char* frame_buffer; +}; +#endif + +enum RotationType +{ + CLOCKWISE = 0, + ZERO = 1, + COUNTER_CLOCKWISE = 2 +}; + +// ---------------------------------------------------------------------------- +class FrameRotation +{ +public: + RotationType rotation; + + cv::Mat rotate_frame(cv::Mat frame); +}; + +#endif //CAMERA_H diff --git a/ftnoir_tracker_pt/doc/logo.png b/ftnoir_tracker_pt/doc/logo.png Binary files differindex 95032a25..85590691 100644 --- a/ftnoir_tracker_pt/doc/logo.png +++ b/ftnoir_tracker_pt/doc/logo.png diff --git a/ftnoir_tracker_pt/doc/settings1.png b/ftnoir_tracker_pt/doc/settings1.png Binary files differindex 35b84c5c..0725f5f4 100644 --- a/ftnoir_tracker_pt/doc/settings1.png +++ b/ftnoir_tracker_pt/doc/settings1.png diff --git a/ftnoir_tracker_pt/doc/settings2.png b/ftnoir_tracker_pt/doc/settings2.png Binary files differindex c6cfd1f3..382ed13a 100644 --- a/ftnoir_tracker_pt/doc/settings2.png +++ b/ftnoir_tracker_pt/doc/settings2.png diff --git a/ftnoir_tracker_pt/doc/settings3.png b/ftnoir_tracker_pt/doc/settings3.png Binary files differindex 5922403d..821453d1 100644 --- a/ftnoir_tracker_pt/doc/settings3.png +++ b/ftnoir_tracker_pt/doc/settings3.png diff --git a/ftnoir_tracker_pt/doc/style.css b/ftnoir_tracker_pt/doc/style.css index a8d3e333..0c3d29a6 100644 --- a/ftnoir_tracker_pt/doc/style.css +++ b/ftnoir_tracker_pt/doc/style.css @@ -1,131 +1,131 @@ -body {
- width: 1000px;
- font-size: 13px;
- color: #000000;
- padding: 0;
- margin: 0 auto;
- background: #444444;
- font-family: verdana,arial;
-}
-
-table {
- border-width: 3px;
- border-color: #0000FF;
- border-style: ridge;
- margin-top: 5px;
- background-color: #E0E0FF;
-}
-
-table.blind {
- border: none;
- background-color: #E6E6E6;
-}
-
-fieldset.blind {
- border: none;
-}
-
-h1 { font-size: 160%; }
-h2 { font-size: 140%; }
-h3 { font-size: 115%; }
-
-.indent {
- margin-left: 25px;
-}
-
-p
-{
- margin-left: 10px;
-}
-
-li
-{
- margin: 10px;
-}
-
-
-dl
-{
- /*width: 80%;*/
- border-bottom: 1px solid #999;
-}
-
-dt
-{
- padding-top: 5px;
- font-weight: bold;
- border-top: 1px solid #999;
-}
-
-dd
-{
- padding: 5px;
-}
-
-
-hr {
- color: #688938;
-}
-
-a:link, a:visited {
- color: #0000BF;
-}
-a:hover {
- color: #0000FF;
-}
-
-a.nav {
- position: relative;
- top: -30px;
- display: block;
- visibility: hidden;
-}
-
-#navbar {
- width: 1000px;
- height: 30px;
- background-color:#1a1a1b;
- position: fixed;
- margin: 0 auto;
- padding: 0;
-}
-
-#navbar ul
-{
- list-style-type: none;
- margin: 0 auto;
- padding: 0;
- overflow: hidden;
-}
-
-#navbar li
-{
- margin: 0 auto;
- padding: 5px;
- float:left;
-}
-
-#navbar a:link,a:visited
-{
- display:block;
- width:150px;
- font-weight:bold;
- color:#e85d02;
- text-align:center;
- /*padding:4px;*/
- text-decoration:none;
- /*text-transform:uppercase;*/
-}
-
-#navbar a:hover,a:active
-{
- color:#ffffff;
-}
-
-#content {
- background-color:#ffffff;
- padding: 15px;
- padding-top: 40px;
- padding-right: 40px;
- margin: 0 auto;
-}
+body { + width: 1000px; + font-size: 13px; + color: #000000; + padding: 0; + margin: 0 auto; + background: #444444; + font-family: verdana,arial; +} + +table { + border-width: 3px; + border-color: #0000FF; + border-style: ridge; + margin-top: 5px; + background-color: #E0E0FF; +} + +table.blind { + border: none; + background-color: #E6E6E6; +} + +fieldset.blind { + border: none; +} + +h1 { font-size: 160%; } +h2 { font-size: 140%; } +h3 { font-size: 115%; } + +.indent { + margin-left: 25px; +} + +p +{ + margin-left: 10px; +} + +li +{ + margin: 10px; +} + + +dl +{ + /*width: 80%;*/ + border-bottom: 1px solid #999; +} + +dt +{ + padding-top: 5px; + font-weight: bold; + border-top: 1px solid #999; +} + +dd +{ + padding: 5px; +} + + +hr { + color: #688938; +} + +a:link, a:visited { + color: #0000BF; +} +a:hover { + color: #0000FF; +} + +a.nav { + position: relative; + top: -30px; + display: block; + visibility: hidden; +} + +#navbar { + width: 1000px; + height: 30px; + background-color:#1a1a1b; + position: fixed; + margin: 0 auto; + padding: 0; +} + +#navbar ul +{ + list-style-type: none; + margin: 0 auto; + padding: 0; + overflow: hidden; +} + +#navbar li +{ + margin: 0 auto; + padding: 5px; + float:left; +} + +#navbar a:link,a:visited +{ + display:block; + width:150px; + font-weight:bold; + color:#e85d02; + text-align:center; + /*padding:4px;*/ + text-decoration:none; + /*text-transform:uppercase;*/ +} + +#navbar a:hover,a:active +{ + color:#ffffff; +} + +#content { + background-color:#ffffff; + padding: 15px; + padding-top: 40px; + padding-right: 40px; + margin: 0 auto; +} diff --git a/ftnoir_tracker_pt/frame_observer.cpp b/ftnoir_tracker_pt/frame_observer.cpp index 281f3d57..76dee351 100644 --- a/ftnoir_tracker_pt/frame_observer.cpp +++ b/ftnoir_tracker_pt/frame_observer.cpp @@ -1,18 +1,18 @@ -/* Copyright (c) 2013 Patrick Ruoff
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- */
-
-#include "frame_observer.h"
-
-//-----------------------------------------------------------------------------
-FrameProvider::~FrameProvider()
-{
- QMutexLocker lock(&observer_mutex);
- for (std::set<FrameObserver*>::iterator iter=frame_observers.begin(); iter!=frame_observers.end(); ++iter)
- {
- (*iter)->on_frame_provider_destroy();
- }
-}
+/* Copyright (c) 2013 Patrick Ruoff + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + */ + +#include "frame_observer.h" + +//----------------------------------------------------------------------------- +FrameProvider::~FrameProvider() +{ + QMutexLocker lock(&observer_mutex); + for (std::set<FrameObserver*>::iterator iter=frame_observers.begin(); iter!=frame_observers.end(); ++iter) + { + (*iter)->on_frame_provider_destroy(); + } +} diff --git a/ftnoir_tracker_pt/frame_observer.h b/ftnoir_tracker_pt/frame_observer.h index c3c20259..ca8ffb46 100644 --- a/ftnoir_tracker_pt/frame_observer.h +++ b/ftnoir_tracker_pt/frame_observer.h @@ -1,76 +1,76 @@ -/* Copyright (c) 2013 Patrick Ruoff
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- */
-
-#ifndef FRAME_OBSERVER_H
-#define FRAME_OBSERVER_H
-
-#include <QMutex>
-#include <opencv2/opencv.hpp>
-#ifndef OPENTRACK_API
-# include <boost/shared_ptr.hpp>
-#else
+/* Copyright (c) 2013 Patrick Ruoff + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + */ + +#ifndef FRAME_OBSERVER_H +#define FRAME_OBSERVER_H + +#include <QMutex> +#include <opencv2/opencv.hpp> +#ifndef OPENTRACK_API +# include <boost/shared_ptr.hpp> +#else # include <memory> -#endif
-#include <set>
-
-//-----------------------------------------------------------------------------
-// Forward declarations
-class FrameObserver;
-
-//-----------------------------------------------------------------------------
-// Provides means to copy frame and point information if it has observers
-// Instantiate a FrameObserver to get the information
-class FrameProvider
-{
- friend class FrameObserver;
-public:
- ~FrameProvider();
-
-protected:
- virtual bool get_frame_and_points(cv::Mat& frame, std::shared_ptr< std::vector<cv::Vec2f> >& points) = 0;
-
- bool has_observers() const { QMutexLocker lock(&observer_mutex); return !frame_observers.empty(); }
-
-private:
- mutable QMutex observer_mutex;
- void add_observer(FrameObserver* obs) { QMutexLocker lock(&observer_mutex); frame_observers.insert(obs); }
- void remove_observer(FrameObserver* obs) { QMutexLocker lock(&observer_mutex); frame_observers.erase(obs); }
- std::set<FrameObserver*> frame_observers;
-};
-
-//-----------------------------------------------------------------------------
-// Used to get frame and point information from MutexedFrameProvider
-// Destroy instance if not interested anymore since a living
-// FrameObserver instance causes MutexedFrameProvider to provide the information,
-// potentially reducing its performance
-class FrameObserver
-{
-public:
- FrameObserver(FrameProvider* provider) : provider(provider) {
- provider->add_observer(this);
- }
-
- ~FrameObserver() {
- if (provider) provider->remove_observer(this);
- }
-
- bool get_frame_and_points(cv::Mat& frame, std::shared_ptr< std::vector<cv::Vec2f> >& points) {
- return provider ? provider->get_frame_and_points(frame, points) : false;
- }
-
- void on_frame_provider_destroy() {
- provider = NULL;
- }
-
-protected:
- FrameProvider* provider;
-
-private:
- FrameObserver(const FrameObserver&);
-};
-
-#endif //FRAME_OBSERVER_H
+#endif +#include <set> + +//----------------------------------------------------------------------------- +// Forward declarations +class FrameObserver; + +//----------------------------------------------------------------------------- +// Provides means to copy frame and point information if it has observers +// Instantiate a FrameObserver to get the information +class FrameProvider +{ + friend class FrameObserver; +public: + ~FrameProvider(); + +protected: + virtual bool get_frame_and_points(cv::Mat& frame, std::shared_ptr< std::vector<cv::Vec2f> >& points) = 0; + + bool has_observers() const { QMutexLocker lock(&observer_mutex); return !frame_observers.empty(); } + +private: + mutable QMutex observer_mutex; + void add_observer(FrameObserver* obs) { QMutexLocker lock(&observer_mutex); frame_observers.insert(obs); } + void remove_observer(FrameObserver* obs) { QMutexLocker lock(&observer_mutex); frame_observers.erase(obs); } + std::set<FrameObserver*> frame_observers; +}; + +//----------------------------------------------------------------------------- +// Used to get frame and point information from MutexedFrameProvider +// Destroy instance if not interested anymore since a living +// FrameObserver instance causes MutexedFrameProvider to provide the information, +// potentially reducing its performance +class FrameObserver +{ +public: + FrameObserver(FrameProvider* provider) : provider(provider) { + provider->add_observer(this); + } + + ~FrameObserver() { + if (provider) provider->remove_observer(this); + } + + bool get_frame_and_points(cv::Mat& frame, std::shared_ptr< std::vector<cv::Vec2f> >& points) { + return provider ? provider->get_frame_and_points(frame, points) : false; + } + + void on_frame_provider_destroy() { + provider = NULL; + } + +protected: + FrameProvider* provider; + +private: + FrameObserver(const FrameObserver&); +}; + +#endif //FRAME_OBSERVER_H diff --git a/ftnoir_tracker_pt/ftnoir_tracker_pt.cpp b/ftnoir_tracker_pt/ftnoir_tracker_pt.cpp index 219c8990..3fa6910d 100644 --- a/ftnoir_tracker_pt/ftnoir_tracker_pt.cpp +++ b/ftnoir_tracker_pt/ftnoir_tracker_pt.cpp @@ -1,264 +1,264 @@ -/* Copyright (c) 2012 Patrick Ruoff
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- */
-
-#include "ftnoir_tracker_pt.h"
-#include <QHBoxLayout>
-#include <cmath>
-#include <QDebug>
-#include <QFile>
-#include <QCoreApplication>
-
-using namespace std;
-using namespace cv;
-
-//#define PT_PERF_LOG //log performance
-
-const float rad2deg = 180.0/3.14159265;
-const float deg2rad = 1.0/rad2deg;
-
-//-----------------------------------------------------------------------------
-Tracker::Tracker()
- : mutex(QMutex::Recursive),
- commands(0),
- video_widget(NULL),
- video_frame(NULL),
- tracking_valid(false),
- new_settings(nullptr)
-
-{
- qDebug()<<"Tracker::Tracker";
-}
-
-Tracker::~Tracker()
-{
- qDebug()<<"Tracker::~Tracker";
- // terminate tracker thread
- set_command(ABORT);
- wait();
- s.video_widget = false;
- delete video_widget;
- video_widget = NULL;
- if (video_frame->layout()) delete video_frame->layout();
-}
-
-void Tracker::set_command(Command command)
-{
- //QMutexLocker lock(&mutex);
- commands |= command;
-}
-
-void Tracker::reset_command(Command command)
-{
- //QMutexLocker lock(&mutex);
- commands &= ~command;
-}
-
-void Tracker::run()
-{
- qDebug()<<"Tracker:: Thread started";
-
-#ifdef PT_PERF_LOG
- QFile log_file(QCoreApplication::applicationDirPath() + "/PointTrackerPerformance.txt");
- if (!log_file.open(QIODevice::WriteOnly | QIODevice::Text)) return;
- QTextStream log_stream(&log_file);
-#endif
-
- time.start();
- double dt;
- bool new_frame;
- forever
- {
- if (commands & ABORT) break;
- if (commands & PAUSE) continue;
- commands = 0;
- apply_inner();
- dt = time.start() / 1000000000.;
-
- new_frame = camera.get_frame(dt, &frame);
-
- if (new_frame && !frame.empty())
- {
- QMutexLocker lock(&mutex);
-
- frame = frame_rotation.rotate_frame(frame);
- const std::vector<cv::Vec2f>& points = point_extractor.extract_points(frame, dt, true);
- for (auto p : points)
- {
- auto p2 = cv::Point(p[0] * frame.cols + frame.cols/2, -p[1] * frame.cols + frame.rows/2);
- cv::Scalar color(0, 255, 0);
- cv::line(frame,
- cv::Point(p2.x - 20, p2.y),
- cv::Point(p2.x + 20, p2.y),
- color,
- 4);
- cv::line(frame,
- cv::Point(p2.x, p2.y - 20),
- cv::Point(p2.x, p2.y + 20),
- color,
- 4);
- }
- tracking_valid = point_tracker.track(points, camera.get_info().f, dt);
- video_widget->update_image(frame);
- }
-#ifdef PT_PERF_LOG
- log_stream<<"dt: "<<dt;
- if (!frame.empty()) log_stream<<" fps: "<<camera.get_info().fps;
- log_stream<<"\n";
-#endif
- }
-
- qDebug()<<"Tracker:: Thread stopping";
-}
-void Tracker::apply(settings& s)
-{
- // caller guarantees object lifetime
- new_settings = &s;
-}
-
-void Tracker::apply_inner()
-{
- settings* tmp = new_settings.exchange(nullptr);
- if (tmp == nullptr)
- return;
- auto& s = *tmp;
- qDebug()<<"Tracker:: Applying settings";
- camera.set_device_index(s.cam_index);
- camera.set_res(s.cam_res_x, s.cam_res_y);
- camera.set_fps(s.cam_fps);
- camera.set_f(s.cam_f);
- frame_rotation.rotation = static_cast<RotationType>(static_cast<int>(s.cam_roll));
- point_extractor.threshold_val = s.threshold;
- point_extractor.threshold_secondary_val = s.threshold_secondary;
- point_extractor.min_size = s.min_point_size;
- point_extractor.max_size = s.max_point_size;
- {
- cv::Vec3f M01(s.m01_x, s.m01_y, s.m01_z);
- cv::Vec3f M02(s.m02_x, s.m02_y, s.m02_z);
- point_tracker.point_model = std::shared_ptr<PointModel>(new PointModel(M01, M02));
- }
- point_tracker.dynamic_pose_resolution = s.dyn_pose_res;
- point_tracker.dt_reset = s.reset_time / 1000.0;
- t_MH = cv::Vec3f(s.t_MH_x, s.t_MH_y, s.t_MH_z);
- R_GC = Matx33f( cos(deg2rad*s.cam_yaw), 0, sin(deg2rad*s.cam_yaw),
- 0, 1, 0,
- -sin(deg2rad*s.cam_yaw), 0, cos(deg2rad*s.cam_yaw));
- R_GC = R_GC * Matx33f( 1, 0, 0,
- 0, cos(deg2rad*s.cam_pitch), sin(deg2rad*s.cam_pitch),
- 0, -sin(deg2rad*s.cam_pitch), cos(deg2rad*s.cam_pitch));
-
- FrameTrafo X_MH(Matx33f::eye(), t_MH);
- X_GH_0 = R_GC * X_MH;
-
- qDebug()<<"Tracker::apply ends";
-}
-
-void Tracker::reset()
-{
- QMutexLocker lock(&mutex);
- point_tracker.reset();
-}
-
-void Tracker::center()
-{
- point_tracker.reset(); // we also do a reset here since there is no reset shortkey yet
- QMutexLocker lock(&mutex);
- FrameTrafo X_CM_0 = point_tracker.get_pose();
- FrameTrafo X_MH(Matx33f::eye(), t_MH);
- X_GH_0 = R_GC * X_CM_0 * X_MH;
-}
-
-bool Tracker::get_frame_and_points(cv::Mat& frame_copy, std::shared_ptr< std::vector<Vec2f> >& points)
-{
- QMutexLocker lock(&mutex);
- if (frame.empty()) return false;
-
- // copy the frame and points from the tracker thread
- frame_copy = frame.clone();
- points = std::shared_ptr< vector<Vec2f> >(new vector<Vec2f>(point_extractor.get_points()));
- return true;
-}
-
-void Tracker::refreshVideo()
-{
- if (video_widget) video_widget->update_frame_and_points();
-}
-
-void Tracker::StartTracker(QFrame *parent_window)
-{
- this->video_frame = parent_window;
- video_frame->setAttribute(Qt::WA_NativeWindow);
- video_frame->show();
- video_widget = new PTVideoWidget(video_frame, this);
- QHBoxLayout* video_layout = new QHBoxLayout(parent_window);
- video_layout->setContentsMargins(0, 0, 0, 0);
- video_layout->addWidget(video_widget);
- video_frame->setLayout(video_layout);
- video_widget->resize(video_frame->width(), video_frame->height());
- camera.start();
- apply(s);
- start();
- reset_command(PAUSE);
-}
-
-#ifndef OPENTRACK_API
-void Tracker::StopTracker(bool exit)
-{
- set_command(PAUSE);
-}
-#endif
-
-#ifdef OPENTRACK_API
-#define THeadPoseData double
-#endif
-
-void Tracker::GetHeadPoseData(THeadPoseData *data)
-{
- {
- QMutexLocker lock(&mutex);
-
- if (!tracking_valid) return;
-
- FrameTrafo X_CM = point_tracker.get_pose();
- FrameTrafo X_MH(Matx33f::eye(), t_MH);
- FrameTrafo X_GH = R_GC * X_CM * X_MH;
- Matx33f R = X_GH.R * X_GH_0.R.t();
- Vec3f t = X_GH.t - X_GH_0.t;
-
- // get translation(s)
- data[TX] = t[0] / 10.0; // convert to cm
- data[TY] = t[1] / 10.0;
- data[TZ] = t[2] / 10.0;
-
- // translate rotation matrix from opengl (G) to roll-pitch-yaw (E) frame
- // -z -> x, y -> z, x -> -y
- Matx33f R_EG( 0, 0,-1,
- -1, 0, 0,
- 0, 1, 0);
- R = R_EG * R * R_EG.t();
-
- // extract rotation angles
- float alpha, beta, gamma;
- beta = atan2( -R(2,0), sqrt(R(2,1)*R(2,1) + R(2,2)*R(2,2)) );
- alpha = atan2( R(1,0), R(0,0));
- gamma = atan2( R(2,1), R(2,2));
-
- data[Yaw] = rad2deg * alpha;
- data[Pitch] = - rad2deg * beta; // FTNoIR expects a minus here
- data[Roll] = rad2deg * gamma;
- }
-}
-
-//-----------------------------------------------------------------------------
-#ifdef OPENTRACK_API
-extern "C" OPENTRACK_EXPORT ITracker* CALLING_CONVENTION GetConstructor()
-#else
-#pragma comment(linker, "/export:GetTracker=_GetTracker@0")
-OPENTRACK_EXPORT ITrackerPtr __stdcall GetTracker()
-#endif
-{
- return new Tracker;
-}
+/* Copyright (c) 2012 Patrick Ruoff + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + */ + +#include "ftnoir_tracker_pt.h" +#include <QHBoxLayout> +#include <cmath> +#include <QDebug> +#include <QFile> +#include <QCoreApplication> + +using namespace std; +using namespace cv; + +//#define PT_PERF_LOG //log performance + +const float rad2deg = 180.0/3.14159265; +const float deg2rad = 1.0/rad2deg; + +//----------------------------------------------------------------------------- +Tracker::Tracker() + : mutex(QMutex::Recursive), + commands(0), + video_widget(NULL), + video_frame(NULL), + tracking_valid(false), + new_settings(nullptr) + +{ + qDebug()<<"Tracker::Tracker"; +} + +Tracker::~Tracker() +{ + qDebug()<<"Tracker::~Tracker"; + // terminate tracker thread + set_command(ABORT); + wait(); + s.video_widget = false; + delete video_widget; + video_widget = NULL; + if (video_frame->layout()) delete video_frame->layout(); +} + +void Tracker::set_command(Command command) +{ + //QMutexLocker lock(&mutex); + commands |= command; +} + +void Tracker::reset_command(Command command) +{ + //QMutexLocker lock(&mutex); + commands &= ~command; +} + +void Tracker::run() +{ + qDebug()<<"Tracker:: Thread started"; + +#ifdef PT_PERF_LOG + QFile log_file(QCoreApplication::applicationDirPath() + "/PointTrackerPerformance.txt"); + if (!log_file.open(QIODevice::WriteOnly | QIODevice::Text)) return; + QTextStream log_stream(&log_file); +#endif + + time.start(); + double dt; + bool new_frame; + forever + { + if (commands & ABORT) break; + if (commands & PAUSE) continue; + commands = 0; + apply_inner(); + dt = time.start() / 1000000000.; + + new_frame = camera.get_frame(dt, &frame); + + if (new_frame && !frame.empty()) + { + QMutexLocker lock(&mutex); + + frame = frame_rotation.rotate_frame(frame); + const std::vector<cv::Vec2f>& points = point_extractor.extract_points(frame, dt, true); + for (auto p : points) + { + auto p2 = cv::Point(p[0] * frame.cols + frame.cols/2, -p[1] * frame.cols + frame.rows/2); + cv::Scalar color(0, 255, 0); + cv::line(frame, + cv::Point(p2.x - 20, p2.y), + cv::Point(p2.x + 20, p2.y), + color, + 4); + cv::line(frame, + cv::Point(p2.x, p2.y - 20), + cv::Point(p2.x, p2.y + 20), + color, + 4); + } + tracking_valid = point_tracker.track(points, camera.get_info().f, dt); + video_widget->update_image(frame); + } +#ifdef PT_PERF_LOG + log_stream<<"dt: "<<dt; + if (!frame.empty()) log_stream<<" fps: "<<camera.get_info().fps; + log_stream<<"\n"; +#endif + } + + qDebug()<<"Tracker:: Thread stopping"; +} +void Tracker::apply(settings& s) +{ + // caller guarantees object lifetime + new_settings = &s; +} + +void Tracker::apply_inner() +{ + settings* tmp = new_settings.exchange(nullptr); + if (tmp == nullptr) + return; + auto& s = *tmp; + qDebug()<<"Tracker:: Applying settings"; + camera.set_device_index(s.cam_index); + camera.set_res(s.cam_res_x, s.cam_res_y); + camera.set_fps(s.cam_fps); + camera.set_f(s.cam_f); + frame_rotation.rotation = static_cast<RotationType>(static_cast<int>(s.cam_roll)); + point_extractor.threshold_val = s.threshold; + point_extractor.threshold_secondary_val = s.threshold_secondary; + point_extractor.min_size = s.min_point_size; + point_extractor.max_size = s.max_point_size; + { + cv::Vec3f M01(s.m01_x, s.m01_y, s.m01_z); + cv::Vec3f M02(s.m02_x, s.m02_y, s.m02_z); + point_tracker.point_model = std::shared_ptr<PointModel>(new PointModel(M01, M02)); + } + point_tracker.dynamic_pose_resolution = s.dyn_pose_res; + point_tracker.dt_reset = s.reset_time / 1000.0; + t_MH = cv::Vec3f(s.t_MH_x, s.t_MH_y, s.t_MH_z); + R_GC = Matx33f( cos(deg2rad*s.cam_yaw), 0, sin(deg2rad*s.cam_yaw), + 0, 1, 0, + -sin(deg2rad*s.cam_yaw), 0, cos(deg2rad*s.cam_yaw)); + R_GC = R_GC * Matx33f( 1, 0, 0, + 0, cos(deg2rad*s.cam_pitch), sin(deg2rad*s.cam_pitch), + 0, -sin(deg2rad*s.cam_pitch), cos(deg2rad*s.cam_pitch)); + + FrameTrafo X_MH(Matx33f::eye(), t_MH); + X_GH_0 = R_GC * X_MH; + + qDebug()<<"Tracker::apply ends"; +} + +void Tracker::reset() +{ + QMutexLocker lock(&mutex); + point_tracker.reset(); +} + +void Tracker::center() +{ + point_tracker.reset(); // we also do a reset here since there is no reset shortkey yet + QMutexLocker lock(&mutex); + FrameTrafo X_CM_0 = point_tracker.get_pose(); + FrameTrafo X_MH(Matx33f::eye(), t_MH); + X_GH_0 = R_GC * X_CM_0 * X_MH; +} + +bool Tracker::get_frame_and_points(cv::Mat& frame_copy, std::shared_ptr< std::vector<Vec2f> >& points) +{ + QMutexLocker lock(&mutex); + if (frame.empty()) return false; + + // copy the frame and points from the tracker thread + frame_copy = frame.clone(); + points = std::shared_ptr< vector<Vec2f> >(new vector<Vec2f>(point_extractor.get_points())); + return true; +} + +void Tracker::refreshVideo() +{ + if (video_widget) video_widget->update_frame_and_points(); +} + +void Tracker::StartTracker(QFrame *parent_window) +{ + this->video_frame = parent_window; + video_frame->setAttribute(Qt::WA_NativeWindow); + video_frame->show(); + video_widget = new PTVideoWidget(video_frame, this); + QHBoxLayout* video_layout = new QHBoxLayout(parent_window); + video_layout->setContentsMargins(0, 0, 0, 0); + video_layout->addWidget(video_widget); + video_frame->setLayout(video_layout); + video_widget->resize(video_frame->width(), video_frame->height()); + camera.start(); + apply(s); + start(); + reset_command(PAUSE); +} + +#ifndef OPENTRACK_API +void Tracker::StopTracker(bool exit) +{ + set_command(PAUSE); +} +#endif + +#ifdef OPENTRACK_API +#define THeadPoseData double +#endif + +void Tracker::GetHeadPoseData(THeadPoseData *data) +{ + { + QMutexLocker lock(&mutex); + + if (!tracking_valid) return; + + FrameTrafo X_CM = point_tracker.get_pose(); + FrameTrafo X_MH(Matx33f::eye(), t_MH); + FrameTrafo X_GH = R_GC * X_CM * X_MH; + Matx33f R = X_GH.R * X_GH_0.R.t(); + Vec3f t = X_GH.t - X_GH_0.t; + + // get translation(s) + data[TX] = t[0] / 10.0; // convert to cm + data[TY] = t[1] / 10.0; + data[TZ] = t[2] / 10.0; + + // translate rotation matrix from opengl (G) to roll-pitch-yaw (E) frame + // -z -> x, y -> z, x -> -y + Matx33f R_EG( 0, 0,-1, + -1, 0, 0, + 0, 1, 0); + R = R_EG * R * R_EG.t(); + + // extract rotation angles + float alpha, beta, gamma; + beta = atan2( -R(2,0), sqrt(R(2,1)*R(2,1) + R(2,2)*R(2,2)) ); + alpha = atan2( R(1,0), R(0,0)); + gamma = atan2( R(2,1), R(2,2)); + + data[Yaw] = rad2deg * alpha; + data[Pitch] = - rad2deg * beta; // FTNoIR expects a minus here + data[Roll] = rad2deg * gamma; + } +} + +//----------------------------------------------------------------------------- +#ifdef OPENTRACK_API +extern "C" OPENTRACK_EXPORT ITracker* CALLING_CONVENTION GetConstructor() +#else +#pragma comment(linker, "/export:GetTracker=_GetTracker@0") +OPENTRACK_EXPORT ITrackerPtr __stdcall GetTracker() +#endif +{ + return new Tracker; +} diff --git a/ftnoir_tracker_pt/ftnoir_tracker_pt.h b/ftnoir_tracker_pt/ftnoir_tracker_pt.h index 63b8353e..3d9a83fd 100644 --- a/ftnoir_tracker_pt/ftnoir_tracker_pt.h +++ b/ftnoir_tracker_pt/ftnoir_tracker_pt.h @@ -1,94 +1,94 @@ -/* Copyright (c) 2012 Patrick Ruoff
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- */
-
-#ifndef FTNOIR_TRACKER_PT_H
-#define FTNOIR_TRACKER_PT_H
-
-#ifdef OPENTRACK_API
-# include "facetracknoir/plugin-api.hpp"
-#endif
-#include "ftnoir_tracker_pt_settings.h"
-#include "frame_observer.h"
-#include "camera.h"
-#include "point_extractor.h"
-#include "point_tracker.h"
-#include "pt_video_widget.h"
-#include "facetracknoir/timer.hpp"
-
-#include <QThread>
-#include <QMutex>
-#include <QMutexLocker>
-#include <QTime>
-#include <opencv2/opencv.hpp>
-#include <atomic>
-#ifndef OPENTRACK_API
-# include <boost/shared_ptr.hpp>
-#else
+/* Copyright (c) 2012 Patrick Ruoff + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + */ + +#ifndef FTNOIR_TRACKER_PT_H +#define FTNOIR_TRACKER_PT_H + +#ifdef OPENTRACK_API +# include "facetracknoir/plugin-api.hpp" +#endif +#include "ftnoir_tracker_pt_settings.h" +#include "frame_observer.h" +#include "camera.h" +#include "point_extractor.h" +#include "point_tracker.h" +#include "pt_video_widget.h" +#include "facetracknoir/timer.hpp" + +#include <QThread> +#include <QMutex> +#include <QMutexLocker> +#include <QTime> +#include <opencv2/opencv.hpp> +#include <atomic> +#ifndef OPENTRACK_API +# include <boost/shared_ptr.hpp> +#else # include <memory> -#endif
-#include <vector>
-
-//-----------------------------------------------------------------------------
-// Constantly processes the tracking chain in a separate thread
-class Tracker : public ITracker, QThread, public FrameProvider
-{
-public:
- Tracker();
- virtual ~Tracker();
- virtual void StartTracker(QFrame* parent_window);
- virtual void GetHeadPoseData(double* data);
- virtual void refreshVideo();
-
- void apply(settings& s);
- void apply_inner();
- void center();
- void reset(); // reset the trackers internal state variables
- void run();
-
- void get_pose(FrameTrafo* X_CM) { QMutexLocker lock(&mutex); *X_CM = point_tracker.get_pose(); }
- int get_n_points() { QMutexLocker lock(&mutex); return point_extractor.get_points().size(); }
- void get_cam_info(CamInfo* info) { QMutexLocker lock(&mutex); *info = camera.get_info(); }
-
-protected:
- // --- MutexedFrameProvider interface ---
- virtual bool get_frame_and_points(cv::Mat& frame, std::shared_ptr< std::vector<cv::Vec2f> >& points);
-
- // --- thread ---
- QMutex mutex;
- // thread commands
- enum Command {
- ABORT = 1<<0,
- PAUSE = 1<<1
- };
- void set_command(Command command);
- void reset_command(Command command);
- volatile int commands;
-
- CVCamera camera;
- FrameRotation frame_rotation;
- PointExtractor point_extractor;
- PointTracker point_tracker;
-
- FrameTrafo X_GH_0; // for centering
- cv::Vec3f t_MH; // translation from model frame to head frame
- cv::Matx33f R_GC; // rotation from opengl reference frame to camera frame
-
- // --- ui ---
- cv::Mat frame; // the output frame for display
-
- PTVideoWidget* video_widget;
- QFrame* video_frame;
- bool tracking_valid;
-
- settings s;
- std::atomic<settings*> new_settings;
- Timer time;
-};
-
-#undef VideoWidget
-
-#endif // FTNOIR_TRACKER_PT_H
+#endif +#include <vector> + +//----------------------------------------------------------------------------- +// Constantly processes the tracking chain in a separate thread +class Tracker : public ITracker, QThread, public FrameProvider +{ +public: + Tracker(); + virtual ~Tracker(); + virtual void StartTracker(QFrame* parent_window); + virtual void GetHeadPoseData(double* data); + virtual void refreshVideo(); + + void apply(settings& s); + void apply_inner(); + void center(); + void reset(); // reset the trackers internal state variables + void run(); + + void get_pose(FrameTrafo* X_CM) { QMutexLocker lock(&mutex); *X_CM = point_tracker.get_pose(); } + int get_n_points() { QMutexLocker lock(&mutex); return point_extractor.get_points().size(); } + void get_cam_info(CamInfo* info) { QMutexLocker lock(&mutex); *info = camera.get_info(); } + +protected: + // --- MutexedFrameProvider interface --- + virtual bool get_frame_and_points(cv::Mat& frame, std::shared_ptr< std::vector<cv::Vec2f> >& points); + + // --- thread --- + QMutex mutex; + // thread commands + enum Command { + ABORT = 1<<0, + PAUSE = 1<<1 + }; + void set_command(Command command); + void reset_command(Command command); + volatile int commands; + + CVCamera camera; + FrameRotation frame_rotation; + PointExtractor point_extractor; + PointTracker point_tracker; + + FrameTrafo X_GH_0; // for centering + cv::Vec3f t_MH; // translation from model frame to head frame + cv::Matx33f R_GC; // rotation from opengl reference frame to camera frame + + // --- ui --- + cv::Mat frame; // the output frame for display + + PTVideoWidget* video_widget; + QFrame* video_frame; + bool tracking_valid; + + settings s; + std::atomic<settings*> new_settings; + Timer time; +}; + +#undef VideoWidget + +#endif // FTNOIR_TRACKER_PT_H diff --git a/ftnoir_tracker_pt/ftnoir_tracker_pt_dialog.cpp b/ftnoir_tracker_pt/ftnoir_tracker_pt_dialog.cpp index ae84ce8c..e037a099 100644 --- a/ftnoir_tracker_pt/ftnoir_tracker_pt_dialog.cpp +++ b/ftnoir_tracker_pt/ftnoir_tracker_pt_dialog.cpp @@ -1,314 +1,314 @@ -/* Copyright (c) 2012 Patrick Ruoff
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- */
-
-#include "ftnoir_tracker_pt_dialog.h"
-
-#include <QMessageBox>
-#include <QDebug>
-#include <opencv2/opencv.hpp>
-#ifndef OPENTRACK_API
-# include <boost/shared_ptr.hpp>
-#else
-# include <memory>
-#endif
-#include <vector>
-
-using namespace std;
-
-//-----------------------------------------------------------------------------
-TrackerDialog::TrackerDialog()
- : tracker(NULL),
- video_widget_dialog(NULL),
- timer(this),
- trans_calib_running(false)
-{
- qDebug()<<"TrackerDialog::TrackerDialog";
- setAttribute(Qt::WA_DeleteOnClose, false);
-
- ui.setupUi( this );
-
- vector<string> device_names;
- get_camera_device_names(device_names);
- for (vector<string>::iterator iter = device_names.begin(); iter != device_names.end(); ++iter)
- {
- ui.camdevice_combo->addItem(iter->c_str());
- }
-
- ui.camroll_combo->addItem("-90");
- ui.camroll_combo->addItem("0");
- ui.camroll_combo->addItem("90");
-
- tie_setting(s.dyn_pose_res, ui.dynpose_check);
- tie_setting(s.reset_time, ui.reset_spin);
-
- tie_setting(s.cam_index, ui.camdevice_combo);
- tie_setting(s.cam_f, ui.f_dspin);
- 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.cam_roll, ui.camroll_combo);
- tie_setting(s.cam_pitch, ui.campitch_spin);
- tie_setting(s.cam_yaw, ui.camyaw_spin);
-
- tie_setting(s.threshold_secondary, ui.threshold_secondary_slider);
- tie_setting(s.threshold, ui.threshold_slider);
-
- tie_setting(s.min_point_size, ui.mindiam_spin);
- tie_setting(s.max_point_size, ui.maxdiam_spin);
-
- tie_setting(s.clip_by, ui.clip_bheight_spin);
- tie_setting(s.clip_bz, ui.clip_blength_spin);
- tie_setting(s.clip_ty, ui.clip_theight_spin);
- tie_setting(s.clip_tz, ui.clip_tlength_spin);
-
- tie_setting(s.cap_x, ui.cap_width_spin);
- tie_setting(s.cap_y, ui.cap_height_spin);
- tie_setting(s.cap_z, ui.cap_length_spin);
-
- tie_setting(s.m01_x, ui.m1x_spin);
- tie_setting(s.m01_y, ui.m1y_spin);
- tie_setting(s.m01_z, ui.m1z_spin);
-
- tie_setting(s.m02_x, ui.m2x_spin);
- tie_setting(s.m02_y, ui.m2y_spin);
- tie_setting(s.m02_z, ui.m2z_spin);
-
- tie_setting(s.t_MH_x, ui.tx_spin);
- tie_setting(s.t_MH_y, ui.ty_spin);
- tie_setting(s.t_MH_z, ui.tz_spin);
-
- connect( ui.tcalib_button,SIGNAL(toggled(bool)), this,SLOT(startstop_trans_calib(bool)) );
- connect(ui.reset_button, SIGNAL(clicked()), this, SLOT(doReset()));
-
- connect(ui.ok_button, SIGNAL(clicked()), this, SLOT(doOK()));
- connect(ui.cancel_button, SIGNAL(clicked()), this, SLOT(doCancel()));
- connect(ui.btnApply, SIGNAL(clicked()), this, SLOT(doApply()));
-
- ui.model_tabs->setCurrentIndex(s.active_model_panel);
-
- connect(ui.model_tabs, SIGNAL(currentChanged(int)), this, SLOT(set_model(int)));
- connect(&timer,SIGNAL(timeout()), this,SLOT(poll_tracker_info()));
- timer.start(100);
-
- connect(s.b.get(), SIGNAL(bundleChanged()), this, SLOT(do_apply_without_saving()));
-}
-
-void TrackerDialog::set_model_clip()
-{
- s.m01_x = 0;
- s.m01_y = static_cast<double>(s.clip_ty);
- s.m01_z = -static_cast<double>(s.clip_tz);
- s.m02_x = 0;
- s.m02_y = -static_cast<double>(s.clip_by);
- s.m02_z = -static_cast<double>(s.clip_bz);
-
- settings_changed();
-}
-
-void TrackerDialog::set_model_cap()
-{
- s.m01_x = -static_cast<double>(s.cap_x);
- s.m01_y = -static_cast<double>(s.cap_y);
- s.m01_z = -static_cast<double>(s.cap_z);
- s.m02_x = static_cast<double>(s.cap_x);
- s.m02_y = -static_cast<double>(s.cap_y);
- s.m02_z = -static_cast<double>(s.cap_z);
-
- settings_changed();
-}
-
-void TrackerDialog::set_model_custom()
-{
- settings_changed();
-}
-
-void TrackerDialog::set_model(int val)
-{
- s.active_model_panel = val;
-}
-
-void TrackerDialog::startstop_trans_calib(bool start)
-{
- if (start)
- {
- qDebug()<<"TrackerDialog:: Starting translation calibration";
- trans_calib.reset();
- trans_calib_running = true;
- }
- else
- {
- qDebug()<<"TrackerDialog:: Stoppping translation calibration";
- trans_calib_running = false;
- {
- auto tmp = trans_calib.get_estimate();
- s.t_MH_x = tmp[0];
- s.t_MH_y = tmp[1];
- s.t_MH_z = tmp[2];
- }
- settings_changed();
- }
-}
-
-void TrackerDialog::trans_calib_step()
-{
- if (tracker)
- {
- FrameTrafo X_CM;
- tracker->get_pose(&X_CM);
- trans_calib.update(X_CM.R, X_CM.t);
- cv::Vec3f t_MH = trans_calib.get_estimate();
- s.t_MH_x = t_MH[0];
- s.t_MH_y = t_MH[1];
- s.t_MH_z = t_MH[2];
- }
-}
-
-void TrackerDialog::settings_changed()
-{
- if (tracker) tracker->apply(s);
-}
-
-void TrackerDialog::doCenter()
-{
- if (tracker) tracker->center();
-}
-
-void TrackerDialog::doReset()
-{
- if (tracker) tracker->reset();
-}
-
-void TrackerDialog::save()
-{
- do_apply_without_saving();
- s.b->save();
-}
-
-void TrackerDialog::doOK()
-{
- save();
- close();
-}
-
-void TrackerDialog::do_apply_without_saving()
-{
- switch (s.active_model_panel) {
- default:
- case 0:
- set_model_clip();
- break;
- case 1:
- set_model_cap();
- break;
- case 2:
- set_model_custom();
- break;
- }
- if (tracker) tracker->apply(s);
-}
-
-void TrackerDialog::doApply()
-{
- save();
-}
-
-void TrackerDialog::doCancel()
-{
- s.b->revert();
- close();
-}
-
-void TrackerDialog::widget_destroyed(QObject* obj)
-{
- if (obj == video_widget_dialog) {
- // widget was / will be already deleted by Qt
- destroy_video_widget(false);
- }
-}
-
-void TrackerDialog::create_video_widget()
-{
- // this should not happen but better be sure
- if (video_widget_dialog) destroy_video_widget();
- if (!tracker) return;
-
- video_widget_dialog = new VideoWidgetDialog(this, tracker);
- video_widget_dialog->setAttribute( Qt::WA_DeleteOnClose );
- connect( video_widget_dialog, SIGNAL(destroyed(QObject*)), this, SLOT(widget_destroyed(QObject*)) );
- video_widget_dialog->show();
-}
-
-void TrackerDialog::destroy_video_widget(bool do_delete /*= true*/)
-{
- if (video_widget_dialog) {
- if (do_delete) delete video_widget_dialog;
- video_widget_dialog = NULL;
- }
-}
-
-void TrackerDialog::poll_tracker_info()
-{
- if (tracker)
- {
- QString to_print;
-
- // display caminfo
- CamInfo info;
- tracker->get_cam_info(&info);
- to_print = QString::number(info.res_x)+"x"+QString::number(info.res_y)+" @ "+QString::number(info.fps)+" FPS";
- ui.caminfo_label->setText(to_print);
-
- // display pointinfo
- int n_points = tracker->get_n_points();
- to_print = QString::number(n_points);
- if (n_points == 3)
- to_print += " OK!";
- else
- to_print += " BAD!";
- ui.pointinfo_label->setText(to_print);
-
- // update calibration
- if (trans_calib_running) trans_calib_step();
-
- // update videowidget
- if (video_widget_dialog) {
- video_widget_dialog->get_video_widget()->update_frame_and_points();
- }
- }
- else
- {
- QString to_print = "Tracker offline";
- ui.caminfo_label->setText(to_print);
- ui.pointinfo_label->setText(to_print);
- }
-}
-
-void TrackerDialog::registerTracker(ITracker *t)
-{
- qDebug()<<"TrackerDialog:: Tracker registered";
- tracker = static_cast<Tracker*>(t);
- if (isVisible() & s.b->modifiedp())
- tracker->apply(s);
- ui.tcalib_button->setEnabled(true);
- //ui.center_button->setEnabled(true);
- ui.reset_button->setEnabled(true);
-}
-
-void TrackerDialog::unRegisterTracker()
-{
- qDebug()<<"TrackerDialog:: Tracker un-registered";
- tracker = NULL;
- destroy_video_widget();
- ui.tcalib_button->setEnabled(false);
- //ui.center_button->setEnabled(false);
- ui.reset_button->setEnabled(false);
-}
-
-extern "C" OPENTRACK_EXPORT ITrackerDialog* CALLING_CONVENTION GetDialog( )
-{
- return new TrackerDialog;
-}
+/* Copyright (c) 2012 Patrick Ruoff + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + */ + +#include "ftnoir_tracker_pt_dialog.h" + +#include <QMessageBox> +#include <QDebug> +#include <opencv2/opencv.hpp> +#ifndef OPENTRACK_API +# include <boost/shared_ptr.hpp> +#else +# include <memory> +#endif +#include <vector> + +using namespace std; + +//----------------------------------------------------------------------------- +TrackerDialog::TrackerDialog() + : tracker(NULL), + video_widget_dialog(NULL), + timer(this), + trans_calib_running(false) +{ + qDebug()<<"TrackerDialog::TrackerDialog"; + setAttribute(Qt::WA_DeleteOnClose, false); + + ui.setupUi( this ); + + vector<string> device_names; + get_camera_device_names(device_names); + for (vector<string>::iterator iter = device_names.begin(); iter != device_names.end(); ++iter) + { + ui.camdevice_combo->addItem(iter->c_str()); + } + + ui.camroll_combo->addItem("-90"); + ui.camroll_combo->addItem("0"); + ui.camroll_combo->addItem("90"); + + tie_setting(s.dyn_pose_res, ui.dynpose_check); + tie_setting(s.reset_time, ui.reset_spin); + + tie_setting(s.cam_index, ui.camdevice_combo); + tie_setting(s.cam_f, ui.f_dspin); + 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.cam_roll, ui.camroll_combo); + tie_setting(s.cam_pitch, ui.campitch_spin); + tie_setting(s.cam_yaw, ui.camyaw_spin); + + tie_setting(s.threshold_secondary, ui.threshold_secondary_slider); + tie_setting(s.threshold, ui.threshold_slider); + + tie_setting(s.min_point_size, ui.mindiam_spin); + tie_setting(s.max_point_size, ui.maxdiam_spin); + + tie_setting(s.clip_by, ui.clip_bheight_spin); + tie_setting(s.clip_bz, ui.clip_blength_spin); + tie_setting(s.clip_ty, ui.clip_theight_spin); + tie_setting(s.clip_tz, ui.clip_tlength_spin); + + tie_setting(s.cap_x, ui.cap_width_spin); + tie_setting(s.cap_y, ui.cap_height_spin); + tie_setting(s.cap_z, ui.cap_length_spin); + + tie_setting(s.m01_x, ui.m1x_spin); + tie_setting(s.m01_y, ui.m1y_spin); + tie_setting(s.m01_z, ui.m1z_spin); + + tie_setting(s.m02_x, ui.m2x_spin); + tie_setting(s.m02_y, ui.m2y_spin); + tie_setting(s.m02_z, ui.m2z_spin); + + tie_setting(s.t_MH_x, ui.tx_spin); + tie_setting(s.t_MH_y, ui.ty_spin); + tie_setting(s.t_MH_z, ui.tz_spin); + + connect( ui.tcalib_button,SIGNAL(toggled(bool)), this,SLOT(startstop_trans_calib(bool)) ); + connect(ui.reset_button, SIGNAL(clicked()), this, SLOT(doReset())); + + connect(ui.ok_button, SIGNAL(clicked()), this, SLOT(doOK())); + connect(ui.cancel_button, SIGNAL(clicked()), this, SLOT(doCancel())); + connect(ui.btnApply, SIGNAL(clicked()), this, SLOT(doApply())); + + ui.model_tabs->setCurrentIndex(s.active_model_panel); + + connect(ui.model_tabs, SIGNAL(currentChanged(int)), this, SLOT(set_model(int))); + connect(&timer,SIGNAL(timeout()), this,SLOT(poll_tracker_info())); + timer.start(100); + + connect(s.b.get(), SIGNAL(bundleChanged()), this, SLOT(do_apply_without_saving())); +} + +void TrackerDialog::set_model_clip() +{ + s.m01_x = 0; + s.m01_y = static_cast<double>(s.clip_ty); + s.m01_z = -static_cast<double>(s.clip_tz); + s.m02_x = 0; + s.m02_y = -static_cast<double>(s.clip_by); + s.m02_z = -static_cast<double>(s.clip_bz); + + settings_changed(); +} + +void TrackerDialog::set_model_cap() +{ + s.m01_x = -static_cast<double>(s.cap_x); + s.m01_y = -static_cast<double>(s.cap_y); + s.m01_z = -static_cast<double>(s.cap_z); + s.m02_x = static_cast<double>(s.cap_x); + s.m02_y = -static_cast<double>(s.cap_y); + s.m02_z = -static_cast<double>(s.cap_z); + + settings_changed(); +} + +void TrackerDialog::set_model_custom() +{ + settings_changed(); +} + +void TrackerDialog::set_model(int val) +{ + s.active_model_panel = val; +} + +void TrackerDialog::startstop_trans_calib(bool start) +{ + if (start) + { + qDebug()<<"TrackerDialog:: Starting translation calibration"; + trans_calib.reset(); + trans_calib_running = true; + } + else + { + qDebug()<<"TrackerDialog:: Stoppping translation calibration"; + trans_calib_running = false; + { + auto tmp = trans_calib.get_estimate(); + s.t_MH_x = tmp[0]; + s.t_MH_y = tmp[1]; + s.t_MH_z = tmp[2]; + } + settings_changed(); + } +} + +void TrackerDialog::trans_calib_step() +{ + if (tracker) + { + FrameTrafo X_CM; + tracker->get_pose(&X_CM); + trans_calib.update(X_CM.R, X_CM.t); + cv::Vec3f t_MH = trans_calib.get_estimate(); + s.t_MH_x = t_MH[0]; + s.t_MH_y = t_MH[1]; + s.t_MH_z = t_MH[2]; + } +} + +void TrackerDialog::settings_changed() +{ + if (tracker) tracker->apply(s); +} + +void TrackerDialog::doCenter() +{ + if (tracker) tracker->center(); +} + +void TrackerDialog::doReset() +{ + if (tracker) tracker->reset(); +} + +void TrackerDialog::save() +{ + do_apply_without_saving(); + s.b->save(); +} + +void TrackerDialog::doOK() +{ + save(); + close(); +} + +void TrackerDialog::do_apply_without_saving() +{ + switch (s.active_model_panel) { + default: + case 0: + set_model_clip(); + break; + case 1: + set_model_cap(); + break; + case 2: + set_model_custom(); + break; + } + if (tracker) tracker->apply(s); +} + +void TrackerDialog::doApply() +{ + save(); +} + +void TrackerDialog::doCancel() +{ + s.b->revert(); + close(); +} + +void TrackerDialog::widget_destroyed(QObject* obj) +{ + if (obj == video_widget_dialog) { + // widget was / will be already deleted by Qt + destroy_video_widget(false); + } +} + +void TrackerDialog::create_video_widget() +{ + // this should not happen but better be sure + if (video_widget_dialog) destroy_video_widget(); + if (!tracker) return; + + video_widget_dialog = new VideoWidgetDialog(this, tracker); + video_widget_dialog->setAttribute( Qt::WA_DeleteOnClose ); + connect( video_widget_dialog, SIGNAL(destroyed(QObject*)), this, SLOT(widget_destroyed(QObject*)) ); + video_widget_dialog->show(); +} + +void TrackerDialog::destroy_video_widget(bool do_delete /*= true*/) +{ + if (video_widget_dialog) { + if (do_delete) delete video_widget_dialog; + video_widget_dialog = NULL; + } +} + +void TrackerDialog::poll_tracker_info() +{ + if (tracker) + { + QString to_print; + + // display caminfo + CamInfo info; + tracker->get_cam_info(&info); + to_print = QString::number(info.res_x)+"x"+QString::number(info.res_y)+" @ "+QString::number(info.fps)+" FPS"; + ui.caminfo_label->setText(to_print); + + // display pointinfo + int n_points = tracker->get_n_points(); + to_print = QString::number(n_points); + if (n_points == 3) + to_print += " OK!"; + else + to_print += " BAD!"; + ui.pointinfo_label->setText(to_print); + + // update calibration + if (trans_calib_running) trans_calib_step(); + + // update videowidget + if (video_widget_dialog) { + video_widget_dialog->get_video_widget()->update_frame_and_points(); + } + } + else + { + QString to_print = "Tracker offline"; + ui.caminfo_label->setText(to_print); + ui.pointinfo_label->setText(to_print); + } +} + +void TrackerDialog::registerTracker(ITracker *t) +{ + qDebug()<<"TrackerDialog:: Tracker registered"; + tracker = static_cast<Tracker*>(t); + if (isVisible() & s.b->modifiedp()) + tracker->apply(s); + ui.tcalib_button->setEnabled(true); + //ui.center_button->setEnabled(true); + ui.reset_button->setEnabled(true); +} + +void TrackerDialog::unRegisterTracker() +{ + qDebug()<<"TrackerDialog:: Tracker un-registered"; + tracker = NULL; + destroy_video_widget(); + ui.tcalib_button->setEnabled(false); + //ui.center_button->setEnabled(false); + ui.reset_button->setEnabled(false); +} + +extern "C" OPENTRACK_EXPORT ITrackerDialog* CALLING_CONVENTION GetDialog( ) +{ + return new TrackerDialog; +} diff --git a/ftnoir_tracker_pt/ftnoir_tracker_pt_dialog.h b/ftnoir_tracker_pt/ftnoir_tracker_pt_dialog.h index 5cb09130..a4d9c4b5 100644 --- a/ftnoir_tracker_pt/ftnoir_tracker_pt_dialog.h +++ b/ftnoir_tracker_pt/ftnoir_tracker_pt_dialog.h @@ -1,70 +1,70 @@ -/* Copyright (c) 2012 Patrick Ruoff
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- */
-
-#ifndef FTNOIR_TRACKER_PT_DIALOG_H
-#define FTNOIR_TRACKER_PT_DIALOG_H
-
-#ifdef OPENTRACK_API
-# include "facetracknoir/plugin-api.hpp"
-#else
-#include "..\ftnoir_tracker_base\ftnoir_tracker_base.h"
-#endif
-#include "ftnoir_tracker_pt_settings.h"
-#include "ftnoir_tracker_pt.h"
-#include "trans_calib.h"
-#include "pt_video_widget.h"
-#include "ui_FTNoIR_PT_Controls.h"
-
-#include <QTimer>
-
-//-----------------------------------------------------------------------------
-// The dialog that shows up when the user presses "Settings"
-class TrackerDialog : public QWidget, Ui::UICPTClientControls, public ITrackerDialog
-{
- Q_OBJECT
-public:
- TrackerDialog();
- void registerTracker(ITracker *tracker);
- void unRegisterTracker();
- void save();
- void trans_calib_step();
-
-public slots:
- void doCenter();
- void doReset();
- void doOK();
- void doApply();
- void doCancel();
- void do_apply_without_saving();
-
- void startstop_trans_calib(bool start);
- void widget_destroyed(QObject* obj);
- void create_video_widget();
- void poll_tracker_info();
- void set_model(int idx);
-
-protected:
- void destroy_video_widget(bool do_delete = true);
-
- void set_model_clip();
- void set_model_cap();
- void set_model_custom();
-
- void settings_changed();
-
- settings s;
- Tracker* tracker;
- VideoWidgetDialog* video_widget_dialog;
- QTimer timer;
-
- TranslationCalibrator trans_calib;
- bool trans_calib_running;
-
- Ui::UICPTClientControls ui;
-};
-
-#endif //FTNOIR_TRACKER_PT_DIALOG_H
+/* Copyright (c) 2012 Patrick Ruoff + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + */ + +#ifndef FTNOIR_TRACKER_PT_DIALOG_H +#define FTNOIR_TRACKER_PT_DIALOG_H + +#ifdef OPENTRACK_API +# include "facetracknoir/plugin-api.hpp" +#else +#include "..\ftnoir_tracker_base\ftnoir_tracker_base.h" +#endif +#include "ftnoir_tracker_pt_settings.h" +#include "ftnoir_tracker_pt.h" +#include "trans_calib.h" +#include "pt_video_widget.h" +#include "ui_FTNoIR_PT_Controls.h" + +#include <QTimer> + +//----------------------------------------------------------------------------- +// The dialog that shows up when the user presses "Settings" +class TrackerDialog : public QWidget, Ui::UICPTClientControls, public ITrackerDialog +{ + Q_OBJECT +public: + TrackerDialog(); + void registerTracker(ITracker *tracker); + void unRegisterTracker(); + void save(); + void trans_calib_step(); + +public slots: + void doCenter(); + void doReset(); + void doOK(); + void doApply(); + void doCancel(); + void do_apply_without_saving(); + + void startstop_trans_calib(bool start); + void widget_destroyed(QObject* obj); + void create_video_widget(); + void poll_tracker_info(); + void set_model(int idx); + +protected: + void destroy_video_widget(bool do_delete = true); + + void set_model_clip(); + void set_model_cap(); + void set_model_custom(); + + void settings_changed(); + + settings s; + Tracker* tracker; + VideoWidgetDialog* video_widget_dialog; + QTimer timer; + + TranslationCalibrator trans_calib; + bool trans_calib_running; + + Ui::UICPTClientControls ui; +}; + +#endif //FTNOIR_TRACKER_PT_DIALOG_H diff --git a/ftnoir_tracker_pt/ftnoir_tracker_pt_dll.cpp b/ftnoir_tracker_pt/ftnoir_tracker_pt_dll.cpp index dd7b08d6..07e1d9e7 100644 --- a/ftnoir_tracker_pt/ftnoir_tracker_pt_dll.cpp +++ b/ftnoir_tracker_pt/ftnoir_tracker_pt_dll.cpp @@ -1,42 +1,42 @@ -/* Copyright (c) 2012 Patrick Ruoff
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- */
-
-#include "ftnoir_tracker_pt_dll.h"
-#include <QIcon>
-
-//-----------------------------------------------------------------------------
-void TrackerDll::getFullName(QString *strToBeFilled)
-{
- *strToBeFilled = "PointTracker 1.1";
-}
-
-void TrackerDll::getShortName(QString *strToBeFilled)
-{
- *strToBeFilled = "PointTracker";
-}
-
-void TrackerDll::getDescription(QString *strToBeFilled)
-{
- *strToBeFilled = "Tracks a 3-point model with know geometry like Freetrack / TrackIR";
-}
-
-void TrackerDll::getIcon(QIcon *icon)
-{
- *icon = QIcon(":/Resources/Logo_IR.png");
-}
-
-
-#ifdef OPENTRACK_API
-# include "facetracknoir/plugin-support.h"
-extern "C" OPENTRACK_EXPORT Metadata* CALLING_CONVENTION GetMetadata()
-#else
-# pragma comment(linker, "/export:GetTrackerDll=_GetTrackerDll@0")
-OPENTRACK_EXPORT ITrackerDllPtr __stdcall GetTrackerDll()
-#endif
-{
- return new TrackerDll;
-}
+/* Copyright (c) 2012 Patrick Ruoff + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + */ + +#include "ftnoir_tracker_pt_dll.h" +#include <QIcon> + +//----------------------------------------------------------------------------- +void TrackerDll::getFullName(QString *strToBeFilled) +{ + *strToBeFilled = "PointTracker 1.1"; +} + +void TrackerDll::getShortName(QString *strToBeFilled) +{ + *strToBeFilled = "PointTracker"; +} + +void TrackerDll::getDescription(QString *strToBeFilled) +{ + *strToBeFilled = "Tracks a 3-point model with know geometry like Freetrack / TrackIR"; +} + +void TrackerDll::getIcon(QIcon *icon) +{ + *icon = QIcon(":/Resources/Logo_IR.png"); +} + + +#ifdef OPENTRACK_API +# include "facetracknoir/plugin-support.h" +extern "C" OPENTRACK_EXPORT Metadata* CALLING_CONVENTION GetMetadata() +#else +# pragma comment(linker, "/export:GetTrackerDll=_GetTrackerDll@0") +OPENTRACK_EXPORT ITrackerDllPtr __stdcall GetTrackerDll() +#endif +{ + return new TrackerDll; +} diff --git a/ftnoir_tracker_pt/ftnoir_tracker_pt_dll.h b/ftnoir_tracker_pt/ftnoir_tracker_pt_dll.h index fce7aec2..50f66a35 100644 --- a/ftnoir_tracker_pt/ftnoir_tracker_pt_dll.h +++ b/ftnoir_tracker_pt/ftnoir_tracker_pt_dll.h @@ -1,26 +1,26 @@ -/* Copyright (c) 2012 Patrick Ruoff
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- */
-
-#if defined(OPENTRACK_API)
-# include "facetracknoir/plugin-api.hpp"
-#else
-# include "../ftnoir_tracker_base/ftnoir_tracker_base.h"
-#endif
-
-//-----------------------------------------------------------------------------
-class TrackerDll :
-#if defined(OPENTRACK_API)
- public Metadata
-#else
- public ITrackerDll
-#endif
-{
- void getFullName(QString *strToBeFilled);
- void getShortName(QString *strToBeFilled);
- void getDescription(QString *strToBeFilled);
- void getIcon(QIcon *icon);
-};
+/* Copyright (c) 2012 Patrick Ruoff + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + */ + +#if defined(OPENTRACK_API) +# include "facetracknoir/plugin-api.hpp" +#else +# include "../ftnoir_tracker_base/ftnoir_tracker_base.h" +#endif + +//----------------------------------------------------------------------------- +class TrackerDll : +#if defined(OPENTRACK_API) + public Metadata +#else + public ITrackerDll +#endif +{ + void getFullName(QString *strToBeFilled); + void getShortName(QString *strToBeFilled); + void getDescription(QString *strToBeFilled); + void getIcon(QIcon *icon); +}; diff --git a/ftnoir_tracker_pt/ftnoir_tracker_pt_settings.h b/ftnoir_tracker_pt/ftnoir_tracker_pt_settings.h index 1eca1e35..e4cb9ad3 100644 --- a/ftnoir_tracker_pt/ftnoir_tracker_pt_settings.h +++ b/ftnoir_tracker_pt/ftnoir_tracker_pt_settings.h @@ -1,81 +1,81 @@ -/* Copyright (c) 2012 Patrick Ruoff
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- */
-
-#ifndef FTNOIR_TRACKER_PT_SETTINGS_H
-#define FTNOIR_TRACKER_PT_SETTINGS_H
-
-#include <opencv2/opencv.hpp>
-#include "point_tracker.h"
-
-#include "facetracknoir/options.h"
-using namespace options;
-
-struct settings
-{
- pbundle b;
- value<int> cam_index,
- cam_res_x,
- cam_res_y,
- cam_fps,
- cam_roll,
- cam_pitch,
- cam_yaw,
- threshold,
- threshold_secondary,
- min_point_size,
- max_point_size;
- value<double> cam_f;
-
- value<int> m01_x, m01_y, m01_z;
- value<int> m02_x, m02_y, m02_z;
- value<bool> dyn_pose_res, video_widget;
-
- value<int> t_MH_x, t_MH_y, t_MH_z;
-
- value<int> reset_time;
-
- value<int> clip_ty, clip_tz, clip_by, clip_bz;
- value<int> active_model_panel, cap_x, cap_y, cap_z;
-
- settings() :
- b(bundle("tracker-pt")),
- cam_index(b, "camera-index", 0),
- cam_res_x(b, "camera-res-width", 640),
- cam_res_y(b, "camera-res-height", 480),
- cam_fps(b, "camera-fps", 30),
- cam_roll(b, "camera-roll", 1),
- cam_pitch(b, "camera-pitch", 0),
- cam_yaw(b, "camera-yaw", 0),
- threshold(b, "threshold-primary", 128),
- threshold_secondary(b, "threshold-secondary", 128),
- min_point_size(b, "min-point-size", 10),
- max_point_size(b, "max-point-size", 50),
- cam_f(b, "camera-focal-length", 1),
- m01_x(b, "m_01-x", 0),
- m01_y(b, "m_01-y", 0),
- m01_z(b, "m_01-z", 0),
- m02_x(b, "m_02-x", 0),
- m02_y(b, "m_02-y", 0),
- m02_z(b, "m_02-z", 0),
- dyn_pose_res(b, "dynamic-pose-resolution", false),
- video_widget(b, "video-widget", true),
- t_MH_x(b, "model-centroid-x", 0),
- t_MH_y(b, "model-centroid-y", 0),
- t_MH_z(b, "model-centroid-z", 0),
- reset_time(b, "reset-time", 2000),
- clip_ty(b, "clip-ty", 0),
- clip_tz(b, "clip-tz", 0),
- clip_by(b, "clip-by", 0),
- clip_bz(b, "clip-bz", 0),
- active_model_panel(b, "active-model-panel", 0),
- cap_x(b, "cap-x", 0),
- cap_y(b, "cap-y", 0),
- cap_z(b, "cap-z", 0)
- {}
-};
-
-#endif //FTNOIR_TRACKER_PT_SETTINGS_H
+/* Copyright (c) 2012 Patrick Ruoff + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + */ + +#ifndef FTNOIR_TRACKER_PT_SETTINGS_H +#define FTNOIR_TRACKER_PT_SETTINGS_H + +#include <opencv2/opencv.hpp> +#include "point_tracker.h" + +#include "facetracknoir/options.h" +using namespace options; + +struct settings +{ + pbundle b; + value<int> cam_index, + cam_res_x, + cam_res_y, + cam_fps, + cam_roll, + cam_pitch, + cam_yaw, + threshold, + threshold_secondary, + min_point_size, + max_point_size; + value<double> cam_f; + + value<int> m01_x, m01_y, m01_z; + value<int> m02_x, m02_y, m02_z; + value<bool> dyn_pose_res, video_widget; + + value<int> t_MH_x, t_MH_y, t_MH_z; + + value<int> reset_time; + + value<int> clip_ty, clip_tz, clip_by, clip_bz; + value<int> active_model_panel, cap_x, cap_y, cap_z; + + settings() : + b(bundle("tracker-pt")), + cam_index(b, "camera-index", 0), + cam_res_x(b, "camera-res-width", 640), + cam_res_y(b, "camera-res-height", 480), + cam_fps(b, "camera-fps", 30), + cam_roll(b, "camera-roll", 1), + cam_pitch(b, "camera-pitch", 0), + cam_yaw(b, "camera-yaw", 0), + threshold(b, "threshold-primary", 128), + threshold_secondary(b, "threshold-secondary", 128), + min_point_size(b, "min-point-size", 10), + max_point_size(b, "max-point-size", 50), + cam_f(b, "camera-focal-length", 1), + m01_x(b, "m_01-x", 0), + m01_y(b, "m_01-y", 0), + m01_z(b, "m_01-z", 0), + m02_x(b, "m_02-x", 0), + m02_y(b, "m_02-y", 0), + m02_z(b, "m_02-z", 0), + dyn_pose_res(b, "dynamic-pose-resolution", false), + video_widget(b, "video-widget", true), + t_MH_x(b, "model-centroid-x", 0), + t_MH_y(b, "model-centroid-y", 0), + t_MH_z(b, "model-centroid-z", 0), + reset_time(b, "reset-time", 2000), + clip_ty(b, "clip-ty", 0), + clip_tz(b, "clip-tz", 0), + clip_by(b, "clip-by", 0), + clip_bz(b, "clip-bz", 0), + active_model_panel(b, "active-model-panel", 0), + cap_x(b, "cap-x", 0), + cap_y(b, "cap-y", 0), + cap_z(b, "cap-z", 0) + {} +}; + +#endif //FTNOIR_TRACKER_PT_SETTINGS_H diff --git a/ftnoir_tracker_pt/point_extractor.cpp b/ftnoir_tracker_pt/point_extractor.cpp index 968fe23e..b0e29270 100644 --- a/ftnoir_tracker_pt/point_extractor.cpp +++ b/ftnoir_tracker_pt/point_extractor.cpp @@ -1,163 +1,163 @@ -/* Copyright (c) 2012 Patrick Ruoff
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- */
-
-#include "point_extractor.h"
-#include <QDebug>
-
-
-using namespace cv;
-using namespace std;
-
-
-PointExtractor::PointExtractor(){
- //if (!AllocConsole()){}
- //else SetConsoleTitle("debug");
- //freopen("CON", "w", stdout);
- //freopen("CON", "w", stderr);
-}
-// ----------------------------------------------------------------------------
-const vector<Vec2f>& PointExtractor::extract_points(Mat frame, float /*dt*/, bool draw_output)
-{
- const int W = frame.cols;
- const int H = frame.rows;
-
- if (frame_last.cols != W || frame_last.rows != H)
- {
- frame_last = cv::Mat();
- }
-
- // clear old points
- points.clear();
-
- // convert to grayscale
- Mat frame_gray;
- cvtColor(frame, frame_gray, CV_RGB2GRAY);
-
- int secondary = threshold_secondary_val;
-
- // mask for everything that passes the threshold (or: the upper threshold of the hysteresis)
- Mat frame_bin;
- // only used if draw_output
- Mat frame_bin_copy;
- // mask for everything that passes
- Mat frame_bin_low;
- // mask for lower-threshold && combined result of last, needs to remain in scope until drawing, but is only used if secondary != 0
- Mat frame_last_and_low;
-
- if(secondary==0){
- threshold(frame_gray, frame_bin, threshold_val, 255, THRESH_BINARY);
- }else{
- // we recombine a number of buffers, this might be slower than a single loop of per-pixel logic
- // but it might as well be faster if openCV makes good use of SIMD
- float t = threshold_val;
- //float hyst = float(threshold_secondary_val)/512.;
- //threshold(frame_gray, frame_bin, (t + ((255.-t)*hyst)), 255, THRESH_BINARY);
- float hyst = float(threshold_secondary_val)/256.;
- threshold(frame_gray, frame_bin, t, 255, THRESH_BINARY);
- threshold(frame_gray, frame_bin_low,std::max(float(1), t - (t*hyst)), 255, THRESH_BINARY);
-
- if(draw_output) frame_bin.copyTo(frame_bin_copy);
- if(frame_last.empty()){
- frame_bin.copyTo(frame_last);
- }else{
- // keep pixels from last if they are above lower threshold
- bitwise_and(frame_last, frame_bin_low, frame_last_and_low);
- // union of pixels >= higher threshold and pixels >= lower threshold
- bitwise_or(frame_bin, frame_last_and_low, frame_last);
- frame_last.copyTo(frame_bin);
- }
- }
- unsigned int region_size_min = 3.14*min_size*min_size/4.0;
- unsigned int region_size_max = 3.14*max_size*max_size/4.0;
-
- int blob_index = 1;
- for (int y=0; y<H; y++)
- {
- if (blob_index >= 255) break;
- for (int x=0; x<W; x++)
- {
- if (blob_index >= 255) break;
-
- // find connected components with floodfill
- if (frame_bin.at<unsigned char>(y,x) != 255) continue;
- Rect rect;
-
- floodFill(frame_bin, Point(x,y), Scalar(blob_index), &rect, Scalar(0), Scalar(0), FLOODFILL_FIXED_RANGE);
- blob_index++;
-
- // calculate the size of the connected component
- unsigned int region_size = 0;
- for (int i=rect.y; i < (rect.y+rect.height); i++)
- {
- for (int j=rect.x; j < (rect.x+rect.width); j++)
- {
- if (frame_bin.at<unsigned char>(i,j) != blob_index-1) continue;
- region_size++;
- }
- }
-
- if (region_size < region_size_min || region_size > region_size_max) continue;
-
- // calculate the center of mass:
- // mx = (sum_ij j*f(frame_grey_ij)) / (sum_ij f(frame_grey_ij))
- // my = ...
- // f maps from [threshold,256] -> [0, 1], lower values are mapped to 0
- float m = 0;
- float mx = 0;
- float my = 0;
- for (int i=rect.y; i < (rect.y+rect.height); i++)
- {
- for (int j=rect.x; j < (rect.x+rect.width); j++)
- {
- if (frame_bin.at<unsigned char>(i,j) != blob_index-1) continue;
- float val;
-
- if(secondary==0){
- val = frame_gray.at<unsigned char>(i,j);
- val = float(val - threshold_val)/(256 - threshold_val);
- val = val*val; // makes it more stable (less emphasis on low values, more on the peak)
- }else{
- //hysteresis point detection gets stability from ignoring pixel noise so we decidedly leave the actual pixel values out of the picture
- val = frame_last.at<unsigned char>(i,j) / 256.;
- }
-
- m += val;
- mx += j * val;
- my += i * val;
- }
- }
-
- // convert to centered camera coordinate system with y axis upwards
- Vec2f c;
- c[0] = (mx/m - W/2)/W;
- c[1] = -(my/m - H/2)/W;
- //qDebug()<<blob_index<<" => "<<c[0]<<" "<<c[1];
- points.push_back(c);
- }
- }
-
- // draw output image
- if (draw_output) {
- vector<Mat> channels;
- if(secondary==0){
- frame_bin.setTo(170, frame_bin);
- channels.push_back(frame_gray + frame_bin);
- channels.push_back(frame_gray - frame_bin);
- channels.push_back(frame_gray - frame_bin);
- }else{
- frame_bin_copy.setTo(120, frame_bin_copy);
- frame_bin_low.setTo(90, frame_bin_low);
- channels.push_back(frame_gray + frame_bin_copy);
- channels.push_back(frame_gray + frame_last_and_low);
- channels.push_back(frame_gray + frame_bin_low);
- //channels.push_back(frame_gray + frame_bin);
- }
- merge(channels, frame);
- }
-
- return points;
-}
+/* Copyright (c) 2012 Patrick Ruoff + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + */ + +#include "point_extractor.h" +#include <QDebug> + + +using namespace cv; +using namespace std; + + +PointExtractor::PointExtractor(){ + //if (!AllocConsole()){} + //else SetConsoleTitle("debug"); + //freopen("CON", "w", stdout); + //freopen("CON", "w", stderr); +} +// ---------------------------------------------------------------------------- +const vector<Vec2f>& PointExtractor::extract_points(Mat frame, float /*dt*/, bool draw_output) +{ + const int W = frame.cols; + const int H = frame.rows; + + if (frame_last.cols != W || frame_last.rows != H) + { + frame_last = cv::Mat(); + } + + // clear old points + points.clear(); + + // convert to grayscale + Mat frame_gray; + cvtColor(frame, frame_gray, CV_RGB2GRAY); + + int secondary = threshold_secondary_val; + + // mask for everything that passes the threshold (or: the upper threshold of the hysteresis) + Mat frame_bin; + // only used if draw_output + Mat frame_bin_copy; + // mask for everything that passes + Mat frame_bin_low; + // mask for lower-threshold && combined result of last, needs to remain in scope until drawing, but is only used if secondary != 0 + Mat frame_last_and_low; + + if(secondary==0){ + threshold(frame_gray, frame_bin, threshold_val, 255, THRESH_BINARY); + }else{ + // we recombine a number of buffers, this might be slower than a single loop of per-pixel logic + // but it might as well be faster if openCV makes good use of SIMD + float t = threshold_val; + //float hyst = float(threshold_secondary_val)/512.; + //threshold(frame_gray, frame_bin, (t + ((255.-t)*hyst)), 255, THRESH_BINARY); + float hyst = float(threshold_secondary_val)/256.; + threshold(frame_gray, frame_bin, t, 255, THRESH_BINARY); + threshold(frame_gray, frame_bin_low,std::max(float(1), t - (t*hyst)), 255, THRESH_BINARY); + + if(draw_output) frame_bin.copyTo(frame_bin_copy); + if(frame_last.empty()){ + frame_bin.copyTo(frame_last); + }else{ + // keep pixels from last if they are above lower threshold + bitwise_and(frame_last, frame_bin_low, frame_last_and_low); + // union of pixels >= higher threshold and pixels >= lower threshold + bitwise_or(frame_bin, frame_last_and_low, frame_last); + frame_last.copyTo(frame_bin); + } + } + unsigned int region_size_min = 3.14*min_size*min_size/4.0; + unsigned int region_size_max = 3.14*max_size*max_size/4.0; + + int blob_index = 1; + for (int y=0; y<H; y++) + { + if (blob_index >= 255) break; + for (int x=0; x<W; x++) + { + if (blob_index >= 255) break; + + // find connected components with floodfill + if (frame_bin.at<unsigned char>(y,x) != 255) continue; + Rect rect; + + floodFill(frame_bin, Point(x,y), Scalar(blob_index), &rect, Scalar(0), Scalar(0), FLOODFILL_FIXED_RANGE); + blob_index++; + + // calculate the size of the connected component + unsigned int region_size = 0; + for (int i=rect.y; i < (rect.y+rect.height); i++) + { + for (int j=rect.x; j < (rect.x+rect.width); j++) + { + if (frame_bin.at<unsigned char>(i,j) != blob_index-1) continue; + region_size++; + } + } + + if (region_size < region_size_min || region_size > region_size_max) continue; + + // calculate the center of mass: + // mx = (sum_ij j*f(frame_grey_ij)) / (sum_ij f(frame_grey_ij)) + // my = ... + // f maps from [threshold,256] -> [0, 1], lower values are mapped to 0 + float m = 0; + float mx = 0; + float my = 0; + for (int i=rect.y; i < (rect.y+rect.height); i++) + { + for (int j=rect.x; j < (rect.x+rect.width); j++) + { + if (frame_bin.at<unsigned char>(i,j) != blob_index-1) continue; + float val; + + if(secondary==0){ + val = frame_gray.at<unsigned char>(i,j); + val = float(val - threshold_val)/(256 - threshold_val); + val = val*val; // makes it more stable (less emphasis on low values, more on the peak) + }else{ + //hysteresis point detection gets stability from ignoring pixel noise so we decidedly leave the actual pixel values out of the picture + val = frame_last.at<unsigned char>(i,j) / 256.; + } + + m += val; + mx += j * val; + my += i * val; + } + } + + // convert to centered camera coordinate system with y axis upwards + Vec2f c; + c[0] = (mx/m - W/2)/W; + c[1] = -(my/m - H/2)/W; + //qDebug()<<blob_index<<" => "<<c[0]<<" "<<c[1]; + points.push_back(c); + } + } + + // draw output image + if (draw_output) { + vector<Mat> channels; + if(secondary==0){ + frame_bin.setTo(170, frame_bin); + channels.push_back(frame_gray + frame_bin); + channels.push_back(frame_gray - frame_bin); + channels.push_back(frame_gray - frame_bin); + }else{ + frame_bin_copy.setTo(120, frame_bin_copy); + frame_bin_low.setTo(90, frame_bin_low); + channels.push_back(frame_gray + frame_bin_copy); + channels.push_back(frame_gray + frame_last_and_low); + channels.push_back(frame_gray + frame_bin_low); + //channels.push_back(frame_gray + frame_bin); + } + merge(channels, frame); + } + + return points; +} diff --git a/ftnoir_tracker_pt/point_extractor.h b/ftnoir_tracker_pt/point_extractor.h index ff36f3ce..8a76747b 100644 --- a/ftnoir_tracker_pt/point_extractor.h +++ b/ftnoir_tracker_pt/point_extractor.h @@ -1,35 +1,35 @@ -/* Copyright (c) 2012 Patrick Ruoff
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- */
-
-#ifndef POINTEXTRACTOR_H
-#define POINTEXTRACTOR_H
-
-#include <opencv2/opencv.hpp>
-#include <opencv2/imgproc/imgproc_c.h>
-
-// ----------------------------------------------------------------------------
-// Extracts points from an opencv image
-class PointExtractor
-{
-public:
- // extracts points from frame and draws some processing info into frame, if draw_output is set
- // dt: time since last call in seconds
- // WARNING: returned reference is valid as long as object
- const std::vector<cv::Vec2f>& extract_points(cv::Mat frame, float dt, bool draw_output);
- const std::vector<cv::Vec2f>& get_points() { return points; }
- PointExtractor();
-
- int threshold_val;
- int threshold_secondary_val;
- int min_size, max_size;
-
-protected:
- std::vector<cv::Vec2f> points;
- cv::Mat frame_last;
-};
-
-#endif //POINTEXTRACTOR_H
+/* Copyright (c) 2012 Patrick Ruoff + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + */ + +#ifndef POINTEXTRACTOR_H +#define POINTEXTRACTOR_H + +#include <opencv2/opencv.hpp> +#include <opencv2/imgproc/imgproc_c.h> + +// ---------------------------------------------------------------------------- +// Extracts points from an opencv image +class PointExtractor +{ +public: + // extracts points from frame and draws some processing info into frame, if draw_output is set + // dt: time since last call in seconds + // WARNING: returned reference is valid as long as object + const std::vector<cv::Vec2f>& extract_points(cv::Mat frame, float dt, bool draw_output); + const std::vector<cv::Vec2f>& get_points() { return points; } + PointExtractor(); + + int threshold_val; + int threshold_secondary_val; + int min_size, max_size; + +protected: + std::vector<cv::Vec2f> points; + cv::Mat frame_last; +}; + +#endif //POINTEXTRACTOR_H diff --git a/ftnoir_tracker_pt/point_tracker.cpp b/ftnoir_tracker_pt/point_tracker.cpp index f83ff437..e9892d67 100644 --- a/ftnoir_tracker_pt/point_tracker.cpp +++ b/ftnoir_tracker_pt/point_tracker.cpp @@ -1,375 +1,375 @@ -/* Copyright (c) 2012 Patrick Ruoff
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- */
-
-#include "point_tracker.h"
-
-#include <vector>
-#include <algorithm>
-#include <cmath>
-
-#include <QDebug>
-
-using namespace cv;
-using namespace std;
-
-const float PI = 3.14159265358979323846f;
-
-// ----------------------------------------------------------------------------
-static void get_row(const Matx33f& m, int i, Vec3f& v)
-{
- v[0] = m(i,0);
- v[1] = m(i,1);
- v[2] = m(i,2);
-}
-
-static void set_row(Matx33f& m, int i, const Vec3f& v)
-{
- m(i,0) = v[0];
- m(i,1) = v[1];
- m(i,2) = v[2];
-}
-
-// ----------------------------------------------------------------------------
-PointModel::PointModel(Vec3f M01, Vec3f M02)
- : M01(M01),
- M02(M02)
-{
- // calculate u
- u = M01.cross(M02);
- u /= norm(u);
-
- // calculate projection matrix on M01,M02 plane
- float s11 = M01.dot(M01);
- float s12 = M01.dot(M02);
- float s22 = M02.dot(M02);
- P = 1.0/(s11*s22-s12*s12) * Matx22f(s22, -s12,
- -s12, s11);
-
- // calculate d and d_order for simple freetrack-like point correspondence
- vector<Vec2f> points;
- points.push_back(Vec2f(0,0));
- points.push_back(Vec2f(M01[0], M01[1]));
- points.push_back(Vec2f(M02[0], M02[1]));
- // fit line to orthographically projected points
- // ERROR: yields wrong results with colinear points?!
- /*
- Vec4f line;
- fitLine(points, line, CV_DIST_L2, 0, 0.01, 0.01);
- d[0] = line[0]; d[1] = line[1];
- */
- // TODO: fix this
- d = Vec2f(M01[0]-M02[0], M01[1]-M02[1]);
-
- // sort model points
- get_d_order(points, d_order);
-}
-
-#ifdef OPENTRACK_API
-static bool d_vals_sort(const pair<float,int> a, const pair<float,int> b)
-{
- return a.first < b.first;
-}
-#endif
-
-void PointModel::get_d_order(const std::vector<cv::Vec2f>& points, int d_order[]) const
-{
- // get sort indices with respect to d scalar product
- vector< pair<float,int> > d_vals;
- for (unsigned i = 0; i<points.size(); ++i)
- d_vals.push_back(pair<float, int>(d.dot(points[i]), i));
-
- std::sort(d_vals.begin(),
- d_vals.end(),
-#ifdef OPENTRACK_API
- d_vals_sort
-#else
- comp
-#endif
- );
-
- for (unsigned i = 0; i<points.size(); ++i)
- d_order[i] = d_vals[i].second;
-}
-
-
-// ----------------------------------------------------------------------------
-PointTracker::PointTracker() :
- dynamic_pose_resolution(true),
- dt_reset(1),
- init_phase(true),
- dt_valid(0),
- v_t(0,0,0),
- v_r(0,0,0)
-{
- X_CM.t[2] = 1000; // default position: 1 m away from cam;
-}
-
-void PointTracker::reset()
-{
- // enter init phase and reset velocities
- init_phase = true;
- dt_valid = 0;
- reset_velocities();
-}
-
-void PointTracker::reset_velocities()
-{
- v_t = Vec3f(0,0,0);
- v_r = Vec3f(0,0,0);
-}
-
-
-bool PointTracker::track(const vector<Vec2f>& points, float f, float dt)
-{
- if (!dynamic_pose_resolution) init_phase = true;
-
- dt_valid += dt;
- // if there was no valid tracking result for too long, do a reset
- if (dt_valid > dt_reset)
- {
- //qDebug()<<"dt_valid "<<dt_valid<<" > dt_reset "<<dt_reset;
- reset();
- }
-
- bool no_model =
-#ifdef OPENTRACK_API
- point_model.get() == NULL;
-#else
- !point_model;
-#endif
-
- // if there is a pointtracking problem, reset the velocities
- if (no_model || points.size() != PointModel::N_POINTS)
- {
- //qDebug()<<"Wrong number of points!";
- reset_velocities();
- return false;
- }
-
- X_CM_old = X_CM; // backup old transformation for velocity calculation
-
- if (!init_phase)
- predict(dt_valid);
-
- // if there is a point correspondence problem something has gone wrong, do a reset
- if (!find_correspondences(points, f))
- {
- //qDebug()<<"Error in finding point correspondences!";
- X_CM = X_CM_old; // undo prediction
- reset();
- return false;
- }
-
- (void) POSIT(f);
- //qDebug()<<"Number of POSIT iterations: "<<n_iter;
-
- if (!init_phase)
- update_velocities(dt_valid);
-
- // we have a valid tracking result, leave init phase and reset time since valid result
- init_phase = false;
- dt_valid = 0;
- return true;
-}
-
-void PointTracker::predict(float dt)
-{
- // predict with constant velocity
- Matx33f R;
- Rodrigues(dt*v_r, R);
- X_CM.R = R*X_CM.R;
- X_CM.t += dt * v_t;
-}
-
-void PointTracker::update_velocities(float dt)
-{
- // update velocities
- Rodrigues(X_CM.R*X_CM_old.R.t(), v_r);
- v_r /= dt;
- v_t = (X_CM.t - X_CM_old.t)/dt;
-}
-
-bool PointTracker::find_correspondences(const vector<Vec2f>& points, float f)
-{
- if (init_phase) {
- // We do a simple freetrack-like sorting in the init phase...
- // sort points
- int point_d_order[PointModel::N_POINTS];
- point_model->get_d_order(points, point_d_order);
-
- // set correspondences
- for (int i=0; i<PointModel::N_POINTS; ++i)
- {
- p[point_model->d_order[i]] = points[point_d_order[i]];
- }
- }
- else {
- // ... otherwise we look at the distance to the projection of the expected model points
- // project model points under current pose
- p_exp[0] = project(Vec3f(0,0,0), f);
- p_exp[1] = project(point_model->M01, f);
- p_exp[2] = project(point_model->M02, f);
-
- // set correspondences by minimum distance to projected model point
- bool point_taken[PointModel::N_POINTS];
- for (int i=0; i<PointModel::N_POINTS; ++i)
- point_taken[i] = false;
-
- float min_sdist = 0;
- int min_idx = 0;
-
- for (int i=0; i<PointModel::N_POINTS; ++i)
- {
- // find closest point to projected model point i
- for (int j=0; j<PointModel::N_POINTS; ++j)
- {
- Vec2f d = p_exp[i]-points[j];
- float sdist = d.dot(d);
- if (sdist < min_sdist || j==0)
- {
- min_idx = j;
- min_sdist = sdist;
- }
- }
- // if one point is closest to more than one model point, abort
- if (point_taken[min_idx]) return false;
- point_taken[min_idx] = true;
- p[i] = points[min_idx];
- }
- }
- return true;
-}
-
-
-
-int PointTracker::POSIT(float f)
-{
- // POSIT algorithm for coplanar points as presented in
- // [Denis Oberkampf, Daniel F. DeMenthon, Larry S. Davis: "Iterative Pose Estimation Using Coplanar Feature Points"]
- // we use the same notation as in the paper here
-
- // The expected rotation used for resolving the ambiguity in POSIT:
- // In every iteration step the rotation closer to R_expected is taken
- Matx33f R_expected;
- if (init_phase)
- R_expected = Matx33f::eye(); // in the init phase, we want to be close to the default pose = no rotation
- else
- R_expected = X_CM.R; // later we want to be close to the last (predicted) rotation
-
- // initial pose = last (predicted) pose
- Vec3f k;
- get_row(R_expected, 2, k);
- float Z0 = init_phase ? 1000 : X_CM.t[2];
-
- float old_epsilon_1 = 0;
- float old_epsilon_2 = 0;
- float epsilon_1 = 1;
- float epsilon_2 = 1;
-
- Vec3f I0, J0;
- Vec2f I0_coeff, J0_coeff;
-
- Vec3f I_1, J_1, I_2, J_2;
- Matx33f R_1, R_2;
- Matx33f* R_current;
-
- const int MAX_ITER = 100;
- const float EPS_THRESHOLD = 1e-4;
-
- int i=1;
- for (; i<MAX_ITER; ++i)
- {
- epsilon_1 = k.dot(point_model->M01)/Z0;
- epsilon_2 = k.dot(point_model->M02)/Z0;
-
- // vector of scalar products <I0, M0i> and <J0, M0i>
- Vec2f I0_M0i(p[1][0]*(1.0 + epsilon_1) - p[0][0],
- p[2][0]*(1.0 + epsilon_2) - p[0][0]);
- Vec2f J0_M0i(p[1][1]*(1.0 + epsilon_1) - p[0][1],
- p[2][1]*(1.0 + epsilon_2) - p[0][1]);
-
- // construct projection of I, J onto M0i plane: I0 and J0
- I0_coeff = point_model->P * I0_M0i;
- J0_coeff = point_model->P * J0_M0i;
- I0 = I0_coeff[0]*point_model->M01 + I0_coeff[1]*point_model->M02;
- J0 = J0_coeff[0]*point_model->M01 + J0_coeff[1]*point_model->M02;
-
- // calculate u component of I, J
- float II0 = I0.dot(I0);
- float IJ0 = I0.dot(J0);
- float JJ0 = J0.dot(J0);
- float rho, theta;
- if (JJ0 == II0) {
- rho = sqrt(abs(2*IJ0));
- theta = -PI/4;
- if (IJ0<0) theta *= -1;
- }
- else {
- rho = sqrt(sqrt( (JJ0-II0)*(JJ0-II0) + 4*IJ0*IJ0 ));
- theta = atan( -2*IJ0 / (JJ0-II0) );
- if (JJ0 - II0 < 0) theta += PI;
- theta /= 2;
- }
-
- // construct the two solutions
- I_1 = I0 + rho*cos(theta)*point_model->u;
- I_2 = I0 - rho*cos(theta)*point_model->u;
-
- J_1 = J0 + rho*sin(theta)*point_model->u;
- J_2 = J0 - rho*sin(theta)*point_model->u;
-
- float norm_const = 1.0/norm(I_1); // all have the same norm
-
- // create rotation matrices
- I_1 *= norm_const; J_1 *= norm_const;
- I_2 *= norm_const; J_2 *= norm_const;
-
- set_row(R_1, 0, I_1);
- set_row(R_1, 1, J_1);
- set_row(R_1, 2, I_1.cross(J_1));
-
- set_row(R_2, 0, I_2);
- set_row(R_2, 1, J_2);
- set_row(R_2, 2, I_2.cross(J_2));
-
- // the single translation solution
- Z0 = norm_const * f;
-
- // pick the rotation solution closer to the expected one
- // in simple metric d(A,B) = || I - A * B^T ||
- float R_1_deviation = norm(Matx33f::eye() - R_expected * R_1.t());
- float R_2_deviation = norm(Matx33f::eye() - R_expected * R_2.t());
-
- if (R_1_deviation < R_2_deviation)
- R_current = &R_1;
- else
- R_current = &R_2;
-
- get_row(*R_current, 2, k);
-
- // check for convergence condition
- if (abs(epsilon_1 - old_epsilon_1) + abs(epsilon_2 - old_epsilon_2) < EPS_THRESHOLD)
- break;
- old_epsilon_1 = epsilon_1;
- old_epsilon_2 = epsilon_2;
- }
-
- // apply results
- X_CM.R = *R_current;
- X_CM.t[0] = p[0][0] * Z0/f;
- X_CM.t[1] = p[0][1] * Z0/f;
- X_CM.t[2] = Z0;
-
- return i;
-
- //Rodrigues(X_CM.R, r);
- //qDebug()<<"iter: "<<i;
- //qDebug()<<"t: "<<X_CM.t[0]<<' '<<X_CM.t[1]<<' '<<X_CM.t[2];
- //Vec3f r;
- //
- //qDebug()<<"r: "<<r[0]<<' '<<r[1]<<' '<<r[2]<<'\n';
-}
+/* Copyright (c) 2012 Patrick Ruoff + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + */ + +#include "point_tracker.h" + +#include <vector> +#include <algorithm> +#include <cmath> + +#include <QDebug> + +using namespace cv; +using namespace std; + +const float PI = 3.14159265358979323846f; + +// ---------------------------------------------------------------------------- +static void get_row(const Matx33f& m, int i, Vec3f& v) +{ + v[0] = m(i,0); + v[1] = m(i,1); + v[2] = m(i,2); +} + +static void set_row(Matx33f& m, int i, const Vec3f& v) +{ + m(i,0) = v[0]; + m(i,1) = v[1]; + m(i,2) = v[2]; +} + +// ---------------------------------------------------------------------------- +PointModel::PointModel(Vec3f M01, Vec3f M02) + : M01(M01), + M02(M02) +{ + // calculate u + u = M01.cross(M02); + u /= norm(u); + + // calculate projection matrix on M01,M02 plane + float s11 = M01.dot(M01); + float s12 = M01.dot(M02); + float s22 = M02.dot(M02); + P = 1.0/(s11*s22-s12*s12) * Matx22f(s22, -s12, + -s12, s11); + + // calculate d and d_order for simple freetrack-like point correspondence + vector<Vec2f> points; + points.push_back(Vec2f(0,0)); + points.push_back(Vec2f(M01[0], M01[1])); + points.push_back(Vec2f(M02[0], M02[1])); + // fit line to orthographically projected points + // ERROR: yields wrong results with colinear points?! + /* + Vec4f line; + fitLine(points, line, CV_DIST_L2, 0, 0.01, 0.01); + d[0] = line[0]; d[1] = line[1]; + */ + // TODO: fix this + d = Vec2f(M01[0]-M02[0], M01[1]-M02[1]); + + // sort model points + get_d_order(points, d_order); +} + +#ifdef OPENTRACK_API +static bool d_vals_sort(const pair<float,int> a, const pair<float,int> b) +{ + return a.first < b.first; +} +#endif + +void PointModel::get_d_order(const std::vector<cv::Vec2f>& points, int d_order[]) const +{ + // get sort indices with respect to d scalar product + vector< pair<float,int> > d_vals; + for (unsigned i = 0; i<points.size(); ++i) + d_vals.push_back(pair<float, int>(d.dot(points[i]), i)); + + std::sort(d_vals.begin(), + d_vals.end(), +#ifdef OPENTRACK_API + d_vals_sort +#else + comp +#endif + ); + + for (unsigned i = 0; i<points.size(); ++i) + d_order[i] = d_vals[i].second; +} + + +// ---------------------------------------------------------------------------- +PointTracker::PointTracker() : + dynamic_pose_resolution(true), + dt_reset(1), + init_phase(true), + dt_valid(0), + v_t(0,0,0), + v_r(0,0,0) +{ + X_CM.t[2] = 1000; // default position: 1 m away from cam; +} + +void PointTracker::reset() +{ + // enter init phase and reset velocities + init_phase = true; + dt_valid = 0; + reset_velocities(); +} + +void PointTracker::reset_velocities() +{ + v_t = Vec3f(0,0,0); + v_r = Vec3f(0,0,0); +} + + +bool PointTracker::track(const vector<Vec2f>& points, float f, float dt) +{ + if (!dynamic_pose_resolution) init_phase = true; + + dt_valid += dt; + // if there was no valid tracking result for too long, do a reset + if (dt_valid > dt_reset) + { + //qDebug()<<"dt_valid "<<dt_valid<<" > dt_reset "<<dt_reset; + reset(); + } + + bool no_model = +#ifdef OPENTRACK_API + point_model.get() == NULL; +#else + !point_model; +#endif + + // if there is a pointtracking problem, reset the velocities + if (no_model || points.size() != PointModel::N_POINTS) + { + //qDebug()<<"Wrong number of points!"; + reset_velocities(); + return false; + } + + X_CM_old = X_CM; // backup old transformation for velocity calculation + + if (!init_phase) + predict(dt_valid); + + // if there is a point correspondence problem something has gone wrong, do a reset + if (!find_correspondences(points, f)) + { + //qDebug()<<"Error in finding point correspondences!"; + X_CM = X_CM_old; // undo prediction + reset(); + return false; + } + + (void) POSIT(f); + //qDebug()<<"Number of POSIT iterations: "<<n_iter; + + if (!init_phase) + update_velocities(dt_valid); + + // we have a valid tracking result, leave init phase and reset time since valid result + init_phase = false; + dt_valid = 0; + return true; +} + +void PointTracker::predict(float dt) +{ + // predict with constant velocity + Matx33f R; + Rodrigues(dt*v_r, R); + X_CM.R = R*X_CM.R; + X_CM.t += dt * v_t; +} + +void PointTracker::update_velocities(float dt) +{ + // update velocities + Rodrigues(X_CM.R*X_CM_old.R.t(), v_r); + v_r /= dt; + v_t = (X_CM.t - X_CM_old.t)/dt; +} + +bool PointTracker::find_correspondences(const vector<Vec2f>& points, float f) +{ + if (init_phase) { + // We do a simple freetrack-like sorting in the init phase... + // sort points + int point_d_order[PointModel::N_POINTS]; + point_model->get_d_order(points, point_d_order); + + // set correspondences + for (int i=0; i<PointModel::N_POINTS; ++i) + { + p[point_model->d_order[i]] = points[point_d_order[i]]; + } + } + else { + // ... otherwise we look at the distance to the projection of the expected model points + // project model points under current pose + p_exp[0] = project(Vec3f(0,0,0), f); + p_exp[1] = project(point_model->M01, f); + p_exp[2] = project(point_model->M02, f); + + // set correspondences by minimum distance to projected model point + bool point_taken[PointModel::N_POINTS]; + for (int i=0; i<PointModel::N_POINTS; ++i) + point_taken[i] = false; + + float min_sdist = 0; + int min_idx = 0; + + for (int i=0; i<PointModel::N_POINTS; ++i) + { + // find closest point to projected model point i + for (int j=0; j<PointModel::N_POINTS; ++j) + { + Vec2f d = p_exp[i]-points[j]; + float sdist = d.dot(d); + if (sdist < min_sdist || j==0) + { + min_idx = j; + min_sdist = sdist; + } + } + // if one point is closest to more than one model point, abort + if (point_taken[min_idx]) return false; + point_taken[min_idx] = true; + p[i] = points[min_idx]; + } + } + return true; +} + + + +int PointTracker::POSIT(float f) +{ + // POSIT algorithm for coplanar points as presented in + // [Denis Oberkampf, Daniel F. DeMenthon, Larry S. Davis: "Iterative Pose Estimation Using Coplanar Feature Points"] + // we use the same notation as in the paper here + + // The expected rotation used for resolving the ambiguity in POSIT: + // In every iteration step the rotation closer to R_expected is taken + Matx33f R_expected; + if (init_phase) + R_expected = Matx33f::eye(); // in the init phase, we want to be close to the default pose = no rotation + else + R_expected = X_CM.R; // later we want to be close to the last (predicted) rotation + + // initial pose = last (predicted) pose + Vec3f k; + get_row(R_expected, 2, k); + float Z0 = init_phase ? 1000 : X_CM.t[2]; + + float old_epsilon_1 = 0; + float old_epsilon_2 = 0; + float epsilon_1 = 1; + float epsilon_2 = 1; + + Vec3f I0, J0; + Vec2f I0_coeff, J0_coeff; + + Vec3f I_1, J_1, I_2, J_2; + Matx33f R_1, R_2; + Matx33f* R_current; + + const int MAX_ITER = 100; + const float EPS_THRESHOLD = 1e-4; + + int i=1; + for (; i<MAX_ITER; ++i) + { + epsilon_1 = k.dot(point_model->M01)/Z0; + epsilon_2 = k.dot(point_model->M02)/Z0; + + // vector of scalar products <I0, M0i> and <J0, M0i> + Vec2f I0_M0i(p[1][0]*(1.0 + epsilon_1) - p[0][0], + p[2][0]*(1.0 + epsilon_2) - p[0][0]); + Vec2f J0_M0i(p[1][1]*(1.0 + epsilon_1) - p[0][1], + p[2][1]*(1.0 + epsilon_2) - p[0][1]); + + // construct projection of I, J onto M0i plane: I0 and J0 + I0_coeff = point_model->P * I0_M0i; + J0_coeff = point_model->P * J0_M0i; + I0 = I0_coeff[0]*point_model->M01 + I0_coeff[1]*point_model->M02; + J0 = J0_coeff[0]*point_model->M01 + J0_coeff[1]*point_model->M02; + + // calculate u component of I, J + float II0 = I0.dot(I0); + float IJ0 = I0.dot(J0); + float JJ0 = J0.dot(J0); + float rho, theta; + if (JJ0 == II0) { + rho = sqrt(abs(2*IJ0)); + theta = -PI/4; + if (IJ0<0) theta *= -1; + } + else { + rho = sqrt(sqrt( (JJ0-II0)*(JJ0-II0) + 4*IJ0*IJ0 )); + theta = atan( -2*IJ0 / (JJ0-II0) ); + if (JJ0 - II0 < 0) theta += PI; + theta /= 2; + } + + // construct the two solutions + I_1 = I0 + rho*cos(theta)*point_model->u; + I_2 = I0 - rho*cos(theta)*point_model->u; + + J_1 = J0 + rho*sin(theta)*point_model->u; + J_2 = J0 - rho*sin(theta)*point_model->u; + + float norm_const = 1.0/norm(I_1); // all have the same norm + + // create rotation matrices + I_1 *= norm_const; J_1 *= norm_const; + I_2 *= norm_const; J_2 *= norm_const; + + set_row(R_1, 0, I_1); + set_row(R_1, 1, J_1); + set_row(R_1, 2, I_1.cross(J_1)); + + set_row(R_2, 0, I_2); + set_row(R_2, 1, J_2); + set_row(R_2, 2, I_2.cross(J_2)); + + // the single translation solution + Z0 = norm_const * f; + + // pick the rotation solution closer to the expected one + // in simple metric d(A,B) = || I - A * B^T || + float R_1_deviation = norm(Matx33f::eye() - R_expected * R_1.t()); + float R_2_deviation = norm(Matx33f::eye() - R_expected * R_2.t()); + + if (R_1_deviation < R_2_deviation) + R_current = &R_1; + else + R_current = &R_2; + + get_row(*R_current, 2, k); + + // check for convergence condition + if (abs(epsilon_1 - old_epsilon_1) + abs(epsilon_2 - old_epsilon_2) < EPS_THRESHOLD) + break; + old_epsilon_1 = epsilon_1; + old_epsilon_2 = epsilon_2; + } + + // apply results + X_CM.R = *R_current; + X_CM.t[0] = p[0][0] * Z0/f; + X_CM.t[1] = p[0][1] * Z0/f; + X_CM.t[2] = Z0; + + return i; + + //Rodrigues(X_CM.R, r); + //qDebug()<<"iter: "<<i; + //qDebug()<<"t: "<<X_CM.t[0]<<' '<<X_CM.t[1]<<' '<<X_CM.t[2]; + //Vec3f r; + // + //qDebug()<<"r: "<<r[0]<<' '<<r[1]<<' '<<r[2]<<'\n'; +} diff --git a/ftnoir_tracker_pt/point_tracker.h b/ftnoir_tracker_pt/point_tracker.h index 3ff9c724..512681fc 100644 --- a/ftnoir_tracker_pt/point_tracker.h +++ b/ftnoir_tracker_pt/point_tracker.h @@ -1,129 +1,129 @@ -/* Copyright (c) 2012 Patrick Ruoff
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- */
-
-#ifndef POINTTRACKER_H
-#define POINTTRACKER_H
-
-#include <opencv2/opencv.hpp>
-#ifndef OPENTRACK_API
-# include <boost/shared_ptr.hpp>
-#else
+/* Copyright (c) 2012 Patrick Ruoff + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + */ + +#ifndef POINTTRACKER_H +#define POINTTRACKER_H + +#include <opencv2/opencv.hpp> +#ifndef OPENTRACK_API +# include <boost/shared_ptr.hpp> +#else # include <memory> -#endif
-#include <list>
-
-// ----------------------------------------------------------------------------
-// Affine frame trafo
-class FrameTrafo
-{
-public:
- FrameTrafo() : R(cv::Matx33f::eye()), t(0,0,0) {}
- FrameTrafo(const cv::Matx33f& R, const cv::Vec3f& t) : R(R),t(t) {}
-
- cv::Matx33f R;
- cv::Vec3f t;
-};
-
-inline FrameTrafo operator*(const FrameTrafo& X, const FrameTrafo& Y)
-{
- return FrameTrafo(X.R*Y.R, X.R*Y.t + X.t);
-}
-
-inline FrameTrafo operator*(const cv::Matx33f& X, const FrameTrafo& Y)
-{
- return FrameTrafo(X*Y.R, X*Y.t);
-}
-
-inline FrameTrafo operator*(const FrameTrafo& X, const cv::Matx33f& Y)
-{
- return FrameTrafo(X.R*Y, X.t);
-}
-
-inline cv::Vec3f operator*(const FrameTrafo& X, const cv::Vec3f& v)
-{
- return X.R*v + X.t;
-}
-
-
-// ----------------------------------------------------------------------------
-// Describes a 3-point model
-// nomenclature as in
-// [Denis Oberkampf, Daniel F. DeMenthon, Larry S. Davis: "Iterative Pose Estimation Using Coplanar Feature Points"]
-class PointModel
-{
- friend class PointTracker;
-public:
- static const int N_POINTS = 3;
-
- PointModel(cv::Vec3f M01, cv::Vec3f M02);
-
- const cv::Vec3f& get_M01() const { return M01; };
- const cv::Vec3f& get_M02() const { return M02; };
-
-protected:
- cv::Vec3f M01; // M01 in model frame
- cv::Vec3f M02; // M02 in model frame
-
- cv::Vec3f u; // unit vector perpendicular to M01,M02-plane
-
- cv::Matx22f P;
-
- cv::Vec2f d; // discriminant vector for point correspondence
- int d_order[3]; // sorting of projected model points with respect to d scalar product
-
- void get_d_order(const std::vector<cv::Vec2f>& points, int d_order[]) const;
-};
-
-// ----------------------------------------------------------------------------
-// Tracks a 3-point model
-// implementing the POSIT algorithm for coplanar points as presented in
-// [Denis Oberkampf, Daniel F. DeMenthon, Larry S. Davis: "Iterative Pose Estimation Using Coplanar Feature Points"]
-class PointTracker
-{
-public:
- PointTracker();
-
- // 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
- bool track(const std::vector<cv::Vec2f>& points, float f, float dt);
- std::shared_ptr<PointModel> point_model;
-
- bool dynamic_pose_resolution;
- float dt_reset;
-
- FrameTrafo get_pose() const { return X_CM; }
- void reset();
-
-protected:
- inline cv::Vec2f project(const cv::Vec3f& v_M, float f)
- {
- cv::Vec3f v_C = X_CM * v_M;
- return cv::Vec2f(f*v_C[0]/v_C[2], f*v_C[1]/v_C[2]);
- }
-
- bool find_correspondences(const std::vector<cv::Vec2f>& points, float f);
-
- cv::Vec2f p[PointModel::N_POINTS]; // the points in model order
- cv::Vec2f p_exp[PointModel::N_POINTS]; // the expected point positions
-
- void predict(float dt);
- void update_velocities(float dt);
- void reset_velocities();
-
-
- int POSIT(float f); // The POSIT algorithm, returns the number of iterations
-
- bool init_phase;
- float dt_valid; // time since last valid tracking result
- cv::Vec3f v_t; // velocities
- cv::Vec3f v_r;
- FrameTrafo X_CM; // trafo from model to camera
- FrameTrafo X_CM_old;
-};
-
-#endif //POINTTRACKER_H
+#endif +#include <list> + +// ---------------------------------------------------------------------------- +// Affine frame trafo +class FrameTrafo +{ +public: + FrameTrafo() : R(cv::Matx33f::eye()), t(0,0,0) {} + FrameTrafo(const cv::Matx33f& R, const cv::Vec3f& t) : R(R),t(t) {} + + cv::Matx33f R; + cv::Vec3f t; +}; + +inline FrameTrafo operator*(const FrameTrafo& X, const FrameTrafo& Y) +{ + return FrameTrafo(X.R*Y.R, X.R*Y.t + X.t); +} + +inline FrameTrafo operator*(const cv::Matx33f& X, const FrameTrafo& Y) +{ + return FrameTrafo(X*Y.R, X*Y.t); +} + +inline FrameTrafo operator*(const FrameTrafo& X, const cv::Matx33f& Y) +{ + return FrameTrafo(X.R*Y, X.t); +} + +inline cv::Vec3f operator*(const FrameTrafo& X, const cv::Vec3f& v) +{ + return X.R*v + X.t; +} + + +// ---------------------------------------------------------------------------- +// Describes a 3-point model +// nomenclature as in +// [Denis Oberkampf, Daniel F. DeMenthon, Larry S. Davis: "Iterative Pose Estimation Using Coplanar Feature Points"] +class PointModel +{ + friend class PointTracker; +public: + static const int N_POINTS = 3; + + PointModel(cv::Vec3f M01, cv::Vec3f M02); + + const cv::Vec3f& get_M01() const { return M01; }; + const cv::Vec3f& get_M02() const { return M02; }; + +protected: + cv::Vec3f M01; // M01 in model frame + cv::Vec3f M02; // M02 in model frame + + cv::Vec3f u; // unit vector perpendicular to M01,M02-plane + + cv::Matx22f P; + + cv::Vec2f d; // discriminant vector for point correspondence + int d_order[3]; // sorting of projected model points with respect to d scalar product + + void get_d_order(const std::vector<cv::Vec2f>& points, int d_order[]) const; +}; + +// ---------------------------------------------------------------------------- +// Tracks a 3-point model +// implementing the POSIT algorithm for coplanar points as presented in +// [Denis Oberkampf, Daniel F. DeMenthon, Larry S. Davis: "Iterative Pose Estimation Using Coplanar Feature Points"] +class PointTracker +{ +public: + PointTracker(); + + // 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 + bool track(const std::vector<cv::Vec2f>& points, float f, float dt); + std::shared_ptr<PointModel> point_model; + + bool dynamic_pose_resolution; + float dt_reset; + + FrameTrafo get_pose() const { return X_CM; } + void reset(); + +protected: + inline cv::Vec2f project(const cv::Vec3f& v_M, float f) + { + cv::Vec3f v_C = X_CM * v_M; + return cv::Vec2f(f*v_C[0]/v_C[2], f*v_C[1]/v_C[2]); + } + + bool find_correspondences(const std::vector<cv::Vec2f>& points, float f); + + cv::Vec2f p[PointModel::N_POINTS]; // the points in model order + cv::Vec2f p_exp[PointModel::N_POINTS]; // the expected point positions + + void predict(float dt); + void update_velocities(float dt); + void reset_velocities(); + + + int POSIT(float f); // The POSIT algorithm, returns the number of iterations + + bool init_phase; + float dt_valid; // time since last valid tracking result + cv::Vec3f v_t; // velocities + cv::Vec3f v_r; + FrameTrafo X_CM; // trafo from model to camera + FrameTrafo X_CM_old; +}; + +#endif //POINTTRACKER_H diff --git a/ftnoir_tracker_pt/pt_video_widget.cpp b/ftnoir_tracker_pt/pt_video_widget.cpp index 02817cbf..cb3dc48e 100644 --- a/ftnoir_tracker_pt/pt_video_widget.cpp +++ b/ftnoir_tracker_pt/pt_video_widget.cpp @@ -1,64 +1,64 @@ -/* Copyright (c) 2012 Patrick Ruoff
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * 20130312, WVR: Add 7 lines to resizeGL after resize_frame. This should lower CPU-load.
- */
-
-#include "pt_video_widget.h"
-
-#include <QDebug>
-#include <QHBoxLayout>
-
-using namespace cv;
-using namespace std;
-
-void PTVideoWidget::update_image(const cv::Mat& frame)
-{
- QMutexLocker foo(&mtx);
- _frame = frame.clone();
- freshp = true;
-}
-
-// ----------------------------------------------------------------------------
-VideoWidgetDialog::VideoWidgetDialog(QWidget *parent, FrameProvider* provider)
- : QDialog(parent),
- video_widget(NULL)
-{
- const int VIDEO_FRAME_WIDTH = 640;
- const int VIDEO_FRAME_HEIGHT = 480;
-
- video_widget = new PTVideoWidget(this, provider);
-
- QHBoxLayout* layout = new QHBoxLayout();
- layout->setContentsMargins(0, 0, 0, 0);
- layout->addWidget(video_widget);
- if (this->layout()) delete this->layout();
- setLayout(layout);
- resize(VIDEO_FRAME_WIDTH, VIDEO_FRAME_HEIGHT);
-}
-
-void PTVideoWidget::update_and_repaint()
-{
- QMutexLocker foo(&mtx);
- if (_frame.empty() || !freshp)
- return;
- freshp = false;
- QImage qframe = QImage(_frame.cols, _frame.rows, QImage::Format_RGB888);
- uchar* data = qframe.bits();
- const int pitch = qframe.bytesPerLine();
- for (int y = 0; y < _frame.rows; y++)
- for (int x = 0; x < _frame.cols; x++)
- {
- const auto& elt = _frame.at<Vec3b>(y, x);
- const cv::Scalar elt2 = static_cast<cv::Scalar>(elt);
- data[y * pitch + x * 3 + 0] = elt2.val[2];
- data[y * pitch + x * 3 + 1] = elt2.val[1];
- data[y * pitch + x * 3 + 2] = elt2.val[0];
- }
- qframe = qframe.scaled(size(), Qt::IgnoreAspectRatio, Qt::FastTransformation);
- texture = qframe;
- update();
-}
+/* Copyright (c) 2012 Patrick Ruoff + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * 20130312, WVR: Add 7 lines to resizeGL after resize_frame. This should lower CPU-load. + */ + +#include "pt_video_widget.h" + +#include <QDebug> +#include <QHBoxLayout> + +using namespace cv; +using namespace std; + +void PTVideoWidget::update_image(const cv::Mat& frame) +{ + QMutexLocker foo(&mtx); + _frame = frame.clone(); + freshp = true; +} + +// ---------------------------------------------------------------------------- +VideoWidgetDialog::VideoWidgetDialog(QWidget *parent, FrameProvider* provider) + : QDialog(parent), + video_widget(NULL) +{ + const int VIDEO_FRAME_WIDTH = 640; + const int VIDEO_FRAME_HEIGHT = 480; + + video_widget = new PTVideoWidget(this, provider); + + QHBoxLayout* layout = new QHBoxLayout(); + layout->setContentsMargins(0, 0, 0, 0); + layout->addWidget(video_widget); + if (this->layout()) delete this->layout(); + setLayout(layout); + resize(VIDEO_FRAME_WIDTH, VIDEO_FRAME_HEIGHT); +} + +void PTVideoWidget::update_and_repaint() +{ + QMutexLocker foo(&mtx); + if (_frame.empty() || !freshp) + return; + freshp = false; + QImage qframe = QImage(_frame.cols, _frame.rows, QImage::Format_RGB888); + uchar* data = qframe.bits(); + const int pitch = qframe.bytesPerLine(); + for (int y = 0; y < _frame.rows; y++) + for (int x = 0; x < _frame.cols; x++) + { + const auto& elt = _frame.at<Vec3b>(y, x); + const cv::Scalar elt2 = static_cast<cv::Scalar>(elt); + data[y * pitch + x * 3 + 0] = elt2.val[2]; + data[y * pitch + x * 3 + 1] = elt2.val[1]; + data[y * pitch + x * 3 + 2] = elt2.val[0]; + } + qframe = qframe.scaled(size(), Qt::IgnoreAspectRatio, Qt::FastTransformation); + texture = qframe; + update(); +} diff --git a/ftnoir_tracker_pt/pt_video_widget.h b/ftnoir_tracker_pt/pt_video_widget.h index f7de4db8..1be5f5f2 100644 --- a/ftnoir_tracker_pt/pt_video_widget.h +++ b/ftnoir_tracker_pt/pt_video_widget.h @@ -1,71 +1,71 @@ -/* Copyright (c) 2012 Patrick Ruoff
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- */
-
-#pragma once
-
-#include "frame_observer.h"
-#include <QObject>
-#include <QTime>
-#include <QDialog>
-#include <opencv2/opencv.hpp>
-#ifndef OPENTRACK_API
-# include <QGLWidget>
-# include <boost/shared_ptr.hpp>
-#else
+/* Copyright (c) 2012 Patrick Ruoff + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + */ + +#pragma once + +#include "frame_observer.h" +#include <QObject> +#include <QTime> +#include <QDialog> +#include <opencv2/opencv.hpp> +#ifndef OPENTRACK_API +# include <QGLWidget> +# include <boost/shared_ptr.hpp> +#else # include <memory> -# if defined(_WIN32)
-# include <dshow.h>
-# endif
-#endif
-#include <QPainter>
-#include <QPaintEvent>
-#include <QTimer>
-
-class PTVideoWidget : public QWidget, public FrameObserver
-{
- Q_OBJECT
-
-public:
- PTVideoWidget(QWidget *parent, FrameProvider* provider) :
- QWidget(parent),
- /* to avoid linker errors */ FrameObserver(provider),
- freshp(false)
- {
- connect(&timer, SIGNAL(timeout()), this, SLOT(update_and_repaint()));
- timer.start(40);
- }
- void update_image(const cv::Mat &frame);
- void update_frame_and_points() {}
-protected slots:
- void paintEvent( QPaintEvent* e ) {
- QMutexLocker foo(&mtx);
- QPainter painter(this);
- painter.drawImage(e->rect(), texture);
- }
- void update_and_repaint();
-private:
- QMutex mtx;
- QImage texture;
- QTimer timer;
- cv::Mat _frame;
- bool freshp;
-};
-
-// ----------------------------------------------------------------------------
-// A VideoWidget embedded in a dialog frame
-class VideoWidgetDialog : public QDialog
-{
- Q_OBJECT
-public:
- VideoWidgetDialog(QWidget *parent, FrameProvider* provider);
- virtual ~VideoWidgetDialog() {}
-
- PTVideoWidget* get_video_widget() { return video_widget; }
-
-private:
- PTVideoWidget* video_widget;
-};
+# if defined(_WIN32) +# include <dshow.h> +# endif +#endif +#include <QPainter> +#include <QPaintEvent> +#include <QTimer> + +class PTVideoWidget : public QWidget, public FrameObserver +{ + Q_OBJECT + +public: + PTVideoWidget(QWidget *parent, FrameProvider* provider) : + QWidget(parent), + /* to avoid linker errors */ FrameObserver(provider), + freshp(false) + { + connect(&timer, SIGNAL(timeout()), this, SLOT(update_and_repaint())); + timer.start(40); + } + void update_image(const cv::Mat &frame); + void update_frame_and_points() {} +protected slots: + void paintEvent( QPaintEvent* e ) { + QMutexLocker foo(&mtx); + QPainter painter(this); + painter.drawImage(e->rect(), texture); + } + void update_and_repaint(); +private: + QMutex mtx; + QImage texture; + QTimer timer; + cv::Mat _frame; + bool freshp; +}; + +// ---------------------------------------------------------------------------- +// A VideoWidget embedded in a dialog frame +class VideoWidgetDialog : public QDialog +{ + Q_OBJECT +public: + VideoWidgetDialog(QWidget *parent, FrameProvider* provider); + virtual ~VideoWidgetDialog() {} + + PTVideoWidget* get_video_widget() { return video_widget; } + +private: + PTVideoWidget* video_widget; +}; diff --git a/ftnoir_tracker_pt/trans_calib.cpp b/ftnoir_tracker_pt/trans_calib.cpp index 9b75a1b6..729a0b7f 100644 --- a/ftnoir_tracker_pt/trans_calib.cpp +++ b/ftnoir_tracker_pt/trans_calib.cpp @@ -1,44 +1,44 @@ -/* Copyright (c) 2012 Patrick Ruoff
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- */
-
-#include "trans_calib.h"
-
-using namespace cv;
-
-//-----------------------------------------------------------------------------
-TranslationCalibrator::TranslationCalibrator()
-{
- reset();
-}
-
-void TranslationCalibrator::reset()
-{
- P = Matx66f::zeros();
- y = Vec6f(0,0,0, 0,0,0);
-}
-
-void TranslationCalibrator::update(const Matx33f& R_CM_k, const Vec3f& t_CM_k)
-{
- Matx<float, 6,3> H_k_T = Matx<float, 6,3>::zeros();
- for (int i=0; i<3; ++i) {
- for (int j=0; j<3; ++j) {
- H_k_T(i,j) = R_CM_k(j,i);
- }
- }
- for (int i=0; i<3; ++i)
- {
- H_k_T(3+i,i) = 1.0;
- }
- P += H_k_T * H_k_T.t();
- y += H_k_T * t_CM_k;
-}
-
-Vec3f TranslationCalibrator::get_estimate()
-{
- Vec6f x = P.inv() * y;
- return Vec3f(-x[0], -x[1], -x[2]);
+/* Copyright (c) 2012 Patrick Ruoff + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + */ + +#include "trans_calib.h" + +using namespace cv; + +//----------------------------------------------------------------------------- +TranslationCalibrator::TranslationCalibrator() +{ + reset(); +} + +void TranslationCalibrator::reset() +{ + P = Matx66f::zeros(); + y = Vec6f(0,0,0, 0,0,0); +} + +void TranslationCalibrator::update(const Matx33f& R_CM_k, const Vec3f& t_CM_k) +{ + Matx<float, 6,3> H_k_T = Matx<float, 6,3>::zeros(); + for (int i=0; i<3; ++i) { + for (int j=0; j<3; ++j) { + H_k_T(i,j) = R_CM_k(j,i); + } + } + for (int i=0; i<3; ++i) + { + H_k_T(3+i,i) = 1.0; + } + P += H_k_T * H_k_T.t(); + y += H_k_T * t_CM_k; +} + +Vec3f TranslationCalibrator::get_estimate() +{ + Vec6f x = P.inv() * y; + return Vec3f(-x[0], -x[1], -x[2]); }
\ No newline at end of file diff --git a/ftnoir_tracker_pt/trans_calib.h b/ftnoir_tracker_pt/trans_calib.h index f2521690..609c9af1 100644 --- a/ftnoir_tracker_pt/trans_calib.h +++ b/ftnoir_tracker_pt/trans_calib.h @@ -1,39 +1,39 @@ -/* Copyright (c) 2012 Patrick Ruoff
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- */
-
-#ifndef TRANSCALIB_H
-#define TRANSCALIB_H
-
-#include <opencv2/opencv.hpp>
-
-//-----------------------------------------------------------------------------
-// Calibrates the translation from head to model = t_MH
-// by recursive least squares /
-// kalman filter in information form with identity noise covariance
-// measurement equation when head position = t_CH is fixed:
-// (R_CM_k , Id)*(-t_MH, t_CH) = t_CM_k
-
-class TranslationCalibrator
-{
-public:
- TranslationCalibrator();
-
- // reset the calibration process
- void reset();
-
- // update the current estimate
- void update(const cv::Matx33f& R_CM_k, const cv::Vec3f& t_CM_k);
-
- // get the current estimate for t_MH
- cv::Vec3f get_estimate();
-
-protected:
- cv::Matx66f P; // normalized precision matrix = inverse covariance
- cv::Vec6f y; // P*(-t_MH, t_CH)
-};
-
+/* Copyright (c) 2012 Patrick Ruoff + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + */ + +#ifndef TRANSCALIB_H +#define TRANSCALIB_H + +#include <opencv2/opencv.hpp> + +//----------------------------------------------------------------------------- +// Calibrates the translation from head to model = t_MH +// by recursive least squares / +// kalman filter in information form with identity noise covariance +// measurement equation when head position = t_CH is fixed: +// (R_CM_k , Id)*(-t_MH, t_CH) = t_CM_k + +class TranslationCalibrator +{ +public: + TranslationCalibrator(); + + // reset the calibration process + void reset(); + + // update the current estimate + void update(const cv::Matx33f& R_CM_k, const cv::Vec3f& t_CM_k); + + // get the current estimate for t_MH + cv::Vec3f get_estimate(); + +protected: + cv::Matx66f P; // normalized precision matrix = inverse covariance + cv::Vec6f y; // P*(-t_MH, t_CH) +}; + #endif //TRANSCALIB_H
\ No newline at end of file |