diff options
Diffstat (limited to 'FTNoIR_Tracker_PT')
40 files changed, 5211 insertions, 0 deletions
diff --git a/FTNoIR_Tracker_PT/FTNoIR_PT_Controls.ui b/FTNoIR_Tracker_PT/FTNoIR_PT_Controls.ui new file mode 100644 index 00000000..7bb7eb50 --- /dev/null +++ b/FTNoIR_Tracker_PT/FTNoIR_PT_Controls.ui @@ -0,0 +1,1856 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>UICPTClientControls</class>
+ <widget class="QWidget" name="UICPTClientControls">
+ <property name="windowModality">
+ <enum>Qt::ApplicationModal</enum>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>395</width>
+ <height>552</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/icon.ico</normaloff>:/Resources/icon.ico</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="QVBoxLayout" name="verticalLayout_6">
+ <item>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="1" column="0">
+ <widget class="QCheckBox" name="dynpose_check">
+ <property name="toolTip">
+ <string/>
+ </property>
+ <property name="text">
+ <string>Dynamic Pose Resolution</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2">
+ <widget class="QLabel" name="label_39">
+ <property name="text">
+ <string>Sleep time</string>
+ </property>
+ <property name="buddy">
+ <cstring>sleep_spin</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="3">
+ <layout class="QHBoxLayout" name="horizontalLayout_11">
+ <item>
+ <widget class="QSpinBox" name="sleep_spin">
+ <property name="toolTip">
+ <string>Time the tracker thread sleeps after each processed frame</string>
+ </property>
+ <property name="suffix">
+ <string/>
+ </property>
+ <property name="maximum">
+ <number>9999</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_40">
+ <property name="text">
+ <string>ms</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="2">
+ <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="1" column="3">
+ <layout class="QHBoxLayout" name="horizontalLayout_12">
+ <item>
+ <widget class="QSpinBox" name="reset_spin">
+ <property name="toolTip">
+ <string>Time until automatic reset of tracker's internal state when no valid tracking result is found</string>
+ </property>
+ <property name="maximum">
+ <number>9999</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_42">
+ <property name="text">
+ <string>ms</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="0" column="0">
+ <widget class="QCheckBox" name="videowidget_check">
+ <property name="toolTip">
+ <string>Whether to update the content of the VideoWidget</string>
+ </property>
+ <property name="text">
+ <string>Show VideoWidget</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <spacer name="horizontalSpacer_7">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>30</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="0" column="1">
+ <spacer name="horizontalSpacer_11">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>30</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="2" column="0">
+ <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>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox_3">
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>85</height>
+ </size>
+ </property>
+ <property name="title">
+ <string>Enable Axis</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_5">
+ <item>
+ <layout class="QGridLayout" name="gridLayout_2">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_6">
+ <property name="text">
+ <string>Roll:</string>
+ </property>
+ <property name="buddy">
+ <cstring>chkEnableRoll</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_9">
+ <property name="text">
+ <string>Pitch:</string>
+ </property>
+ <property name="buddy">
+ <cstring>chkEnablePitch</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_11">
+ <property name="text">
+ <string>Yaw:</string>
+ </property>
+ <property name="buddy">
+ <cstring>chkEnableYaw</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QCheckBox" name="chkEnableRoll">
+ <property name="maximumSize">
+ <size>
+ <width>20</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="layoutDirection">
+ <enum>Qt::LeftToRight</enum>
+ </property>
+ <property name="styleSheet">
+ <string notr="true"/>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QCheckBox" name="chkEnablePitch">
+ <property name="maximumSize">
+ <size>
+ <width>20</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="layoutDirection">
+ <enum>Qt::LeftToRight</enum>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QCheckBox" name="chkEnableYaw">
+ <property name="maximumSize">
+ <size>
+ <width>20</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="layoutDirection">
+ <enum>Qt::LeftToRight</enum>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="3">
+ <widget class="QLabel" name="label_14">
+ <property name="text">
+ <string>X:</string>
+ </property>
+ <property name="buddy">
+ <cstring>chkEnableX</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="4">
+ <widget class="QCheckBox" name="chkEnableX">
+ <property name="maximumSize">
+ <size>
+ <width>20</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="layoutDirection">
+ <enum>Qt::LeftToRight</enum>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="3">
+ <widget class="QLabel" name="label_15">
+ <property name="text">
+ <string>Y:</string>
+ </property>
+ <property name="buddy">
+ <cstring>chkEnableY</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="4">
+ <widget class="QCheckBox" name="chkEnableY">
+ <property name="maximumSize">
+ <size>
+ <width>20</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="layoutDirection">
+ <enum>Qt::LeftToRight</enum>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="3">
+ <widget class="QLabel" name="label_16">
+ <property name="text">
+ <string>Z:</string>
+ </property>
+ <property name="buddy">
+ <cstring>chkEnableZ</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="4">
+ <widget class="QCheckBox" name="chkEnableZ">
+ <property name="maximumSize">
+ <size>
+ <width>20</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="layoutDirection">
+ <enum>Qt::LeftToRight</enum>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2">
+ <spacer name="horizontalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Minimum</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="2">
+ <spacer name="horizontalSpacer_5">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Minimum</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="2" column="2">
+ <spacer name="horizontalSpacer_8">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Minimum</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_4">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </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>
+ <widget class="QPushButton" name="videowidget_button">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>130</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="locale">
+ <locale language="English" country="UnitedStates"/>
+ </property>
+ <property name="text">
+ <string>VideoWidget</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_12">
+ <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>
+ <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_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>
+ <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>videowidget_check</tabstop>
+ <tabstop>sleep_spin</tabstop>
+ <tabstop>dynpose_check</tabstop>
+ <tabstop>reset_spin</tabstop>
+ <tabstop>reset_button</tabstop>
+ <tabstop>chkEnableRoll</tabstop>
+ <tabstop>chkEnablePitch</tabstop>
+ <tabstop>chkEnableYaw</tabstop>
+ <tabstop>chkEnableX</tabstop>
+ <tabstop>chkEnableY</tabstop>
+ <tabstop>chkEnableZ</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/FTNoIR_Tracker_PT.rc b/FTNoIR_Tracker_PT/FTNoIR_Tracker_PT.rc new file mode 100644 index 00000000..11c5d52f --- /dev/null +++ b/FTNoIR_Tracker_PT/FTNoIR_Tracker_PT.rc @@ -0,0 +1,61 @@ +// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+LANGUAGE 9, 1
+#pragma code_page(1252)
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/FTNoIR_Tracker_PT/FTNoIR_Tracker_PT_vc10.vcxproj b/FTNoIR_Tracker_PT/FTNoIR_Tracker_PT_vc10.vcxproj new file mode 100644 index 00000000..b777077b --- /dev/null +++ b/FTNoIR_Tracker_PT/FTNoIR_Tracker_PT_vc10.vcxproj @@ -0,0 +1,212 @@ +<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Template|Win32">
+ <Configuration>Template</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectName>FTNoIR_Tracker_PT</ProjectName>
+ <ProjectGuid>{7A2A2560-9253-4CC8-A9D5-4B9D9C224D9D}</ProjectGuid>
+ <RootNamespace>FTNoIR_Tracker_PT</RootNamespace>
+ <Keyword>Qt4VSv1.0</Keyword>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)\bin\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)\$(Configuration)\</IntDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)/bin_dbg\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)\$(Configuration)\</IntDir>
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Template|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Template|Win32'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Template|Win32'" />
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <Optimization>MaxSpeed</Optimization>
+ <AdditionalIncludeDirectories>.;.\GeneratedFiles;.\GeneratedFiles\$(Configuration);$(QTDIR)\include;$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(OPENCV_DIR)\include;$(BOOST_DIR);$(QTDIR)\include\QtOpenGL;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>UNICODE;WIN32;QT_DLL;QT_NO_DEBUG;NDEBUG;QT_CORE_LIB;QT_GUI_LIB;FTNOIR_TRACKER_BASE_LIB;QT_OPENGL_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <TreatWChar_tAsBuiltInType>false</TreatWChar_tAsBuiltInType>
+ <DebugInformationFormat>
+ </DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>qtmain.lib;QtCore4.lib;QtGui4.lib;QtOpenGL4.lib;opengl32.lib;glu32.lib;opencv_core242.lib;opencv_imgproc242.lib;opencv_calib3d242.lib;videoInput_vc10.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(ProjectName).dll</OutputFile>
+ <AdditionalLibraryDirectories>$(QTDIR)\lib;$(OPENCV_DIR)\x86\vc10\lib;$(ProjectDir)\videoInput;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <IgnoreSpecificDefaultLibraries>atlthunk.lib;libcmt;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <SubSystem>Windows</SubSystem>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>.;.\GeneratedFiles;.\GeneratedFiles\$(Configuration);$(QTDIR)\include;$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(OPENCV_DIR)\include;$(BOOST_DIR);$(QTDIR)\include\QtOpenGL;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>UNICODE;WIN32;QT_DLL;QT_CORE_LIB;QT_GUI_LIB;FTNOIR_TRACKER_BASE_LIB;QT_OPENGL_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <TreatWChar_tAsBuiltInType>false</TreatWChar_tAsBuiltInType>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>qtmaind.lib;QtCored4.lib;QtGuid4.lib;QtOpenGLd4.lib;opengl32.lib;glu32.lib;opencv_core242d.lib;opencv_imgproc242d.lib;opencv_calib3d242d.lib;videoInput_vc10.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(ProjectName).dll</OutputFile>
+ <AdditionalLibraryDirectories>$(QTDIR)\lib;$(OPENCV_DIR)\x86\vc10\lib;$(ProjectDir)\videoInput;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <IgnoreSpecificDefaultLibraries>atlthunk.lib;libcmt;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Windows</SubSystem>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="camera.cpp" />
+ <ClCompile Include="frame_observer.cpp" />
+ <ClCompile Include="ftnoir_tracker_pt.cpp" />
+ <ClCompile Include="ftnoir_tracker_pt_dialog.cpp" />
+ <ClCompile Include="ftnoir_tracker_pt_dll.cpp" />
+ <ClCompile Include="ftnoir_tracker_pt_settings.cpp" />
+ <ClCompile Include="point_extractor.cpp" />
+ <ClCompile Include="point_tracker.cpp" />
+ <ClCompile Include="timer.cpp" />
+ <ClCompile Include="trans_calib.cpp" />
+ <ClCompile Include="video_widget.cpp" />
+ <ClCompile Include="GeneratedFiles\qrc_ftnoir_tracker_pt.cpp">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ </PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ </PrecompiledHeader>
+ </ClCompile>
+ <ClCompile Include="GeneratedFiles\Release\moc_ftnoir_tracker_pt_dialog.cpp">
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Template|Win32'">true</ExcludedFromBuild>
+ </ClCompile>
+ <ClCompile Include="GeneratedFiles\Release\moc_video_widget.cpp">
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Template|Win32'">true</ExcludedFromBuild>
+ </ClCompile>
+ <ClCompile Include="GeneratedFiles\Debug\moc_ftnoir_tracker_pt_dialog.cpp">
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Template|Win32'">true</ExcludedFromBuild>
+ </ClCompile>
+ <ClCompile Include="GeneratedFiles\Debug\moc_video_widget.cpp">
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Template|Win32'">true</ExcludedFromBuild>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="camera.h" />
+ <ClInclude Include="..\FTNoIR_Tracker_Base\ftnoir_tracker_base.h" />
+ <ClInclude Include="..\FTNoIR_Tracker_Base\ftnoir_tracker_base_global.h" />
+ <CustomBuild Include="ftnoir_tracker_pt.h">
+ <Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ </Message>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ </Command>
+ <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalInputs)</AdditionalInputs>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(Outputs)</Outputs>
+ <Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ </Message>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ </Command>
+ <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalInputs)</AdditionalInputs>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(Outputs)</Outputs>
+ </CustomBuild>
+ <CustomBuild Include="ftnoir_tracker_pt_dialog.h">
+ <Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Moc%27ing ftnoir_tracker_pt_dialog.h...</Message>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DQT_DLL -DQT_CORE_LIB -DQT_GUI_LIB -DFTNOIR_TRACKER_BASE_LIB -DQT_OPENGL_LIB -D_WINDLL "-I." "-I.\GeneratedFiles" "-I.\GeneratedFiles\$(Configuration)\." "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(OPENCV_DIR)\include" "-I$(BOOST_DIR)\." "-I$(QTDIR)\include\QtOpenGL"</Command>
+ <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath);%(AdditionalInputs)</AdditionalInputs>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\GeneratedFiles\$(Configuration)\moc_%(Filename).cpp;%(Outputs)</Outputs>
+ <Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Moc%27ing ftnoir_tracker_pt_dialog.h...</Message>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DQT_DLL -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DFTNOIR_TRACKER_BASE_LIB -DQT_OPENGL_LIB -D_WINDLL "-I." "-I.\GeneratedFiles" "-I.\GeneratedFiles\$(Configuration)\." "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(OPENCV_DIR)\include" "-I$(BOOST_DIR)\." "-I$(QTDIR)\include\QtOpenGL"</Command>
+ <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath);%(AdditionalInputs)</AdditionalInputs>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\GeneratedFiles\$(Configuration)\moc_%(Filename).cpp;%(Outputs)</Outputs>
+ </CustomBuild>
+ <ClInclude Include="frame_observer.h" />
+ <ClInclude Include="ftnoir_tracker_pt_settings.h" />
+ <ClInclude Include="point_extractor.h" />
+ <ClInclude Include="point_tracker.h" />
+ <ClInclude Include="resource.h" />
+ <ClInclude Include="timer.h" />
+ <ClInclude Include="trans_calib.h" />
+ <CustomBuild Include="video_widget.h">
+ <Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Moc%27ing video_widget.h...</Message>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DQT_DLL -DQT_CORE_LIB -DQT_GUI_LIB -DFTNOIR_TRACKER_BASE_LIB -DQT_OPENGL_LIB -D_WINDLL "-I." "-I.\GeneratedFiles" "-I.\GeneratedFiles\$(Configuration)\." "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(OPENCV_DIR)\include" "-I$(BOOST_DIR)\." "-I$(QTDIR)\include\QtOpenGL"</Command>
+ <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath);%(AdditionalInputs)</AdditionalInputs>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\GeneratedFiles\$(Configuration)\moc_%(Filename).cpp;%(Outputs)</Outputs>
+ <Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Moc%27ing video_widget.h...</Message>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DQT_DLL -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DFTNOIR_TRACKER_BASE_LIB -DQT_OPENGL_LIB -D_WINDLL "-I." "-I.\GeneratedFiles" "-I.\GeneratedFiles\$(Configuration)\." "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(OPENCV_DIR)\include" "-I$(BOOST_DIR)\." "-I$(QTDIR)\include\QtOpenGL"</Command>
+ <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath);%(AdditionalInputs)</AdditionalInputs>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\GeneratedFiles\$(Configuration)\moc_%(Filename).cpp;%(Outputs)</Outputs>
+ </CustomBuild>
+ <ClInclude Include="GeneratedFiles\ui_FTNoIR_PT_Controls.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <CustomBuild Include="FTNoIR_PT_Controls.ui">
+ <Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Uic%27ing %(Filename)%(Extension)...</Message>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\uic.exe" -o ".\GeneratedFiles\ui_%(Filename).h" "%(FullPath)"
+</Command>
+ <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(QTDIR)\bin\uic.exe;%(AdditionalInputs)</AdditionalInputs>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\GeneratedFiles\ui_%(Filename).h;%(Outputs)</Outputs>
+ <Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Uic%27ing %(Filename)%(Extension)...</Message>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\uic.exe" -o ".\GeneratedFiles\ui_%(Filename).h" "%(FullPath)"
+</Command>
+ <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(QTDIR)\bin\uic.exe;%(AdditionalInputs)</AdditionalInputs>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\GeneratedFiles\ui_%(Filename).h;%(Outputs)</Outputs>
+ </CustomBuild>
+ <CustomBuild Include="ftnoir_tracker_pt.qrc">
+ <Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Rcc%27ing %(Filename)%(Extension)...</Message>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\rcc.exe" -name "%(Filename)" -no-compress "%(FullPath)" -o .\GeneratedFiles\qrc_%(Filename).cpp
+</Command>
+ <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(FullPath);.\Resources\icon.ico;.\Resources\Logo_IR.png;%(AdditionalInputs)</AdditionalInputs>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\GeneratedFiles\qrc_%(Filename).cpp;%(Outputs)</Outputs>
+ <Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Rcc%27ing %(Filename)%(Extension)...</Message>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\rcc.exe" -name "%(Filename)" -no-compress "%(FullPath)" -o .\GeneratedFiles\qrc_%(Filename).cpp
+</Command>
+ <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(FullPath);.\Resources\icon.ico;.\Resources\Logo_IR.png;%(AdditionalInputs)</AdditionalInputs>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\GeneratedFiles\qrc_%(Filename).cpp;%(Outputs)</Outputs>
+ </CustomBuild>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="FTNoIR_Tracker_PT.rc" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+ <ProjectExtensions>
+ <VisualStudio>
+ <UserProperties lreleaseOptions="" lupdateOnBuild="0" lupdateOptions="" MocDir=".\GeneratedFiles\$(ConfigurationName)" MocOptions="" QtVersion_x0020_Win32="$(DefaultQtVersion)" RccDir=".\GeneratedFiles" UicDir=".\GeneratedFiles" />
+ </VisualStudio>
+ </ProjectExtensions>
+</Project>
\ No newline at end of file diff --git a/FTNoIR_Tracker_PT/Resources/Logo_IR.png b/FTNoIR_Tracker_PT/Resources/Logo_IR.png Binary files differnew file mode 100644 index 00000000..95032a25 --- /dev/null +++ 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 differnew file mode 100644 index 00000000..14207a67 --- /dev/null +++ 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 differnew file mode 100644 index 00000000..5ad4ee65 --- /dev/null +++ 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 differnew file mode 100644 index 00000000..04880138 --- /dev/null +++ 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 differnew file mode 100644 index 00000000..72667ac7 --- /dev/null +++ b/FTNoIR_Tracker_PT/Resources/clip_side.png diff --git a/FTNoIR_Tracker_PT/Resources/icon.ico b/FTNoIR_Tracker_PT/Resources/icon.ico Binary files differnew file mode 100644 index 00000000..c4b2aedc --- /dev/null +++ b/FTNoIR_Tracker_PT/Resources/icon.ico diff --git a/FTNoIR_Tracker_PT/camera.cpp b/FTNoIR_Tracker_PT/camera.cpp new file mode 100644 index 00000000..21a910c1 --- /dev/null +++ b/FTNoIR_Tracker_PT/camera.cpp @@ -0,0 +1,263 @@ +/* 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 "camera.h"
+#include <QDebug>
+
+using namespace cv;
+
+// ----------------------------------------------------------------------------
+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);
+ }
+}
+
+// ----------------------------------------------------------------------------
+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();
+ }
+}
+
+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;
+}
+
+// ----------------------------------------------------------------------------
+/*
+void CVCamera::start()
+{
+ cap = cvCreateCameraCapture(desired_index);
+ // extract camera info
+ if (cap)
+ {
+ active = true;
+ active_index = desired_index;
+ cam_info.res_x = cvGetCaptureProperty(cap, CV_CAP_PROP_FRAME_WIDTH);
+ cam_info.res_y = cvGetCaptureProperty(cap, CV_CAP_PROP_FRAME_HEIGHT);
+ }
+}
+
+void CVCamera::stop()
+{
+ if (cap) cvReleaseCapture(&cap);
+ active = false;
+}
+
+bool CVCamera::_get_frame(Mat* frame)
+{
+ if (cap && cvGrabFrame(cap) != 0)
+ {
+ // retrieve frame
+ IplImage* _img = cvRetrieveFrame(cap, 0);
+ if(_img)
+ {
+ if(_img->origin == IPL_ORIGIN_TL)
+ *frame = Mat(_img);
+ else
+ {
+ Mat temp(_img);
+ flip(temp, *frame, 0);
+ }
+ 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) cvSetCaptureProperty(cap, CV_CAP_PROP_FPS, cam_desired.fps);
+}
+
+void CVCamera::_set_res()
+{
+ if (cap)
+ {
+ cvSetCaptureProperty(cap, CV_CAP_PROP_FRAME_WIDTH, cam_desired.res_x);
+ cvSetCaptureProperty(cap, CV_CAP_PROP_FRAME_HEIGHT, cam_desired.res_y);
+ cam_info.res_x = cvGetCaptureProperty(cap, CV_CAP_PROP_FRAME_WIDTH);
+ cam_info.res_y = cvGetCaptureProperty(cap, CV_CAP_PROP_FRAME_HEIGHT);
+ }
+}
+*/
+
+// ----------------------------------------------------------------------------
+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();
+}
+
+
+// ----------------------------------------------------------------------------
+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;
+ }
+}
\ No newline at end of file diff --git a/FTNoIR_Tracker_PT/camera.h b/FTNoIR_Tracker_PT/camera.h new file mode 100644 index 00000000..c0876d0a --- /dev/null +++ b/FTNoIR_Tracker_PT/camera.h @@ -0,0 +1,139 @@ +/* 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>
+#include "videoInput/videoInput.h"
+#include <boost/shared_ptr.hpp>
+#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;
+
+ bool active;
+ int desired_index;
+ int active_index;
+ CamInfo cam_info;
+ CamInfo cam_desired;
+ float dt_valid;
+ float dt_mean;
+};
+
+
+// ----------------------------------------------------------------------------
+// camera based on OpenCV's videoCapture
+/*
+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();
+
+ CvCapture* cap;
+};
+*/
+
+// ----------------------------------------------------------------------------
+// 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;
+};
+
+
+// ----------------------------------------------------------------------------
+class FrameRotation
+{
+public:
+ typedef enum Rotation
+ {
+ CLOCKWISE = -1,
+ ZERO = 0,
+ COUNTER_CLOCKWISE = 1
+ };
+ Rotation rotation;
+
+ cv::Mat rotate_frame(cv::Mat frame);
+};
+
+#endif //CAMERA_H
diff --git a/FTNoIR_Tracker_PT/doc/index.htm b/FTNoIR_Tracker_PT/doc/index.htm new file mode 100644 index 00000000..87b7356f --- /dev/null +++ b/FTNoIR_Tracker_PT/doc/index.htm @@ -0,0 +1,262 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + +<head> + <title>FTNoIR PointTracker Help</title> + + <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" /> + + <meta name="author" + content="Patrick Ruoff (C14)"/> + <meta name="keywords" + content="facetracknoir infrared point model tracker plugin"/> + <meta name="description" + content="Pointtracker plugin for FaceTrackNoIR"/> + + <link rel="shortcut icon" href="ptrack.ico" type="image/vnd.microsoft.icon" /> + <link rel="stylesheet" type="text/css" href="style.css" /> +</head> + +<body> +<div id="navbar"> +<ul class="navbar"> +<li class="navbar"><a class="navbar" href="#about">About</a></li> +<li class="navbar"><a class="navbar" href="#settings">Settings</a></li> +<li class="navbar"><a class="navbar" href="#setup">Filter Setup</a></li> +<li class="navbar"><a class="navbar" href="#support">Support</a></li> +<li class="navbar"><a class="navbar" href="#changelog">ChangeLog</a></li> +<li class="navbar"><a class="navbar" href="#build_instructions">Build Instructions</a></li> +</ul> +</div> + +<div id="content"> +<div style="text-align:center"><h1>FaceTrackNoIR PointTracker Plugin</h1><img src="logo.png" alt="PointTracker Plugin Logo" /></div> + +<a class="nav" id="about"></a> +<h2>About</h2> +<div class="indent"> +<p> +PointTracker is a plugin for the free head tracking software <a href="http://facetracknoir.sourceforge.net">FaceTrackNoIR</a> +which introduces the capability to track a (typically IR-) point model comprising 3 bright points to FaceTrackNoIR, +much like the popular free tracking software <a href="http://www.free-track.net/">Freetrack</a> does.<br/> +It was created as a stable modular alternative to Freetrack, which has some stability issues with newer systems and seems to be no longer actively developped. +</p> +</div> + +<a class="nav" id="settings"></a> +<h2>Settings</h2> +<div class="indent"> +<p> +This section desribes the various settings of the PointTracker plugin in detail. +</p> + +<img src="settings1.png" alt="Settings Pane 1"/> +<dl> +<dt>Show VideoWidget</dt><dd>Whether the video widget is updated or not. It may save some performance to turn this off when not needed</dd> +<dt>Sleep time</dt><dd>Time the tracking thread sleeps after each processed image. It's inverse should be below the framefrate you want to achieve. +(check the framerate in the status region when tracker is active, in case the sleep time is too high, the framerate will decrease). +Low values will result in more CPU-load.</dd> +<dt>Dynamic Pose Resolution</dt><dd>Whether the point correspondence and pose ambiquity is resolved using a more sophisticated dynamic algorithm (constant velocity prediction) or a simple static resolution. +Dynamic pose resolution can capture more extreme poses but may occasionally get stuck in a wrong pose estimates so that a reset of the internal state becomes neccessary.</dd> +<dt>Auto-reset time</dt><dd>If no valid tracking result can be found when using dynamic pose resolution, the tracker will automatically reset its internal state (used for resolving the pose ambiguity and point correspondence) +and return to a fail-safe initialization phase that assumes a neutral pose after this time. +Decrease this time, if you get stuck in a wrong pose too often.</dd> +<dt>Reset</dt><dd>Manually reset the trackers internal state used for dynamic pose resolution and return to a fail-safe initialization phase that assumes a neutral pose. +You may use this in case you get stuck in a wrong pose.</dd> +<dt>Enable Axis ...</dt><dd>Which axis to use for FTNoIR.</dd> +</dl> + +<img src="settings2.png" alt="Settings Pane 2"/> +<dl> +<dt>Device</dt><dd>The camera used for tracking.</dd> +<dt>Resolution</dt><dd>The desired capture resolution. If your camera does not support the entered resolution the true output resolution may be different or even invalid. +You may check the true capture resolution in the status area while the tracker is running. A higher resolution results in more accurate point positions and will increase the +stability of the tracking result, as long as the signal/noise ratio is sufficiently high.</dd> +<dt>FPS</dt><dd>The desired capture framerate. Again, if your camera does not support the entered framerate, the true caputre framerate may be different or invalid. +You may check the true processing framerate in the status area while the tracker is running.</dd> +<dt>F/W</dt><dd>The focal length of the camera divided by the sensor width (of course in the same units). +In case you don't have access to your camera's specifications, you can measure this yourself by placing a plane object of known width (for example a piece of cardboard) in front of the camera until it fills the whole image width. +Then measure the distance between the object and the camera and divide by the object width.</dd> +<dt>VideoWidget</dt><dd>Shows a resizable stand-alone video widget that shows the same content as the integrated video widget in FTNoIR. +Update rate is only 10 fps and may lag behind a bit. Mainly useful during calibration of the point extraction. Same as for the integrated wiget, to save resources, this widget should only be shown when needed.</dd> +<dt>Roll Pitch Yaw...</dt><dd>The orientation of the camera relative to the reference frame. +If these angles are setup properly, the direction of translations may not be correct. +Roll is treated in a special way since it is implemented as a frame rotation by +/- 90 deg that is transparent to the rest of the processing pipeline. +</dd> +<dt>Threshold</dt><dd>The threshold for point recognition. Areas above the threshold are shown in blue in the VideoWidget. +Since point accuracy is best if the points are as big as possible in pixels, the theshold should be chosen as low as possible (stop before the contour of the points becomes "noisy"). +If small reflections are being falsely classified as points, increasing the minimum point diameter (see below) may help.</dd> +<dt>Min Diameter</dt><dd>Minimum diameter of blobs to be classified as a pointmodel-point.</dd> +<dt>Max Diameter</dt><dd>Maximum diameter of blobs to be classified as a pointmodel-point.</dd> +<dt>Status</dt><dd>The tracker's status is shown in this area while the tracker is running. +The FPS shown here correspond to the framerate of the whole tracker processing chain and may be lower than what your camera is able to provide, when<br/> +1. The processing gets not enough CPU time<br/> +2. The sleep time of the tracking thread is set too high<br/></dd> +</dl> + +<img src="settings3.png" alt="Settings Pane 3"/> +<dl> +<dt>Model Selection and Dimensions ...</dt><dd> +First select your model type (point, clip, custom), then enter the dimensions of your model in milimeters here.<br/> +For the custom setting, the coordinates of the two remaining model points have to be entered (reference point M0 is at (0,0,0)) in a pose where the model roughly faces the camera. +For orientation, the coordinates for the standard Freetrack clip are (0,40,-30), (0,-70,-80) and the ones for the cap (40,-60,-100), (-40,-60,-100).<br/> +When using a custom point-model configuration, the following restrictions should be observed:<br/> +The plane in which the 3 points lie should never be parallel to the image plane, M0-M1 and M0-M2 should be roughly perpendicular.</dd> + +<dt>Model Position</dt><dd>The vector from the model to the center of the head in the model frame. Can be calibrated automatically.</dd> +<dt>Calibrate</dt><dd>In order to automatically calibrate the model-head offset, do the following:<br/>Press the Calibrate button, then look around while not moving your shoulder. (i.e. only rotation, no translation). +Do not stay in one pose for too long. The current translation estimate will be updated in real time. As soon as the values stabilized sufficiently, press the Calibrate button again to stop the calibration process.</dd> +</dl> +</div> + +<a class="nav" id="setup"></a> +<h2>Filter Setup</h2> +<div class="indent"> +<p> +This section desribes how the FTNoIR filter work and what the recommended settings for PointTracker are. +</p> +<p> +Filtering is always a tradeoff between stability, accuracy and responsiveness. +</p> +<p> +The <q>Smoothing</q> filter in FTNoIR is just a simple average over the last n samples. +Since this filter produces input lag no matter how fast the head-movements are, it is recommended to turn it off by setting samples to 1. +</p> +<p> +In the filter tab, it is recommended to select <q>Accela Filter Mk2</q>. +Accela is a non-linear filter that works as follows:<br/> +It looks at the difference between the new raw values <i>new_val</i> from the tracker and the last filtered value <i>old_val</i> +and maps this difference via the customizable response function <i>f</i> via:<br/> +</p> +<p style="text-align: center"> +<i>new_val = old_val + f(new_val - old_val) / reduction_factor</i> +</p> +<p> +So by setting <i>f(x) = reduction_factor * x</i>, one will get no filtering at all.<br/> +If you set lower values for small x, small deviations (usually noise) will get dampened. +This results in a dynamic dead-zone around the current position. +</p> +<p> +The last two points are used by accela to extrapolate for large deviations. +So in order to get a fast unfiltered response for large deviations, the line connecting the last two points should have a slope >= <i>reduction_factor</i>. +</p> +<p> +More aggressive accela settings than the default FTNoIR accela settings are recommended in order to decrease the filtering lag and fully use the potential of point tracking.<br/> +My current settings are: +</p> +<pre class="indent"><code> +[Accela] +Reduction=20 + +[Curves-Accela-Scaling-Rotation] +point-count=4 +point-0-x=0.1 +point-0-y=0 +point-1-x=1.43 +point-1-y=2.45 +point-2-x=2.0 +point-2-y=5.44 +point-3-x=2.06 +point-3-y=6 +</code></pre> +<p> +The curve is not too different from the standard one (except that I like a small dynamic dead zone for steady aiming, that's why the curve has a slope of 0 at the beginning).<br/> +However, the reduction factor is decreased to a value of 20 (compared to the standard value of 100). This implies that each value of the curve is effectively 5 times higher than in standard FTNoIR (see formula above), which means higher responsiveness but can also lead to jitter/shaking.<br/> +Keep in mind that there are no <q>best filter settings</q>. Since filtering is always a compromise it's a matter of personal taste and +playing around with the filter settings is highly recommended. +</p> +</div> + +<a class="nav" id="support"></a> +<h2>Support</h2> +<div class="indent"> +<p> +For questions/feedback about the plugin, post to the <a href="https://sourceforge.net/projects/facetracknoir/forums">FTNoIR-Forum</a>.<br/> +In case you like this plugin and would like to support the author, you may consider making a donation. +</p> +<div style="text-align:center"> +<form action="https://www.paypal.com/cgi-bin/webscr" method="post"> +<fieldset class="blind"> +<input type="hidden" name="cmd" value="_s-xclick"/> +<input type="hidden" name="encrypted" value="-----BEGIN PKCS7-----MIIHJwYJKoZIhvcNAQcEoIIHGDCCBxQCAQExggEwMIIBLAIBADCBlDCBjjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtQYXlQYWwgSW5jLjETMBEGA1UECxQKbGl2ZV9jZXJ0czERMA8GA1UEAxQIbGl2ZV9hcGkxHDAaBgkqhkiG9w0BCQEWDXJlQHBheXBhbC5jb20CAQAwDQYJKoZIhvcNAQEBBQAEgYCa+2zPZ+6vFPqveJsBIjFLpy54m7tl0AdojRr/K5qa3QJDyRBhGwGAP2jRihkmZFE2oKlfLpkz7nrwOQY/wFEPkggO+cABxUfjcQVpIupHEtwdV0hMklLs0RmACJy802yfi1yTiCpJ4hvWN+VfUI3gOiZ9uRZ3L4iGXES7xtqJbDELMAkGBSsOAwIaBQAwgaQGCSqGSIb3DQEHATAUBggqhkiG9w0DBwQIeopHzcJ8XBOAgYCYJFyTejSplEOwF21aQ01qQOads9Z+RUVI+hlvM/pHTjimaZPKSis3poAeqv6wKn40DpLNxDnmcT+Y9KXhrV+Gy4GZCPaeNzq2vquQ2ZVN0fTr84QVmKqPkjMBGmJAHSLCcZswUddemJgoD1uyvS0kNbchvxw7gDXJnJeBRNyXXKCCA4cwggODMIIC7KADAgECAgEAMA0GCSqGSIb3DQEBBQUAMIGOMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxFDASBgNVBAoTC1BheVBhbCBJbmMuMRMwEQYDVQQLFApsaXZlX2NlcnRzMREwDwYDVQQDFAhsaXZlX2FwaTEcMBoGCSqGSIb3DQEJARYNcmVAcGF5cGFsLmNvbTAeFw0wNDAyMTMxMDEzMTVaFw0zNTAyMTMxMDEzMTVaMIGOMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxFDASBgNVBAoTC1BheVBhbCBJbmMuMRMwEQYDVQQLFApsaXZlX2NlcnRzMREwDwYDVQQDFAhsaXZlX2FwaTEcMBoGCSqGSIb3DQEJARYNcmVAcGF5cGFsLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwUdO3fxEzEtcnI7ZKZL412XvZPugoni7i7D7prCe0AtaHTc97CYgm7NsAtJyxNLixmhLV8pyIEaiHXWAh8fPKW+R017+EmXrr9EaquPmsVvTywAAE1PMNOKqo2kl4Gxiz9zZqIajOm1fZGWcGS0f5JQ2kBqNbvbg2/Za+GJ/qwUCAwEAAaOB7jCB6zAdBgNVHQ4EFgQUlp98u8ZvF71ZP1LXChvsENZklGswgbsGA1UdIwSBszCBsIAUlp98u8ZvF71ZP1LXChvsENZklGuhgZSkgZEwgY4xCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLUGF5UGFsIEluYy4xEzARBgNVBAsUCmxpdmVfY2VydHMxETAPBgNVBAMUCGxpdmVfYXBpMRwwGgYJKoZIhvcNAQkBFg1yZUBwYXlwYWwuY29tggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAgV86VpqAWuXvX6Oro4qJ1tYVIT5DgWpE692Ag422H7yRIr/9j/iKG4Thia/Oflx4TdL+IFJBAyPK9v6zZNZtBgPBynXb048hsP16l2vi0k5Q2JKiPDsEfBhGI+HnxLXEaUWAcVfCsQFvd2A1sxRr67ip5y2wwBelUecP3AjJ+YcxggGaMIIBlgIBATCBlDCBjjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtQYXlQYWwgSW5jLjETMBEGA1UECxQKbGl2ZV9jZXJ0czERMA8GA1UEAxQIbGl2ZV9hcGkxHDAaBgkqhkiG9w0BCQEWDXJlQHBheXBhbC5jb20CAQAwCQYFKw4DAhoFAKBdMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTEyMDkyMzA5NTcwOFowIwYJKoZIhvcNAQkEMRYEFG/qW7uo4R4m5uFYegcZaZsTPAcUMA0GCSqGSIb3DQEBAQUABIGAGygLfrR6IQbG2xZY2OrwKkfmRwiwtnXpLBnSbnWb7XxUOMhvM6962RiKBQBGP0+XYw0S9yu8ZHx7tqz/3bcMfGjtz7PwixYx6Rm8Z29ja78aUy5FmU7fc9yAWFxLHptSliK1dJBPxdQa9J2YSDvPQPAj+AdB9sJvqJoMoxTFGM4=-----END PKCS7----- +"/> +<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif" name="submit" alt="PayPal - The safer, easier way to pay online!"/> +<img alt="" src="https://www.paypalobjects.com/de_DE/i/scr/pixel.gif" width="1" height="1"/> +</fieldset> +</form> +</div> +</div> + +<a class="nav" id="changelog"></a> +<h2>ChangeLog</h2> +<div class="indent"> +<h3>1.1</h3> +<ul> +<li>Added camera yaw and roll correction (intended for vertically mounted cameras)</li> +<li>Improved point extraction algorithm, thanks to Michael Welter</li> +<li>UI improvements: Select camera by device name, different VideoWidget architecture</li> +<li>Bugfixes: Removed 99 FPS limitation</li> +</ul> + +<h3>1.0</h3> +<ul> +<li>Added camera pitch correction</li> +<li>Better communication with FTNoIR: output axis configuration, status report</li> +</ul> + +<h3>1.0 beta</h3> +<ul> +<li>Switchted to videoInput library for capture. Desired capture resolution and fps can now be customized</li> +<li>Introduced dynamic point-correspondence and POSIT-ambiguity resolution, which allows for the reconstruction of more extreme poses</li> +<li>More convenient freetrack-like model dimension GUI</li> +<li>Bugfixes: VideoWidget skipping frames, Timer resolution too low for accurate FPS measurement</li> +</ul> +</div> + +<a class="nav" id="build_instructions"></a> +<h2>Build Instructions</h2> +<div class="indent"> +<p> +This section describes what you need to do in order to build PointTracker yourself.<br/> +You can find the sources at the <a href="https://sourceforge.net/projects/ftnoirpt/">project site</a> +or as part of the <a href="https://sourceforge.net/projects/facetracknoir/">FTNoIR sources</a>. +</p> +<p> The project was created with Visual Studio. </p> + +<h3>Dependencies</h3> +<ul> +<li>Qt 4.8.2 library</li> +<li>Qt plugin for Visual studio</li> +<li>OpenCV 2.4 prebuilt for Windows</li> +<li>Boost 1.47</li> +</ul> + +<h3>Details</h3> +<div class="indent"> +<h4>Common</h4> +<ul> +<li>setup environment variable "QTDIR" (example value "D:\Devel\Libs\Qt\4.8.2")</li> +<li>add "%QTDIR%\bin" to PATH</li> +<li>setup environment variable "BOOST_DIR" (example value "D:\Devel\Libs\boost_1_47_0")</li> +<li>setup environment variable "OPENCV_DIR" (example value "D:\Devel\Libs\opencv\build")</li> +</ul> +<h4>Debug</h4> +<p>opencv linked dynamically:</p> +<ul> +<li>add "%OPENCV_DIR%\x86\vc9\bin" to PATH</li> +</ul> +<p>(in case of different Visual studio, change PATH and linker dependencies accordingly)</p> +<h4>Release</h4> +<p>opencv linked statically:</p> +<ul> +<li>custom build a statically linked version of opencv with the buil-option BUILD_WITH_STATIC_CRT set to OFF!</li> +<li>copy resulting libaries to "%OPENCV_DIR%\x86\vc9\static_lib"</li> +</ul> +<p>(in case of different Visual studio, change PATH and linker dependencies accordingly)</p> +</div> +</div> + +</div> + +</body> +</html>
\ No newline at end of file diff --git a/FTNoIR_Tracker_PT/doc/logo.png b/FTNoIR_Tracker_PT/doc/logo.png Binary files differnew file mode 100644 index 00000000..95032a25 --- /dev/null +++ b/FTNoIR_Tracker_PT/doc/logo.png diff --git a/FTNoIR_Tracker_PT/doc/ptrack.ico b/FTNoIR_Tracker_PT/doc/ptrack.ico Binary files differnew file mode 100644 index 00000000..c4b2aedc --- /dev/null +++ b/FTNoIR_Tracker_PT/doc/ptrack.ico diff --git a/FTNoIR_Tracker_PT/doc/settings1.png b/FTNoIR_Tracker_PT/doc/settings1.png Binary files differnew file mode 100644 index 00000000..35b84c5c --- /dev/null +++ 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 differnew file mode 100644 index 00000000..c6cfd1f3 --- /dev/null +++ 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 differnew file mode 100644 index 00000000..5922403d --- /dev/null +++ b/FTNoIR_Tracker_PT/doc/settings3.png diff --git a/FTNoIR_Tracker_PT/doc/style.css b/FTNoIR_Tracker_PT/doc/style.css new file mode 100644 index 00000000..a8d3e333 --- /dev/null +++ b/FTNoIR_Tracker_PT/doc/style.css @@ -0,0 +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;
+}
diff --git a/FTNoIR_Tracker_PT/frame_observer.cpp b/FTNoIR_Tracker_PT/frame_observer.cpp new file mode 100644 index 00000000..7e4bb3e3 --- /dev/null +++ b/FTNoIR_Tracker_PT/frame_observer.cpp @@ -0,0 +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 (auto iter=frame_observers.begin(); iter!=frame_observers.end(); ++iter)
+ {
+ (*iter)->on_frame_provider_destroy();
+ }
+}
\ No newline at end of file diff --git a/FTNoIR_Tracker_PT/frame_observer.h b/FTNoIR_Tracker_PT/frame_observer.h new file mode 100644 index 00000000..4afbd72c --- /dev/null +++ b/FTNoIR_Tracker_PT/frame_observer.h @@ -0,0 +1,72 @@ +/* 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>
+#include <boost/shared_ptr.hpp>
+#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, boost::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, boost::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
\ No newline at end of file diff --git a/FTNoIR_Tracker_PT/ftnoir_tracker_pt.cpp b/FTNoIR_Tracker_PT/ftnoir_tracker_pt.cpp new file mode 100644 index 00000000..88a3fc8d --- /dev/null +++ b/FTNoIR_Tracker_PT/ftnoir_tracker_pt.cpp @@ -0,0 +1,265 @@ +/* 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;
+using namespace boost;
+
+//#define PT_PERF_LOG //log performance
+
+const float rad2deg = 180.0/3.14159265;
+const float deg2rad = 1.0/rad2deg;
+
+//-----------------------------------------------------------------------------
+Tracker::Tracker()
+ : frame_count(0),
+ commands(0),
+ video_widget(NULL),
+ video_frame(NULL),
+ tracking_valid(false)
+{
+ qDebug()<<"Tracker::Tracker";
+ TrackerSettings settings;
+ settings.load_ini();
+ apply(settings);
+ camera.start();
+ start();
+}
+
+Tracker::~Tracker()
+{
+ qDebug()<<"Tracker::~Tracker";
+ // terminate tracker thread
+ set_command(ABORT);
+ wait();
+ // destroy video widget
+ show_video_widget = false;
+ update_show_video_widget();
+}
+
+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();
+ float dt;
+ bool new_frame;
+ forever
+ {
+ {
+ QMutexLocker lock(&mutex);
+
+ if (commands & ABORT) break;
+ if (commands & PAUSE) continue;
+ commands = 0;
+
+ dt = time.elapsed() / 1000.0;
+ time.restart();
+
+ new_frame = camera.get_frame(dt, &frame);
+ if (new_frame && !frame.empty())
+ {
+ frame = frame_rotation.rotate_frame(frame);
+ const std::vector<cv::Vec2f>& points = point_extractor.extract_points(frame, dt, has_observers());
+ tracking_valid = point_tracker.track(points, camera.get_info().f, dt);
+ frame_count++;
+ }
+#ifdef PT_PERF_LOG
+ log_stream<<"dt: "<<dt;
+ if (!frame.empty()) log_stream<<" fps: "<<camera.get_info().fps;
+ log_stream<<"\n";
+#endif
+ }
+ msleep(sleep_time);
+ }
+
+ qDebug()<<"Tracker:: Thread stopping";
+}
+
+void Tracker::apply(const TrackerSettings& settings)
+{
+ qDebug()<<"Tracker:: Applying settings";
+ QMutexLocker lock(&mutex);
+ camera.set_device_index(settings.cam_index);
+ camera.set_res(settings.cam_res_x, settings.cam_res_y);
+ camera.set_fps(settings.cam_fps);
+ camera.set_f(settings.cam_f);
+ frame_rotation.rotation = static_cast<FrameRotation::Rotation>(settings.cam_roll);
+ point_extractor.threshold_val = settings.threshold;
+ point_extractor.min_size = settings.min_point_size;
+ point_extractor.max_size = settings.max_point_size;
+ point_tracker.point_model = boost::shared_ptr<PointModel>(new PointModel(settings.M01, settings.M02));
+ point_tracker.dynamic_pose_resolution = settings.dyn_pose_res;
+ sleep_time = settings.sleep_time;
+ point_tracker.dt_reset = settings.reset_time / 1000.0;
+ show_video_widget = settings.video_widget;
+ update_show_video_widget();
+ bEnableRoll = settings.bEnableRoll;
+ bEnablePitch = settings.bEnablePitch;
+ bEnableYaw = settings.bEnableYaw;
+ bEnableX = settings.bEnableX;
+ bEnableY = settings.bEnableY;
+ bEnableZ = settings.bEnableZ;
+
+ t_MH = settings.t_MH;
+ R_GC = Matx33f( cos(deg2rad*settings.cam_yaw), 0, sin(deg2rad*settings.cam_yaw),
+ 0, 1, 0,
+ -sin(deg2rad*settings.cam_yaw), 0, cos(deg2rad*settings.cam_yaw));
+ R_GC = R_GC * Matx33f( 1, 0, 0,
+ 0, cos(deg2rad*settings.cam_pitch), sin(deg2rad*settings.cam_pitch),
+ 0, -sin(deg2rad*settings.cam_pitch), cos(deg2rad*settings.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, boost::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 = boost::shared_ptr< vector<Vec2f> >(new vector<Vec2f>(point_extractor.get_points()));
+ return true;
+}
+
+void Tracker::update_show_video_widget()
+{
+ if (!show_video_widget && video_widget) {
+ delete video_widget;
+ video_widget = NULL;
+ if (video_frame->layout()) delete video_frame->layout();
+ }
+ else if (video_frame && show_video_widget && !video_widget)
+ {
+ const int VIDEO_FRAME_WIDTH = 252;
+ const int VIDEO_FRAME_HEIGHT = 189;
+
+ video_widget = new VideoWidget(video_frame, this);
+ QHBoxLayout* video_layout = new QHBoxLayout();
+ 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);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// ITracker interface
+void Tracker::Initialize(QFrame *video_frame)
+{
+ qDebug("Tracker::Initialize");
+ // setup video frame
+ this->video_frame = video_frame;
+ video_frame->setAttribute(Qt::WA_NativeWindow);
+ video_frame->show();
+ update_show_video_widget();
+}
+
+void Tracker::refreshVideo()
+{
+ if (video_widget) video_widget->update_frame_and_points();
+}
+
+void Tracker::StartTracker(HWND parent_window)
+{
+ reset_command(PAUSE);
+}
+
+void Tracker::StopTracker(bool exit)
+{
+ set_command(PAUSE);
+}
+
+bool Tracker::GiveHeadPoseData(THeadPoseData *data)
+{
+ {
+ QMutexLocker lock(&mutex);
+
+ if (!tracking_valid) return false;
+
+ 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)
+ if (bEnableX) data->x = t[0] / 10.0; // convert to cm
+ if (bEnableY) data->y = t[1] / 10.0;
+ if (bEnableZ) data->z = 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));
+
+ if (bEnableYaw) data->yaw = rad2deg * alpha;
+ if (bEnablePitch) data->pitch = - rad2deg * beta; // FTNoIR expects a minus here
+ if (bEnableRoll) data->roll = rad2deg * gamma;
+ }
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+#pragma comment(linker, "/export:GetTracker=_GetTracker@0")
+
+FTNOIR_TRACKER_BASE_EXPORT ITrackerPtr __stdcall GetTracker()
+{
+ return new Tracker;
+}
\ No newline at end of file diff --git a/FTNoIR_Tracker_PT/ftnoir_tracker_pt.h b/FTNoIR_Tracker_PT/ftnoir_tracker_pt.h new file mode 100644 index 00000000..6eef945a --- /dev/null +++ b/FTNoIR_Tracker_PT/ftnoir_tracker_pt.h @@ -0,0 +1,99 @@ +/* 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
+
+#include "..\ftnoir_tracker_base\ftnoir_tracker_base.h"
+#include "ftnoir_tracker_pt_settings.h"
+#include "frame_observer.h"
+#include "camera.h"
+#include "point_extractor.h"
+#include "point_tracker.h"
+#include "video_widget.h"
+#include "timer.h"
+
+#include <QThread>
+#include <QMutex>
+#include <QTime>
+#include <opencv2/opencv.hpp>
+#include <boost/shared_ptr.hpp>
+#include <vector>
+
+//-----------------------------------------------------------------------------
+// Constantly processes the tracking chain in a separate thread
+class Tracker : public ITracker, QThread, public FrameProvider
+{
+public:
+ Tracker();
+ ~Tracker();
+
+ // --- ITracker interface ---
+ virtual void Initialize(QFrame *videoframe);
+ virtual void StartTracker(HWND parent_window);
+ virtual void StopTracker(bool exit);
+ virtual bool GiveHeadPoseData(THeadPoseData *data);
+ virtual void refreshVideo();
+
+ void apply(const TrackerSettings& settings);
+ 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, boost::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);
+ int commands;
+
+ int sleep_time;
+
+ // --- tracking chain ---
+ VICamera camera;
+ FrameRotation frame_rotation;
+ PointExtractor point_extractor;
+ PointTracker point_tracker;
+ bool tracking_valid;
+
+ 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
+
+ void update_show_video_widget();
+ bool show_video_widget;
+ VideoWidget* video_widget;
+ QFrame* video_frame;
+
+ // --- misc ---
+ bool bEnableRoll;
+ bool bEnablePitch;
+ bool bEnableYaw;
+ bool bEnableX;
+ bool bEnableY;
+ bool bEnableZ;
+
+ long frame_count;
+ Timer time;
+};
+
+#endif // FTNOIR_TRACKER_PT_H
diff --git a/FTNoIR_Tracker_PT/ftnoir_tracker_pt.qrc b/FTNoIR_Tracker_PT/ftnoir_tracker_pt.qrc new file mode 100644 index 00000000..9b510981 --- /dev/null +++ b/FTNoIR_Tracker_PT/ftnoir_tracker_pt.qrc @@ -0,0 +1,10 @@ +<RCC>
+ <qresource prefix="/">
+ <file>Resources/icon.ico</file>
+ <file>Resources/cap_front.png</file>
+ <file>Resources/cap_side.png</file>
+ <file>Resources/clip_front.png</file>
+ <file>Resources/clip_side.png</file>
+ <file>Resources/Logo_IR.png</file>
+ </qresource>
+</RCC>
diff --git a/FTNoIR_Tracker_PT/ftnoir_tracker_pt_dialog.cpp b/FTNoIR_Tracker_PT/ftnoir_tracker_pt_dialog.cpp new file mode 100644 index 00000000..c99f4d67 --- /dev/null +++ b/FTNoIR_Tracker_PT/ftnoir_tracker_pt_dialog.cpp @@ -0,0 +1,406 @@ +/* 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>
+#include <boost/shared_ptr.hpp>
+#include <vector>
+
+using namespace std;
+
+//-----------------------------------------------------------------------------
+TrackerDialog::TrackerDialog()
+ : settings_dirty(false),
+ tracker(NULL),
+ video_widget_dialog(NULL),
+ timer(this),
+ trans_calib_running(false)
+{
+ qDebug()<<"TrackerDialog::TrackerDialog";
+ setAttribute(Qt::WA_DeleteOnClose, false);
+
+ ui.setupUi( this );
+
+ settings.load_ini();
+ dialog_settings.load_ini();
+
+ // initialize ui values
+ ui.videowidget_check->setChecked(settings.video_widget);
+ ui.dynpose_check->setChecked(settings.dyn_pose_res);
+ ui.sleep_spin->setValue(settings.sleep_time);
+ ui.reset_spin->setValue(settings.reset_time);
+
+ vector<string> device_names;
+ get_camera_device_names(device_names);
+ for (auto iter = device_names.begin(); iter != device_names.end(); ++iter)
+ {
+ ui.camdevice_combo->addItem(iter->c_str());
+ }
+ ui.camdevice_combo->setCurrentIndex(settings.cam_index);
+
+ ui.f_dspin->setValue(settings.cam_f);
+ ui.res_x_spin->setValue(settings.cam_res_x);
+ ui.res_y_spin->setValue(settings.cam_res_y);
+ ui.fps_spin->setValue(settings.cam_fps);
+
+ ui.camroll_combo->addItem("-90", -1);
+ ui.camroll_combo->addItem("0" , 0);
+ ui.camroll_combo->addItem("90" , 1);
+ int i = ui.camroll_combo->findData(settings.cam_roll);
+ ui.camroll_combo->setCurrentIndex(i>=0 ? i : 0);
+
+ ui.campitch_spin->setValue(settings.cam_pitch);
+ ui.camyaw_spin->setValue(settings.cam_yaw);
+ ui.threshold_slider->setValue(settings.threshold);
+
+ ui.chkEnableRoll->setChecked(settings.bEnableRoll);
+ ui.chkEnablePitch->setChecked(settings.bEnablePitch);
+ ui.chkEnableYaw->setChecked(settings.bEnableYaw);
+ ui.chkEnableX->setChecked(settings.bEnableX);
+ ui.chkEnableY->setChecked(settings.bEnableY);
+ ui.chkEnableZ->setChecked(settings.bEnableZ);
+
+ ui.mindiam_spin->setValue(settings.min_point_size);
+ ui.maxdiam_spin->setValue(settings.max_point_size);
+ ui.model_tabs->setCurrentIndex(dialog_settings.active_model_panel);
+ ui.clip_bheight_spin->setValue(dialog_settings.clip_by);
+ ui.clip_blength_spin->setValue(dialog_settings.clip_bz);
+ ui.clip_theight_spin->setValue(dialog_settings.clip_ty);
+ ui.clip_tlength_spin->setValue(dialog_settings.clip_tz);
+ ui.cap_width_spin->setValue(dialog_settings.cap_x);
+ ui.cap_height_spin->setValue(dialog_settings.cap_y);
+ ui.cap_length_spin->setValue(dialog_settings.cap_z);
+ ui.m1x_spin->setValue(dialog_settings.M01x);
+ ui.m1y_spin->setValue(dialog_settings.M01y);
+ ui.m1z_spin->setValue(dialog_settings.M01z);
+ ui.m2x_spin->setValue(dialog_settings.M02x);
+ ui.m2y_spin->setValue(dialog_settings.M02y);
+ ui.m2z_spin->setValue(dialog_settings.M02z);
+ ui.tx_spin->setValue(settings.t_MH[0]);
+ ui.ty_spin->setValue(settings.t_MH[1]);
+ ui.tz_spin->setValue(settings.t_MH[2]);
+
+ // connect Qt signals and slots
+ connect( ui.videowidget_check,SIGNAL(toggled(bool)), this,SLOT(set_video_widget(bool)) );
+ connect( ui.dynpose_check,SIGNAL(toggled(bool)), this,SLOT(set_dyn_pose_res(bool)) );
+ connect( ui.sleep_spin,SIGNAL(valueChanged(int)), this,SLOT(set_sleep_time(int)) );
+ connect( ui.reset_spin,SIGNAL(valueChanged(int)), this,SLOT(set_reset_time(int)) );
+ connect( ui.camdevice_combo,SIGNAL(currentIndexChanged(int)), this,SLOT(set_cam_index(int)) );
+ connect( ui.f_dspin,SIGNAL(valueChanged(double)), this,SLOT(set_cam_f(double)) );
+ connect( ui.res_x_spin,SIGNAL(valueChanged(int)), this,SLOT(set_cam_res_x(int)) );
+ connect( ui.res_y_spin,SIGNAL(valueChanged(int)), this,SLOT(set_cam_res_y(int)) );
+ connect( ui.fps_spin,SIGNAL(valueChanged(int)), this,SLOT(set_cam_fps(int)) );
+ connect( ui.camroll_combo,SIGNAL(currentIndexChanged(int)), this,SLOT(set_cam_roll(int)) );
+ connect( ui.campitch_spin,SIGNAL(valueChanged(int)), this,SLOT(set_cam_pitch(int)) );
+ connect( ui.camyaw_spin,SIGNAL(valueChanged(int)), this,SLOT(set_cam_yaw(int)) );
+ connect( ui.threshold_slider,SIGNAL(sliderMoved(int)), this,SLOT(set_threshold(int)) );
+
+ connect( ui.chkEnableRoll,SIGNAL(toggled(bool)), this,SLOT(set_ena_roll(bool)) );
+ connect( ui.chkEnablePitch,SIGNAL(toggled(bool)), this,SLOT(set_ena_pitch(bool)) );
+ connect( ui.chkEnableYaw,SIGNAL(toggled(bool)), this,SLOT(set_ena_yaw(bool)) );
+ connect( ui.chkEnableX,SIGNAL(toggled(bool)), this,SLOT(set_ena_x(bool)) );
+ connect( ui.chkEnableY,SIGNAL(toggled(bool)), this,SLOT(set_ena_y(bool)) );
+ connect( ui.chkEnableZ,SIGNAL(toggled(bool)), this,SLOT(set_ena_z(bool)) );
+
+ connect( ui.mindiam_spin,SIGNAL(valueChanged(int)), this,SLOT(set_min_point_size(int)) );
+ connect( ui.maxdiam_spin,SIGNAL(valueChanged(int)), this,SLOT(set_max_point_size(int)) );
+ connect( ui.model_tabs,SIGNAL(currentChanged(int)), this,SLOT(set_model(int)) );
+ connect( ui.clip_theight_spin,SIGNAL(valueChanged(int)), this,SLOT(set_clip_t_height(int)) );
+ connect( ui.clip_tlength_spin,SIGNAL(valueChanged(int)), this,SLOT(set_clip_t_length(int)) );
+ connect( ui.clip_bheight_spin,SIGNAL(valueChanged(int)), this,SLOT(set_clip_b_height(int)) );
+ connect( ui.clip_blength_spin,SIGNAL(valueChanged(int)), this,SLOT(set_clip_b_length(int)) );
+ connect( ui.cap_width_spin,SIGNAL(valueChanged(int)), this,SLOT(set_cap_width(int)) );
+ connect( ui.cap_height_spin,SIGNAL(valueChanged(int)), this,SLOT(set_cap_height(int)) );
+ connect( ui.cap_length_spin,SIGNAL(valueChanged(int)), this,SLOT(set_cap_length(int)) );
+ connect( ui.m1x_spin,SIGNAL(valueChanged(int)), this,SLOT(set_m1x(int)) );
+ connect( ui.m1y_spin,SIGNAL(valueChanged(int)), this,SLOT(set_m1y(int)) );
+ connect( ui.m1z_spin,SIGNAL(valueChanged(int)), this,SLOT(set_m1z(int)) );
+ connect( ui.m2x_spin,SIGNAL(valueChanged(int)), this,SLOT(set_m2x(int)) );
+ connect( ui.m2y_spin,SIGNAL(valueChanged(int)), this,SLOT(set_m2y(int)) );
+ connect( ui.m2z_spin,SIGNAL(valueChanged(int)), this,SLOT(set_m2z(int)) );
+ connect( ui.tx_spin,SIGNAL(valueChanged(int)), this,SLOT(set_tx(int)) );
+ connect( ui.ty_spin,SIGNAL(valueChanged(int)), this,SLOT(set_ty(int)) );
+ connect( ui.tz_spin,SIGNAL(valueChanged(int)), this,SLOT(set_tz(int)) );
+
+ connect( ui.tcalib_button,SIGNAL(toggled(bool)), this,SLOT(startstop_trans_calib(bool)) );
+
+ connect( ui.videowidget_button,SIGNAL(clicked()), this,SLOT(create_video_widget()) );
+
+ connect(ui.reset_button, SIGNAL(clicked()), this, SLOT(doReset()));
+ //connect(ui.center_button, SIGNAL(clicked()), this, SLOT(doCenter()));
+
+ connect(ui.ok_button, SIGNAL(clicked()), this, SLOT(doOK()));
+ connect(ui.cancel_button, SIGNAL(clicked()), this, SLOT(doCancel()));
+
+ connect(&timer,SIGNAL(timeout()), this,SLOT(poll_tracker_info()));
+ timer.start(100);
+}
+
+TrackerDialog::~TrackerDialog()
+{
+ qDebug()<<"TrackerDialog::~TrackerDialog";
+}
+
+void TrackerDialog::set_cam_roll(int idx)
+{
+ settings.cam_roll = ui.camroll_combo->itemData(idx).toInt();
+ settings_changed();
+}
+
+void TrackerDialog::set_model_clip()
+{
+ settings.M01[0] = 0;
+ settings.M01[1] = dialog_settings.clip_ty;
+ settings.M01[2] = -dialog_settings.clip_tz;
+ settings.M02[0] = 0;
+ settings.M02[1] = -dialog_settings.clip_by;
+ settings.M02[2] = -dialog_settings.clip_bz;
+
+ settings_changed();
+}
+
+void TrackerDialog::set_model_cap()
+{
+ settings.M01[0] = -dialog_settings.cap_x;
+ settings.M01[1] = -dialog_settings.cap_y;
+ settings.M01[2] = -dialog_settings.cap_z;
+ settings.M02[0] = dialog_settings.cap_x;
+ settings.M02[1] = -dialog_settings.cap_y;
+ settings.M02[2] = -dialog_settings.cap_z;
+
+ settings_changed();
+}
+
+void TrackerDialog::set_model_custom()
+{
+ settings.M01[0] = dialog_settings.M01x;
+ settings.M01[1] = dialog_settings.M01y;
+ settings.M01[2] = dialog_settings.M01z;
+ settings.M02[0] = dialog_settings.M02x;
+ settings.M02[1] = dialog_settings.M02y;
+ settings.M02[2] = dialog_settings.M02z;
+
+ settings_changed();
+}
+
+void TrackerDialog::set_model(int val)
+{
+ dialog_settings.active_model_panel = val;
+
+ switch (val) {
+
+ case TrackerDialogSettings::MODEL_CLIP:
+ set_model_clip();
+ break;
+
+ case TrackerDialogSettings::MODEL_CAP:
+ set_model_cap();
+ break;
+
+ case TrackerDialogSettings::MODEL_CUSTOM:
+ set_model_custom();
+ break;
+
+ default:
+ break;
+ }
+}
+
+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;
+ settings.t_MH = trans_calib.get_estimate();
+ 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();
+ //qDebug()<<"TrackerDialog:: Current translation estimate: "<<t_MH[0]<<t_MH[1]<<t_MH[2];
+ ui.tx_spin->setValue(t_MH[0]);
+ ui.ty_spin->setValue(t_MH[1]);
+ ui.tz_spin->setValue(t_MH[2]);
+ }
+}
+
+void TrackerDialog::settings_changed()
+{
+ settings_dirty = true;
+ if (tracker) tracker->apply(settings);
+}
+
+void TrackerDialog::doCenter()
+{
+ if (tracker) tracker->center();
+}
+
+void TrackerDialog::doReset()
+{
+ if (tracker) tracker->reset();
+}
+
+void TrackerDialog::doOK()
+{
+ settings.save_ini();
+ dialog_settings.save_ini();
+ close();
+}
+
+void TrackerDialog::doCancel()
+{
+ if (settings_dirty) {
+ int ret = QMessageBox::question ( this, "Settings have changed", "Do you want to save the settings?",
+ QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel, QMessageBox::Discard );
+ switch (ret) {
+ case QMessageBox::Save:
+ settings.save_ini();
+ dialog_settings.save_ini();
+ close();
+ break;
+ case QMessageBox::Discard:
+ close();
+ break;
+ case QMessageBox::Cancel:
+ // Cancel was clicked
+ break;
+ default:
+ // should never be reached
+ break;
+ }
+ }
+ else {
+ 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();
+
+ ui.videowidget_button->setEnabled(false);
+}
+
+void TrackerDialog::destroy_video_widget(bool do_delete /*= true*/)
+{
+ if (video_widget_dialog) {
+ if (do_delete) delete video_widget_dialog;
+ video_widget_dialog = NULL;
+ }
+ if (tracker) ui.videowidget_button->setEnabled(true);
+}
+
+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);
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// ITrackerDialog interface
+void TrackerDialog::Initialize(QWidget *parent)
+{
+ QPoint offsetpos(200, 200);
+ if (parent) {
+ this->move(parent->pos() + offsetpos);
+ }
+ show();
+}
+
+void TrackerDialog::registerTracker(ITracker *t)
+{
+ qDebug()<<"TrackerDialog:: Tracker registered";
+ tracker = static_cast<Tracker*>(t);
+ if (isVisible() && settings_dirty) tracker->apply(settings);
+ ui.videowidget_button->setEnabled(true);
+ 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.videowidget_button->setEnabled(false);
+ ui.tcalib_button->setEnabled(false);
+ //ui.center_button->setEnabled(false);
+ ui.reset_button->setEnabled(false);
+}
+
+//-----------------------------------------------------------------------------
+#pragma comment(linker, "/export:GetTrackerDialog=_GetTrackerDialog@0")
+
+FTNOIR_TRACKER_BASE_EXPORT ITrackerDialogPtr __stdcall GetTrackerDialog( )
+{
+ return new TrackerDialog;
+}
\ No newline at end of file diff --git a/FTNoIR_Tracker_PT/ftnoir_tracker_pt_dialog.h b/FTNoIR_Tracker_PT/ftnoir_tracker_pt_dialog.h new file mode 100644 index 00000000..bf0a90f2 --- /dev/null +++ b/FTNoIR_Tracker_PT/ftnoir_tracker_pt_dialog.h @@ -0,0 +1,116 @@ +/* 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
+
+#include "..\ftnoir_tracker_base\ftnoir_tracker_base.h"
+#include "ftnoir_tracker_pt_settings.h"
+#include "ftnoir_tracker_pt.h"
+#include "trans_calib.h"
+#include "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();
+ ~TrackerDialog();
+
+ // ITrackerDialog interface
+ void Initialize(QWidget *parent);
+ void registerTracker(ITracker *tracker);
+ void unRegisterTracker();
+
+ void trans_calib_step();
+
+protected slots:
+ // ugly qt stuff
+ void set_video_widget(bool val) { settings.video_widget = val; settings_changed(); }
+ void set_dyn_pose_res(bool val) { settings.dyn_pose_res = val; settings_changed(); }
+ void set_sleep_time(int val) { settings.sleep_time = val; settings_changed(); }
+ void set_reset_time(int val) { settings.reset_time = val; settings_changed(); }
+ void set_cam_index(int idx) { settings.cam_index = idx; settings_changed(); }
+ void set_cam_f(double val) { settings.cam_f = val; settings_changed(); }
+ void set_cam_res_x(int val) { settings.cam_res_x = val; settings_changed(); }
+ void set_cam_res_y(int val) { settings.cam_res_y = val; settings_changed(); }
+ void set_cam_fps(int val) { settings.cam_fps = val; settings_changed(); }
+ void set_cam_roll(int idx);
+ void set_cam_pitch(int val) { settings.cam_pitch = val; settings_changed(); }
+ void set_cam_yaw(int val) { settings.cam_yaw = val; settings_changed(); }
+ void set_min_point_size(int val) { settings.min_point_size = val; settings_changed(); }
+ void set_max_point_size(int val) { settings.max_point_size = val; settings_changed(); }
+ void set_threshold(int val) { settings.threshold = val; settings_changed(); }
+ void set_ena_roll(bool val) { settings.bEnableRoll = val; settings_changed(); }
+ void set_ena_pitch(bool val) { settings.bEnablePitch = val; settings_changed(); }
+ void set_ena_yaw(bool val) { settings.bEnableYaw = val; settings_changed(); }
+ void set_ena_x(bool val) { settings.bEnableX = val; settings_changed(); }
+ void set_ena_y(bool val) { settings.bEnableY = val; settings_changed(); }
+ void set_ena_z(bool val) { settings.bEnableZ = val; settings_changed(); }
+
+ void set_clip_t_height(int val) { dialog_settings.clip_ty = val; set_model_clip(); }
+ void set_clip_t_length(int val) { dialog_settings.clip_tz = val; set_model_clip(); }
+ void set_clip_b_height(int val) { dialog_settings.clip_by = val; set_model_clip(); }
+ void set_clip_b_length(int val) { dialog_settings.clip_bz = val; set_model_clip(); }
+ void set_cap_width(int val) { dialog_settings.cap_x = val; set_model_cap(); }
+ void set_cap_height(int val) { dialog_settings.cap_y = val; set_model_cap(); }
+ void set_cap_length(int val) { dialog_settings.cap_z = val; set_model_cap(); }
+ void set_m1x(int val) { dialog_settings.M01x = val; set_model_custom(); }
+ void set_m1y(int val) { dialog_settings.M01y = val; set_model_custom(); }
+ void set_m1z(int val) { dialog_settings.M01z = val; set_model_custom(); }
+ void set_m2x(int val) { dialog_settings.M02x = val; set_model_custom(); }
+ void set_m2y(int val) { dialog_settings.M02y = val; set_model_custom(); }
+ void set_m2z(int val) { dialog_settings.M02z = val; set_model_custom(); }
+ void set_tx(int val) { settings.t_MH[0] = val; settings_changed(); }
+ void set_ty(int val) { settings.t_MH[1] = val; settings_changed(); }
+ void set_tz(int val) { settings.t_MH[2] = val; settings_changed(); }
+ void set_model(int model_id);
+
+ void doCenter();
+ void doReset();
+
+ void doOK();
+ void doCancel();
+
+ void startstop_trans_calib(bool start);
+
+ void widget_destroyed(QObject* obj);
+
+ void create_video_widget();
+
+ void poll_tracker_info();
+
+protected:
+ void destroy_video_widget(bool do_delete = true);
+
+ void set_model_clip();
+ void set_model_cap();
+ void set_model_custom();
+
+ void settings_changed();
+
+ TrackerSettings settings;
+ TrackerDialogSettings dialog_settings;
+ bool settings_dirty;
+
+ Tracker* tracker;
+ QTimer timer;
+
+ VideoWidgetDialog* video_widget_dialog;
+
+ TranslationCalibrator trans_calib;
+ bool trans_calib_running;
+
+ Ui::UICPTClientControls ui;
+};
+
+#endif //FTNOIR_TRACKER_PT_DIALOG_H
\ No newline at end of file diff --git a/FTNoIR_Tracker_PT/ftnoir_tracker_pt_dll.cpp b/FTNoIR_Tracker_PT/ftnoir_tracker_pt_dll.cpp new file mode 100644 index 00000000..3a73f679 --- /dev/null +++ b/FTNoIR_Tracker_PT/ftnoir_tracker_pt_dll.cpp @@ -0,0 +1,40 @@ +/* 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/icon.ico");
+}
+
+
+//-----------------------------------------------------------------------------
+#pragma comment(linker, "/export:GetTrackerDll=_GetTrackerDll@0")
+
+FTNOIR_TRACKER_BASE_EXPORT ITrackerDllPtr __stdcall GetTrackerDll()
+{
+ return new TrackerDll;
+}
diff --git a/FTNoIR_Tracker_PT/ftnoir_tracker_pt_dll.h b/FTNoIR_Tracker_PT/ftnoir_tracker_pt_dll.h new file mode 100644 index 00000000..15ad63aa --- /dev/null +++ b/FTNoIR_Tracker_PT/ftnoir_tracker_pt_dll.h @@ -0,0 +1,19 @@ +/* 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_base\ftnoir_tracker_base.h"
+
+//-----------------------------------------------------------------------------
+class TrackerDll : public ITrackerDll
+{
+ // ITrackerDll interface
+ void Initialize() {}
+ void getFullName(QString *strToBeFilled);
+ void getShortName(QString *strToBeFilled);
+ void getDescription(QString *strToBeFilled);
+ void getIcon(QIcon *icon);
+};
\ No newline at end of file diff --git a/FTNoIR_Tracker_PT/ftnoir_tracker_pt_settings.cpp b/FTNoIR_Tracker_PT/ftnoir_tracker_pt_settings.cpp new file mode 100644 index 00000000..13ef49ec --- /dev/null +++ b/FTNoIR_Tracker_PT/ftnoir_tracker_pt_settings.cpp @@ -0,0 +1,154 @@ +/* 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 <QCoreApplication>
+#include <QSettings>
+
+//-----------------------------------------------------------------------------
+void TrackerSettings::load_ini()
+{
+ qDebug("TrackerSettings::load_ini()");
+
+ QSettings settings("Abbequerque Inc.", "FaceTrackNoIR"); // Registry settings (in HK_USER)
+ QString currentFile = settings.value( "SettingsFile", QCoreApplication::applicationDirPath() + "/Settings/default.ini" ).toString();
+ QSettings iniFile( currentFile, QSettings::IniFormat ); // Application settings (in INI-file)
+
+ iniFile.beginGroup( "PointTracker" );
+
+ cam_index = iniFile.value("CameraId", 0).toInt();
+ cam_f = iniFile.value("CameraF", 1).toFloat();
+ cam_res_x = iniFile.value("CameraResX", 640).toInt();
+ cam_res_y = iniFile.value("CameraResY", 480).toInt();
+ cam_fps = iniFile.value("CameraFPS", 30).toInt();
+ cam_roll = iniFile.value("CameraRoll", 0).toInt();
+ cam_pitch = iniFile.value("CameraPitch", 0).toInt();
+ cam_yaw = iniFile.value("CameraYaw", 0).toInt();
+ threshold = iniFile.value("PointExtractThreshold", 128).toInt();
+ min_point_size = iniFile.value("PointExtractMinSize", 2).toInt();
+ max_point_size = iniFile.value("PointExtractMaxSize", 50).toInt();
+ M01[0] = iniFile.value("PointModelM01x", 0).toFloat();
+ M01[1] = iniFile.value("PointModelM01y", 40).toFloat();
+ M01[2] = iniFile.value("PointModelM01z", -30).toFloat();
+ M02[0] = iniFile.value("PointModelM02x", 0).toFloat();
+ M02[1] = iniFile.value("PointModelM02y", -70).toFloat();
+ M02[2] = iniFile.value("PointModelM02z", -80).toFloat();
+ t_MH[0] = iniFile.value("tMHx", 0).toFloat();
+ t_MH[1] = iniFile.value("tMHy", 0).toFloat();
+ t_MH[2] = iniFile.value("tMHz", 0).toFloat();
+ dyn_pose_res = iniFile.value("DynamicPoseResolution", true).toBool();
+ video_widget = iniFile.value("VideoWidget", true).toBool();
+ sleep_time = iniFile.value("SleepTime", 10).toInt();
+ reset_time = iniFile.value("ResetTime", 1000).toInt();
+
+ bEnableRoll = iniFile.value("EnableRoll", 1).toBool();
+ bEnablePitch = iniFile.value("EnablePitch", 1).toBool();
+ bEnableYaw = iniFile.value("EnableYaw", 1).toBool();
+ bEnableX = iniFile.value("EnableX", 1).toBool();
+ bEnableY = iniFile.value("EnableY", 1).toBool();
+ bEnableZ = iniFile.value("EnableZ", 1).toBool();
+
+ iniFile.endGroup();
+}
+
+void TrackerSettings::save_ini() const
+{
+ qDebug("TrackerSettings::save_ini()");
+
+ QSettings settings("Abbequerque Inc.", "FaceTrackNoIR"); // Registry settings (in HK_USER)
+ QString currentFile = settings.value( "SettingsFile", QCoreApplication::applicationDirPath() + "/Settings/default.ini" ).toString();
+ QSettings iniFile( currentFile, QSettings::IniFormat ); // Application settings (in INI-file)
+
+ iniFile.beginGroup ( "PointTracker" );
+
+ iniFile.setValue("CameraId", cam_index);
+ iniFile.setValue("CameraF", cam_f);
+ iniFile.setValue("CameraResX", cam_res_x);
+ iniFile.setValue("CameraResY", cam_res_y);
+ iniFile.setValue("CameraFPS", cam_fps);
+ iniFile.setValue("CameraRoll", cam_roll);
+ iniFile.setValue("CameraPitch", cam_pitch);
+ iniFile.setValue("CameraYaw", cam_yaw);
+ iniFile.setValue("PointExtractThreshold", threshold);
+ iniFile.setValue("PointExtractMinSize", min_point_size);
+ iniFile.setValue("PointExtractMaxSize", max_point_size);
+ iniFile.setValue("PointModelM01x", M01[0]);
+ iniFile.setValue("PointModelM01y", M01[1]);
+ iniFile.setValue("PointModelM01z", M01[2]);
+ iniFile.setValue("PointModelM02x", M02[0]);
+ iniFile.setValue("PointModelM02y", M02[1]);
+ iniFile.setValue("PointModelM02z", M02[2]);
+ iniFile.setValue("tMHx", t_MH[0]);
+ iniFile.setValue("tMHy", t_MH[1]);
+ iniFile.setValue("tMHz", t_MH[2]);
+ iniFile.setValue("DynamicPoseResolution", dyn_pose_res);
+ iniFile.setValue("VideoWidget", video_widget);
+ iniFile.setValue("SleepTime", sleep_time);
+ iniFile.setValue("ResetTime", reset_time);
+
+ iniFile.setValue( "EnableRoll", bEnableRoll );
+ iniFile.setValue( "EnablePitch", bEnablePitch );
+ iniFile.setValue( "EnableYaw", bEnableYaw );
+ iniFile.setValue( "EnableX", bEnableX );
+ iniFile.setValue( "EnableY", bEnableY );
+ iniFile.setValue( "EnableZ", bEnableZ );
+
+ iniFile.endGroup();
+}
+
+//-----------------------------------------------------------------------------
+void TrackerDialogSettings::load_ini()
+{
+ qDebug("TrackerDialogSettings::load_ini()");
+
+ QSettings settings("Abbequerque Inc.", "FaceTrackNoIR"); // Registry settings (in HK_USER)
+ QString currentFile = settings.value( "SettingsFile", QCoreApplication::applicationDirPath() + "/Settings/default.ini" ).toString();
+ QSettings iniFile( currentFile, QSettings::IniFormat ); // Application settings (in INI-file)
+
+ iniFile.beginGroup( "PointTrackerDialog" );
+
+ active_model_panel = iniFile.value("ActiveModelPanel", MODEL_CLIP).toInt();
+ M01x = iniFile.value("CustomM01x", 0).toInt();
+ M01y = iniFile.value("CustomM01y", 40).toInt();
+ M01z = iniFile.value("CustomM01z", -30).toInt();
+ M02x = iniFile.value("CustomM02x", 0).toInt();
+ M02y = iniFile.value("CustomM02y", -70).toInt();
+ M02z = iniFile.value("CustomM02z", -80).toInt();
+ clip_ty = iniFile.value("ClipTopHeight", 40).toInt();
+ clip_tz = iniFile.value("ClipTopLength", 30).toInt();
+ clip_by = iniFile.value("ClipBottomHeight", 70).toInt();
+ clip_bz = iniFile.value("ClipBottomLength", 80).toInt();
+ cap_x = iniFile.value("CapHalfWidth", 40).toInt();
+ cap_y = iniFile.value("CapHeight", 60).toInt();
+ cap_z = iniFile.value("CapLength", 100).toInt();
+}
+
+void TrackerDialogSettings::save_ini() const
+{
+ qDebug("TrackerDialogSettings::save_ini()");
+
+ QSettings settings("Abbequerque Inc.", "FaceTrackNoIR"); // Registry settings (in HK_USER)
+ QString currentFile = settings.value( "SettingsFile", QCoreApplication::applicationDirPath() + "/Settings/default.ini" ).toString();
+ QSettings iniFile( currentFile, QSettings::IniFormat ); // Application settings (in INI-file)
+
+ iniFile.beginGroup ( "PointTrackerDialog" );
+
+ iniFile.setValue("ActiveModelPanel", active_model_panel);
+ iniFile.setValue("CustomM01x", M01x);
+ iniFile.setValue("CustomM01y", M01y);
+ iniFile.setValue("CustomM01z", M01z);
+ iniFile.setValue("CustomM02x", M02x);
+ iniFile.setValue("CustomM02y", M02y);
+ iniFile.setValue("CustomM02z", M02z);
+ iniFile.setValue("ClipTopHeight", clip_ty);
+ iniFile.setValue("ClipTopLength", clip_tz);
+ iniFile.setValue("ClipBottomHeight", clip_by);
+ iniFile.setValue("ClipBottomLength", clip_bz);
+ iniFile.setValue("CapHalfWidth", cap_x);
+ iniFile.setValue("CapHeight", cap_y);
+ iniFile.setValue("CapLength", cap_z);
+}
\ No newline at end of file diff --git a/FTNoIR_Tracker_PT/ftnoir_tracker_pt_settings.h b/FTNoIR_Tracker_PT/ftnoir_tracker_pt_settings.h new file mode 100644 index 00000000..1cf60853 --- /dev/null +++ b/FTNoIR_Tracker_PT/ftnoir_tracker_pt_settings.h @@ -0,0 +1,88 @@ +/* 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"
+
+
+//-----------------------------------------------------------------------------
+// Tracker settings and their ini-IO
+struct TrackerSettings
+{
+ // camera
+ int cam_index;
+ float cam_f;
+ int cam_res_x;
+ int cam_res_y;
+ int cam_fps;
+ int cam_roll;
+ int cam_pitch;
+ int cam_yaw;
+
+ // point extraction
+ int threshold;
+ int min_point_size;
+ int max_point_size;
+
+ // point tracking
+ cv::Vec3f M01;
+ cv::Vec3f M02;
+ bool dyn_pose_res;
+
+ // head to model translation
+ cv::Vec3f t_MH;
+
+ int sleep_time; // in ms
+ int reset_time; // in ms
+ bool video_widget;
+
+ bool bEnableRoll;
+ bool bEnablePitch;
+ bool bEnableYaw;
+ bool bEnableX;
+ bool bEnableY;
+ bool bEnableZ;
+
+ void load_ini();
+ void save_ini() const;
+};
+
+
+//-----------------------------------------------------------------------------
+// Settings specific to the tracker dialog and their ini-IO
+struct TrackerDialogSettings
+{
+ enum
+ {
+ MODEL_CLIP,
+ MODEL_CAP,
+ MODEL_CUSTOM
+ };
+ int active_model_panel;
+
+ int M01x;
+ int M01y;
+ int M01z;
+ int M02x;
+ int M02y;
+ int M02z;
+ int clip_ty;
+ int clip_tz;
+ int clip_by;
+ int clip_bz;
+ int cap_x;
+ int cap_y;
+ int cap_z;
+
+ void load_ini();
+ void save_ini() const;
+};
+
+#endif //FTNOIR_TRACKER_PT_SETTINGS_H
\ No newline at end of file diff --git a/FTNoIR_Tracker_PT/point_extractor.cpp b/FTNoIR_Tracker_PT/point_extractor.cpp new file mode 100644 index 00000000..76a152a7 --- /dev/null +++ b/FTNoIR_Tracker_PT/point_extractor.cpp @@ -0,0 +1,101 @@ +/* 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;
+
+// ----------------------------------------------------------------------------
+const vector<Vec2f>& PointExtractor::extract_points(Mat frame, float dt, bool draw_output)
+{
+ const int W = frame.cols;
+ const int H = frame.rows;
+
+ // clear old points
+ points.clear();
+
+ // convert to grayscale
+ Mat frame_gray;
+ cvtColor(frame, frame_gray, CV_RGB2GRAY);
+
+ // convert to binary
+ Mat frame_bin;
+ threshold(frame_gray, frame_bin, threshold_val, 255, THRESH_BINARY);
+
+ 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 = 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)
+ 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;
+ points.push_back(c);
+ }
+ }
+
+ // draw output image
+ if (draw_output) {
+ vector<Mat> channels;
+ 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);
+ merge(channels, frame);
+ }
+
+ return points;
+}
diff --git a/FTNoIR_Tracker_PT/point_extractor.h b/FTNoIR_Tracker_PT/point_extractor.h new file mode 100644 index 00000000..b142d2bb --- /dev/null +++ b/FTNoIR_Tracker_PT/point_extractor.h @@ -0,0 +1,31 @@ +/* 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>
+
+// ----------------------------------------------------------------------------
+// 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; }
+
+ int threshold_val;
+ int min_size, max_size;
+
+protected:
+ std::vector<cv::Vec2f> points;
+};
+
+#endif //POINTEXTRACTOR_H
diff --git a/FTNoIR_Tracker_PT/point_tracker.cpp b/FTNoIR_Tracker_PT/point_tracker.cpp new file mode 100644 index 00000000..acde9154 --- /dev/null +++ b/FTNoIR_Tracker_PT/point_tracker.cpp @@ -0,0 +1,359 @@ +/* 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 boost;
+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);
+}
+
+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 (int i = 0; i<points.size(); ++i)
+ d_vals.push_back(pair<float, int>(d.dot(points[i]), i));
+
+ struct
+ {
+ bool operator()(const pair<float, int>& a, const pair<float, int>& b) { return a.first < b.first; }
+ } comp;
+ sort(d_vals.begin(), d_vals.end(), comp);
+
+ for (int i = 0; i<points.size(); ++i)
+ d_order[i] = d_vals[i].second;
+}
+
+
+// ----------------------------------------------------------------------------
+PointTracker::PointTracker()
+ : init_phase(true),
+ dt_valid(0),
+ dt_reset(1),
+ v_t(0,0,0),
+ v_r(0,0,0),
+ dynamic_pose_resolution(true)
+{
+ 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();
+ }
+
+ // if there is a pointtracking problem, reset the velocities
+ if (!point_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;
+ }
+
+ int n_iter = 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(X_CM.R, 2, k);
+ float Z0 = 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 new file mode 100644 index 00000000..f52e9dd7 --- /dev/null +++ b/FTNoIR_Tracker_PT/point_tracker.h @@ -0,0 +1,125 @@ +/* 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>
+#include <boost/shared_ptr.hpp>
+#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);
+ boost::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/resource.h b/FTNoIR_Tracker_PT/resource.h new file mode 100644 index 00000000..c14e94ad --- /dev/null +++ b/FTNoIR_Tracker_PT/resource.h @@ -0,0 +1,14 @@ +//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by FTNoIR_Tracker_PT.rc
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 101
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/FTNoIR_Tracker_PT/timer.cpp b/FTNoIR_Tracker_PT/timer.cpp new file mode 100644 index 00000000..363b5b09 --- /dev/null +++ b/FTNoIR_Tracker_PT/timer.cpp @@ -0,0 +1,66 @@ +/* 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 "timer.h"
+
+#include <stdlib.h>
+
+// ----------------------------------------------------------------------------
+Timer::Timer()
+: startTime(0), endTime(0), running(false)
+{
+#ifdef WIN32
+ QueryPerformanceFrequency(&frequency);
+ startCount.QuadPart = 0;
+ endCount.QuadPart = 0;
+#else
+ startCount.tv_sec = startCount.tv_usec = 0;
+ endCount.tv_sec = endCount.tv_usec = 0;
+#endif
+}
+
+
+void Timer::start()
+{
+#ifdef WIN32
+ QueryPerformanceCounter(&startCount);
+#else
+ gettimeofday(&startCount, NULL);
+#endif
+ running = true;
+}
+
+
+void Timer::stop()
+{
+#ifdef WIN32
+ QueryPerformanceCounter(&endCount);
+#else
+ gettimeofday(&endCount, NULL);
+#endif
+ running = false;
+}
+
+
+double Timer::elapsed()
+{
+#ifdef WIN32
+ if (running)
+ QueryPerformanceCounter(&endCount);
+
+ startTime = startCount.QuadPart * (1e3 / frequency.QuadPart);
+ endTime = endCount.QuadPart * (1e3 / frequency.QuadPart);
+#else
+ if(!stopped)
+ gettimeofday(&endCount, NULL);
+
+ startTime = (startCount.tv_sec * 1e3) + startCount.tv_usec;
+ endTime = (endCount.tv_sec * 1e3) + endCount.tv_usec;
+#endif
+
+ return endTime - startTime;
+}
\ No newline at end of file diff --git a/FTNoIR_Tracker_PT/timer.h b/FTNoIR_Tracker_PT/timer.h new file mode 100644 index 00000000..f189e23c --- /dev/null +++ b/FTNoIR_Tracker_PT/timer.h @@ -0,0 +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.
+ */
+
+#ifndef PT_TIMER_H
+#define PT_TIMER_H
+
+#ifdef WIN32 // Windows system specific
+#include <windows.h>
+#else // Unix based system specific
+#include <sys/time.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// High resolution timer based on http://www.songho.ca/misc/timer/timer.html
+class Timer
+{
+public:
+ Timer();
+
+ void start();
+ void stop();
+ void restart() { start(); } // for Qt compatibility
+ double elapsed(); // get elapsed time in ms
+
+protected:
+ double startTime; // starting time in ms
+ double endTime; // ending time in ms
+ bool running;
+
+#ifdef WIN32
+ LARGE_INTEGER frequency; // ticks per second
+ LARGE_INTEGER startCount;
+ LARGE_INTEGER endCount;
+#else
+ timeval startCount;
+ timeval endCount;
+#endif
+};
+
+#endif //PT_TIMER_H
\ No newline at end of file diff --git a/FTNoIR_Tracker_PT/trans_calib.cpp b/FTNoIR_Tracker_PT/trans_calib.cpp new file mode 100644 index 00000000..9b75a1b6 --- /dev/null +++ b/FTNoIR_Tracker_PT/trans_calib.cpp @@ -0,0 +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]);
+}
\ No newline at end of file diff --git a/FTNoIR_Tracker_PT/trans_calib.h b/FTNoIR_Tracker_PT/trans_calib.h new file mode 100644 index 00000000..f2521690 --- /dev/null +++ b/FTNoIR_Tracker_PT/trans_calib.h @@ -0,0 +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)
+};
+
+#endif //TRANSCALIB_H
\ No newline at end of file diff --git a/FTNoIR_Tracker_PT/video_widget.cpp b/FTNoIR_Tracker_PT/video_widget.cpp new file mode 100644 index 00000000..236faaf7 --- /dev/null +++ b/FTNoIR_Tracker_PT/video_widget.cpp @@ -0,0 +1,119 @@ +/* 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 "video_widget.h"
+
+#include <QDebug>
+#include <QHBoxLayout>
+
+using namespace cv;
+using namespace std;
+using namespace boost;
+
+// ----------------------------------------------------------------------------
+void VideoWidget::initializeGL()
+{
+ glClearColor(0.0, 0.0, 0.0, 0.0);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+}
+
+void VideoWidget::resizeGL(int w, int h)
+{
+ // setup 1 to 1 projection
+ glViewport(0, 0, w, h);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0, w, 0, h, -1, 1);
+ resize_frame();
+ glDisable(GL_DEPTH_TEST);
+ glBegin(GL_QUADS);
+ glVertex2f(0,0);
+ glVertex2f(1,0);
+ glVertex2f(1,1);
+ glVertex2f(0,1);
+ glEnd();
+}
+
+void VideoWidget::paintGL()
+{
+ glClear(GL_COLOR_BUFFER_BIT);
+ if (!resized_qframe.isNull())
+ {
+ glDrawPixels(resized_qframe.width(), resized_qframe.height(), GL_RGBA, GL_UNSIGNED_BYTE, resized_qframe.bits());
+
+ const int crosshair_radius = 10;
+ const int crosshair_thickness = 1;
+
+ if (points)
+ {
+ glColor3f(1.0, 0.0, 0.0);
+ glLineWidth(crosshair_thickness);
+ int x,y;
+ for (vector<Vec2f>::iterator iter = points->begin();
+ iter != points->end();
+ ++iter)
+ {
+ x = (*iter)[0] * resized_qframe.width() + resized_qframe.width()/2.0 + 0.5;
+ y = (*iter)[1] * resized_qframe.width() + resized_qframe.height()/2.0 + 0.5;
+
+ glBegin(GL_LINES);
+ glVertex2i(x-crosshair_radius, y);
+ glVertex2i(x+crosshair_radius, y);
+ glEnd();
+ glBegin(GL_LINES);
+ glVertex2i(x, y-crosshair_radius);
+ glVertex2i(x, y+crosshair_radius);
+ glEnd();
+ }
+ }
+ }
+ glFlush();
+}
+
+
+void VideoWidget::resize_frame()
+{
+ if (!qframe.isNull())
+ resized_qframe = qframe.scaled(this->size(), Qt::KeepAspectRatio);
+}
+
+
+void VideoWidget::update_frame_and_points()
+{
+ if (!get_frame_and_points(frame, points)) return;
+
+ // convert to QImage
+ if (frame.channels() == 3)
+ qframe = QImage((const unsigned char*)(frame.data), frame.cols, frame.rows, frame.step, QImage::Format_RGB888).rgbSwapped();
+ else if (frame.channels() == 1)
+ qframe = QImage((const unsigned char*)(frame.data), frame.cols, frame.rows, frame.step, QImage::Format_Indexed8);
+ qframe = QGLWidget::convertToGLFormat(qframe);
+
+ resize_frame();
+ updateGL();
+}
+
+// ----------------------------------------------------------------------------
+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 VideoWidget(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);
+}
\ No newline at end of file diff --git a/FTNoIR_Tracker_PT/video_widget.h b/FTNoIR_Tracker_PT/video_widget.h new file mode 100644 index 00000000..dd5fb642 --- /dev/null +++ b/FTNoIR_Tracker_PT/video_widget.h @@ -0,0 +1,58 @@ +/* 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 VIDEOWIDGET_H
+#define VIDEOWIDGET_H
+
+#include "frame_observer.h"
+
+#include <QGLWidget>
+#include <QTime>
+#include <QDialog>
+#include <opencv2/opencv.hpp>
+#include <boost/shared_ptr.hpp>
+
+// ----------------------------------------------------------------------------
+// OpenGL based widget to display an OpenCV image with some points on top
+class VideoWidget : public QGLWidget, public FrameObserver
+{
+ Q_OBJECT
+
+public:
+ VideoWidget(QWidget *parent, FrameProvider* provider) : QGLWidget(parent), FrameObserver(provider) {}
+
+ virtual void initializeGL();
+ virtual void resizeGL(int w, int h);
+ virtual void paintGL();
+
+ void update_frame_and_points();
+
+private:
+ void resize_frame();
+
+ cv::Mat frame;
+ QImage qframe;
+ QImage resized_qframe;
+
+ boost::shared_ptr< std::vector<cv::Vec2f> > points;
+};
+
+// ----------------------------------------------------------------------------
+// A VideoWidget embedded in a dialog frame
+class VideoWidgetDialog : public QDialog
+{
+public:
+ VideoWidgetDialog(QWidget *parent, FrameProvider* provider);
+ virtual ~VideoWidgetDialog() {}
+
+ VideoWidget* get_video_widget() { return video_widget; }
+
+private:
+ VideoWidget* video_widget;
+};
+
+#endif // VIDEOWIDGET_H
|