diff options
Diffstat (limited to 'ftnoir_tracker_aruco')
-rw-r--r-- | ftnoir_tracker_aruco/ar_video_widget.cpp | 12 | ||||
-rw-r--r-- | ftnoir_tracker_aruco/ar_video_widget.h | 22 | ||||
-rw-r--r-- | ftnoir_tracker_aruco/aruco-trackercontrols.ui | 425 | ||||
-rw-r--r-- | ftnoir_tracker_aruco/ftnoir_tracker_aruco.cpp | 457 | ||||
-rw-r--r-- | ftnoir_tracker_aruco/ftnoir_tracker_aruco.h | 59 | ||||
-rw-r--r-- | ftnoir_tracker_aruco/ftnoir_tracker_aruco_dll.h | 3 | ||||
-rw-r--r-- | ftnoir_tracker_aruco/include/boarddetector.h | 2 | ||||
-rw-r--r-- | ftnoir_tracker_aruco/include/cameraparameters.h | 6 | ||||
-rw-r--r-- | ftnoir_tracker_aruco/include/cvdrawingutils.h | 2 | ||||
-rw-r--r-- | ftnoir_tracker_aruco/include/exports.h | 6 | ||||
-rw-r--r-- | ftnoir_tracker_aruco/include/marker.h | 16 | ||||
-rw-r--r-- | ftnoir_tracker_aruco/include/markerdetector.h | 64 | ||||
-rw-r--r-- | ftnoir_tracker_aruco/trans_calib.cpp | 44 | ||||
-rw-r--r-- | ftnoir_tracker_aruco/trans_calib.h | 39 |
14 files changed, 578 insertions, 579 deletions
diff --git a/ftnoir_tracker_aruco/ar_video_widget.cpp b/ftnoir_tracker_aruco/ar_video_widget.cpp index 9a089213..61a611ea 100644 --- a/ftnoir_tracker_aruco/ar_video_widget.cpp +++ b/ftnoir_tracker_aruco/ar_video_widget.cpp @@ -40,3 +40,15 @@ void ArucoVideoWidget::update_and_repaint() texture = qframe2; update(); } + +void ArucoVideoWidget::paintEvent(QPaintEvent* e) +{ + QMutexLocker foo(&mtx); + QPainter(this).drawImage(e->rect(), texture); +} + +ArucoVideoWidget::ArucoVideoWidget(QWidget* parent): QWidget(parent) +{ + connect(&timer, SIGNAL(timeout()), this, SLOT(update_and_repaint())); + timer.start(60); +}
\ No newline at end of file diff --git a/ftnoir_tracker_aruco/ar_video_widget.h b/ftnoir_tracker_aruco/ar_video_widget.h index e2cf4d9f..820ba7d0 100644 --- a/ftnoir_tracker_aruco/ar_video_widget.h +++ b/ftnoir_tracker_aruco/ar_video_widget.h @@ -22,26 +22,18 @@ class ArucoVideoWidget : public QWidget { Q_OBJECT - -public: - ArucoVideoWidget(QWidget *parent) : QWidget(parent) { - connect(&timer, SIGNAL(timeout()), this, SLOT(update_and_repaint())); - timer.start(60); - } - void update_image(const cv::Mat& frame); -protected slots: - void paintEvent( QPaintEvent* e ) { - QMutexLocker foo(&mtx); - QPainter painter(this); - painter.drawImage(e->rect(), texture); - } - void update_and_repaint(); - + private: QMutex mtx; QImage texture; QTimer timer; cv::Mat _frame; +private slots: + void update_and_repaint(); +public: + ArucoVideoWidget(QWidget *parent); + void update_image(const cv::Mat& frame); + void paintEvent( QPaintEvent*) override; }; #endif // VIDEOWIDGET_H diff --git a/ftnoir_tracker_aruco/aruco-trackercontrols.ui b/ftnoir_tracker_aruco/aruco-trackercontrols.ui index 1d5a4241..099dec02 100644 --- a/ftnoir_tracker_aruco/aruco-trackercontrols.ui +++ b/ftnoir_tracker_aruco/aruco-trackercontrols.ui @@ -9,8 +9,8 @@ <rect> <x>0</x> <y>0</y> - <width>615</width> - <height>326</height> + <width>562</width> + <height>178</height> </rect> </property> <property name="sizePolicy"> @@ -19,67 +19,160 @@ <verstretch>0</verstretch> </sizepolicy> </property> - <property name="maximumSize"> - <size> - <width>6666</width> - <height>6666</height> - </size> - </property> <property name="windowTitle"> - <string>HT tracker settings</string> + <string>Tracker settings</string> </property> <layout class="QGridLayout" name="gridLayout"> - <property name="spacing"> - <number>7</number> - </property> - <item row="9" column="1" rowspan="3"> - <widget class="QGroupBox" name="groupBox_2"> - <property name="title"> - <string>Head position</string> - </property> - <property name="alignment"> - <set>Qt::AlignCenter</set> + <item row="1" column="1"> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> </property> - <layout class="QGridLayout" name="gridLayout_2"> - <item row="2" column="0"> - <widget class="QLabel" name="label_7"> - <property name="text"> - <string>TY</string> + </widget> + </item> + <item row="0" column="0"> + <widget class="QFrame" name="frame"> + <layout class="QGridLayout" name="gridLayout_3"> + <item row="0" column="1"> + <widget class="QDoubleSpinBox" name="cameraFOV"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="locale"> + <locale language="English" country="UnitedStates"/> + </property> + <property name="minimum"> + <double>35.000000000000000</double> + </property> + <property name="maximum"> + <double>180.000000000000000</double> + </property> + <property name="value"> + <double>52.000000000000000</double> </property> </widget> </item> <item row="1" column="0"> - <widget class="QLabel" name="label_5"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Frames per second</string> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="label_4"> + <property name="text"> + <string>Resolution</string> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="label"> <property name="text"> - <string>TX</string> + <string>Horizontal FOV</string> </property> </widget> </item> <item row="1" column="1"> - <widget class="QDoubleSpinBox" name="cx"> + <widget class="QComboBox" name="cameraFPS"> <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> - <property name="minimum"> - <double>-10000.000000000000000</double> + <item> + <property name="text"> + <string notr="true">Default</string> + </property> + </item> + <item> + <property name="text"> + <string>30</string> + </property> + </item> + <item> + <property name="text"> + <string>60</string> + </property> + </item> + <item> + <property name="text"> + <string>120</string> + </property> + </item> + <item> + <property name="text"> + <string>180</string> + </property> + </item> + </widget> + </item> + <item row="3" column="1"> + <widget class="QComboBox" name="resolution"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> </property> - <property name="maximum"> - <double>10000.000000000000000</double> + <item> + <property name="text"> + <string>640x480</string> + </property> + </item> + <item> + <property name="text"> + <string>320x240</string> + </property> + </item> + <item> + <property name="text"> + <string>320x200</string> + </property> + </item> + <item> + <property name="text"> + <string>Default (not recommended!)</string> + </property> + </item> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Camera name</string> </property> </widget> </item> - <item row="3" column="0"> - <widget class="QLabel" name="label_8"> + <item row="2" column="1"> + <widget class="QComboBox" name="cameraName"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item row="0" column="1"> + <widget class="QFrame" name="frame_2"> + <layout class="QGridLayout" name="gridLayout_2"> + <item row="1" column="0"> + <widget class="QLabel" name="label_5"> <property name="text"> - <string>TZ</string> + <string>Head X</string> </property> </widget> </item> - <item row="3" column="1"> - <widget class="QDoubleSpinBox" name="cz"> + <item row="2" column="1"> + <widget class="QDoubleSpinBox" name="cy"> <property name="sizePolicy"> <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> <horstretch>0</horstretch> @@ -94,8 +187,8 @@ </property> </widget> </item> - <item row="2" column="1"> - <widget class="QDoubleSpinBox" name="cy"> + <item row="1" column="1"> + <widget class="QDoubleSpinBox" name="cx"> <property name="sizePolicy"> <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> <horstretch>0</horstretch> @@ -110,264 +203,48 @@ </property> </widget> </item> - </layout> - </widget> - </item> - <item row="0" column="3" rowspan="3" colspan="2"> - <widget class="QGroupBox" name="groupBox"> - <property name="title"> - <string>Enable axes</string> - </property> - <layout class="QFormLayout" name="formLayout"> - <property name="horizontalSpacing"> - <number>7</number> - </property> - <property name="leftMargin"> - <number>6</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>6</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item row="0" column="0"> - <widget class="QCheckBox" name="rx"> - <property name="text"> - <string>RX</string> + <item row="3" column="1"> + <widget class="QDoubleSpinBox" name="cz"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QCheckBox" name="tx"> - <property name="text"> - <string>TX</string> + <property name="minimum"> + <double>-10000.000000000000000</double> </property> - </widget> - </item> - <item row="1" column="0"> - <widget class="QCheckBox" name="ry"> - <property name="text"> - <string>RY</string> + <property name="maximum"> + <double>10000.000000000000000</double> </property> </widget> </item> - <item row="1" column="1"> - <widget class="QCheckBox" name="ty"> + <item row="3" column="0"> + <widget class="QLabel" name="label_8"> <property name="text"> - <string>TY</string> + <string>Head Z </string> </property> </widget> </item> <item row="2" column="0"> - <widget class="QCheckBox" name="rz"> + <widget class="QLabel" name="label_7"> <property name="text"> - <string>RZ</string> + <string>Head Y</string> </property> </widget> </item> - <item row="2" column="1"> - <widget class="QCheckBox" name="tz"> + <item row="4" column="1"> + <widget class="QPushButton" name="btn_calibrate"> <property name="text"> - <string>TZ</string> + <string>Calibrate</string> </property> </widget> </item> </layout> </widget> </item> - <item row="1" column="0"> - <widget class="QLabel" name="label_2"> - <property name="text"> - <string>Frames per second</string> - </property> - </widget> - </item> - <item row="2" column="1" colspan="2"> - <widget class="QComboBox" name="cameraName"/> - </item> - <item row="1" column="1" colspan="2"> - <widget class="QComboBox" name="cameraFPS"> - <item> - <property name="text"> - <string notr="true">Default</string> - </property> - </item> - <item> - <property name="text"> - <string>30</string> - </property> - </item> - <item> - <property name="text"> - <string>60</string> - </property> - </item> - <item> - <property name="text"> - <string>120</string> - </property> - </item> - <item> - <property name="text"> - <string>180</string> - </property> - </item> - </widget> - </item> - <item row="7" column="1"> - <widget class="QCheckBox" name="red_only"> - <property name="text"> - <string>Recommended!</string> - </property> - </widget> - </item> - <item row="2" column="0"> - <widget class="QLabel" name="label_3"> - <property name="text"> - <string>Camera name</string> - </property> - </widget> - </item> - <item row="0" column="1" colspan="2"> - <widget class="QDoubleSpinBox" name="cameraFOV"> - <property name="locale"> - <locale language="English" country="UnitedStates"/> - </property> - <property name="minimum"> - <double>35.000000000000000</double> - </property> - <property name="maximum"> - <double>180.000000000000000</double> - </property> - <property name="value"> - <double>52.000000000000000</double> - </property> - </widget> - </item> - <item row="6" column="2" rowspan="5" colspan="3"> - <widget class="QLabel" name="label_6"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string><html><head/><body><p>The ARUCO Library has been developed by the Ava group of the Univeristy of Cordoba, Spain</p><p>Rafael Muñoz Salinas &lt;<a href="mailto:rmsalinas@uco.es"><span style=" text-decoration: underline; color:#0057ae;">rmsalinas@uco.es</span></a>&gt;</p><p>&lt;<a href="https://github.com/rmsalinas/aruco"><span style=" text-decoration: underline; color:#0057ae;">https://github.com/rmsalinas/aruco</span></a>&gt;</p></body></html></string> - </property> - <property name="textFormat"> - <enum>Qt::RichText</enum> - </property> - <property name="alignment"> - <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> - </property> - <property name="wordWrap"> - <bool>true</bool> - </property> - <property name="margin"> - <number>4</number> - </property> - <property name="openExternalLinks"> - <bool>true</bool> - </property> - <property name="textInteractionFlags"> - <set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> - </property> - </widget> - </item> - <item row="7" column="0"> - <widget class="QLabel" name="label_10"> - <property name="text"> - <string>Red channel only</string> - </property> - </widget> - </item> - <item row="6" column="1"> - <widget class="QComboBox" name="resolution"> - <item> - <property name="text"> - <string>640x480</string> - </property> - </item> - <item> - <property name="text"> - <string>320x240</string> - </property> - </item> - <item> - <property name="text"> - <string>320x200</string> - </property> - </item> - <item> - <property name="text"> - <string>Default (not recommended!)</string> - </property> - </item> - </widget> - </item> - <item row="0" column="0"> - <widget class="QLabel" name="label"> - <property name="text"> - <string>Horizontal FOV</string> - </property> - </widget> - </item> - <item row="11" column="4"> - <widget class="QDialogButtonBox" name="buttonBox"> - <property name="standardButtons"> - <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> - </property> - </widget> - </item> - <item row="8" column="1"> - <widget class="QDoubleSpinBox" name="marker_pitch"> - <property name="minimum"> - <double>-180.000000000000000</double> - </property> - <property name="maximum"> - <double>180.000000000000000</double> - </property> - </widget> - </item> - <item row="6" column="0"> - <widget class="QLabel" name="label_4"> - <property name="text"> - <string>Resolution</string> - </property> - </widget> - </item> - <item row="8" column="0"> - <widget class="QLabel" name="label_9"> - <property name="text"> - <string>Marker pitch</string> - </property> - </widget> - </item> </layout> </widget> - <tabstops> - <tabstop>cameraFOV</tabstop> - <tabstop>cameraFPS</tabstop> - <tabstop>cameraName</tabstop> - <tabstop>resolution</tabstop> - <tabstop>red_only</tabstop> - <tabstop>marker_pitch</tabstop> - <tabstop>cx</tabstop> - <tabstop>cy</tabstop> - <tabstop>cz</tabstop> - <tabstop>rx</tabstop> - <tabstop>ry</tabstop> - <tabstop>rz</tabstop> - <tabstop>tx</tabstop> - <tabstop>ty</tabstop> - <tabstop>tz</tabstop> - <tabstop>buttonBox</tabstop> - </tabstops> <resources/> <connections/> <designerdata> diff --git a/ftnoir_tracker_aruco/ftnoir_tracker_aruco.cpp b/ftnoir_tracker_aruco/ftnoir_tracker_aruco.cpp index ae7ca0b5..fd8a8ce1 100644 --- a/ftnoir_tracker_aruco/ftnoir_tracker_aruco.cpp +++ b/ftnoir_tracker_aruco/ftnoir_tracker_aruco.cpp @@ -5,17 +5,16 @@ * copyright notice and this permission notice appear in all copies. */ -#include "ftnoir_tracker_base/ftnoir_tracker_base.h" -#include "ftnoir_tracker_aruco.h" -#include "ui_aruco-trackercontrols.h" -#include "facetracknoir/global-settings.h" -#include <cmath> -#include <QMutexLocker> -#include <aruco.h> -#include <opencv2/opencv.hpp> -#include <opencv/highgui.h> #include <vector> #include <cstdio> +#include <cmath> +#include <algorithm> +#include <QMutexLocker> +#include "./include/markerdetector.h" +#include "ftnoir_tracker_aruco.h" +#include "facetracknoir/plugin-api.hpp" +#include <opencv2/core/core.hpp> +#include <opencv2/highgui/highgui.hpp> #if defined(_WIN32) # undef NOMINMAX @@ -30,51 +29,51 @@ static QList<QString> get_camera_names(void) { QList<QString> ret; #if defined(_WIN32) - // Create the System Device Enumerator. - HRESULT hr; - ICreateDevEnum *pSysDevEnum = NULL; - hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void **)&pSysDevEnum); - if (FAILED(hr)) - { - return ret; - } - // Obtain a class enumerator for the video compressor category. - IEnumMoniker *pEnumCat = NULL; - hr = pSysDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnumCat, 0); - - if (hr == S_OK) { - // Enumerate the monikers. - IMoniker *pMoniker = NULL; - ULONG cFetched; - while (pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK) { - IPropertyBag *pPropBag; - hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pPropBag); - if (SUCCEEDED(hr)) { - // To retrieve the filter's friendly name, do the following: - VARIANT varName; - VariantInit(&varName); - hr = pPropBag->Read(L"FriendlyName", &varName, 0); - if (SUCCEEDED(hr)) - { - // Display the name in your UI somehow. - QString str((QChar*)varName.bstrVal, wcslen(varName.bstrVal)); - ret.append(str); - } - VariantClear(&varName); - - ////// To create an instance of the filter, do the following: - ////IBaseFilter *pFilter; - ////hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter, - //// (void**)&pFilter); - // Now add the filter to the graph. - //Remember to release pFilter later. - pPropBag->Release(); - } - pMoniker->Release(); - } - pEnumCat->Release(); - } - pSysDevEnum->Release(); + // Create the System Device Enumerator. + HRESULT hr; + ICreateDevEnum *pSysDevEnum = NULL; + hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void **)&pSysDevEnum); + if (FAILED(hr)) + { + return ret; + } + // Obtain a class enumerator for the video compressor category. + IEnumMoniker *pEnumCat = NULL; + hr = pSysDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnumCat, 0); + + if (hr == S_OK) { + // Enumerate the monikers. + IMoniker *pMoniker = NULL; + ULONG cFetched; + while (pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK) { + IPropertyBag *pPropBag; + hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pPropBag); + if (SUCCEEDED(hr)) { + // To retrieve the filter's friendly name, do the following: + VARIANT varName; + VariantInit(&varName); + hr = pPropBag->Read(L"FriendlyName", &varName, 0); + if (SUCCEEDED(hr)) + { + // Display the name in your UI somehow. + QString str((QChar*)varName.bstrVal, wcslen(varName.bstrVal)); + ret.append(str); + } + VariantClear(&varName); + + ////// To create an instance of the filter, do the following: + ////IBaseFilter *pFilter; + ////hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter, + //// (void**)&pFilter); + // Now add the filter to the graph. + //Remember to release pFilter later. + pPropBag->Release(); + } + pMoniker->Release(); + } + pEnumCat->Release(); + } + pSysDevEnum->Release(); #else for (int i = 0; i < 16; i++) { char buf[128]; @@ -90,15 +89,15 @@ static QList<QString> get_camera_names(void) { } typedef struct { - int width; - int height; + int width; + int height; } resolution_tuple; static resolution_tuple resolution_choices[] = { - { 640, 480 }, - { 320, 240 }, - { 320, 200 }, - { 0, 0 } + { 640, 480 }, + { 320, 240 }, + { 320, 200 }, + { 0, 0 } }; Tracker::Tracker() : stop(false), layout(nullptr), videoWidget(nullptr) @@ -109,8 +108,8 @@ Tracker::~Tracker() { stop = true; wait(); - if (videoWidget) - delete videoWidget; + if (videoWidget) + delete videoWidget; if(layout) delete layout; qDebug() << "releasing camera, brace for impact"; @@ -137,12 +136,20 @@ void Tracker::StartTracker(QFrame* videoframe) #define HT_PI 3.1415926535 +void Tracker::getRT(cv::Matx33d& r_, cv::Vec3d& t_) +{ + QMutexLocker l(&mtx); + + r_ = r; + t_ = t; +} + void Tracker::run() { - int res = s.resolution; - if (res < 0 || res >= (int)(sizeof(resolution_choices) / sizeof(resolution_tuple))) - res = 0; - resolution_tuple r = resolution_choices[res]; + int rint = s.resolution; + if (rint < 0 || rint >= (int)(sizeof(resolution_choices) / sizeof(resolution_tuple))) + rint = 0; + resolution_tuple res = resolution_choices[rint]; int fps; switch (static_cast<int>(s.force_fps)) { @@ -164,23 +171,19 @@ void Tracker::run() break; } camera = cv::VideoCapture(s.camera_index); - if (r.width) + if (res.width) { - camera.set(CV_CAP_PROP_FRAME_WIDTH, r.width); - camera.set(CV_CAP_PROP_FRAME_HEIGHT, r.height); + camera.set(CV_CAP_PROP_FRAME_WIDTH, res.width); + camera.set(CV_CAP_PROP_FRAME_HEIGHT, res.height); } if (fps) camera.set(CV_CAP_PROP_FPS, fps); - + aruco::MarkerDetector detector; detector.setDesiredSpeed(3); cv::Rect last_roi(65535, 65535, 0, 0); - cv::Mat color, color_, grayscale, rvec, tvec; - - const double stateful_coeff = 0.88; - if (!camera.isOpened()) { fprintf(stderr, "aruco tracker: can't open camera\n"); @@ -191,23 +194,17 @@ void Tracker::run() auto last_time = cv::getTickCount(); int cur_fps = 0; int last_fps = 0; - cv::Point2f last_centroid; - bool first = true; while (!stop) { - if (!camera.read(color_)) + cv::Mat color; + if (!camera.read(color)) continue; auto tm = cv::getTickCount(); - color_.copyTo(color); - if (s.red_only) - { - cv::Mat channel[3]; - cv::split(color, channel); - grayscale = channel[2]; - } else - cv::cvtColor(color, grayscale, cv::COLOR_BGR2GRAY); - + + cv::Mat grayscale; + cv::cvtColor(color, grayscale, cv::COLOR_BGR2GRAY); + const int scale = frame.cols > 480 ? 2 : 1; detector.setThresholdParams(scale > 1 ? 11 : 7, 4); @@ -225,27 +222,33 @@ void Tracker::run() const double size_min = 0.04; const double size_max = 0.38; - - if (last_roi.width > 0 && - (detector.detect(grayscale(last_roi), markers, cv::Mat(), cv::Mat(), -1, false), - markers.size() == 1 && markers[0].size() == 4)) + + bool roi_valid = false; + + if (last_roi.width > 0 && last_roi.height) { detector.setMinMaxSize(std::max(0.01, size_min * grayscale.cols / last_roi.width), std::min(1.0, size_max * grayscale.cols / last_roi.width)); - auto& m = markers.at(0); - for (int i = 0; i < 4; i++) + if (detector.detect(grayscale(last_roi), markers, cv::Mat(), cv::Mat(), -1, false), + markers.size() == 1 && markers[0].size() == 4) { - auto& p = m.at(i); - p.x += last_roi.x; - p.y += last_roi.y; + auto& m = markers.at(0); + for (int i = 0; i < 4; i++) + { + auto& p = m.at(i); + p.x += last_roi.x; + p.y += last_roi.y; + } + roi_valid = true; } } - else + + if (!roi_valid) { detector.setMinMaxSize(size_min, size_max); detector.detect(grayscale, markers, cv::Mat(), cv::Mat(), -1, false); } - + if (markers.size() == 1 && markers[0].size() == 4) { const auto& m = markers.at(0); for (int i = 0; i < 4; i++) @@ -268,97 +271,122 @@ void Tracker::run() frame = color.clone(); ::sprintf(buf, "Hz: %d", last_fps); - cv::putText(frame, buf, cv::Point(10, 32), cv::FONT_HERSHEY_PLAIN, scale, cv::Scalar(0, 255, 0), scale); + cv::putText(frame, buf, cv::Point(10, 32), cv::FONT_HERSHEY_PLAIN, scale, cv::Scalar(0, 255, 0), 1); ::sprintf(buf, "Jiffies: %ld", (long) (10000 * (time - tm) / freq)); - cv::putText(frame, buf, cv::Point(10, 54), cv::FONT_HERSHEY_PLAIN, scale, cv::Scalar(80, 255, 0), scale); - + cv::putText(frame, buf, cv::Point(10, 54), cv::FONT_HERSHEY_PLAIN, scale, cv::Scalar(80, 255, 0), 1); + if (markers.size() == 1 && markers[0].size() == 4) { const auto& m = markers.at(0); const float size = 40; - - const double p = s.marker_pitch; - const double sq = sin(p * HT_PI / 180); - const double cq = cos(p * HT_PI / 180); cv::Mat obj_points(4,3,CV_32FC1); - obj_points.at<float>(1,0)=-size + s.headpos_x; - obj_points.at<float>(1,1)=-size * cq + s.headpos_y; - obj_points.at<float>(1,2)=-size * sq + s.headpos_z; - obj_points.at<float>(2,0)=size + s.headpos_x; - obj_points.at<float>(2,1)=-size * cq + s.headpos_y; - obj_points.at<float>(2,2)=-size * sq + s.headpos_z; - obj_points.at<float>(3,0)=size + s.headpos_x; - obj_points.at<float>(3,1)=size * cq + s.headpos_y; - obj_points.at<float>(3,2)=size * sq + s.headpos_z; - obj_points.at<float>(0,0)=-size + s.headpos_x; - obj_points.at<float>(0,1)=size * cq + s.headpos_y; - obj_points.at<float>(0,2)=size * sq + s.headpos_z; - - last_roi = cv::Rect(65535, 65535, 0, 0); - + const int x1=1, x2=2, x3=3, x4=0; + obj_points.at<float>(x1,0)=-size + s.headpos_x; + obj_points.at<float>(x1,1)=-size + s.headpos_y; + obj_points.at<float>(x1,2)= 0 + s.headpos_z; + + obj_points.at<float>(x2,0)=size + s.headpos_x; + obj_points.at<float>(x2,1)=-size + s.headpos_y; + obj_points.at<float>(x2,2)= 0 + s.headpos_z; + + obj_points.at<float>(x3,0)=size + s.headpos_x; + obj_points.at<float>(x3,1)=size + s.headpos_y; + obj_points.at<float>(x3,2)= 0 + s.headpos_z; + + obj_points.at<float>(x4,0)= -size + s.headpos_x; + obj_points.at<float>(x4,1)= size + s.headpos_y; + obj_points.at<float>(x4,2)= 0 + s.headpos_z; + + cv::Vec3d rvec, tvec; + + cv::solvePnP(obj_points, m, intrinsics, dist_coeffs, rvec, tvec, false, cv::P3P); + + std::vector<cv::Point2f> roi_projection(4); + + { + std::vector<cv::Point2f> repr2; + std::vector<cv::Point3f> centroid; + centroid.push_back(cv::Point3f(0, 0, 0)); + cv::projectPoints(centroid, rvec, tvec, intrinsics, dist_coeffs, repr2); + + { + auto s = cv::Scalar(255, 0, 255); + cv::circle(frame, repr2.at(0), 4, s, -1); + } + } + for (int i = 0; i < 4; i++) { - auto foo = m.at(i); - last_roi.x = std::min<int>(foo.x, last_roi.x); - last_roi.y = std::min<int>(foo.y, last_roi.y); - last_roi.width = std::max<int>(foo.x, last_roi.width); - last_roi.height = std::max<int>(foo.y, last_roi.height); + obj_points.at<float>(i, 0) -= s.headpos_x; + obj_points.at<float>(i, 1) -= s.headpos_y; + obj_points.at<float>(i, 2) -= s.headpos_z; } + + { + cv::Mat rvec_, tvec_; + cv::solvePnP(obj_points, m, intrinsics, dist_coeffs, rvec_, tvec_, false, cv::P3P); + tvec = tvec_; + } + + cv::Mat roi_points = obj_points * c_search_window; + cv::projectPoints(roi_points, rvec, tvec, intrinsics, dist_coeffs, roi_projection); + + last_roi = cv::Rect(color.cols-1, color.rows-1, 0, 0); + + for (int i = 0; i < 4; i++) { - last_roi.width -= last_roi.x; - last_roi.height -= last_roi.y; - last_roi.x -= last_roi.width * stateful_coeff; - last_roi.y -= last_roi.height * stateful_coeff; - last_roi.width *= stateful_coeff * 3; - last_roi.height *= stateful_coeff * 3; - last_roi.x = std::max<int>(0, last_roi.x); - last_roi.y = std::max<int>(0, last_roi.y); - last_roi.width = std::min<int>(grayscale.cols - last_roi.x, last_roi.width); - last_roi.height = std::min<int>(grayscale.rows - last_roi.y, last_roi.height); + auto proj = roi_projection[i]; + int min_x = std::min<int>(proj.x, last_roi.x), + min_y = std::min<int>(proj.y, last_roi.y); + + int max_x = std::max<int>(proj.x, last_roi.width), + max_y = std::max<int>(proj.y, last_roi.height); + + last_roi.x = min_x; + last_roi.y = min_y; + + last_roi.width = max_x; + last_roi.height = max_y; } + + if (last_roi.x < 0) + last_roi.x = 0; + if (last_roi.y < 0) + last_roi.y = 0; + + if (last_roi.width+1 > color.cols) + last_roi.width = color.cols-1; + + if (last_roi.height+1 > color.rows) + last_roi.height = color.rows-1; - cv::solvePnP(obj_points, m, intrinsics, dist_coeffs, rvec, tvec, !first, cv::ITERATIVE); - first = false; - cv::Mat rotation_matrix = cv::Mat::zeros(3, 3, CV_64FC1); - cv::Mat junk1(3, 3, CV_64FC1), junk2(3, 3, CV_64FC1); - cv::Rodrigues(rvec, rotation_matrix); + last_roi.width -= last_roi.x; + last_roi.height -= last_roi.y; + + auto rmat = cv::Matx33d::zeros(); + cv::Matx33d m_r(3, 3, CV_64FC1), m_q(3, 3, CV_64FC1); + cv::Rodrigues(rvec, rmat); { - cv::Vec3d euler = cv::RQDecomp3x3(rotation_matrix, junk1, junk2); - - if (fabs(euler[0]) + fabs(s.marker_pitch) > 60) - { - first = true; - qDebug() << "reset levmarq due to pitch breakage"; - } + cv::Vec3d euler = cv::RQDecomp3x3(rmat, m_r, m_q); QMutexLocker lck(&mtx); for (int i = 0; i < 3; i++) - pose[i] = tvec.at<double>(i); - + pose[i] = tvec(i); pose[Yaw] = euler[1]; pose[Pitch] = -euler[0]; pose[Roll] = euler[2]; - } - std::vector<cv::Point2f> repr2; - std::vector<cv::Point3f> centroid; - centroid.push_back(cv::Point3f(0, 0, 0)); - cv::projectPoints(centroid, rvec, tvec, intrinsics, dist_coeffs, repr2); - - { - auto s = cv::Scalar(255, 0, 255); - cv::circle(frame, repr2.at(0), 4, s, -1); + r = rmat; + t = tvec; } - - last_centroid = repr2[0]; + + if (roi_valid) + cv::rectangle(frame, last_roi, cv::Scalar(255, 0, 255), 1); } else - { last_roi = cv::Rect(65535, 65535, 0, 0); - first = true; - } if (frame.rows > 0) videoWidget->update_image(frame); @@ -368,28 +396,22 @@ void Tracker::run() void Tracker::GetHeadPoseData(double *data) { QMutexLocker lck(&mtx); - - if (s.eyaw) - data[Yaw] = pose[Yaw]; - if (s.epitch) - data[Pitch] = pose[Pitch]; - if (s.eroll) - data[Roll] = pose[Roll]; - if (s.ex) - data[TX] = pose[TX] * .1; - if (s.ey) - data[TY] = pose[TY] * .1; - if (s.ez) - data[TZ] = pose[TZ] * .1; + + data[Yaw] = pose[Yaw]; + data[Pitch] = pose[Pitch]; + data[Roll] = pose[Roll]; + data[TX] = pose[TX] * .1; + data[TY] = pose[TY] * .1; + data[TZ] = pose[TZ] * .1; } class TrackerDll : public Metadata { - // ITrackerDll interface - void getFullName(QString *strToBeFilled); - void getShortName(QString *strToBeFilled); - void getDescription(QString *strToBeFilled); - void getIcon(QIcon *icon); + // ITrackerDll interface + void getFullName(QString *strToBeFilled); + void getShortName(QString *strToBeFilled); + void getDescription(QString *strToBeFilled); + void getIcon(QIcon *icon); }; //----------------------------------------------------------------------------- @@ -400,12 +422,12 @@ void TrackerDll::getFullName(QString *strToBeFilled) void TrackerDll::getShortName(QString *strToBeFilled) { - *strToBeFilled = "aruco"; + *strToBeFilled = "aruco"; } void TrackerDll::getDescription(QString *strToBeFilled) { - *strToBeFilled = ""; + *strToBeFilled = ""; } void TrackerDll::getIcon(QIcon *icon) @@ -417,28 +439,19 @@ void TrackerDll::getIcon(QIcon *icon) //----------------------------------------------------------------------------- //#pragma comment(linker, "/export:GetTrackerDll=_GetTrackerDll@0") -extern "C" FTNOIR_TRACKER_BASE_EXPORT Metadata* CALLING_CONVENTION GetMetadata() +extern "C" OPENTRACK_EXPORT Metadata* GetMetadata() { - return new TrackerDll; + return new TrackerDll; } //#pragma comment(linker, "/export:GetTracker=_GetTracker@0") -extern "C" FTNOIR_TRACKER_BASE_EXPORT ITracker* CALLING_CONVENTION GetConstructor() +extern "C" OPENTRACK_EXPORT ITracker* GetConstructor() { return new Tracker; } -//////////////////////////////////////////////////////////////////////////////// -// Factory function that creates instances if the Tracker-settings dialog object. - -// Export both decorated and undecorated names. -// GetTrackerDialog - Undecorated name, which can be easily used with GetProcAddress -// Win32 API function. -// _GetTrackerDialog@0 - Common name decoration for __stdcall functions in C language. -//#pragma comment(linker, "/export:GetTrackerDialog=_GetTrackerDialog@0") - -extern "C" FTNOIR_TRACKER_BASE_EXPORT ITrackerDialog* CALLING_CONVENTION GetDialog( ) +extern "C" OPENTRACK_EXPORT ITrackerDialog* GetDialog( ) { return new TrackerControls; } @@ -446,26 +459,54 @@ extern "C" FTNOIR_TRACKER_BASE_EXPORT ITrackerDialog* CALLING_CONVENTION GetDial TrackerControls::TrackerControls() { tracker = nullptr; - ui.setupUi(this); + calib_timer.setInterval(200); + ui.setupUi(this); setAttribute(Qt::WA_NativeWindow, true); + ui.cameraName->addItems(get_camera_names()); tie_setting(s.camera_index, ui.cameraName); - tie_setting(s.resolution, ui.resolution); + tie_setting(s.resolution, ui.resolution); tie_setting(s.force_fps, ui.cameraFPS); tie_setting(s.fov, ui.cameraFOV); - tie_setting(s.eyaw, ui.rx); - tie_setting(s.epitch, ui.ry); - tie_setting(s.eroll, ui.rz); - tie_setting(s.ex, ui.tx); - tie_setting(s.ey, ui.ty); - tie_setting(s.ez, ui.tz); tie_setting(s.headpos_x, ui.cx); tie_setting(s.headpos_y, ui.cy); tie_setting(s.headpos_z, ui.cz); - tie_setting(s.red_only, ui.red_only); - tie_setting(s.marker_pitch, ui.marker_pitch); connect(ui.buttonBox, SIGNAL(accepted()), this, SLOT(doOK())); connect(ui.buttonBox, SIGNAL(rejected()), this, SLOT(doCancel())); - ui.cameraName->addItems(get_camera_names()); + connect(ui.btn_calibrate, SIGNAL(clicked()), this, SLOT(toggleCalibrate())); + connect(this, SIGNAL(destroyed()), this, SLOT(cleanupCalib())); + connect(&calib_timer, SIGNAL(timeout()), this, SLOT(update_tracker_calibration())); +} + +void TrackerControls::toggleCalibrate() +{ + if (!calib_timer.isActive()) + { + calibrator.reset(); + calib_timer.start(); + } else { + cleanupCalib(); + } +} + +void TrackerControls::cleanupCalib() +{ + if (calib_timer.isActive()) + calib_timer.stop(); +} + +void TrackerControls::update_tracker_calibration() +{ + if (calib_timer.isActive() && tracker) + { + cv::Matx33d r; + cv::Vec3d t; + tracker->getRT(r, t); + calibrator.update(r, t); + auto pos = calibrator.get_estimate() * .1; + s.headpos_x = pos(0); + s.headpos_y = pos(1); + s.headpos_z = pos(2); + } } void TrackerControls::doOK() @@ -473,11 +514,11 @@ void TrackerControls::doOK() s.b->save(); if (tracker) tracker->reload(); - this->close(); + this->close(); } void TrackerControls::doCancel() { - s.b->revert(); + s.b->reload(); this->close(); } diff --git a/ftnoir_tracker_aruco/ftnoir_tracker_aruco.h b/ftnoir_tracker_aruco/ftnoir_tracker_aruco.h index 4cab84b5..3d37dacd 100644 --- a/ftnoir_tracker_aruco/ftnoir_tracker_aruco.h +++ b/ftnoir_tracker_aruco/ftnoir_tracker_aruco.h @@ -5,10 +5,8 @@ * copyright notice and this permission notice appear in all copies. */ -#ifndef FTNOIR_TRACKER_HT_H -#define FTNOIR_TRACKER_HT_H +#pragma once -#include "ftnoir_tracker_base/ftnoir_tracker_base.h" #include "ui_aruco-trackercontrols.h" #include "ar_video_widget.h" #include <QObject> @@ -16,18 +14,20 @@ #include <QMutex> #include <QHBoxLayout> #include <QDialog> -#include <opencv2/opencv.hpp> -#include <opencv/highgui.h> +#include <QTimer> #include "facetracknoir/options.h" +#include "ftnoir_tracker_aruco/trans_calib.h" +#include "facetracknoir/plugin-api.hpp" + +#include <opencv2/core/core.hpp> +#include <opencv2/highgui/highgui.hpp> + using namespace options; struct settings { pbundle b; value<double> fov, headpos_x, headpos_y, headpos_z; value<int> camera_index, force_fps, resolution; - value<bool> red_only; - value<bool> eyaw, epitch, eroll, ex, ey, ez; - value<double> marker_pitch; settings() : b(bundle("aruco-tracker")), fov(b, "field-of-view", 56), @@ -36,59 +36,52 @@ struct settings { headpos_z(b, "headpos-z", 0), camera_index(b, "camera-index", 0), force_fps(b, "force-fps", 0), - resolution(b, "force-resolution", 0), - red_only(b, "red-only", false), - eyaw(b, "enable-y", true), - epitch(b, "enable-p", true), - eroll(b, "enable-r", true), - ex(b, "enable-x", true), - ey(b, "enable-y", true), - ez(b, "enable-z", true), - marker_pitch(b, "marker-pitch", 0) + resolution(b, "force-resolution", 0) {} }; class Tracker : protected QThread, public ITracker { Q_OBJECT + static constexpr double c_search_window = 2.2; public: - Tracker(); - virtual ~Tracker(); + Tracker(); + ~Tracker() override; void StartTracker(QFrame* frame); void GetHeadPoseData(double *data); void run(); void reload() { s.b->reload(); } + void getRT(cv::Matx33d &r, cv::Vec3d &t); private: QMutex mtx; volatile bool stop; QHBoxLayout* layout; - ArucoVideoWidget* videoWidget; + ArucoVideoWidget* videoWidget; settings s; double pose[6]; cv::Mat frame; cv::VideoCapture camera; + cv::Matx33d r; + cv::Vec3d t; }; -// Widget that has controls for FTNoIR protocol client-settings. class TrackerControls : public QWidget, public ITrackerDialog { Q_OBJECT public: TrackerControls(); - void registerTracker(ITracker * x) { - tracker = dynamic_cast<Tracker*>(x); - } - void unRegisterTracker() { - tracker = nullptr; - } + void registerTracker(ITracker * x) { tracker = dynamic_cast<Tracker*>(x); } + void unRegisterTracker() { tracker = nullptr; } private: - Ui::Form ui; + Ui::Form ui; Tracker* tracker; settings s; + TranslationCalibrator calibrator; + QTimer calib_timer; private slots: - void doOK(); - void doCancel(); + void doOK(); + void doCancel(); + void toggleCalibrate(); + void cleanupCalib(); + void update_tracker_calibration(); }; - -#endif - diff --git a/ftnoir_tracker_aruco/ftnoir_tracker_aruco_dll.h b/ftnoir_tracker_aruco/ftnoir_tracker_aruco_dll.h index ffdc5262..66e57100 100644 --- a/ftnoir_tracker_aruco/ftnoir_tracker_aruco_dll.h +++ b/ftnoir_tracker_aruco/ftnoir_tracker_aruco_dll.h @@ -5,8 +5,7 @@ * copyright notice and this permission notice appear in all copies. */ -#include "ftnoir_tracker_base/ftnoir_tracker_base.h" -#include "facetracknoir/global-settings.h" +#include "facetracknoir/plugin-api.hpp" //----------------------------------------------------------------------------- class TrackerDll : public Metadata diff --git a/ftnoir_tracker_aruco/include/boarddetector.h b/ftnoir_tracker_aruco/include/boarddetector.h index 4770b5c9..a0ee2361 100644 --- a/ftnoir_tracker_aruco/include/boarddetector.h +++ b/ftnoir_tracker_aruco/include/boarddetector.h @@ -134,6 +134,6 @@ private: }; -} +}; #endif diff --git a/ftnoir_tracker_aruco/include/cameraparameters.h b/ftnoir_tracker_aruco/include/cameraparameters.h index c3381a74..a419afbe 100644 --- a/ftnoir_tracker_aruco/include/cameraparameters.h +++ b/ftnoir_tracker_aruco/include/cameraparameters.h @@ -28,7 +28,7 @@ or implied, of Rafael Muñoz Salinas. #ifndef _Aruco_CameraParameters_H #define _Aruco_CameraParameters_H #include "exports.h" -#include <opencv2/opencv.hpp> +#include <opencv2/core/core.hpp> #include <string> using namespace std; namespace aruco @@ -105,7 +105,7 @@ public: * @param invert: indicates if the output projection matrix has to yield a horizontally inverted image because image data has not been stored in the order of glDrawPixels: bottom-to-top. */ void glGetProjectionMatrix( cv::Size orgImgSize, cv::Size size,double proj_matrix[16],double gnear,double gfar,bool invert=false )throw(cv::Exception); - + /** * setup camera for an Ogre project. * Use: @@ -117,7 +117,7 @@ public: * As in OpenGL, it assumes no camera distorsion */ void OgreGetProjectionMatrix( cv::Size orgImgSize, cv::Size size,double proj_matrix[16],double gnear,double gfar,bool invert=false )throw(cv::Exception); - + private: //GL routines diff --git a/ftnoir_tracker_aruco/include/cvdrawingutils.h b/ftnoir_tracker_aruco/include/cvdrawingutils.h index 38e9986e..ff67242f 100644 --- a/ftnoir_tracker_aruco/include/cvdrawingutils.h +++ b/ftnoir_tracker_aruco/include/cvdrawingutils.h @@ -46,7 +46,7 @@ namespace aruco static void draw3dCube(cv::Mat &Image,Board &m,const CameraParameters &CP); }; -} +}; #endif diff --git a/ftnoir_tracker_aruco/include/exports.h b/ftnoir_tracker_aruco/include/exports.h index 154605ec..aaeb94e4 100644 --- a/ftnoir_tracker_aruco/include/exports.h +++ b/ftnoir_tracker_aruco/include/exports.h @@ -25,7 +25,7 @@ The views and conclusions contained in the software and documentation are those authors and should not be interpreted as representing official policies, either expressed or implied, of Rafael Muñoz Salinas. ********************************/ - + #ifndef __OPENARUCO_CORE_TYPES_H__ @@ -37,9 +37,9 @@ or implied, of Rafael Muñoz Salinas. #if (defined WIN32 || defined _WIN32 || defined WINCE) && defined DSO_EXPORTS - #define ARUCO_EXPORTS __declspec(dllexport) + #define ARUCO_EXPORTS __declspec(dllexport) #else - #define ARUCO_EXPORTS + #define ARUCO_EXPORTS __attribute__ ((visibility ("default"))) #endif diff --git a/ftnoir_tracker_aruco/include/marker.h b/ftnoir_tracker_aruco/include/marker.h index dc6bb28c..89961002 100644 --- a/ftnoir_tracker_aruco/include/marker.h +++ b/ftnoir_tracker_aruco/include/marker.h @@ -29,7 +29,7 @@ or implied, of Rafael Muñoz Salinas. #define _Aruco_Marker_H #include <vector> #include <iostream> -#include <opencv2/opencv.hpp> +#include <opencv2/core/core.hpp> #include "exports.h" #include "cameraparameters.h" using namespace std; @@ -81,12 +81,12 @@ public: * @param setYPerperdicular If set the Y axis will be perpendicular to the surface. Otherwise, it will be the Z axis */ void calculateExtrinsics(float markerSize,cv::Mat CameraMatrix,cv::Mat Distorsion=cv::Mat(),bool setYPerperdicular=true)throw(cv::Exception); - + /**Given the extrinsic camera parameters returns the GL_MODELVIEW matrix for opengl. * Setting this matrix, the reference coordinate system will be set in this marker */ void glGetModelViewMatrix( double modelview_matrix[16])throw(cv::Exception); - + /** * Returns position vector and orientation quaternion for an Ogre scene node or entity. * Use: @@ -97,8 +97,8 @@ public: * mySceneNode->setOrientation( ogreOrient ); * ... */ - void OgreGetPoseParameters( double position[3], double orientation[4] )throw(cv::Exception); - + void OgreGetPoseParameters( double position[3], double orientation[4] )throw(cv::Exception); + /**Returns the centroid of the marker */ cv::Point2f getCenter()const; @@ -132,11 +132,11 @@ public: return str; } - - + + private: void rotateXAxis(cv::Mat &rotation); - + }; } diff --git a/ftnoir_tracker_aruco/include/markerdetector.h b/ftnoir_tracker_aruco/include/markerdetector.h index 4d6e7b90..6f489c34 100644 --- a/ftnoir_tracker_aruco/include/markerdetector.h +++ b/ftnoir_tracker_aruco/include/markerdetector.h @@ -27,7 +27,7 @@ or implied, of Rafael Muñoz Salinas. ********************************/ #ifndef _ARUCO_MarkerDetector_H #define _ARUCO_MarkerDetector_H -#include <opencv2/opencv.hpp> +#include <opencv2/core/core.hpp> #include <cstdio> #include <iostream> #include "cameraparameters.h" @@ -47,27 +47,25 @@ class ARUCO_EXPORTS MarkerDetector class MarkerCandidate: public Marker{ public: MarkerCandidate(){} - MarkerCandidate(const Marker &M): Marker(M){} + MarkerCandidate(const Marker &M): Marker(M){} MarkerCandidate(const MarkerCandidate &M): Marker(M){ contour=M.contour; idx=M.idx; } - MarkerCandidate operator=(const MarkerCandidate &M){ - if (this == &M) - return *this; + MarkerCandidate & operator=(const MarkerCandidate &M){ (*(Marker*)this)=(*(Marker*)&M); contour=M.contour; idx=M.idx; - return M; + return *this; } - + vector<cv::Point> contour;//all the points of its contour int idx;//index position in the global contour list }; public: /** - * See + * See */ MarkerDetector(); @@ -161,17 +159,17 @@ public: * of cols and rows. * @param min size of the contour to consider a possible marker as valid (0,1] * @param max size of the contour to consider a possible marker as valid [0,1) - * + * */ void setMinMaxSize(float min=0.03,float max=0.5)throw(cv::Exception); - + /**reads the min and max sizes employed * @param min output size of the contour to consider a possible marker as valid (0,1] * @param max output size of the contour to consider a possible marker as valid [0,1) - * + * */ void getMinMaxSize(float &min,float &max){min=_minSize;max=_maxSize;} - + /**Enables/Disables erosion process that is REQUIRED for chessboard like boards. * By default, this property is enabled */ @@ -210,10 +208,10 @@ public: markerIdDetector_ptrfunc=markerdetector_func; } - /** Use an smaller version of the input image for marker detection. + /** Use an smaller version of the input image for marker detection. * If your marker is small enough, you can employ an smaller image to perform the detection without noticeable reduction in the precision. * Internally, we are performing a pyrdown operation - * + * * @param level number of times the image size is divided by 2. Internally, we are performing a pyrdown. */ void pyrDown(unsigned int level){pyrdown_level=level;} @@ -247,17 +245,17 @@ public: * @return true if the operation succeed */ bool warp(cv::Mat &in,cv::Mat &out,cv::Size size, std::vector<cv::Point2f> points)throw (cv::Exception); - - - + + + /** Refine MarkerCandidate Corner using LINES method * @param candidate candidate to refine corners */ - void refineCandidateLines(MarkerCandidate &candidate); - - + void refineCandidateLines(MarkerCandidate &candidate); + + /**DEPRECATED!!! Use the member function in CameraParameters - * + * * Given the intrinsic camera parameters returns the GL_PROJECTION matrix for opengl. * PLease NOTE that when using OpenGL, it is assumed no camera distorsion! So, if it is not true, you should have * undistor image @@ -308,26 +306,26 @@ private: */ int perimeter(std::vector<cv::Point2f> &a); - + // //GL routines -// +// // static void argConvGLcpara2( double cparam[3][4], int width, int height, double gnear, double gfar, double m[16], bool invert )throw(cv::Exception); // static int arParamDecompMat( double source[3][4], double cpara[3][4], double trans[3][4] )throw(cv::Exception); // static double norm( double a, double b, double c ); // static double dot( double a1, double a2, double a3, // double b1, double b2, double b3 ); -// +// //detection of the void findBestCornerInRegion_harris(const cv::Mat & grey,vector<cv::Point2f> & Corners,int blockSize); - - + + // auxiliar functions to perform LINES refinement void interpolate2Dline( const vector< cv::Point > &inPoints, cv::Point3f &outLine); - cv::Point2f getCrossPoint(const cv::Point3f& line1, const cv::Point3f& line2); - - - /**Given a vector vinout with elements and a boolean vector indicating the lements from it to remove, + cv::Point2f getCrossPoint(const cv::Point3f& line1, const cv::Point3f& line2); + + + /**Given a vector vinout with elements and a boolean vector indicating the lements from it to remove, * this function remove the elements * @param vinout * @param toRemove @@ -353,5 +351,9 @@ private: void draw(cv::Mat out,const std::vector<Marker> &markers ); }; -} + + + + +}; #endif diff --git a/ftnoir_tracker_aruco/trans_calib.cpp b/ftnoir_tracker_aruco/trans_calib.cpp new file mode 100644 index 00000000..369de449 --- /dev/null +++ b/ftnoir_tracker_aruco/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 Matx33d& R_CM_k, const Vec3d& t_CM_k) +{ + Matx<double, 6,3> H_k_T = Matx<double, 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]); +} diff --git a/ftnoir_tracker_aruco/trans_calib.h b/ftnoir_tracker_aruco/trans_calib.h new file mode 100644 index 00000000..5a2d7c0f --- /dev/null +++ b/ftnoir_tracker_aruco/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/core/core.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::Matx33d& R_CM_k, const cv::Vec3d& t_CM_k); + + // get the current estimate for t_MH + cv::Vec3f get_estimate(); + +private: + cv::Matx66f P; // normalized precision matrix = inverse covariance + cv::Vec6f y; // P*(-t_MH, t_CH) +}; + +#endif //TRANSCALIB_H |