Integration of OpenCV's ArUco Marker Detection (see new parameter "RGBD/MarkerDetection")

This commit is contained in:
matlabbe
2019-02-18 18:19:55 -05:00
parent 08f3e6c08e
commit d6ca37a9e7
18 changed files with 859 additions and 23 deletions

View File

@@ -197,7 +197,7 @@ public:
const std::string & id,
const Transform & transform);
void removeCoordinate(const std::string & id);
void removeAllCoordinates();
void removeAllCoordinates(const std::string & prefix = "");
const std::set<std::string> & getAddedCoordinates() const {return _coordinates;}
void addOrUpdateLine(

View File

@@ -128,6 +128,7 @@ public:
void setUserLoopClosureColor(const QColor & color);
void setVirtualLoopClosureColor(const QColor & color);
void setNeighborMergedColor(const QColor & color);
void setLandmarkColor(const QColor & color);
void setRejectedLoopClosureColor(const QColor & color);
void setLocalPathColor(const QColor & color);
void setGlobalPathColor(const QColor & color);
@@ -170,6 +171,7 @@ private:
QColor _loopClosureUserColor;
QColor _loopClosureVirtualColor;
QColor _neighborMergedColor;
QColor _landmarkColor;
QColor _loopClosureRejectedColor;
QColor _localPathColor;
QColor _globalPathColor;

View File

@@ -261,6 +261,7 @@ private:
void createAndAddFeaturesToMap(int nodeId, const Transform & pose, int mapId);
Transform alignPosesToGroundTruth(const std::map<int, Transform> & poses, const std::map<int, Transform> & groundTruth);
void drawKeypoints(const std::multimap<int, cv::KeyPoint> & refWords, const std::multimap<int, cv::KeyPoint> & loopWords);
void drawLandmarks(cv::Mat & image, const Signature & signature);
void setupMainLayout(bool vertical);
void updateSelectSourceMenu();
void applyPrefSettings(const rtabmap::ParametersMap & parameters, bool postParamEvent);

View File

@@ -163,6 +163,9 @@ public:
bool isGraphsShown() const;
bool isLabelsShown() const;
bool isLandmarksShown() const;
bool isMarkerDetection() const;
double getMarkerLength() const;
double getVoxel() const;
double getNoiseRadius() const;
int getNoiseMinNeighbors() const;

View File

@@ -1328,14 +1328,17 @@ void CloudViewer::removeCoordinate(const std::string & id)
}
}
void CloudViewer::removeAllCoordinates()
void CloudViewer::removeAllCoordinates(const std::string & prefix)
{
std::set<std::string> coordinates = _coordinates;
for(std::set<std::string>::iterator iter = coordinates.begin(); iter!=coordinates.end(); ++iter)
{
this->removeCoordinate(*iter);
if(prefix.empty() || iter->find(prefix) != std::string::npos)
{
this->removeCoordinate(*iter);
}
}
UASSERT(_coordinates.empty());
UASSERT(!prefix.empty() || _coordinates.empty());
}
void CloudViewer::addOrUpdateLine(

View File

@@ -243,6 +243,7 @@ GraphViewer::GraphViewer(QWidget * parent) :
_loopClosureUserColor(Qt::red),
_loopClosureVirtualColor(Qt::magenta),
_neighborMergedColor(QColor(255,170,0)),
_landmarkColor(Qt::darkGreen),
_loopClosureRejectedColor(Qt::black),
_localPathColor(Qt::cyan),
_globalPathColor(Qt::darkMagenta),
@@ -478,6 +479,10 @@ void GraphViewer::updateGraph(const std::map<int, Transform> & poses,
{
linkItem->setColor(_loopClosureUserColor);
}
else if(iter->second.type() == Link::kLandmark)
{
linkItem->setColor(_landmarkColor);
}
else if(iter->second.type() == Link::kLocalSpaceClosure || iter->second.type() == Link::kLocalTimeClosure)
{
if(_intraInterSessionColors)
@@ -1331,6 +1336,17 @@ void GraphViewer::setNeighborMergedColor(const QColor & color)
}
}
}
void GraphViewer::setLandmarkColor(const QColor & color)
{
_landmarkColor = color;
for(QMultiMap<int, LinkItem*>::iterator iter=_linkItems.begin(); iter!=_linkItems.end(); ++iter)
{
if(iter.value()->linkType() == Link::kLandmark)
{
iter.value()->setColor(_landmarkColor);
}
}
}
void GraphViewer::setRejectedLoopClosureColor(const QColor & color)
{
_loopClosureRejectedColor = color;
@@ -1497,6 +1513,7 @@ void GraphViewer::restoreDefaults()
setUserLoopClosureColor(Qt::red);
setVirtualLoopClosureColor(Qt::magenta);
setNeighborMergedColor(QColor(255,170,0));
setLandmarkColor(Qt::darkGreen);
setGridMapVisible(true);
setGraphVisible(true);
setGlobalPathVisible(true);
@@ -1546,6 +1563,7 @@ void GraphViewer::contextMenuEvent(QContextMenuEvent * event)
QAction * aChangeUserLoopColor = menuLink->addAction(tr("User loop closure"));
QAction * aChangeVirtualLoopColor = menuLink->addAction(tr("Virtual loop closure"));
QAction * aChangeNeighborMergedColor = menuLink->addAction(tr("Neighbor merged"));
QAction * aChangeLandmarkColor = menuLink->addAction(tr("Landmark"));
QAction * aChangeRejectedLoopColor = menuLink->addAction(tr("Outlier loop closure"));
QAction * aChangeRejectedLoopThr = menuLink->addAction(tr("Set outlier threshold..."));
QAction * aChangeLocalPathColor = menuLink->addAction(tr("Local path"));
@@ -1562,11 +1580,12 @@ void GraphViewer::contextMenuEvent(QContextMenuEvent * event)
aChangeUserLoopColor->setIcon(createIcon(_loopClosureUserColor));
aChangeVirtualLoopColor->setIcon(createIcon(_loopClosureVirtualColor));
aChangeNeighborMergedColor->setIcon(createIcon(_neighborMergedColor));
aChangeLandmarkColor->setIcon(createIcon(_landmarkColor));
aChangeRejectedLoopColor->setIcon(createIcon(_loopClosureRejectedColor));
aChangeLocalPathColor->setIcon(createIcon(_localPathColor));
aChangeGlobalPathColor->setIcon(createIcon(_globalPathColor));
aChangeGTColor->setIcon(createIcon(_gtPathColor));
aChangeGPSColor->setIcon(createIcon(_gpsPathColor));
aChangeGPSColor->setIcon(createIcon(_gpsPathColor));;
aChangeIntraSessionLoopColor->setIcon(createIcon(_loopIntraSessionColor));
aChangeInterSessionLoopColor->setIcon(createIcon(_loopInterSessionColor));
aChangeNeighborColor->setIconVisibleInMenu(true);
@@ -1843,6 +1862,10 @@ void GraphViewer::contextMenuEvent(QContextMenuEvent * event)
{
color = _neighborMergedColor;
}
else if(r == aChangeLandmarkColor)
{
color = _landmarkColor;
}
else if(r == aChangeRejectedLoopColor)
{
color = _loopClosureRejectedColor;
@@ -1907,6 +1930,10 @@ void GraphViewer::contextMenuEvent(QContextMenuEvent * event)
{
this->setNeighborMergedColor(color);
}
else if(r == aChangeLandmarkColor)
{
this->setLandmarkColor(color);
}
else if(r == aChangeRejectedLoopColor)
{
this->setRejectedLoopClosureColor(color);

View File

@@ -119,6 +119,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <rtabmap/core/OctoMap.h>
#endif
#ifdef HAVE_OPENCV_ARUCO
#include <opencv2/aruco.hpp>
#endif
#define LOG_FILE_NAME "LogRtabmap.txt"
#define SHARE_SHOW_LOG_FILE "share/rtabmap/showlogs.m"
#define SHARE_GET_PRECISION_RECALL_FILE "share/rtabmap/getPrecisionRecall.m"
@@ -1770,8 +1774,27 @@ void MainWindow::processStats(const rtabmap::Statistics & stat)
//update image views
{
UCvMat2QImageThread qimageThread(signature.sensorData().imageRaw());
UCvMat2QImageThread qimageLoopThread(loopSignature.sensorData().imageRaw());
cv::Mat refImage = signature.sensorData().imageRaw();
cv::Mat loopImage = loopSignature.sensorData().imageRaw();
if( _preferencesDialog->isMarkerDetection() &&
_preferencesDialog->isLandmarksShown())
{
//draw markers
if(!signature.getLandmarks().empty())
{
refImage = refImage.clone();
drawLandmarks(refImage, signature);
}
if(!loopSignature.getLandmarks().empty())
{
loopImage = loopImage.clone();
drawLandmarks(loopImage, loopSignature);
}
}
UCvMat2QImageThread qimageThread(refImage);
UCvMat2QImageThread qimageLoopThread(loopImage);
qimageThread.start();
qimageLoopThread.start();
qimageThread.join();
@@ -2624,6 +2647,30 @@ void MainWindow::updateMapCloud(
}
#endif
// Add landmarks to 3D Map view
#if PCL_VERSION_COMPARE(>=, 1, 7, 2)
_cloudViewer->removeAllCoordinates("landmark_");
#endif
if(_preferencesDialog->isLandmarksShown())
{
for(std::map<int, Transform>::const_iterator iter=posesIn.begin(); iter!=posesIn.end() && iter->first<0; ++iter)
{
#if PCL_VERSION_COMPARE(>=, 1, 7, 2)
_cloudViewer->addOrUpdateCoordinate(uFormat("landmark_%d", -iter->first), iter->second, _preferencesDialog->getMarkerLength()/2.0, false);
#endif
if(_preferencesDialog->isLabelsShown())
{
std::string num = uNumber2Str(-iter->first);
_cloudViewer->addOrUpdateText(
std::string("landmark_str_") + num,
num,
iter->second,
0.1,
Qt::yellow);
}
}
}
// Update occupancy grid map in 3D map view and graph view
if(_ui->graphicsView_graphView->isVisible())
{
@@ -4289,6 +4336,51 @@ void MainWindow::drawKeypoints(const std::multimap<int, cv::KeyPoint> & refWords
_ui->imageView_loopClosure->update();
}
void MainWindow::drawLandmarks(cv::Mat & image, const Signature & signature)
{
for(std::map<int, Link>::const_iterator iter=signature.getLandmarks().begin(); iter!=signature.getLandmarks().end(); ++iter)
{
CameraModel model;
if(!signature.sensorData().cameraModels().empty() &&
signature.sensorData().cameraModels()[0].isValidForProjection())
{
model = signature.sensorData().cameraModels()[0];
}
else if(signature.sensorData().stereoCameraModel().isValidForProjection())
{
model = signature.sensorData().stereoCameraModel().left();
}
if(model.isValidForProjection())
{
Transform t = model.localTransform().inverse() * iter->second.transform();
cv::Vec3d rvec, tvec;
tvec.val[0] = t.x();
tvec.val[1] = t.y();
tvec.val[2] = t.z();
cv::Mat R;
t.rotationMatrix().convertTo(R, CV_64F);
cv::Rodrigues(R, rvec);
//cv::aruco::drawAxis(image, model.K(), model.D(), rvec, tvec, _preferencesDialog->getMarkerLength() * 0.5f);
// project axis points
std::vector< cv::Point3f > axisPoints;
float length = _preferencesDialog->getMarkerLength() * 0.5f;
axisPoints.push_back(cv::Point3f(0, 0, 0));
axisPoints.push_back(cv::Point3f(length, 0, 0));
axisPoints.push_back(cv::Point3f(0, length, 0));
axisPoints.push_back(cv::Point3f(0, 0, length));
std::vector< cv::Point2f > imagePoints;
projectPoints(axisPoints, rvec, tvec, model.K(), model.D(), imagePoints);
// draw axis lines
cv::line(image, imagePoints[0], imagePoints[1], cv::Scalar(0, 0, 255), 3);
cv::line(image, imagePoints[0], imagePoints[2], cv::Scalar(0, 255, 0), 3);
cv::line(image, imagePoints[0], imagePoints[3], cv::Scalar(255, 0, 0), 3);
cv::putText(image, uNumber2Str(-iter->first), imagePoints[0], cv::FONT_HERSHEY_SIMPLEX, 0.75, cv::Scalar(0, 255, 255), 2);
}
}
}
void MainWindow::showEvent(QShowEvent* anEvent)
{
//if the config file doesn't exist, make the GUI obsolete

View File

@@ -322,6 +322,17 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
_ui->checkBox_showOdomFrustums->setChecked(false);
#endif
//if OpenCV < 3.4.2
#if CV_MAJOR_VERSION < 3 || (CV_MAJOR_VERSION == 3 && (CV_MINOR_VERSION <4 || (CV_MINOR_VERSION ==4 && CV_SUBMINOR_VERSION<2)))
_ui->ArucoDictionary->setItemData(17, 0, Qt::UserRole - 1);
_ui->ArucoDictionary->setItemData(18, 0, Qt::UserRole - 1);
_ui->ArucoDictionary->setItemData(19, 0, Qt::UserRole - 1);
_ui->ArucoDictionary->setItemData(20, 0, Qt::UserRole - 1);
#endif
#ifndef HAVE_OPENCV_ARUCO
_ui->label_markerDetection->setText(_ui->label_markerDetection->text()+" This option works only if OpenCV has been built with \"aruco\" module.");
#endif
// in case we change the ui, we should not forget to change stuff related to this parameter
UASSERT(_ui->odom_registration->count() == 4);
@@ -482,6 +493,7 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
connect(_ui->checkBox_showGraphs, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteCloudRenderingPanel()));
connect(_ui->checkBox_showLabels, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteCloudRenderingPanel()));
connect(_ui->checkBox_showLandmarks, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteCloudRenderingPanel()));
connect(_ui->radioButton_noFiltering, SIGNAL(toggled(bool)), this, SLOT(makeObsoleteCloudRenderingPanel()));
connect(_ui->radioButton_nodeFiltering, SIGNAL(toggled(bool)), this, SLOT(makeObsoleteCloudRenderingPanel()));
@@ -912,6 +924,7 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
_ui->loopClosure_reextract->setObjectName(Parameters::kRGBDLoopClosureReextractFeatures().c_str());
_ui->loopClosure_bunlde->setObjectName(Parameters::kRGBDLocalBundleOnLoopClosure().c_str());
_ui->checkbox_rgbd_createOccupancyGrid->setObjectName(Parameters::kRGBDCreateOccupancyGrid().c_str());
_ui->RGBDMarkerDetection->setObjectName(Parameters::kRGBDMarkerDetection().c_str());
// Registration
_ui->reg_repeatOnce->setObjectName(Parameters::kRegRepeatOnce().c_str());
@@ -1203,6 +1216,13 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
_ui->stereosgbm_p2->setObjectName(Parameters::kStereoSGBMP2().c_str());
_ui->stereosgbm_mode->setObjectName(Parameters::kStereoSGBMMode().c_str());
// Aruco marker
_ui->ArucoDictionary->setObjectName(Parameters::kArucoDictionary().c_str());
_ui->ArucoMarkerLength->setObjectName(Parameters::kArucoMarkerLength().c_str());
_ui->ArucoVarianceLinear->setObjectName(Parameters::kArucoVarianceLinear().c_str());
_ui->ArucoVarianceAngular->setObjectName(Parameters::kArucoVarianceAngular().c_str());
_ui->ArucoCornerRefinementMethod->setObjectName(Parameters::kArucoCornerRefinementMethod().c_str());
// reset default settings for the gui
resetSettings(_ui->groupBox_generalSettingsGui0);
resetSettings(_ui->groupBox_cloudRendering1);
@@ -1574,6 +1594,7 @@ void PreferencesDialog::resetSettings(QGroupBox * groupBox)
_ui->checkBox_showGraphs->setChecked(true);
_ui->checkBox_showLabels->setChecked(false);
_ui->checkBox_showLandmarks->setChecked(true);
_ui->doubleSpinBox_mesh_angleTolerance->setValue(15.0);
_ui->groupBox_organized->setChecked(false);
@@ -1990,6 +2011,7 @@ void PreferencesDialog::readGuiSettings(const QString & filePath)
_ui->checkBox_showGraphs->setChecked(settings.value("showGraphs", _ui->checkBox_showGraphs->isChecked()).toBool());
_ui->checkBox_showLabels->setChecked(settings.value("showLabels", _ui->checkBox_showLabels->isChecked()).toBool());
_ui->checkBox_showLandmarks->setChecked(settings.value("showLandmarks", _ui->checkBox_showLandmarks->isChecked()).toBool());
_ui->radioButton_noFiltering->setChecked(settings.value("noFiltering", _ui->radioButton_noFiltering->isChecked()).toBool());
_ui->radioButton_nodeFiltering->setChecked(settings.value("cloudFiltering", _ui->radioButton_nodeFiltering->isChecked()).toBool());
@@ -2410,6 +2432,8 @@ void PreferencesDialog::writeGuiSettings(const QString & filePath) const
settings.setValue("showGraphs", _ui->checkBox_showGraphs->isChecked());
settings.setValue("showLabels", _ui->checkBox_showLabels->isChecked());
settings.setValue("showLandmarks", _ui->checkBox_showLandmarks->isChecked());
settings.setValue("noFiltering", _ui->radioButton_noFiltering->isChecked());
settings.setValue("cloudFiltering", _ui->radioButton_nodeFiltering->isChecked());
@@ -2862,6 +2886,15 @@ bool PreferencesDialog::validateForm()
_ui->checkbox_odomDisabled->setChecked(false);
}
#if CV_MAJOR_VERSION < 3 || (CV_MAJOR_VERSION == 3 && (CV_MINOR_VERSION <4 || (CV_MINOR_VERSION ==4 && CV_SUBMINOR_VERSION<2)))
if(_ui->ArucoDictionary->currentIndex()>=17)
{
QMessageBox::warning(this, tr("Parameter warning"),
tr("ArUco dictionary: cannot select AprilTag dictionary, OpenCV version should be at least 3.4.2. Setting back to 0."));
_ui->ArucoDictionary->setCurrentIndex(0);
}
#endif
return true;
}
@@ -4600,6 +4633,18 @@ bool PreferencesDialog::isLabelsShown() const
{
return _ui->checkBox_showLabels->isChecked();
}
bool PreferencesDialog::isLandmarksShown() const
{
return _ui->checkBox_showLandmarks->isChecked();
}
bool PreferencesDialog::isMarkerDetection() const
{
return _ui->RGBDMarkerDetection->isChecked();
}
double PreferencesDialog::getMarkerLength() const
{
return _ui->ArucoMarkerLength->value();
}
bool PreferencesDialog::isCloudMeshing() const
{
return _ui->groupBox_organized->isChecked();

View File

@@ -95,15 +95,24 @@
<rect>
<x>0</x>
<y>0</y>
<width>673</width>
<height>2979</height>
<width>680</width>
<height>2986</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_16">
<property name="spacing">
<number>0</number>
</property>
<property name="margin">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
@@ -117,7 +126,7 @@
<enum>QFrame::Raised</enum>
</property>
<property name="currentIndex">
<number>10</number>
<number>18</number>
</property>
<widget class="QWidget" name="page_22">
<layout class="QVBoxLayout" name="verticalLayout_29" stretch="0,1">
@@ -1869,6 +1878,29 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property>
</widget>
</item>
<item row="6" column="2">
<widget class="QLabel" name="label_301">
<property name="text">
<string>Show landmarks.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QCheckBox" name="checkBox_showLandmarks">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
@@ -5141,7 +5173,16 @@ when using the file type, logs are saved in LogRtabmap.txt (located in the worki
<string>Directory of images (optional settings)</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_93">
<property name="margin">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
@@ -11088,6 +11129,323 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</item>
</layout>
</widget>
<widget class="QWidget" name="page_78">
<layout class="QVBoxLayout" name="verticalLayout_137">
<item>
<widget class="QGroupBox" name="groupBox_markerDetection2">
<property name="title">
<string>Marker Detection</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_136">
<item>
<layout class="QGridLayout" name="gridLayout_63" columnstretch="0,1">
<item row="3" column="1">
<widget class="QLabel" name="label_space2_9">
<property name="text">
<string>Angular variance to set on marker detections. Set to &gt;=9999 to use only position (xyz) constraint in graph optimization.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="RGBDMarkerDetection">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QDoubleSpinBox" name="ArucoVarianceLinear">
<property name="suffix">
<string/>
</property>
<property name="decimals">
<number>6</number>
</property>
<property name="minimum">
<double>0.000001000000000</double>
</property>
<property name="singleStep">
<double>0.001000000000000</double>
</property>
<property name="value">
<double>0.001000000000000</double>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_markerDetection">
<property name="text">
<string>Detect static markers to be added as landmarks for graph optimization. If input data have already landmarks, this will be ignored.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="label_space2_6">
<property name="text">
<string>Linear variance to set on marker detections.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_space2_7">
<property name="text">
<string>Marker length. The length (m) of the markers' side.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QDoubleSpinBox" name="ArucoVarianceAngular">
<property name="suffix">
<string/>
</property>
<property name="decimals">
<number>6</number>
</property>
<property name="minimum">
<double>0.000001000000000</double>
</property>
<property name="maximum">
<double>9999.000000000000000</double>
</property>
<property name="singleStep">
<double>0.001000000000000</double>
</property>
<property name="value">
<double>0.001000000000000</double>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QDoubleSpinBox" name="ArucoMarkerLength">
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>4</number>
</property>
<property name="minimum">
<double>0.000100000000000</double>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
<property name="value">
<double>0.100000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="groupBox_31">
<property name="title">
<string>ArUco</string>
</property>
<layout class="QGridLayout" name="gridLayout_106" columnstretch="0,1">
<item row="0" column="0">
<widget class="QComboBox" name="ArucoDictionary">
<item>
<property name="text">
<string>4X4_50</string>
</property>
</item>
<item>
<property name="text">
<string>4X4_100</string>
</property>
</item>
<item>
<property name="text">
<string>4X4_250</string>
</property>
</item>
<item>
<property name="text">
<string>4X4_1000</string>
</property>
</item>
<item>
<property name="text">
<string>5X5_50</string>
</property>
</item>
<item>
<property name="text">
<string>5X5_100</string>
</property>
</item>
<item>
<property name="text">
<string>5X5_250</string>
</property>
</item>
<item>
<property name="text">
<string>5X5_1000</string>
</property>
</item>
<item>
<property name="text">
<string>6X6_50</string>
</property>
</item>
<item>
<property name="text">
<string>6X6_100</string>
</property>
</item>
<item>
<property name="text">
<string>6X6_250</string>
</property>
</item>
<item>
<property name="text">
<string>6X6_1000</string>
</property>
</item>
<item>
<property name="text">
<string>7X7_50</string>
</property>
</item>
<item>
<property name="text">
<string>7X7_100</string>
</property>
</item>
<item>
<property name="text">
<string>7X7_250</string>
</property>
</item>
<item>
<property name="text">
<string>7X7_1000</string>
</property>
</item>
<item>
<property name="text">
<string>ARUCO_ORIGINAL</string>
</property>
</item>
<item>
<property name="text">
<string>APRILTAG_16h5</string>
</property>
</item>
<item>
<property name="text">
<string>APRILTAG_25h9</string>
</property>
</item>
<item>
<property name="text">
<string>APRILTAG_36h10</string>
</property>
</item>
<item>
<property name="text">
<string>APRILTAG_36h11</string>
</property>
</item>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_space2_10">
<property name="text">
<string>Dictionary to use.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QComboBox" name="ArucoCornerRefinementMethod">
<item>
<property name="text">
<string>None</string>
</property>
</item>
<item>
<property name="text">
<string>Subpixel</string>
</property>
</item>
<item>
<property name="text">
<string>Contour</string>
</property>
</item>
<item>
<property name="text">
<string>AprilTag 2</string>
</property>
</item>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_space2_11">
<property name="text">
<string>Corner refinement method.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer_76">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>2627</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="page_12">
<layout class="QVBoxLayout" name="verticalLayout_32" stretch="0,1">
<item>
@@ -15461,7 +15819,16 @@ Lower the ratio -&gt; higher the precision.</string>
<property name="spacing">
<number>0</number>
</property>
<property name="margin">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
@@ -15541,7 +15908,16 @@ Lower the ratio -&gt; higher the precision.</string>
<property name="spacing">
<number>0</number>
</property>
<property name="margin">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
@@ -15653,7 +16029,16 @@ Lower the ratio -&gt; higher the precision.</string>
<property name="spacing">
<number>0</number>
</property>
<property name="margin">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>