Add params to filter out poor stereo flow matches (#1667)

* Add params to filter out poor stereo flow matches

* Added parameters: Vis/CorFlowUseMinEigenVals, Vis/CorFlowMinEigThreshold, Vis/CorFlowErrorThreshold. Renamed Stereo/GetMinEigenVals to Stereo/UseMinEigenVals

* Setting suggested default value of 20 for Vis/CorFlowErrorThreshold

---------

Co-authored-by: matlabbe <[email protected]>
This commit is contained in:
Borong Yuan
2026-03-17 21:53:14 -07:00
committed by GitHub
co-authored by matlabbe
parent 0151f8cdfb
commit 5b985f69be
7 changed files with 318 additions and 89 deletions
+9 -3
View File
@@ -740,8 +740,11 @@ class RTABMAP_CORE_EXPORT Parameters
RTABMAP_PARAM(Vis, CorFlowIterations, int, 30, uFormat("[%s=1] See cv::calcOpticalFlowPyrLK(). Used for optical flow approach.", kVisCorType().c_str())); RTABMAP_PARAM(Vis, CorFlowIterations, int, 30, uFormat("[%s=1] See cv::calcOpticalFlowPyrLK(). Used for optical flow approach.", kVisCorType().c_str()));
RTABMAP_PARAM(Vis, CorFlowEps, float, 0.01, uFormat("[%s=1] See cv::calcOpticalFlowPyrLK(). Used for optical flow approach.", kVisCorType().c_str())); RTABMAP_PARAM(Vis, CorFlowEps, float, 0.01, uFormat("[%s=1] See cv::calcOpticalFlowPyrLK(). Used for optical flow approach.", kVisCorType().c_str()));
RTABMAP_PARAM(Vis, CorFlowMaxLevel, int, 3, uFormat("[%s=1] See cv::calcOpticalFlowPyrLK(). Used for optical flow approach.", kVisCorType().c_str())); RTABMAP_PARAM(Vis, CorFlowMaxLevel, int, 3, uFormat("[%s=1] See cv::calcOpticalFlowPyrLK(). Used for optical flow approach.", kVisCorType().c_str()));
RTABMAP_PARAM(Vis, CorFlowGpu, bool, false, uFormat("[%s=1] Enable GPU version of the optical flow approach (only available if OpenCV is built with CUDA).", kVisCorType().c_str())); RTABMAP_PARAM(Vis, CorFlowUseMinEigenVals, bool, true, uFormat("[%s=1] See cv::calcOpticalFlowPyrLK(). Used for optical flow approach. Use minimum eigen values as an error measure, otherwise L1 distance between patches is used as an error measure.", kVisCorType().c_str()));
#if defined(RTABMAP_G2O) || defined(RTABMAP_ORB_SLAM) RTABMAP_PARAM(Vis, CorFlowMinEigThreshold, float, 1e-4, uFormat("[%s=true] If the minimum eigenvalue of a feature's spatial gradient matrix is less than this threshold, then the feature is filtered out.", kVisCorFlowUseMinEigenVals().c_str()));
RTABMAP_PARAM(Vis, CorFlowErrorThreshold, float, 20, uFormat("[%s=false] Filter out features with error greater than this threshold.", kVisCorFlowUseMinEigenVals().c_str()));
RTABMAP_PARAM(Vis, CorFlowGpu, bool, false, uFormat("[%s=1] Enable GPU version of the optical flow approach (only available if OpenCV is built with CUDA). Note that %s is not used in the GPU implementation.", kVisCorType().c_str(), kVisCorFlowUseMinEigenVals().c_str()));
#if defined(RTABMAP_G2O) || defined(RTABMAP_ORB_SLAM)
RTABMAP_PARAM(Vis, BundleAdjustment, int, 1, "Optimization with bundle adjustment: 0=disabled, 1=g2o, 2=cvsba, 3=Ceres."); RTABMAP_PARAM(Vis, BundleAdjustment, int, 1, "Optimization with bundle adjustment: 0=disabled, 1=g2o, 2=cvsba, 3=Ceres.");
#else #else
RTABMAP_PARAM(Vis, BundleAdjustment, int, 0, "Optimization with bundle adjustment: 0=disabled, 1=g2o, 2=cvsba, 3=Ceres."); RTABMAP_PARAM(Vis, BundleAdjustment, int, 0, "Optimization with bundle adjustment: 0=disabled, 1=g2o, 2=cvsba, 3=Ceres.");
@@ -818,7 +821,10 @@ class RTABMAP_CORE_EXPORT Parameters
RTABMAP_PARAM(Stereo, OpticalFlow, bool, true, "Use optical flow to find stereo correspondences, otherwise a simple block matching approach is used."); RTABMAP_PARAM(Stereo, OpticalFlow, bool, true, "Use optical flow to find stereo correspondences, otherwise a simple block matching approach is used.");
RTABMAP_PARAM(Stereo, SSD, bool, true, uFormat("[%s=false] Use Sum of Squared Differences (SSD) window, otherwise Sum of Absolute Differences (SAD) window is used.", kStereoOpticalFlow().c_str())); RTABMAP_PARAM(Stereo, SSD, bool, true, uFormat("[%s=false] Use Sum of Squared Differences (SSD) window, otherwise Sum of Absolute Differences (SAD) window is used.", kStereoOpticalFlow().c_str()));
RTABMAP_PARAM(Stereo, Eps, double, 0.01, uFormat("[%s=true] Epsilon stop criterion.", kStereoOpticalFlow().c_str())); RTABMAP_PARAM(Stereo, Eps, double, 0.01, uFormat("[%s=true] Epsilon stop criterion.", kStereoOpticalFlow().c_str()));
RTABMAP_PARAM(Stereo, Gpu, bool, false, uFormat("[%s=true] Enable GPU version of the optical flow approach (only available if OpenCV is built with CUDA).", kStereoOpticalFlow().c_str())); RTABMAP_PARAM(Stereo, UseMinEigenVals, bool, true, uFormat("[%s=true] Use minimum eigen values as an error measure, otherwise L1 distance between patches is used as an error measure.", kStereoOpticalFlow().c_str()));
RTABMAP_PARAM(Stereo, MinEigThreshold, double, 1e-4, uFormat("[%s=true] If the minimum eigenvalue of a feature's spatial gradient matrix is less than this threshold, then the feature is filtered out.", kStereoUseMinEigenVals().c_str()));
RTABMAP_PARAM(Stereo, ErrorThreshold, double, 50, uFormat("[%s=false] Filter out features with error greater than this threshold.", kStereoUseMinEigenVals().c_str()));
RTABMAP_PARAM(Stereo, Gpu, bool, false, uFormat("[%s=true] Enable GPU version of the optical flow approach (only available if OpenCV is built with CUDA). Note that %s is not used in the GPU implementation.", kStereoOpticalFlow().c_str(), kStereoUseMinEigenVals().c_str()));
RTABMAP_PARAM(Stereo, DenseStrategy, int, 0, "0=cv::StereoBM, 1=cv::StereoSGBM"); RTABMAP_PARAM(Stereo, DenseStrategy, int, 0, "0=cv::StereoBM, 1=cv::StereoSGBM");
@@ -91,6 +91,9 @@ private:
float _flowEps; float _flowEps;
int _flowMaxLevel; int _flowMaxLevel;
bool _flowGpu; bool _flowGpu;
bool _flowUseMinEigenVals;
float _flowMinEigThreshold;
float _flowErrorThreshold;
float _nndr; float _nndr;
int _nnType; int _nnType;
bool _gmsWithRotation; bool _gmsWithRotation;
+8 -1
View File
@@ -96,16 +96,23 @@ public:
#endif #endif
float epsilon() const {return epsilon_;} float epsilon() const {return epsilon_;}
bool usingMinEigenVals() const {return useMinEigenVals_;}
float minEigThreshold() const {return minEigThreshold_;}
float errorThreshold() const {return errorThreshold_;}
virtual bool isGpuEnabled() const; virtual bool isGpuEnabled() const;
private: private:
void updateStatus( void updateStatus(
const std::vector<cv::Point2f> & leftCorners, const std::vector<cv::Point2f> & leftCorners,
const std::vector<cv::Point2f> & rightCorners, const std::vector<cv::Point2f> & rightCorners,
std::vector<unsigned char> & status) const; std::vector<unsigned char> & status,
std::vector<float> err = {}) const;
private: private:
float epsilon_; float epsilon_;
bool useMinEigenVals_;
float minEigThreshold_;
float errorThreshold_;
bool gpu_; bool gpu_;
}; };
+13 -3
View File
@@ -84,6 +84,9 @@ RegistrationVis::RegistrationVis(const ParametersMap & parameters, Registration
_flowEps(Parameters::defaultVisCorFlowEps()), _flowEps(Parameters::defaultVisCorFlowEps()),
_flowMaxLevel(Parameters::defaultVisCorFlowMaxLevel()), _flowMaxLevel(Parameters::defaultVisCorFlowMaxLevel()),
_flowGpu(Parameters::defaultVisCorFlowGpu()), _flowGpu(Parameters::defaultVisCorFlowGpu()),
_flowUseMinEigenVals(Parameters::defaultVisCorFlowUseMinEigenVals()),
_flowMinEigThreshold(Parameters::defaultVisCorFlowMinEigThreshold()),
_flowErrorThreshold(Parameters::defaultVisCorFlowErrorThreshold()),
_nndr(Parameters::defaultVisCorNNDR()), _nndr(Parameters::defaultVisCorNNDR()),
_nnType(Parameters::defaultVisCorNNType()), _nnType(Parameters::defaultVisCorNNType()),
_gmsWithRotation(Parameters::defaultGMSWithRotation()), _gmsWithRotation(Parameters::defaultGMSWithRotation()),
@@ -145,6 +148,9 @@ void RegistrationVis::parseParameters(const ParametersMap & parameters)
Parameters::parse(parameters, Parameters::kVisCorFlowEps(), _flowEps); Parameters::parse(parameters, Parameters::kVisCorFlowEps(), _flowEps);
Parameters::parse(parameters, Parameters::kVisCorFlowMaxLevel(), _flowMaxLevel); Parameters::parse(parameters, Parameters::kVisCorFlowMaxLevel(), _flowMaxLevel);
Parameters::parse(parameters, Parameters::kVisCorFlowGpu(), _flowGpu); Parameters::parse(parameters, Parameters::kVisCorFlowGpu(), _flowGpu);
Parameters::parse(parameters, Parameters::kVisCorFlowUseMinEigenVals(), _flowUseMinEigenVals);
Parameters::parse(parameters, Parameters::kVisCorFlowMinEigThreshold(), _flowMinEigThreshold);
Parameters::parse(parameters, Parameters::kVisCorFlowErrorThreshold(), _flowErrorThreshold);
Parameters::parse(parameters, Parameters::kVisCorNNDR(), _nndr); Parameters::parse(parameters, Parameters::kVisCorNNDR(), _nndr);
Parameters::parse(parameters, Parameters::kVisCorNNType(), _nnType); Parameters::parse(parameters, Parameters::kVisCorNNType(), _nnType);
Parameters::parse(parameters, Parameters::kGMSWithRotation(), _gmsWithRotation); Parameters::parse(parameters, Parameters::kGMSWithRotation(), _gmsWithRotation);
@@ -656,6 +662,7 @@ Transform RegistrationVis::computeTransformationImpl(
// Find features in the new left image // Find features in the new left image
UDEBUG("guessSet = %d", guessSet?1:0); UDEBUG("guessSet = %d", guessSet?1:0);
std::vector<unsigned char> status; std::vector<unsigned char> status;
std::vector<float> err;
#ifdef HAVE_OPENCV_CUDAOPTFLOW #ifdef HAVE_OPENCV_CUDAOPTFLOW
if (_flowGpu) if (_flowGpu)
{ {
@@ -685,7 +692,6 @@ Transform RegistrationVis::computeTransformationImpl(
else else
#endif #endif
{ {
std::vector<float> err;
UDEBUG("cv::calcOpticalFlowPyrLK() begin"); UDEBUG("cv::calcOpticalFlowPyrLK() begin");
cv::calcOpticalFlowPyrLK( cv::calcOpticalFlowPyrLK(
imageFrom, imageFrom,
@@ -697,7 +703,8 @@ Transform RegistrationVis::computeTransformationImpl(
cv::Size(_flowWinSize, _flowWinSize), cv::Size(_flowWinSize, _flowWinSize),
guessSet ? 0 : _flowMaxLevel, guessSet ? 0 : _flowMaxLevel,
cv::TermCriteria(cv::TermCriteria::COUNT + cv::TermCriteria::EPS, _flowIterations, _flowEps), cv::TermCriteria(cv::TermCriteria::COUNT + cv::TermCriteria::EPS, _flowIterations, _flowEps),
cv::OPTFLOW_LK_GET_MIN_EIGENVALS | (guessSet ? cv::OPTFLOW_USE_INITIAL_FLOW : 0), 1e-4); (_flowUseMinEigenVals ? cv::OPTFLOW_LK_GET_MIN_EIGENVALS : 0) | (guessSet ? cv::OPTFLOW_USE_INITIAL_FLOW : 0),
_flowMinEigThreshold);
UDEBUG("cv::calcOpticalFlowPyrLK() end"); UDEBUG("cv::calcOpticalFlowPyrLK() end");
} }
@@ -706,11 +713,14 @@ Transform RegistrationVis::computeTransformationImpl(
std::vector<cv::Point3f> kptsFrom3DKept(kptsFrom3D.size()); std::vector<cv::Point3f> kptsFrom3DKept(kptsFrom3D.size());
std::vector<int> orignalWordsFromIdsCpy = orignalWordsFromIds; std::vector<int> orignalWordsFromIdsCpy = orignalWordsFromIds;
int ki = 0; int ki = 0;
UASSERT((status.empty() || cornersTo.size() == status.size()) &&
(err.empty() || cornersTo.size() == err.size()));
for(unsigned int i=0; i<status.size(); ++i) for(unsigned int i=0; i<status.size(); ++i)
{ {
if(status[i] && if(status[i] &&
uIsInBounds(cornersTo[i].x, 0.0f, float(imageTo.cols)) && uIsInBounds(cornersTo[i].x, 0.0f, float(imageTo.cols)) &&
uIsInBounds(cornersTo[i].y, 0.0f, float(imageTo.rows))) uIsInBounds(cornersTo[i].y, 0.0f, float(imageTo.rows)) &&
(_flowUseMinEigenVals || err.empty() || err[i] < _flowErrorThreshold))
{ {
if(orignalWordsFromIdsCpy.size()) if(orignalWordsFromIdsCpy.size())
{ {
+22 -6
View File
@@ -113,6 +113,9 @@ std::vector<cv::Point2f> Stereo::computeCorrespondences(
StereoOpticalFlow::StereoOpticalFlow(const ParametersMap & parameters) : StereoOpticalFlow::StereoOpticalFlow(const ParametersMap & parameters) :
Stereo(parameters), Stereo(parameters),
epsilon_(Parameters::defaultStereoEps()), epsilon_(Parameters::defaultStereoEps()),
useMinEigenVals_(Parameters::defaultStereoUseMinEigenVals()),
minEigThreshold_(Parameters::defaultStereoMinEigThreshold()),
errorThreshold_(Parameters::defaultStereoErrorThreshold()),
gpu_(Parameters::defaultStereoGpu()) gpu_(Parameters::defaultStereoGpu())
{ {
this->parseParameters(parameters); this->parseParameters(parameters);
@@ -122,6 +125,9 @@ void StereoOpticalFlow::parseParameters(const ParametersMap & parameters)
{ {
Stereo::parseParameters(parameters); Stereo::parseParameters(parameters);
Parameters::parse(parameters, Parameters::kStereoEps(), epsilon_); Parameters::parse(parameters, Parameters::kStereoEps(), epsilon_);
Parameters::parse(parameters, Parameters::kStereoUseMinEigenVals(), useMinEigenVals_);
Parameters::parse(parameters, Parameters::kStereoMinEigThreshold(), minEigThreshold_);
Parameters::parse(parameters, Parameters::kStereoErrorThreshold(), errorThreshold_);
Parameters::parse(parameters, Parameters::kStereoGpu(), gpu_); Parameters::parse(parameters, Parameters::kStereoGpu(), gpu_);
#ifndef HAVE_OPENCV_CUDAOPTFLOW #ifndef HAVE_OPENCV_CUDAOPTFLOW
if(gpu_) if(gpu_)
@@ -171,11 +177,18 @@ std::vector<cv::Point2f> StereoOpticalFlow::computeCorrespondences(
err, err,
this->winSize(), this->winSize(),
this->maxLevel(), this->maxLevel(),
cv::TermCriteria(cv::TermCriteria::COUNT+cv::TermCriteria::EPS, this->iterations(), epsilon_), cv::TermCriteria(cv::TermCriteria::COUNT+cv::TermCriteria::EPS, this->iterations(), this->epsilon()),
cv::OPTFLOW_LK_GET_MIN_EIGENVALS, 1e-4); this->usingMinEigenVals() ? cv::OPTFLOW_LK_GET_MIN_EIGENVALS : 0, this->minEigThreshold());
UDEBUG("util2d::calcOpticalFlowPyrLKStereo() end"); UDEBUG("util2d::calcOpticalFlowPyrLKStereo() end");
} }
updateStatus(leftCorners, rightCorners, status); if(this->usingMinEigenVals())
{
updateStatus(leftCorners, rightCorners, status);
}
else
{
updateStatus(leftCorners, rightCorners, status, err);
}
return rightCorners; return rightCorners;
} }
@@ -227,14 +240,17 @@ std::vector<cv::Point2f> StereoOpticalFlow::computeCorrespondences(
void StereoOpticalFlow::updateStatus( void StereoOpticalFlow::updateStatus(
const std::vector<cv::Point2f> & leftCorners, const std::vector<cv::Point2f> & leftCorners,
const std::vector<cv::Point2f> & rightCorners, const std::vector<cv::Point2f> & rightCorners,
std::vector<unsigned char> & status) const std::vector<unsigned char> & status,
std::vector<float> err) const
{ {
UASSERT(leftCorners.size() == rightCorners.size() && status.size() == leftCorners.size()); UASSERT(
leftCorners.size() == rightCorners.size() && status.size() == leftCorners.size() &&
(err.empty() || err.size() == leftCorners.size()));
int countFlowRejected = 0; int countFlowRejected = 0;
int countDisparityRejected = 0; int countDisparityRejected = 0;
for(unsigned int i=0; i<status.size(); ++i) for(unsigned int i=0; i<status.size(); ++i)
{ {
if(status[i]!=0) if(status[i]!=0 && (err.empty() || err[i] < this->errorThreshold()))
{ {
float disparity = leftCorners[i].x - rightCorners[i].x; float disparity = leftCorners[i].x - rightCorners[i].x;
if(disparity <= this->minDisparity() || disparity > this->maxDisparity()) if(disparity <= this->minDisparity() || disparity > this->maxDisparity())
+6
View File
@@ -1358,6 +1358,9 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
_ui->odom_flow_iterations->setObjectName(Parameters::kVisCorFlowIterations().c_str()); _ui->odom_flow_iterations->setObjectName(Parameters::kVisCorFlowIterations().c_str());
_ui->odom_flow_eps->setObjectName(Parameters::kVisCorFlowEps().c_str()); _ui->odom_flow_eps->setObjectName(Parameters::kVisCorFlowEps().c_str());
_ui->odom_flow_gpu->setObjectName(Parameters::kVisCorFlowGpu().c_str()); _ui->odom_flow_gpu->setObjectName(Parameters::kVisCorFlowGpu().c_str());
_ui->odom_flow_useMinEigenVals->setObjectName(Parameters::kVisCorFlowUseMinEigenVals().c_str());
_ui->odom_flow_minEigThreshold->setObjectName(Parameters::kVisCorFlowMinEigThreshold().c_str());
_ui->odom_flow_errorThreshold->setObjectName(Parameters::kVisCorFlowErrorThreshold().c_str());
_ui->loopClosure_bundle->setObjectName(Parameters::kVisBundleAdjustment().c_str()); _ui->loopClosure_bundle->setObjectName(Parameters::kVisBundleAdjustment().c_str());
//RegistrationIcp //RegistrationIcp
@@ -1678,6 +1681,9 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
_ui->stereo_maxDisparity->setObjectName(Parameters::kStereoMaxDisparity().c_str()); _ui->stereo_maxDisparity->setObjectName(Parameters::kStereoMaxDisparity().c_str());
_ui->stereo_ssd->setObjectName(Parameters::kStereoSSD().c_str()); _ui->stereo_ssd->setObjectName(Parameters::kStereoSSD().c_str());
_ui->stereo_flow_eps->setObjectName(Parameters::kStereoEps().c_str()); _ui->stereo_flow_eps->setObjectName(Parameters::kStereoEps().c_str());
_ui->stereo_flow_useMinEigenVals->setObjectName(Parameters::kStereoUseMinEigenVals().c_str());
_ui->stereo_flow_minEigThreshold->setObjectName(Parameters::kStereoMinEigThreshold().c_str());
_ui->stereo_flow_errorThreshold->setObjectName(Parameters::kStereoErrorThreshold().c_str());
_ui->stereo_opticalFlow->setObjectName(Parameters::kStereoOpticalFlow().c_str()); _ui->stereo_opticalFlow->setObjectName(Parameters::kStereoOpticalFlow().c_str());
_ui->stereo_flow_gpu->setObjectName(Parameters::kStereoGpu().c_str()); _ui->stereo_flow_gpu->setObjectName(Parameters::kStereoGpu().c_str());
+257 -76
View File
@@ -95,7 +95,7 @@
<enum>QFrame::Raised</enum> <enum>QFrame::Raised</enum>
</property> </property>
<property name="currentIndex"> <property name="currentIndex">
<number>10</number> <number>24</number>
</property> </property>
<widget class="QWidget" name="page_22"> <widget class="QWidget" name="page_22">
<layout class="QVBoxLayout" name="verticalLayout_29" stretch="0,0"> <layout class="QVBoxLayout" name="verticalLayout_29" stretch="0,0">
@@ -16425,7 +16425,7 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
<item> <item>
<widget class="QStackedWidget" name="stackedWidget_odometryType"> <widget class="QStackedWidget" name="stackedWidget_odometryType">
<property name="currentIndex"> <property name="currentIndex">
<number>13</number> <number>1</number>
</property> </property>
<widget class="QWidget" name="page_52"> <widget class="QWidget" name="page_52">
<layout class="QVBoxLayout" name="verticalLayout_77"> <layout class="QVBoxLayout" name="verticalLayout_77">
@@ -16965,6 +16965,22 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
<string>[Visual] Correspondences computation: Optical Flow</string> <string>[Visual] Correspondences computation: Optical Flow</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout_52" columnstretch="0,1"> <layout class="QGridLayout" name="gridLayout_52" columnstretch="0,1">
<item row="0" column="0">
<widget class="QSpinBox" name="odom_flow_winSize">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>999999</number>
</property>
<property name="singleStep">
<number>1</number>
</property>
<property name="value">
<number>21</number>
</property>
</widget>
</item>
<item row="0" column="1"> <item row="0" column="1">
<widget class="QLabel" name="label_201"> <widget class="QLabel" name="label_201">
<property name="text"> <property name="text">
@@ -16978,19 +16994,6 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="1">
<widget class="QLabel" name="label_297">
<property name="text">
<string>Max level.</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"> <item row="1" column="0">
<widget class="QSpinBox" name="odom_flow_iterations"> <widget class="QSpinBox" name="odom_flow_iterations">
<property name="minimum"> <property name="minimum">
@@ -17007,19 +17010,16 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="0"> <item row="1" column="1">
<widget class="QSpinBox" name="odom_flow_winSize"> <widget class="QLabel" name="label_295">
<property name="minimum"> <property name="text">
<number>1</number> <string>Iterations.</string>
</property> </property>
<property name="maximum"> <property name="wordWrap">
<number>999999</number> <bool>true</bool>
</property> </property>
<property name="singleStep"> <property name="textInteractionFlags">
<number>1</number> <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
<property name="value">
<number>21</number>
</property> </property>
</widget> </widget>
</item> </item>
@@ -17042,10 +17042,10 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="1"> <item row="2" column="1">
<widget class="QLabel" name="label_295"> <widget class="QLabel" name="label_296">
<property name="text"> <property name="text">
<string>Iterations.</string> <string>Epsilon.</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -17071,23 +17071,10 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="1"> <item row="3" column="1">
<widget class="QLabel" name="label_296"> <widget class="QLabel" name="label_297">
<property name="text"> <property name="text">
<string>Epsilon.</string> <string>Max level.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLabel" name="label_odom_flow_gpu">
<property name="text">
<string>Use GPU. OpenCV built with CUDA required.</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -17098,12 +17085,109 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</widget> </widget>
</item> </item>
<item row="4" column="0"> <item row="4" column="0">
<widget class="QCheckBox" name="odom_flow_useMinEigenVals">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLabel" name="label_792">
<property name="text">
<string>Use minimum eigen values as an error measure, otherwise L1 distance between patches is used as an error measure.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QDoubleSpinBox" name="odom_flow_minEigThreshold">
<property name="decimals">
<number>6</number>
</property>
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="singleStep">
<double>0.000100000000000</double>
</property>
<property name="value">
<double>0.000100000000000</double>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLabel" name="label_791">
<property name="text">
<string>[Eigen error measure] If the minimum eigenvalue of a feature's spatial gradient matrix is less than this threshold, then the feature is filtered out.</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="QDoubleSpinBox" name="odom_flow_errorThreshold">
<property name="decimals">
<number>6</number>
</property>
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>9999.000000000000000</double>
</property>
<property name="singleStep">
<double>1.000000000000000</double>
</property>
<property name="value">
<double>50.000000000000000</double>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLabel" name="label_793">
<property name="text">
<string>[L1 error measure] Filter out features with error greater than this threshold.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QCheckBox" name="odom_flow_gpu"> <widget class="QCheckBox" name="odom_flow_gpu">
<property name="text"> <property name="text">
<string/> <string/>
</property> </property>
</widget> </widget>
</item> </item>
<item row="7" column="1">
<widget class="QLabel" name="label_odom_flow_gpu">
<property name="text">
<string>Use GPU. OpenCV built with CUDA required. Note that the error measure parameter is not used with the GPU implementation.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>
@@ -23020,6 +23104,35 @@ Lower the ratio -&gt; higher the precision.</string>
<string>Motion estimation: 3D to 3D</string> <string>Motion estimation: 3D to 3D</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout_6" columnstretch="0,1"> <layout class="QGridLayout" name="gridLayout_6" columnstretch="0,1">
<item row="1" column="1">
<widget class="QLabel" name="label_38">
<property name="text">
<string>Refine iterations of the resulting transformation computed by RANSAC. 0 means no refining.</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="QSpinBox" name="loopClosure_bowRefineIterations">
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>10000</number>
</property>
<property name="singleStep">
<number>1</number>
</property>
<property name="value">
<number>10</number>
</property>
</widget>
</item>
<item row="0" column="0"> <item row="0" column="0">
<widget class="QDoubleSpinBox" name="loopClosure_bowInlierDistance"> <widget class="QDoubleSpinBox" name="loopClosure_bowInlierDistance">
<property name="suffix"> <property name="suffix">
@@ -23052,34 +23165,18 @@ Lower the ratio -&gt; higher the precision.</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="0"> <item row="2" column="1">
<widget class="QSpinBox" name="loopClosure_bowRefineIterations"> <spacer name="verticalSpacer_93">
<property name="minimum"> <property name="orientation">
<number>0</number> <enum>Qt::Vertical</enum>
</property> </property>
<property name="maximum"> <property name="sizeHint" stdset="0">
<number>10000</number> <size>
<width>20</width>
<height>40</height>
</size>
</property> </property>
<property name="singleStep"> </spacer>
<number>1</number>
</property>
<property name="value">
<number>10</number>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_38">
<property name="text">
<string>Refine iterations of the resulting transformation computed by RANSAC. 0 means no refining.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item> </item>
</layout> </layout>
</widget> </widget>
@@ -24566,7 +24663,7 @@ Lower the ratio -&gt; higher the precision.</string>
<item> <item>
<widget class="QStackedWidget" name="stackedWidget_icpStrategy"> <widget class="QStackedWidget" name="stackedWidget_icpStrategy">
<property name="currentIndex"> <property name="currentIndex">
<number>2</number> <number>0</number>
</property> </property>
<widget class="QWidget" name="page_90"> <widget class="QWidget" name="page_90">
<layout class="QVBoxLayout" name="verticalLayout_156"> <layout class="QVBoxLayout" name="verticalLayout_156">
@@ -25532,10 +25629,17 @@ Lower the ratio -&gt; higher the precision.</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="10" column="1"> <item row="10" column="0">
<widget class="QLabel" name="label_stereo_flow_gpu"> <widget class="QCheckBox" name="stereo_flow_useMinEigenVals">
<property name="text"> <property name="text">
<string>[OpticalFlow = true] Do optical flow on GPU. RTAB-Map should be built with OpenCV CUDA.</string> <string/>
</property>
</widget>
</item>
<item row="10" column="1">
<widget class="QLabel" name="label_788">
<property name="text">
<string>[OpticalFlow = true] Use minimum eigen values as an error measure, otherwise L1 distance between patches is used as an error measure.</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -25545,13 +25649,90 @@ Lower the ratio -&gt; higher the precision.</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="10" column="0"> <item row="11" column="0">
<widget class="QDoubleSpinBox" name="stereo_flow_minEigThreshold">
<property name="decimals">
<number>6</number>
</property>
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="singleStep">
<double>0.000100000000000</double>
</property>
<property name="value">
<double>0.000100000000000</double>
</property>
</widget>
</item>
<item row="11" column="1">
<widget class="QLabel" name="label_789">
<property name="text">
<string>[OpticalFlow = true / Eigen error measure] If the minimum eigenvalue of a feature's spatial gradient matrix is less than this threshold, then the feature is filtered out.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="12" column="0">
<widget class="QDoubleSpinBox" name="stereo_flow_errorThreshold">
<property name="decimals">
<number>6</number>
</property>
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>9999.000000000000000</double>
</property>
<property name="singleStep">
<double>1.000000000000000</double>
</property>
<property name="value">
<double>50.000000000000000</double>
</property>
</widget>
</item>
<item row="12" column="1">
<widget class="QLabel" name="label_790">
<property name="text">
<string>[OpticalFlow = true / L1 error measure] Filter out features with error greater than this threshold.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="13" column="0">
<widget class="QCheckBox" name="stereo_flow_gpu"> <widget class="QCheckBox" name="stereo_flow_gpu">
<property name="text"> <property name="text">
<string/> <string/>
</property> </property>
</widget> </widget>
</item> </item>
<item row="13" column="1">
<widget class="QLabel" name="label_stereo_flow_gpu">
<property name="text">
<string>[OpticalFlow = true] Do optical flow on GPU. RTAB-Map should be built with OpenCV CUDA. Note that the error measure parameter is not used with the GPU implementation.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>