Merge branch 'master' of github.com:introlab/rtabmap into gtest

This commit is contained in:
matlabbe
2025-12-21 11:59:54 -08:00
129 changed files with 11607 additions and 5269 deletions
@@ -32,6 +32,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <rtabmap/utilite/UEventsHandler.h>
#include <QDialog>
#include <QElapsedTimer>
#include <rtabmap/core/SensorData.h>
#include <rtabmap/core/Parameters.h>
@@ -73,6 +74,9 @@ private:
QCheckBox * showScanCheckbox_;
QCheckBox * markerCheckbox_;
MarkerDetector * markerDetector_;
QElapsedTimer fpsTimer_;
double lastCapturePeriod_;
double previousCaptureStamp_;
};
} /* namespace rtabmap */
+15
View File
@@ -334,6 +334,9 @@ public:
bool getPose(const std::string & id, Transform & pose); //including meshes
bool getCloudVisibility(const std::string & id);
int getCloudColorIndex(const std::string & id) const;
double getCloudOpacity(const std::string & id) const;
int getCloudPointSize(const std::string & id) const;
const QMap<std::string, Transform> & getAddedClouds() const {return _addedClouds;} //including meshes
const QColor & getDefaultBackgroundColor() const;
@@ -399,6 +402,12 @@ public:
void setIntensityRedColormap(bool value);
void setIntensityRainbowColormap(bool value);
void setIntensityMax(float value);
float getCloudColorRangeMin() const;
float getCloudColorRangeMax() const;
bool isCloudColorRangeInverted() const;
void setCloudColorRangeMin(float value);
void setCloudColorRangeMax(float value);
void setCloudColorRangeInverted(bool enabled);
void buildPickingLocator(bool enable);
const std::map<std::string, vtkSmartPointer<vtkOBBTree> > & getLocators() const {return _locators;}
@@ -454,6 +463,10 @@ private:
QAction * _aSetIntensityRedColormap;
QAction * _aSetIntensityRainbowColormap;
QAction * _aSetIntensityMaximum;
QAction * _aSetCloudColorRangeMin;
QAction * _aSetCloudColorRangeMax;
QAction * _aCloudColorRangeInverted;
QAction * _aClearCloudColorRanges;
QAction * _aSetBackgroundColor;
QAction * _aSetRenderingRate;
QAction * _aSetEDLShading;
@@ -494,6 +507,8 @@ private:
double _renderingRate;
vtkProp * _octomapActor;
float _intensityAbsMax;
float _cloudColorRangeMin;
float _cloudColorRangeMax;
double _coordinateFrameScale;
};
@@ -220,6 +220,7 @@ private:
std::map<int, int> mapIds_;
std::map<int, int> weights_;
std::map<int, std::vector<int> > wmStates_;
std::map<int, EnvSensors> envSensors_;
QMap<int, int> idToIndex_;
QList<rtabmap::Link> neighborLinks_;
QList<rtabmap::Link> loopLinks_;
+8 -3
View File
@@ -77,6 +77,7 @@ public:
// Use updateNodeColorByValue() instead with valueName="Posterior".
RTABMAP_DEPRECATED void updatePosterior(const std::map<int, float> & posterior, float fixedMax = 0.0f, int zValueOffset = 0);
void updateNodeColorByValue(const std::string & valueName, const std::map<int, float> & values, float fixedMax = 0.0f, bool invertedColorScale = false, int zValueOffset = 0);
void updateNodeColorByValue(const std::string & valueName, const std::map<int, float> & values, float fixedMin, float fixedMax, bool invertedColorScale = false, unsigned short hueMin=0, unsigned short hueMax=180, int zValueOffset = 0);
void updateLocalPath(const std::vector<int> & localPath);
void setGlobalPath(const std::vector<std::pair<int, Transform> > & globalPath);
void setCurrentGoalID(int id, const Transform & pose = Transform());
@@ -118,8 +119,9 @@ public:
bool isReferentialVisible() const;
bool isLocalRadiusVisible() const;
float getLoopClosureOutlierThr() const {return _loopClosureOutlierThr;}
float getMaxLinkLength() const {return _maxLinkLength;}
float getMinLinkLength() const {return _minLinkLength;}
bool isGraphVisible() const;
bool isNodeVisible() const;
bool isGlobalPathVisible() const;
bool isLocalPathVisible() const;
bool isGtGraphVisible() const;
@@ -158,7 +160,7 @@ public:
void setReferentialVisible(bool visible);
void setLocalRadiusVisible(bool visible);
void setLoopClosureOutlierThr(float value);
void setMaxLinkLength(float value);
void setMinLinkLength(float value);
void setGraphVisible(bool visible);
void setGlobalPathVisible(bool visible);
void setLocalPathVisible(bool visible);
@@ -184,6 +186,9 @@ protected:
virtual void mousePressEvent(QMouseEvent * event);
virtual void contextMenuEvent(QContextMenuEvent * event);
private:
void setupGraphicsScene();
private:
QString _workingDirectory;
QColor _nodeColor;
@@ -237,7 +242,7 @@ private:
QGraphicsEllipseItem * _localRadius;
QGraphicsRectItem * _odomCacheOverlay;
float _loopClosureOutlierThr;
float _maxLinkLength;
float _minLinkLength;
bool _orientationENU;
bool _mouseTracking;
ViewPlane _viewPlane;
+3
View File
@@ -77,6 +77,7 @@ public:
float getDepthColorMapMinRange() const;
float getDepthColorMapMaxRange() const;
uCvQtDepthColorMap getDepthColorMap() const;
bool isDepthColorMapInCameraFrame() const;
float viewScale() const;
@@ -94,6 +95,7 @@ public:
void setDefaultMatchingLineColor(const QColor & color);
void setBackgroundColor(const QColor & color);
void setDepthColorMapRange(float min, float max);
void setDepthColorMapInCameraFrame(bool enabled);
void setFeatures(const std::multimap<int, cv::KeyPoint> & refWords, const cv::Mat & depth = cv::Mat(), const QColor & color = Qt::yellow);
void setFeatures(const std::vector<cv::KeyPoint> & features, const cv::Mat & depth = cv::Mat(), const QColor & color = Qt::yellow);
@@ -167,6 +169,7 @@ private:
QAction * _colorMapBlackToWhite;
QAction * _colorMapRedToBlue;
QAction * _colorMapBlueToRed;
QAction * _colorMapInCameraFrame;
QAction * _colorMapMinRange;
QAction * _colorMapMaxRange;
QAction * _mouseTracking;
+1
View File
@@ -178,6 +178,7 @@ protected Q_SLOTS:
void selectFreenect2();
void selectK4W2();
void selectK4A();
void selectOrbbecSDK();
void selectRealSense();
void selectRealSense2();
void selectRealSense2L515();
@@ -44,6 +44,7 @@ public:
void setMap(const std::map<int, Transform> & poses, const std::map<int, bool> & mask);
std::map<int, Transform> getVisiblePoses() const;
bool isEmpty() const {return _poses.empty();}
void clear();
@@ -0,0 +1,186 @@
/*
Copyright (c) 2010-2025, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the Universite de Sherbrooke nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GUILIB_SRC_POINTCLOUDCOLORHANDLEINTENSITYFIELD_H_
#define GUILIB_SRC_POINTCLOUDCOLORHANDLEINTENSITYFIELD_H_
#include <pcl/visualization/point_cloud_color_handlers.h>
#include <pcl/pcl_config.h>
#include <rtabmap/core/util2d.h>
#include <rtabmap/utilite/UMath.h>
namespace rtabmap
{
class PointCloudColorHandlerIntensityField : public pcl::visualization::PointCloudColorHandler<pcl::PCLPointCloud2>
{
typedef pcl::visualization::PointCloudColorHandler<pcl::PCLPointCloud2>::PointCloud PointCloud;
typedef PointCloud::Ptr PointCloudPtr;
typedef PointCloud::ConstPtr PointCloudConstPtr;
public:
/** \brief Constructor. */
PointCloudColorHandlerIntensityField(const PointCloudConstPtr &cloud, float maxAbsIntensity = 0.0f, int colorMap = 0) : pcl::visualization::PointCloudColorHandler<pcl::PCLPointCloud2>::PointCloudColorHandler(cloud),
maxAbsIntensity_(maxAbsIntensity),
colormap_(colorMap)
{
field_idx_ = pcl::getFieldIndex(*cloud, "intensity");
if (field_idx_ != -1)
capable_ = true;
else
capable_ = false;
}
/** \brief Empty destructor */
virtual ~PointCloudColorHandlerIntensityField() {}
/** \brief Obtain the actual color for the input dataset as vtk scalars.
* \param[out] scalars the output scalars containing the color for the dataset
* \return true if the operation was successful (the handler is capable and
* the input cloud was given as a valid pointer), false otherwise
*/
#if PCL_VERSION_COMPARE(>, 1, 11, 1)
virtual vtkSmartPointer<vtkDataArray> getColor() const
{
vtkSmartPointer<vtkDataArray> scalars;
if (!capable_ || !cloud_)
return scalars;
#else
virtual bool getColor(vtkSmartPointer<vtkDataArray> &scalars) const
{
if (!capable_ || !cloud_)
return (false);
#endif
if (!scalars)
scalars = vtkSmartPointer<vtkUnsignedCharArray>::New();
scalars->SetNumberOfComponents(3);
vtkIdType nr_points = cloud_->width * cloud_->height;
// Allocate enough memory to hold all colors
float *intensities = new float[nr_points];
float intensity;
size_t point_offset = cloud_->fields[field_idx_].offset;
size_t j = 0;
// If XYZ present, check if the points are invalid
int x_idx = pcl::getFieldIndex(*cloud_, "x");
if (x_idx != -1)
{
float x_data, y_data, z_data;
size_t x_point_offset = cloud_->fields[x_idx].offset;
// Color every point
for (vtkIdType cp = 0; cp < nr_points; ++cp,
point_offset += cloud_->point_step,
x_point_offset += cloud_->point_step)
{
// Copy the value at the specified field
memcpy(&intensity, &cloud_->data[point_offset], sizeof(float));
memcpy(&x_data, &cloud_->data[x_point_offset], sizeof(float));
memcpy(&y_data, &cloud_->data[x_point_offset + sizeof(float)], sizeof(float));
memcpy(&z_data, &cloud_->data[x_point_offset + 2 * sizeof(float)], sizeof(float));
if (!std::isfinite(x_data) || !std::isfinite(y_data) || !std::isfinite(z_data))
continue;
intensities[j++] = intensity;
}
}
// No XYZ data checks
else
{
// Color every point
for (vtkIdType cp = 0; cp < nr_points; ++cp, point_offset += cloud_->point_step)
{
// Copy the value at the specified field
memcpy(&intensity, &cloud_->data[point_offset], sizeof(float));
intensities[j++] = intensity;
}
}
if (j != 0)
{
// Allocate enough memory to hold all colors
unsigned char *colors = new unsigned char[j * 3];
float min, max;
if (maxAbsIntensity_ > 0.0f)
{
max = maxAbsIntensity_;
}
else
{
uMinMax(intensities, j, min, max);
}
for (size_t k = 0; k < j; ++k)
{
colors[k * 3 + 0] = colors[k * 3 + 1] = colors[k * 3 + 2] = max > 0 ? (unsigned char)(std::min(intensities[k] / max * 255.0f, 255.0f)) : 255;
if (colormap_ == 1)
{
colors[k * 3 + 0] = 255;
colors[k * 3 + 2] = 0;
}
else if (colormap_ == 2)
{
float r, g, b;
util2d::HSVtoRGB(&r, &g, &b, colors[k * 3 + 0] * 299.0f / 255.0f, 1.0f, 1.0f);
colors[k * 3 + 0] = r * 255.0f;
colors[k * 3 + 1] = g * 255.0f;
colors[k * 3 + 2] = b * 255.0f;
}
}
reinterpret_cast<vtkUnsignedCharArray *>(&(*scalars))->SetNumberOfTuples(j);
reinterpret_cast<vtkUnsignedCharArray *>(&(*scalars))->SetArray(colors, j * 3, 0, vtkUnsignedCharArray::VTK_DATA_ARRAY_DELETE);
}
else
reinterpret_cast<vtkUnsignedCharArray *>(&(*scalars))->SetNumberOfTuples(0);
// delete [] colors;
delete[] intensities;
#if PCL_VERSION_COMPARE(>, 1, 11, 1)
return scalars;
#else
return (true);
#endif
}
protected:
/** \brief Get the name of the class. */
virtual std::string
getName() const { return ("PointCloudColorHandlerIntensityField"); }
/** \brief Get the name of the field used. */
virtual std::string
getFieldName() const { return ("intensity"); }
private:
float maxAbsIntensity_;
int colormap_; // 0=grayscale, 1=redYellow, 2=RainbowHSV
};
} /* namespace rtabmap */
#endif /* GUILIB_SRC_POINTCLOUDCOLORHANDLEINTENSITYFIELD_H_ */
@@ -0,0 +1,187 @@
/*
Copyright (c) 2010-2025, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the Universite de Sherbrooke nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GUILIB_SRC_POINTCLOUDCOLORHANDLEMINMAXGENERICFIELD_H_
#define GUILIB_SRC_POINTCLOUDCOLORHANDLEMINMAXGENERICFIELD_H_
#include <limits>
#include <pcl/visualization/point_cloud_color_handlers.h>
#include <pcl/pcl_config.h>
namespace rtabmap
{
/// Same than pcl::visualization::PointCloudColorHandlerGenericField but with min and max parameters
class PointCloudColorHandlerMinMaxGenericField : public pcl::visualization::PointCloudColorHandler<pcl::PCLPointCloud2>
{
using PointCloud = typename PointCloudColorHandler<pcl::PCLPointCloud2>::PointCloud;
using PointCloudPtr = typename PointCloud::Ptr;
using PointCloudConstPtr = typename PointCloud::ConstPtr;
public:
/** \brief Constructor. */
PointCloudColorHandlerMinMaxGenericField(const PointCloudConstPtr &cloud,
const std::string &field_name,
float min = std::numeric_limits<float>::lowest(),
float max = std::numeric_limits<float>::max(),
bool inverted_color_scale = false)
: pcl::visualization::PointCloudColorHandler<pcl::PCLPointCloud2>(cloud),
field_name_(field_name),
min_(min),
max_(max),
inverted_color_scale_(inverted_color_scale)
{
setInputCloud(cloud);
}
/** \brief Destructor. */
virtual ~PointCloudColorHandlerMinMaxGenericField() {}
/** \brief Get the name of the field used. */
virtual std::string getFieldName() const { return (field_name_); }
#if PCL_VERSION_COMPARE(>, 1, 11, 1)
virtual vtkSmartPointer<vtkDataArray> getColor() const
{
vtkSmartPointer<vtkDataArray> scalars;
if (!capable_ || !cloud_)
return scalars;
#else
virtual bool getColor(vtkSmartPointer<vtkDataArray> &scalars) const
{
if (!capable_ || !cloud_)
return (false);
#endif
if (!scalars)
scalars = vtkSmartPointer<vtkFloatArray>::New ();
scalars->SetNumberOfComponents(1);
vtkIdType nr_points = cloud_->width * cloud_->height;
scalars->SetNumberOfTuples(nr_points);
float *colors = new float[nr_points];
float field_data;
int j = 0;
int point_offset = cloud_->fields[field_idx_].offset;
// If XYZ present, check if the points are invalid
int x_idx = pcl::getFieldIndex(*cloud_, "x");
if (x_idx != -1)
{
float x_data, y_data, z_data;
int x_point_offset = cloud_->fields[x_idx].offset;
// Color every point
for (vtkIdType cp = 0; cp < nr_points; ++cp,
point_offset += cloud_->point_step,
x_point_offset += cloud_->point_step)
{
memcpy(&x_data, &cloud_->data[x_point_offset], sizeof(float));
memcpy(&y_data, &cloud_->data[x_point_offset + sizeof(float)], sizeof(float));
memcpy(&z_data, &cloud_->data[x_point_offset + 2 * sizeof(float)], sizeof(float));
if (!std::isfinite(x_data) || !std::isfinite(y_data) || !std::isfinite(z_data))
continue;
// Copy the value at the specified field
memcpy(&field_data, &cloud_->data[point_offset], pcl::getFieldSize(cloud_->fields[field_idx_].datatype));
if(field_data < min_) {
field_data = min_;
}
if(field_data > max_) {
field_data = max_;
}
colors[j] = field_data * (inverted_color_scale_?-1.0f:1.0f);
j++;
}
}
// No XYZ data checks
else
{
// Color every point
for (vtkIdType cp = 0; cp < nr_points; ++cp, point_offset += cloud_->point_step)
{
// Copy the value at the specified field
// memcpy (&field_data, &cloud_->data[point_offset], sizeof (float));
memcpy(&field_data, &cloud_->data[point_offset], pcl::getFieldSize(cloud_->fields[field_idx_].datatype));
if (!std::isfinite(field_data))
continue;
if(field_data < min_) {
field_data = min_;
}
if(field_data > max_) {
field_data = max_;
}
colors[j] = field_data * (inverted_color_scale_?-1.0f:1.0f);
j++;
}
}
reinterpret_cast<vtkFloatArray *>(&(*scalars))->SetArray(colors, j, 0, vtkFloatArray::VTK_DATA_ARRAY_DELETE);
#if PCL_VERSION_COMPARE(>, 1, 11, 1)
return scalars;
#else
return (true);
#endif
}
using PointCloudColorHandler<pcl::PCLPointCloud2>::getColor;
/** \brief Set the input cloud to be used.
* \param[in] cloud the input cloud to be used by the handler
*/
virtual void
setInputCloud(const PointCloudConstPtr &cloud)
{
PointCloudColorHandler<pcl::PCLPointCloud2>::setInputCloud(cloud);
field_idx_ = pcl::getFieldIndex(*cloud, field_name_);
capable_ = field_idx_ != -1;
if (field_idx_ != -1 && cloud_->fields[field_idx_].datatype != pcl::PCLPointField::PointFieldTypes::FLOAT32)
{
capable_ = false;
PCL_ERROR("[pcl::PointCloudColorHandlerGenericField] This currently only works with float32 fields, but field %s has a different type.\n", field_name_.c_str());
}
}
protected:
/** \brief Class getName method. */
virtual std::string
getName() const { return ("PointCloudColorHandlerMinMaxGenericField"); }
private:
/** \brief Name of the field used to create the color handler. */
std::string field_name_;
float min_;
float max_;
bool inverted_color_scale_;
};
} /* namespace rtabmap */
#endif /* GUILIB_SRC_POINTCLOUDCOLORHANDLEMINMAXGENERICFIELD_H_ */
@@ -98,6 +98,7 @@ public:
kSrcRealSense2 = 9,
kSrcK4A = 10,
kSrcSeerSense = 11,
kSrcOrbbecSDK = 12,
kSrcStereo = 100,
kSrcDC1394 = 100,
@@ -173,6 +174,7 @@ public:
int getOdomRegistrationApproach() const;
double getOdomF2MGravitySigma() const;
bool isOdomDisabled() const;
bool isOdomAsGuessEnabled() const;
bool isOdomSensorAsGt() const;
bool isGroundTruthAligned() const;
@@ -367,11 +369,13 @@ private Q_SLOTS:
void changeDictionaryPath();
void changeOdometryORBSLAMVocabulary();
void changeOdometryOKVISConfigPath();
void changeOdometryVINSConfigPath();
void changeOdometryVINSFusionConfigPath();
void changeOdometryOpenVINSLeftMask();
void changeOdometryOpenVINSRightMask();
void changeIcpPMConfigPath();
void changeSuperPointModelPath();
void changeSuperPointRpautratWeightsPath();
void changeSuperPointRpautratModelPath();
void changePyMatcherPath();
void changePyMatcherModel();
void changePyDescriptorPath();
+12 -12
View File
@@ -117,7 +117,7 @@ inline QImage uCvMat2QImage(
// Assume depth image (float in meters)
const float * data = (const float *)image.data;
float min,max;
if(depthMax>depthMin)
if(depthMin != 0 && depthMax != 0 && depthMax > depthMin)
{
min = depthMin;
max = depthMax;
@@ -127,23 +127,23 @@ inline QImage uCvMat2QImage(
min = max = data[0];
for(unsigned int i=1; i<image.total(); ++i)
{
if(uIsFinite(data[i]) && data[i] > 0)
if(uIsFinite(data[i]) && data[i] != 0)
{
if(!uIsFinite(min) || (data[i] > 0 && data[i]<min))
if(!uIsFinite(min) || (data[i] != 0 && data[i]<min))
{
min = data[i];
}
if(!uIsFinite(max) || (data[i] > 0 && data[i]>max))
if(!uIsFinite(max) || (data[i] != 0 && data[i]>max))
{
max = data[i];
}
}
}
if(depthMax > 0 && depthMax > depthMin)
if(depthMax != 0 && depthMax > depthMin)
{
max = depthMax;
}
if(depthMin>0 && (depthMin < depthMax || depthMin < max))
if(depthMin != 0 && (depthMin < depthMax || depthMin < max))
{
min = depthMin;
}
@@ -198,7 +198,7 @@ inline QImage uCvMat2QImage(
// Assume depth image (unsigned short in mm)
const unsigned short * data = (const unsigned short *)image.data;
unsigned short min,max;
if(depthMax>depthMin)
if(depthMin != 0 && depthMax != 0 && depthMax > depthMin)
{
min = depthMin*1000;
max = depthMax*1000;
@@ -208,23 +208,23 @@ inline QImage uCvMat2QImage(
min = max = data[0];
for(unsigned int i=1; i<image.total(); ++i)
{
if(uIsFinite(data[i]) && data[i] > 0)
if(uIsFinite(data[i]) && data[i] != 0)
{
if(!uIsFinite(min) || (data[i] > 0 && data[i]<min))
if(!uIsFinite(min) || (data[i] != 0 && data[i]<min))
{
min = data[i];
}
if(!uIsFinite(max) || (data[i] > 0 && data[i]>max))
if(!uIsFinite(max) || (data[i] != 0 && data[i]>max))
{
max = data[i];
}
}
}
if(depthMax > 0 && depthMax > depthMin)
if(depthMax != 0 && depthMax > depthMin)
{
max = depthMax*1000;
}
if(depthMin>0 && (depthMin < depthMax || depthMin*1000 < max))
if(depthMin != 0 && (depthMin < depthMax || depthMin*1000 < max))
{
min = depthMin*1000;
}
+18 -1
View File
@@ -86,6 +86,13 @@ AboutDialog::AboutDialog(QWidget * parent) :
_ui->label_sptorch->setText("No");
_ui->label_sptorch_license->setEnabled(false);
#endif
#if defined(RTABMAP_TORCH) && defined(RTABMAP_PYTHON)
_ui->label_sprpautrat->setText("Yes");
_ui->label_sprpautrat_license->setEnabled(true);
#else
_ui->label_sprpautrat->setText("No");
_ui->label_sprpautrat_license->setEnabled(false);
#endif
#ifdef RTABMAP_PYTHON
_ui->label_pymatcher->setText("Yes");
_ui->label_pymatcher_license->setEnabled(true);
@@ -179,6 +186,8 @@ AboutDialog::AboutDialog(QWidget * parent) :
_ui->label_depthai->setText(CameraDepthAI::available() ? "Yes" : "No");
_ui->label_depthai_license->setEnabled(CameraDepthAI::available());
_ui->label_xvsdk->setText(CameraSeerSense::available() ? "Yes" : "No");
_ui->label_orbbec_sdk->setText(CameraOrbbecSDK::available() ? "Yes" : "No");
_ui->label_orbbec_sdk_license->setEnabled(CameraOrbbecSDK::available());
_ui->label_toro->setText(Optimizer::isAvailable(Optimizer::kTypeTORO)?"Yes":"No");
_ui->label_toro_license->setEnabled(Optimizer::isAvailable(Optimizer::kTypeTORO)?true:false);
@@ -281,7 +290,7 @@ AboutDialog::AboutDialog(QWidget * parent) :
_ui->label_msckf_license->setEnabled(false);
#endif
#ifdef RTABMAP_VINS
#ifdef RTABMAP_VINS_FUSION
_ui->label_vins_fusion->setText("Yes");
_ui->label_vins_fusion_license->setEnabled(true);
#else
@@ -297,6 +306,14 @@ AboutDialog::AboutDialog(QWidget * parent) :
_ui->label_openvins_license->setEnabled(false);
#endif
#ifdef RTABMAP_CUVSLAM
_ui->label_cuvslam->setText("Yes");
_ui->label_cuvslam_license->setEnabled(true);
#else
_ui->label_cuvslam->setText("No");
_ui->label_cuvslam_license->setEnabled(false);
#endif
}
AboutDialog::~AboutDialog()
+7 -10
View File
@@ -97,11 +97,7 @@ IF(MSVC)
SET(SRC_FILES ${SRC_FILES} ${HEADERS})
ENDIF(MSVC)
SET(INCLUDE_DIRS
${CMAKE_CURRENT_SOURCE_DIR}/../include
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR} # for qt ui generated in binary dir
)
SET(INCLUDE_DIRS "")
IF(QT4_FOUND)
INCLUDE(${QT_USE_FILE})
@@ -172,9 +168,6 @@ IF(VTK_USE_QVTK)
SET(LIBRARIES ${LIBRARIES} ${QVTK_LIBRARY})
ENDIF(VTK_USE_QVTK)
#include files
INCLUDE_DIRECTORIES(${INCLUDE_DIRS})
add_definitions(${PCL_DEFINITIONS})
# Include presets
@@ -205,8 +198,12 @@ generate_export_header(rtabmap_gui
DEPRECATED_MACRO_NAME RTABMAP_DEPRECATED)
target_include_directories(rtabmap_gui PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../include;${CMAKE_CURRENT_BINARY_DIR}/include;${PUBLIC_INCLUDE_DIRS}>"
"$<INSTALL_INTERFACE:${INSTALL_INCLUDE_DIR};${PUBLIC_INCLUDE_DIRS}>")
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR};${CMAKE_CURRENT_SOURCE_DIR}/../include;${CMAKE_CURRENT_BINARY_DIR};${CMAKE_CURRENT_BINARY_DIR}/include>"
"$<INSTALL_INTERFACE:${INSTALL_INCLUDE_DIR}>")
target_include_directories(rtabmap_gui SYSTEM PUBLIC
"$<BUILD_INTERFACE:${PUBLIC_INCLUDE_DIRS};${INCLUDE_DIRS}>"
"$<INSTALL_INTERFACE:${PUBLIC_INCLUDE_DIRS}>")
TARGET_LINK_LIBRARIES(rtabmap_gui
PUBLIC
+9 -8
View File
@@ -250,17 +250,18 @@ void CalibrationDialog::resetSettings()
cv::Mat drawChessboard(int squareSize, int boardWidth, int boardHeight, int borderSize)
{
int imageWidth = squareSize*boardWidth + borderSize;
int imageHeight = squareSize*boardHeight + borderSize;
cv::Mat chessboard(imageWidth, imageHeight, CV_8UC1, 255);
unsigned char color = 0;
int imageWidth = squareSize*(boardWidth+1) + 2*borderSize;
int imageHeight = squareSize*(boardHeight+1) + 2*borderSize;
cv::Mat chessboard(imageHeight, imageWidth, CV_8UC1, 255);
unsigned char rowColor = 0;
for(int i=borderSize;i<imageHeight-borderSize; i=i+squareSize) {
color=~color;
unsigned char colColor = rowColor;
for(int j=borderSize;j<imageWidth-borderSize;j=j+squareSize) {
cv::Mat roi=chessboard(cv::Rect(i,j,squareSize,squareSize));
roi.setTo(color);
color=~color;
cv::Mat roi=chessboard(cv::Rect(j,i,squareSize,squareSize));
roi.setTo(colColor);
colColor=~colColor;
}
rowColor = ~rowColor;
}
return chessboard;
}
+7 -1
View File
@@ -54,7 +54,9 @@ CameraViewer::CameraViewer(QWidget * parent, const ParametersMap & parameters) :
cloudView_(new CloudViewer(this)),
processingImages_(false),
parameters_(parameters),
markerDetector_(0)
markerDetector_(0),
lastCapturePeriod_(0.0),
previousCaptureStamp_(0.0)
{
qRegisterMetaType<rtabmap::SensorData>("rtabmap::SensorData");
@@ -115,6 +117,7 @@ CameraViewer::CameraViewer(QWidget * parent, const ParametersMap & parameters) :
vlayout->addLayout(layout2);
this->setLayout(vlayout);
fpsTimer_.start();
}
CameraViewer::~CameraViewer()
@@ -180,6 +183,7 @@ void CameraViewer::showImage(const rtabmap::SensorData & data)
imageView_->setImageDepth(depthOrRight);
sizes.append(QString(" Depth=%1x%2").arg(depthOrRight.cols).arg(depthOrRight.rows));
}
sizes.append(QString(" FPS capture=%1 render=%2").arg(lastCapturePeriod_>0.0?(int)round(1.0/lastCapturePeriod_):0).arg((int)round(1.0/fpsTimer_.restart()*1000)));
imageSizeLabel_->setText(sizes);
if(!depthOrRight.empty() &&
@@ -308,6 +312,8 @@ bool CameraViewer::handleEvent(UEvent * event)
{
if(camEvent->data().isValid())
{
lastCapturePeriod_ = camEvent->data().stamp() - previousCaptureStamp_;
previousCaptureStamp_ = camEvent->data().stamp();
if(!processingImages_ && this->isVisible() && camEvent->data().isValid())
{
processingImages_ = true;
+118 -151
View File
@@ -27,6 +27,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "rtabmap/gui/CloudViewer.h"
#include "rtabmap/gui/CloudViewerCellPicker.h"
#include "rtabmap/gui/PointCloudColorHandlerIntensityField.h"
#include "rtabmap/gui/PointCloudColorHandlerMinMaxGenericField.h"
#include <rtabmap/core/Version.h>
#include <rtabmap/core/util3d_transforms.h>
@@ -150,6 +152,8 @@ CloudViewer::CloudViewer(QWidget *parent, CloudViewerInteractorStyle * style) :
_renderingRate(5.0),
_octomapActor(0),
_intensityAbsMax(100.0f),
_cloudColorRangeMin(0.0f),
_cloudColorRangeMax(0.0f),
_coordinateFrameScale(1.0)
{
this->setMinimumSize(200, 200);
@@ -337,6 +341,12 @@ void CloudViewer::createMenu()
_aSetIntensityRainbowColormap->setCheckable(true);
_aSetIntensityRainbowColormap->setChecked(false);
_aSetIntensityMaximum = new QAction("Set maximum absolute intensity...", this);
_aSetCloudColorRangeMin = new QAction("Set minimum color range...", this);
_aSetCloudColorRangeMax = new QAction("Set maximum color range...", this);
_aCloudColorRangeInverted = new QAction("Inverted color scale", this);
_aCloudColorRangeInverted->setCheckable(true);
_aCloudColorRangeInverted->setChecked(false);
_aClearCloudColorRanges = new QAction("Reset ranges", this);
_aSetBackgroundColor = new QAction("Set background color...", this);
_aSetRenderingRate = new QAction("Set rendering rate...", this);
_aSetEDLShading = new QAction("Eye-Dome Lighting Shading", this);
@@ -402,6 +412,12 @@ void CloudViewer::createMenu()
scanMenu->addAction(_aSetIntensityRainbowColormap);
scanMenu->addAction(_aSetIntensityMaximum);
QMenu * cloudMenu = new QMenu("XYZ color", this);
cloudMenu->addAction(_aSetCloudColorRangeMin);
cloudMenu->addAction(_aSetCloudColorRangeMax);
cloudMenu->addAction(_aCloudColorRangeInverted);
cloudMenu->addAction(_aClearCloudColorRanges);
//menus
_menu = new QMenu(this);
_menu->addMenu(cameraMenu);
@@ -412,6 +428,7 @@ void CloudViewer::createMenu()
_menu->addMenu(gridMenu);
_menu->addMenu(normalsMenu);
_menu->addMenu(scanMenu);
_menu->addMenu(cloudMenu);
_menu->addAction(_aSetBackgroundColor);
_menu->addAction(_aSetRenderingRate);
_menu->addAction(_aSetEDLShading);
@@ -465,6 +482,10 @@ void CloudViewer::saveSettings(QSettings & settings, const QString & group) cons
settings.setValue("intensity_rainbow_colormap", this->isIntensityRainbowColormap());
settings.setValue("intensity_max", (double)this->getIntensityMax());
settings.setValue("color_range_min", (double)this->getCloudColorRangeMin());
settings.setValue("color_range_max", (double)this->getCloudColorRangeMax());
settings.setValue("color_range_inverted", (double)this->isCloudColorRangeInverted());
settings.setValue("trajectory_shown", this->isTrajectoryShown());
settings.setValue("trajectory_size", this->getTrajectorySize());
@@ -516,6 +537,10 @@ void CloudViewer::loadSettings(QSettings & settings, const QString & group)
this->setIntensityRainbowColormap(settings.value("intensity_rainbow_colormap", this->isIntensityRainbowColormap()).toBool());
this->setIntensityMax(settings.value("intensity_max", this->getIntensityMax()).toFloat());
this->setCloudColorRangeMin(settings.value("color_range_min", this->getCloudColorRangeMin()).toFloat());
this->setCloudColorRangeMax(settings.value("color_range_max", this->getCloudColorRangeMax()).toFloat());
this->setCloudColorRangeInverted(settings.value("color_range_inverted", this->isCloudColorRangeInverted()).toBool());
this->setTrajectoryShown(settings.value("trajectory_shown", this->isTrajectoryShown()).toBool());
this->setTrajectorySize(settings.value("trajectory_size", this->getTrajectorySize()).toUInt());
@@ -606,153 +631,6 @@ bool CloudViewer::updateCloudPose(
return false;
}
class PointCloudColorHandlerIntensityField : public pcl::visualization::PointCloudColorHandler<pcl::PCLPointCloud2>
{
typedef pcl::visualization::PointCloudColorHandler<pcl::PCLPointCloud2>::PointCloud PointCloud;
typedef PointCloud::Ptr PointCloudPtr;
typedef PointCloud::ConstPtr PointCloudConstPtr;
public:
typedef boost::shared_ptr<PointCloudColorHandlerIntensityField > Ptr;
typedef boost::shared_ptr<const PointCloudColorHandlerIntensityField > ConstPtr;
/** \brief Constructor. */
PointCloudColorHandlerIntensityField (const PointCloudConstPtr &cloud, float maxAbsIntensity = 0.0f, int colorMap = 0) :
pcl::visualization::PointCloudColorHandler<pcl::PCLPointCloud2>::PointCloudColorHandler (cloud),
maxAbsIntensity_(maxAbsIntensity),
colormap_(colorMap)
{
field_idx_ = pcl::getFieldIndex (*cloud, "intensity");
if (field_idx_ != -1)
capable_ = true;
else
capable_ = false;
}
/** \brief Empty destructor */
virtual ~PointCloudColorHandlerIntensityField () {}
/** \brief Obtain the actual color for the input dataset as vtk scalars.
* \param[out] scalars the output scalars containing the color for the dataset
* \return true if the operation was successful (the handler is capable and
* the input cloud was given as a valid pointer), false otherwise
*/
#if PCL_VERSION_COMPARE(>, 1, 11, 1)
virtual vtkSmartPointer<vtkDataArray> getColor () const {
vtkSmartPointer<vtkDataArray> scalars;
if (!capable_ || !cloud_)
return scalars;
#else
virtual bool getColor (vtkSmartPointer<vtkDataArray> &scalars) const {
if (!capable_ || !cloud_)
return (false);
#endif
if (!scalars)
scalars = vtkSmartPointer<vtkUnsignedCharArray>::New ();
scalars->SetNumberOfComponents (3);
vtkIdType nr_points = cloud_->width * cloud_->height;
// Allocate enough memory to hold all colors
float * intensities = new float[nr_points];
float intensity;
size_t point_offset = cloud_->fields[field_idx_].offset;
size_t j = 0;
// If XYZ present, check if the points are invalid
int x_idx = pcl::getFieldIndex (*cloud_, "x");
if (x_idx != -1)
{
float x_data, y_data, z_data;
size_t x_point_offset = cloud_->fields[x_idx].offset;
// Color every point
for (vtkIdType cp = 0; cp < nr_points; ++cp,
point_offset += cloud_->point_step,
x_point_offset += cloud_->point_step)
{
// Copy the value at the specified field
memcpy (&intensity, &cloud_->data[point_offset], sizeof (float));
memcpy (&x_data, &cloud_->data[x_point_offset], sizeof (float));
memcpy (&y_data, &cloud_->data[x_point_offset + sizeof (float)], sizeof (float));
memcpy (&z_data, &cloud_->data[x_point_offset + 2 * sizeof (float)], sizeof (float));
if (!std::isfinite (x_data) || !std::isfinite (y_data) || !std::isfinite (z_data))
continue;
intensities[j++] = intensity;
}
}
// No XYZ data checks
else
{
// Color every point
for (vtkIdType cp = 0; cp < nr_points; ++cp, point_offset += cloud_->point_step)
{
// Copy the value at the specified field
memcpy (&intensity, &cloud_->data[point_offset], sizeof (float));
intensities[j++] = intensity;
}
}
if (j != 0)
{
// Allocate enough memory to hold all colors
unsigned char* colors = new unsigned char[j * 3];
float min, max;
if(maxAbsIntensity_>0.0f)
{
max = maxAbsIntensity_;
}
else
{
uMinMax(intensities, j, min, max);
}
for(size_t k=0; k<j; ++k)
{
colors[k*3+0] = colors[k*3+1] = colors[k*3+2] = max>0?(unsigned char)(std::min(intensities[k]/max*255.0f, 255.0f)):255;
if(colormap_ == 1)
{
colors[k*3+0] = 255;
colors[k*3+2] = 0;
}
else if(colormap_ == 2)
{
float r,g,b;
util2d::HSVtoRGB(&r, &g, &b, colors[k*3+0]*299.0f/255.0f, 1.0f, 1.0f);
colors[k*3+0] = r*255.0f;
colors[k*3+1] = g*255.0f;
colors[k*3+2] = b*255.0f;
}
}
reinterpret_cast<vtkUnsignedCharArray*>(&(*scalars))->SetNumberOfTuples (j);
reinterpret_cast<vtkUnsignedCharArray*>(&(*scalars))->SetArray (colors, j*3, 0, vtkUnsignedCharArray::VTK_DATA_ARRAY_DELETE);
}
else
reinterpret_cast<vtkUnsignedCharArray*>(&(*scalars))->SetNumberOfTuples (0);
//delete [] colors;
delete [] intensities;
#if PCL_VERSION_COMPARE(>, 1, 11, 1)
return scalars;
#else
return (true);
#endif
}
protected:
/** \brief Get the name of the class. */
virtual std::string
getName () const { return ("PointCloudColorHandlerIntensityField"); }
/** \brief Get the name of the field used. */
virtual std::string
getFieldName () const { return ("intensity"); }
private:
float maxAbsIntensity_;
int colormap_; // 0=grayscale, 1=redYellow, 2=RainbowHSV
};
bool CloudViewer::addCloud(
const std::string & id,
const pcl::PCLPointCloud2Ptr & binaryCloud,
@@ -799,11 +677,20 @@ bool CloudViewer::addCloud(
_visualizer->addPointCloud (binaryCloud, colorHandler, origin, orientation, id, viewport);
// x,y,z
colorHandler.reset (new pcl::visualization::PointCloudColorHandlerGenericField<pcl::PCLPointCloud2> (binaryCloud, "x"));
colorHandler.reset (new PointCloudColorHandlerMinMaxGenericField (binaryCloud, "x",
_cloudColorRangeMin==0.0f?std::numeric_limits<float>::lowest():_cloudColorRangeMin,
_cloudColorRangeMax==0.0f?std::numeric_limits<float>::max():_cloudColorRangeMax,
_aCloudColorRangeInverted->isChecked()));
_visualizer->addPointCloud (binaryCloud, colorHandler, origin, orientation, id, viewport);
colorHandler.reset (new pcl::visualization::PointCloudColorHandlerGenericField<pcl::PCLPointCloud2> (binaryCloud, "y"));
colorHandler.reset (new PointCloudColorHandlerMinMaxGenericField (binaryCloud, "y",
_cloudColorRangeMin==0.0f?std::numeric_limits<float>::lowest():_cloudColorRangeMin,
_cloudColorRangeMax==0.0f?std::numeric_limits<float>::max():_cloudColorRangeMax,
_aCloudColorRangeInverted->isChecked()));
_visualizer->addPointCloud (binaryCloud, colorHandler, origin, orientation, id, viewport);
colorHandler.reset (new pcl::visualization::PointCloudColorHandlerGenericField<pcl::PCLPointCloud2> (binaryCloud, "z"));
colorHandler.reset (new PointCloudColorHandlerMinMaxGenericField (binaryCloud, "z",
_cloudColorRangeMin==0.0f?std::numeric_limits<float>::lowest():_cloudColorRangeMin,
_cloudColorRangeMax==0.0f?std::numeric_limits<float>::max():_cloudColorRangeMax,
_aCloudColorRangeInverted->isChecked()));
_visualizer->addPointCloud (binaryCloud, colorHandler, origin, orientation, id, viewport);
if(rgb)
@@ -3285,6 +3172,12 @@ bool CloudViewer::getCloudVisibility(const std::string & id)
return false;
}
int CloudViewer::getCloudColorIndex(const std::string & id) const
{
return _visualizer->getColorHandlerIndex(id);
}
void CloudViewer::setCloudColorIndex(const std::string & id, int index)
{
if(index>0)
@@ -3293,6 +3186,26 @@ void CloudViewer::setCloudColorIndex(const std::string & id, int index)
}
}
double CloudViewer::getCloudOpacity(const std::string & id) const
{
double opacity = 1.0;
if(!_visualizer->getPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_OPACITY, opacity, id))
{
#if VTK_MAJOR_VERSION >= 7
pcl::visualization::ShapeActorMap::iterator am_it = _visualizer->getShapeActorMap()->find (id);
if (am_it != _visualizer->getShapeActorMap()->end ())
{
vtkActor* actor = vtkActor::SafeDownCast (am_it->second);
if(actor)
{
opacity = actor->GetProperty ()->GetOpacity ();
}
}
#endif
}
return opacity;
}
void CloudViewer::setCloudOpacity(const std::string & id, double opacity)
{
double lastOpacity;
@@ -3320,6 +3233,12 @@ void CloudViewer::setCloudOpacity(const std::string & id, double opacity)
#endif
}
int CloudViewer::getCloudPointSize(const std::string & id) const
{
double size = 1.0;
_visualizer->getPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, size, id);
return (int)size;
}
void CloudViewer::setCloudPointSize(const std::string & id, int size)
{
double lastSize;
@@ -3611,9 +3530,33 @@ void CloudViewer::setIntensityMax(float value)
}
else
{
UERROR("Cannot set normals scale < 0, value=%f", value);
UERROR("Cannot set intensity < 0, value=%f", value);
}
}
float CloudViewer::getCloudColorRangeMin() const
{
return _cloudColorRangeMin;
}
float CloudViewer::getCloudColorRangeMax() const
{
return _cloudColorRangeMax;
}
bool CloudViewer::isCloudColorRangeInverted() const
{
return _aCloudColorRangeInverted->isChecked();
}
void CloudViewer::setCloudColorRangeMin(float value)
{
_cloudColorRangeMin = value;
}
void CloudViewer::setCloudColorRangeMax(float value)
{
_cloudColorRangeMax = value;
}
void CloudViewer::setCloudColorRangeInverted(bool enabled)
{
_aCloudColorRangeInverted->setChecked(enabled);
}
void CloudViewer::buildPickingLocator(bool enable)
{
@@ -3984,6 +3927,30 @@ void CloudViewer::handleAction(QAction * a)
{
this->setIntensityRainbowColormap(_aSetIntensityRainbowColormap->isChecked());
}
else if(a == _aSetCloudColorRangeMin)
{
bool ok;
double value = QInputDialog::getDouble(this, tr("Set minimum axis color range"), tr("Range (0=auto)"), _cloudColorRangeMin, -99999, 99999, 2, &ok);
if(ok)
{
this->setCloudColorRangeMin(value);
}
}
else if(a == _aSetCloudColorRangeMax)
{
bool ok;
double value = QInputDialog::getDouble(this, tr("Set maximum axis color range"), tr("Range (0=auto)"), _cloudColorRangeMax, -99999, 99999, 2, &ok);
if(ok)
{
this->setCloudColorRangeMax(value);
}
}
else if(a == _aClearCloudColorRanges)
{
_cloudColorRangeMin = 0.0f;
_cloudColorRangeMax = 0.0f;
_aCloudColorRangeInverted->setChecked(false);
}
else if(a == _aSetBackgroundColor)
{
QColor color = this->getDefaultBackgroundColor();
+100 -13
View File
@@ -394,11 +394,10 @@ DatabaseViewer::DatabaseViewer(const QString & ini, QWidget * parent) :
connect(ui_->toolButton_constraint, SIGNAL(clicked(bool)), this, SLOT(editConstraint()));
connect(ui_->checkBox_enableForAll, SIGNAL(stateChanged(int)), this, SLOT(updateConstraintButtons()));
ui_->horizontalSlider_iterations->setTracking(false);
ui_->horizontalSlider_iterations->setTracking(true);
ui_->horizontalSlider_iterations->setEnabled(false);
ui_->spinBox_optimizationsFrom->setEnabled(false);
connect(ui_->horizontalSlider_iterations, SIGNAL(valueChanged(int)), this, SLOT(sliderIterationsValueChanged(int)));
connect(ui_->horizontalSlider_iterations, SIGNAL(sliderMoved(int)), this, SLOT(sliderIterationsValueChanged(int)));
connect(ui_->spinBox_optimizationsFrom, SIGNAL(editingFinished()), this, SLOT(updateGraphView()));
connect(ui_->comboBox_optimizationFlavor, SIGNAL(activated(int)), this, SLOT(updateGraphView()));
connect(ui_->checkBox_spanAllMaps, SIGNAL(stateChanged(int)), this, SLOT(updateGraphView()));
@@ -445,6 +444,7 @@ DatabaseViewer::DatabaseViewer(const QString & ini, QWidget * parent) :
connect(ui_->graphViewer, SIGNAL(configChanged()), this, SLOT(configModified()));
connect(ui_->graphicsView_A, SIGNAL(configChanged()), this, SLOT(configModified()));
connect(ui_->graphicsView_B, SIGNAL(configChanged()), this, SLOT(configModified()));
connect(cloudViewer_, SIGNAL(configChanged()), this, SLOT(configModified()));
connect(ui_->comboBox_logger_level, SIGNAL(currentIndexChanged(int)), this, SLOT(configModified()));
connect(ui_->actionVertical_Layout, SIGNAL(toggled(bool)), this, SLOT(configModified()));
connect(ui_->actionConcise_Layout, SIGNAL(toggled(bool)), this, SLOT(configModified()));
@@ -453,6 +453,7 @@ DatabaseViewer::DatabaseViewer(const QString & ini, QWidget * parent) :
connect(ui_->checkBox_alignScansCloudsWithGroundTruth, SIGNAL(stateChanged(int)), this, SLOT(updateGraphView()));
connect(ui_->checkBox_ignoreIntermediateNodes, SIGNAL(stateChanged(int)), this, SLOT(configModified()));
connect(ui_->checkBox_ignoreIntermediateNodes, SIGNAL(stateChanged(int)), this, SLOT(updateGraphView()));
connect(ui_->comboBox_env_sensor_graph_colormap, SIGNAL(currentIndexChanged(int)), this, SLOT(updateGraphView()));
connect(ui_->checkBox_timeStats, SIGNAL(stateChanged(int)), this, SLOT(configModified()));
connect(ui_->checkBox_timeStats, SIGNAL(stateChanged(int)), this, SLOT(updateStatistics()));
// Graph view
@@ -653,6 +654,9 @@ void DatabaseViewer::readSettings()
ui_->graphicsView_A->loadSettings(settings, "ImageViewA");
ui_->graphicsView_B->loadSettings(settings, "ImageViewB");
// CloudViewer
cloudViewer_->loadSettings(settings, "CloudViewer");
// ICP parameters
settings.beginGroup("icp");
ui_->spinBox_icp_decimation->setValue(settings.value("decimation", ui_->spinBox_icp_decimation->value()).toInt());
@@ -747,6 +751,9 @@ void DatabaseViewer::writeSettings()
ui_->graphicsView_A->saveSettings(settings, "ImageViewA");
ui_->graphicsView_B->saveSettings(settings, "ImageViewB");
// CloudViewer
cloudViewer_->saveSettings(settings, "CloudViewer");
// save ICP parameters
settings.beginGroup("icp");
settings.setValue("decimation", ui_->spinBox_icp_decimation->value());
@@ -1122,6 +1129,7 @@ bool DatabaseViewer::closeDatabase()
lastWmIds_.clear();
mapIds_.clear();
weights_.clear();
envSensors_.clear();
wmStates_.clear();
links_.clear();
linksAdded_.clear();
@@ -1799,6 +1807,7 @@ void DatabaseViewer::updateIds()
idToIndex_.clear();
mapIds_.clear();
weights_.clear();
envSensors_.clear();
wmStates_.clear();
odomPoses_.clear();
groundTruthPoses_.clear();
@@ -1905,6 +1914,7 @@ void DatabaseViewer::updateIds()
dbDriver_->getNodeInfo(ids_[i], p, mapId, w, l, s, g, v, gps, sensors);
mapIds_.insert(std::make_pair(ids_[i], mapId));
weights_.insert(std::make_pair(ids_[i], w));
envSensors_.insert(std::make_pair(ids_[i], sensors));
if(w>=0)
{
for(std::multimap<int, Link>::iterator iter=links.find(ids_[i]); iter!=links.end() && iter->first==ids_[i]; ++iter)
@@ -5138,6 +5148,15 @@ void DatabaseViewer::update(int value,
cloudViewer_->removeAllLines();
cloudViewer_->removeAllFrustums();
cloudViewer_->removeOccupancyGridMap();
std::map<std::string, std::pair<int, int> > colorIndexAndPointSizeMap;
for(auto iter=cloudViewer_->getAddedClouds().constBegin(); iter!=cloudViewer_->getAddedClouds().constEnd(); ++iter) {
if(uStrContains(iter.key(), "cloud") || uStrContains(iter.key(), "scan")) {
colorIndexAndPointSizeMap.insert(std::make_pair(iter.key(),
std::make_pair(
cloudViewer_->getCloudColorIndex(iter.key())+1,
cloudViewer_->getCloudPointSize(iter.key()))));
}
}
cloudViewer_->removeAllClouds();
cloudViewer_->removeOctomap();
cloudViewer_->removeElevationMap();
@@ -5195,6 +5214,10 @@ void DatabaseViewer::update(int value,
pcl::PointCloud<pcl::PointXYZ>::Ptr scan = util3d::laserScanToPointCloud(laserScanRaw, laserScanRaw.localTransform());
cloudViewer_->addCloud("scan", scan, pose, Qt::yellow);
}
if(colorIndexAndPointSizeMap.find("scan") != colorIndexAndPointSizeMap.end()) {
cloudViewer_->setCloudColorIndex("scan", colorIndexAndPointSizeMap.at("scan").first);
cloudViewer_->setCloudPointSize("scan", colorIndexAndPointSizeMap.at("scan").second);
}
}
// add RGB-D cloud
@@ -5281,6 +5304,10 @@ void DatabaseViewer::update(int value,
}
cloudViewer_->addCloud("cloud", cloudValidPoints, pose);
if(colorIndexAndPointSizeMap.find("cloud") != colorIndexAndPointSizeMap.end()) {
cloudViewer_->setCloudColorIndex("cloud", colorIndexAndPointSizeMap.at("cloud").first);
cloudViewer_->setCloudPointSize("cloud", colorIndexAndPointSizeMap.at("cloud").second);
}
}
else
{
@@ -5404,7 +5431,12 @@ void DatabaseViewer::update(int value,
}
if(ui_->checkBox_showCloud->isChecked())
{
cloudViewer_->addCloud(uFormat("cloud_%d", i), cloud, pose);
std::string cloudName = uFormat("cloud_%d", i);
cloudViewer_->addCloud(cloudName, cloud, pose);
if(colorIndexAndPointSizeMap.find(cloudName) != colorIndexAndPointSizeMap.end()) {
cloudViewer_->setCloudColorIndex(cloudName, colorIndexAndPointSizeMap.at(cloudName).first);
cloudViewer_->setCloudPointSize(cloudName, colorIndexAndPointSizeMap.at(cloudName).second);
}
}
}
}
@@ -5434,7 +5466,12 @@ void DatabaseViewer::update(int value,
cloud = util3d::voxelize(cloud, indices, ui_->doubleSpinBox_voxelSize->value());
}
cloudViewer_->addCloud(uFormat("cloud_%d", i), cloud, pose);
std::string cloudName = uFormat("cloud_%d", i);
cloudViewer_->addCloud(cloudName, cloud, pose);
if(colorIndexAndPointSizeMap.find(cloudName) != colorIndexAndPointSizeMap.end()) {
cloudViewer_->setCloudColorIndex(cloudName, colorIndexAndPointSizeMap.at(cloudName).first);
cloudViewer_->setCloudPointSize(cloudName, colorIndexAndPointSizeMap.at(cloudName).second);
}
}
}
}
@@ -7066,6 +7103,7 @@ void DatabaseViewer::updateConstraintButtons()
void DatabaseViewer::sliderIterationsValueChanged(int value)
{
UDEBUG("sender=%s value=%d currentValue = %d", sender()?sender()->objectName().toStdString().c_str():"NA", value, ui_->horizontalSlider_iterations->value());
if(dbDriver_ && value >=0 && value < (int)graphes_.size())
{
std::map<int, rtabmap::Transform> graph = uValueAt(graphes_, value);
@@ -7208,7 +7246,47 @@ void DatabaseViewer::sliderIterationsValueChanged(int value)
ui_->graphViewer->updateGTGraph(groundTruthPoses_);
ui_->graphViewer->updateGPSGraph(gpsPoses_, gpsValues_);
ui_->graphViewer->updateGraph(graph, graphLinks_, mapIds_, weights_);
if(ui_->checkBox_wmState->isEnabled() &&
if(ui_->comboBox_env_sensor_graph_colormap->currentIndex() != 0)
{
std::map<int, float> colors;
EnvSensor::Type curentType = (EnvSensor::Type)ui_->comboBox_env_sensor_graph_colormap->currentIndex();
for(std::map<int, rtabmap::Transform>::iterator iter=graph.begin(); iter!=graph.end(); ++iter)
{
auto jter = envSensors_.find(iter->first);
if(jter != envSensors_.end() && jter->second.find(curentType) != jter->second.end())
{
colors.insert(std::make_pair(iter->first, jter->second.at(curentType).value()));
}
}
std::string legend;
bool invertedColor = false;
unsigned char hueMax = 240; // blue
switch(curentType)
{
case EnvSensor::kWifiSignalStrength:
legend = "Wifi Signal Strength (dBm)";
invertedColor = true;
hueMax = 120; // green
break;
case EnvSensor::kAmbientTemperature:
legend = "Ambient Temperature (Celcius)";
break;
case EnvSensor::kAmbientAirPressure:
legend = "Ambient Air Pressure (hPa)";
break;
case EnvSensor::kAmbientLight:
legend = "Ambient Light / Illuminance (lx)";
break;
case EnvSensor::kAmbientRelativeHumidity:
legend = "Ambient Relative Humidity (%)";
break;
default:
break;
}
ui_->graphViewer->updateNodeColorByValue(legend, colors, 0.0f, 0.0f, invertedColor, 0, hueMax, 1);
UDEBUG("Updated node color based on env sensor %d", (int)curentType);
}
else if(ui_->checkBox_wmState->isEnabled() &&
ui_->checkBox_wmState->isChecked() &&
!lastWmIds_.empty())
{
@@ -7229,6 +7307,7 @@ void DatabaseViewer::sliderIterationsValueChanged(int value)
{
ui_->graphViewer->updateNodeColorByValue("In WM", colors, 1, false, 1);
}
UDEBUG("Updated node color based working memory state");
}
QGraphicsRectItem * rectScaleItem = 0;
ui_->graphViewer->clearMap();
@@ -7432,13 +7511,16 @@ void DatabaseViewer::sliderIterationsValueChanged(int value)
}
#endif
}
ui_->graphViewer->fitInView(ui_->graphViewer->scene()->itemsBoundingRect(), Qt::KeepAspectRatio);
if(rectScaleItem != 0)
{
ui_->graphViewer->fitInView(rectScaleItem, Qt::KeepAspectRatio);
ui_->graphViewer->scene()->removeItem(rectScaleItem);
delete rectScaleItem;
}
else {
ui_->graphViewer->fitInView(ui_->graphViewer->sceneRect(), Qt::KeepAspectRatio);
}
ui_->graphViewer->update();
ui_->label_iterations->setNum(value);
@@ -8327,7 +8409,7 @@ void DatabaseViewer::refineConstraint(int from, int to, Registration * reg, Regi
}
Transform toPoseInv = filteredScanPoses.at(currentLink.to()).inverse();
dbDriver_->loadNodeData(fromS, !silent, true, !silent, !silent);
dbDriver_->loadNodeData(*fromS, !silent, true, !silent, !silent);
fromS->sensorData().uncompressData();
LaserScan fromScan = fromS->sensorData().laserScanRaw();
int maxPoints = fromScan.size();
@@ -8473,8 +8555,8 @@ void DatabaseViewer::refineConstraint(int from, int to, Registration * reg, Regi
reextractVisualFeatures ||
!silent)
{
dbDriver_->loadNodeData(fromS, reextractVisualFeatures || !silent || (reg->isScanRequired() && ui_->checkBox_icp_from_depth->isChecked()), reg->isScanRequired() || !silent, reg->isUserDataRequired() || !silent, !silent);
dbDriver_->loadNodeData(toS, reextractVisualFeatures || !silent || (reg->isScanRequired() && ui_->checkBox_icp_from_depth->isChecked()), reg->isScanRequired() || !silent, reg->isUserDataRequired() || !silent, !silent);
dbDriver_->loadNodeData(*fromS, reextractVisualFeatures || !silent || (reg->isScanRequired() && ui_->checkBox_icp_from_depth->isChecked()), reg->isScanRequired() || !silent, reg->isUserDataRequired() || !silent, !silent);
dbDriver_->loadNodeData(*toS, reextractVisualFeatures || !silent || (reg->isScanRequired() && ui_->checkBox_icp_from_depth->isChecked()), reg->isScanRequired() || !silent, reg->isUserDataRequired() || !silent, !silent);
if(!silent)
{
@@ -8569,6 +8651,7 @@ void DatabaseViewer::refineConstraint(int from, int to, Registration * reg, Regi
if(!transform.isNull())
{
UASSERT(!info.covariance.empty());
if(!transform.isIdentity())
{
if(info.covariance.at<double>(0,0)<=0.0)
@@ -8762,9 +8845,9 @@ bool DatabaseViewer::addConstraint(int from, int to, Registration * reg, bool si
!silent)
{
// Add sensor data to generate features
dbDriver_->loadNodeData(fromS, reextractVisualFeatures || !silent || (reg->isScanRequired() && ui_->checkBox_icp_from_depth->isChecked()), reg->isScanRequired() || !silent, reg->isUserDataRequired() || !silent, !silent);
dbDriver_->loadNodeData(*fromS, reextractVisualFeatures || !silent || (reg->isScanRequired() && ui_->checkBox_icp_from_depth->isChecked()), reg->isScanRequired() || !silent, reg->isUserDataRequired() || !silent, !silent);
fromS->sensorData().uncompressData();
dbDriver_->loadNodeData(toS, reextractVisualFeatures || !silent || (reg->isScanRequired() && ui_->checkBox_icp_from_depth->isChecked()), reg->isScanRequired() || !silent, reg->isUserDataRequired() || !silent, !silent);
dbDriver_->loadNodeData(*toS, reextractVisualFeatures || !silent || (reg->isScanRequired() && ui_->checkBox_icp_from_depth->isChecked()), reg->isScanRequired() || !silent, reg->isUserDataRequired() || !silent, !silent);
toS->sensorData().uncompressData();
if(reextractVisualFeatures)
{
@@ -9311,14 +9394,18 @@ std::multimap<int, rtabmap::Link> DatabaseViewer::updateLinksWithModifications(
if(findIter!=linksRefined_.end())
{
links.insert(*findIter); // add the refined link
links.insert(std::make_pair(findIter->second.to(), findIter->second.inverse())); // return both ways
if(findIter->second.from() != findIter->second.to()) {
links.insert(std::make_pair(findIter->second.to(), findIter->second.inverse())); // return both ways
}
UDEBUG("Added refined link (%d->%d, %d)", findIter->second.from(), findIter->second.to(), findIter->second.type());
continue;
}
UDEBUG("Added link (%d->%d, %d)", iter->second.from(), iter->second.to(), iter->second.type());
links.insert(*iter);
links.insert(std::make_pair(iter->second.to(), iter->second.inverse())); // return both ways
if(iter->second.from() != iter->second.to()) {
links.insert(std::make_pair(iter->second.to(), iter->second.inverse())); // return both ways
}
}
return links;
+296 -209
View File
@@ -337,17 +337,37 @@ GraphViewer::GraphViewer(QWidget * parent) :
_gridCellSize(0.0f),
_localRadius(0),
_loopClosureOutlierThr(0),
_maxLinkLength(0.02f),
_minLinkLength(0.02f),
_orientationENU(false),
_mouseTracking(false),
_viewPlane(XY),
_ensureFrameVisible(true)
{
this->setScene(new QGraphicsScene(this));
this->setDragMode(QGraphicsView::ScrollHandDrag);
_workingDirectory = QDir::homePath();
this->scene()->clear();
setupGraphicsScene();
// Match by default scan colors from DatabaseViewer
_highlightedNodes.push_back(QPair<QColor, NodeItem*>(Qt::yellow, nullptr));
_highlightedNodes.push_back(QPair<QColor, NodeItem*>(Qt::magenta, nullptr));
this->restoreDefaults();
this->fitInView(this->sceneRect(), Qt::KeepAspectRatio);
}
GraphViewer::~GraphViewer()
{
}
void GraphViewer::setupGraphicsScene()
{
if(this->scene())
{
delete this->scene();
}
this->setScene(new QGraphicsScene(this));
_world = (QGraphicsItem *)this->scene()->addEllipse(QRectF(-0.0001,-0.0001,0.0001,0.0001));
_root = (QGraphicsItem *)this->scene()->addEllipse(QRectF(-0.0001,-0.0001,0.0001,0.0001));
_root->setParentItem(_world);
@@ -485,17 +505,6 @@ GraphViewer::GraphViewer(QWidget * parent) :
_odomCacheOverlay->setBrush(QBrush(QColor(255, 255, 255, 150)));
_odomCacheOverlay->setPen(QPen(Qt::NoPen));
// Match by default scan colors from DatabaseViewer
_highlightedNodes.push_back(QPair<QColor, NodeItem*>(Qt::yellow, nullptr));
_highlightedNodes.push_back(QPair<QColor, NodeItem*>(Qt::magenta, nullptr));
this->restoreDefaults();
this->fitInView(this->sceneRect(), Qt::KeepAspectRatio);
}
GraphViewer::~GraphViewer()
{
}
void GraphViewer::setWorldMapRotation(const float & theta)
@@ -510,18 +519,48 @@ void GraphViewer::updateGraph(const std::map<int, Transform> & poses,
const std::map<int, int> & weights,
const std::set<int> & odomCacheIds)
{
UTimer timer;
bool wasVisible = _graphRoot->isVisible();
_graphRoot->show();
bool wasEmpty = _nodeItems.size() == 0 && _linkItems.size() == 0;
UDEBUG("poses=%d constraints=%d", (int)poses.size(), (int)constraints.size());
//Hide nodes and links
for(QMap<int, NodeItem*>::iterator iter = _nodeItems.begin(); iter!=_nodeItems.end(); ++iter)
if(!_graphRoot->isVisible())
{
UDEBUG("Ignoring updating graph, the graph root is not visible.");
return;
}
UTimer timer;
bool wasEmpty = _nodeItems.size() == 0 && _linkItems.size() == 0 && _gridMap->pixmap().isNull();
UDEBUG("poses=%ld constraints=%ld mapIds=%ld weights=%ld", poses.size(), constraints.size(), mapIds.size(), weights.size());
for(QMultiMap<int, LinkItem*>::iterator iter = _linkItems.begin(); iter!=_linkItems.end(); ++iter)
{
iter.value()->hide();
}
UDEBUG("hidden %d links", _linkItems.size());
int created = 0;
int reused = 0;
int removed = 0;
QMap<int, NodeItem*>::iterator nter = _nodeItems.begin();
std::map<int, Transform>::const_iterator iter=_nodeVisible?poses.begin():poses.end();
while(nter!=_nodeItems.end() || iter!=poses.end())
{
if(nter!=_nodeItems.end() && (iter==poses.end() || nter.key() < iter->first || iter->second.isNull()))
{
// NodeItem is not in poses anymore, increase only _nodeItems iterator
for(int i=0; i<_highlightedNodes.size(); ++i)
{
if(_highlightedNodes[i].second && _highlightedNodes[i].second == nter.value())
{
_highlightedNodes[i].second = nullptr;
}
}
delete nter.value();
nter = _nodeItems.erase(nter);
++removed;
continue;
}
QColor color = _nodeColor;
bool isOdomCache = odomCacheIds.find(iter.key()) != odomCacheIds.end();
if(iter.key()<0)
bool isOdomCache = odomCacheIds.find(iter->first) != odomCacheIds.end();
if(iter->first<0)
{
color = QColor(255-color.red(), 255-color.green(), 255-color.blue());
}
@@ -529,51 +568,50 @@ void GraphViewer::updateGraph(const std::map<int, Transform> & poses,
{
color = _nodeOdomCacheColor;
}
iter.value()->hide();
iter.value()->setColor(color); // reset color
iter.value()->setToolTipInfo(QString());
iter.value()->setZValue(iter.key()<0?21:20);
}
for(QMultiMap<int, LinkItem*>::iterator iter = _linkItems.begin(); iter!=_linkItems.end(); ++iter)
{
iter.value()->hide();
}
for(std::map<int, Transform>::const_iterator iter=poses.begin(); iter!=poses.end(); ++iter)
{
if(!iter->second.isNull())
UASSERT(iter!=poses.end());
if(nter == _nodeItems.end() || nter.key() > iter->first)
{
QMap<int, NodeItem*>::iterator itemIter = _nodeItems.find(iter->first);
if(itemIter != _nodeItems.end())
{
itemIter.value()->setPose(iter->second, _viewPlane);
itemIter.value()->show();
}
else
{
// create node item
QColor color = _nodeColor;
bool isOdomCache = odomCacheIds.find(iter->first) != odomCacheIds.end();
if(iter->first<0)
{
color = QColor(255-color.red(), 255-color.green(), 255-color.blue());
}
else if(isOdomCache)
{
color = _nodeOdomCacheColor;
}
const Transform & pose = iter->second;
NodeItem * item = new NodeItem(iter->first, uContains(mapIds, iter->first)?mapIds.at(iter->first):-1, pose, _nodeRadius, uContains(weights, iter->first)?weights.at(iter->first):-1, _viewPlane, _linkWidth);
this->scene()->addItem(item);
item->setZValue(iter->first<0?21:20);
item->setColor(color);
item->setParentItem(_graphRoot);
item->show();
_nodeItems.insert(iter->first, item);
}
// NodeItem is not in poses, create a new one and increase poses iterator
const Transform & pose = iter->second;
NodeItem * item = new NodeItem(
iter->first,
uValue(mapIds, iter->first, -1),
pose,
_nodeRadius,
uValue(weights, iter->first, -1),
_viewPlane,
_linkWidth);
this->scene()->addItem(item);
item->setZValue(iter->first<0?21:20);
item->setColor(color);
item->setParentItem(_graphRoot);
item->show();
_nodeItems.insert(iter->first, item);
++iter;
++created;
}
else
{
// NodeItem exists for the pose, copy data and increase both iterators
UASSERT(iter->first == nter.key());
nter.value()->setColor(color); // reset color
nter.value()->setToolTipInfo(QString());
nter.value()->setZValue(iter->first<0?21:20);
nter.value()->setPose(iter->second, _viewPlane);
nter.value()->show();
++nter;
++iter;
++reused;
}
}
UDEBUG("Nodes created=%d, reused=%d removed=%d", created, reused, removed);
created = 0;
reused = 0;
removed = 0;
int removedSmallLinks = 0;
int ignoredSmallLinks = 0;
for(std::multimap<int, Link>::const_iterator iter=constraints.begin(); iter!=constraints.end(); ++iter)
{
// make the first id the smallest one
@@ -587,30 +625,28 @@ void GraphViewer::updateGraph(const std::map<int, Transform> & poses,
std::map<int, Transform>::const_iterator jterA = poses.find(idFrom);
std::map<int, Transform>::const_iterator jterB = poses.find(idTo);
LinkItem * linkItem = 0;
if(jterA != poses.end() && jterB != poses.end() &&
_nodeItems.contains(idFrom) && _nodeItems.contains(idTo))
if(jterA != poses.end() && jterB != poses.end())
{
const Transform & poseA = jterA->second;
const Transform & poseB = jterB->second;
QMultiMap<int, LinkItem*>::iterator itemIter = _linkItems.end();
if(_linkItems.contains(idFrom))
QMultiMap<int, LinkItem*>::iterator itemIter = _linkItems.find(idFrom);
bool alreadyAdded = false;
while(itemIter != _linkItems.end() && itemIter.key() == idFrom)
{
itemIter = _linkItems.find(idFrom);
bool alreadyAdded = false;
while(itemIter != _linkItems.end() && itemIter.key() == idFrom)
if(itemIter.value()->to() == idTo)
{
if(itemIter.value()->to() == idTo && itemIter.value()->isVisible())
{
if(itemIter.value()->isVisible()) {
alreadyAdded = true;
break;
} else {
linkItem = itemIter.value();
}
++itemIter;
}
if(alreadyAdded){
continue;
break;
}
++itemIter;
}
if(alreadyAdded){
continue;
}
bool interSessionClosure = false;
@@ -625,11 +661,15 @@ void GraphViewer::updateGraph(const std::map<int, Transform> & poses,
if(isLinkedToOdomCachePoses)
{
_nodeItems.value(idFrom)->setZValue(odomCacheIds.find(idFrom)!=odomCacheIds.end()?24:23);
_nodeItems.value(idTo)->setZValue(odomCacheIds.find(idTo)!=odomCacheIds.end()?24:23);
if(_nodeItems.contains(idFrom)) {
_nodeItems.value(idFrom)->setZValue(odomCacheIds.find(idFrom)!=odomCacheIds.end()?24:23);
}
if(_nodeItems.contains(idTo)) {
_nodeItems.value(idTo)->setZValue(odomCacheIds.find(idTo)!=odomCacheIds.end()?24:23);
}
}
if(poseA.getDistance(poseB) > _maxLinkLength)
if(poseA.getDistance(poseB) > _minLinkLength)
{
if(linkItem == 0)
{
@@ -642,14 +682,24 @@ void GraphViewer::updateGraph(const std::map<int, Transform> & poses,
this->scene()->addItem(linkItem);
linkItem->setParentItem(_graphRoot);
_linkItems.insert(idFrom, linkItem);
++created;
}
else {
linkItem->setPoses(poseA, poseB, _viewPlane);
linkItem->show();
++reused;
}
}
else if(linkItem && itemIter != _linkItems.end())
else if(linkItem)
{
// erase small links
_linkItems.erase(itemIter);
delete linkItem;
linkItem = 0;
++removedSmallLinks;
}
else {
++ignoredSmallLinks;
}
if(linkItem)
@@ -730,71 +780,53 @@ void GraphViewer::updateGraph(const std::map<int, Transform> & poses,
}
}
}
UDEBUG("Links created=%d, reused=%d, small links: removed=%d ignored=%d", created, reused, removedSmallLinks, ignoredSmallLinks);
//remove not used nodes and links
for(QMap<int, NodeItem*>::iterator iter = _nodeItems.begin(); iter!=_nodeItems.end();)
{
if(!iter.value()->isVisible())
{
for(int i=0; i<_highlightedNodes.size(); ++i)
{
if(_highlightedNodes[i].second && _highlightedNodes[i].second == iter.value())
{
_highlightedNodes[i].second = nullptr;
}
}
delete iter.value();
iter = _nodeItems.erase(iter);
}
else
{
iter.value()->setVisible(_nodeVisible);
++iter;
}
}
removed = 0;
int visible = 0;
for(QMultiMap<int, LinkItem*>::iterator iter = _linkItems.begin(); iter!=_linkItems.end();)
{
if(!iter.value()->isVisible())
{
delete iter.value();
iter = _linkItems.erase(iter);
++removed;
}
else
{
++iter;
++visible;
}
}
UDEBUG("Links removed=%d, visible=%d", removed, visible);
if(_nodeItems.size())
{
(--_nodeItems.end()).value()->setColor(_nodeOdomCacheColor);
}
this->scene()->setSceneRect(this->scene()->itemsBoundingRect()); // Re-shrink the scene to it's bounding contents
QRectF rect = this->scene()->sceneRect();
if(!odomCacheIds.empty())
_odomCacheOverlay->setRect(this->scene()->itemsBoundingRect());
_odomCacheOverlay->setRect(rect);
else
_odomCacheOverlay->setRect(0, 0, 0, 0);
if(wasEmpty)
{
QRectF rect = this->scene()->itemsBoundingRect();
this->fitInView(rect.adjusted(-rect.width()/2.0f, -rect.height()/2.0f, rect.width()/2.0f, rect.height()/2.0f), Qt::KeepAspectRatio);
}
_graphRoot->setVisible(wasVisible);
UDEBUG("_nodeItems=%d, _linkItems=%d, timer=%fs", _nodeItems.size(), _linkItems.size(), timer.ticks());
}
void GraphViewer::updateGTGraph(const std::map<int, Transform> & poses)
{
if(!_gtGraphRoot->isVisible())
{
UDEBUG("Ignoring updating gt graph, the graph root is not visible.");
return;
}
UTimer timer;
bool wasVisible = _gtGraphRoot->isVisible();
_gtGraphRoot->show();
bool wasEmpty = _gtNodeItems.size() == 0 && _gtLinkItems.size() == 0;
UDEBUG("poses=%d", (int)poses.size());
//Hide nodes and links
for(QMap<int, NodeItem*>::iterator iter = _gtNodeItems.begin(); iter!=_gtNodeItems.end(); ++iter)
@@ -811,23 +843,26 @@ void GraphViewer::updateGTGraph(const std::map<int, Transform> & poses)
{
if(!iter->second.isNull())
{
QMap<int, NodeItem*>::iterator itemIter = _gtNodeItems.find(iter->first);
if(itemIter != _gtNodeItems.end())
if(_nodeVisible)
{
itemIter.value()->setPose(iter->second, _viewPlane);
itemIter.value()->show();
}
else
{
// create node item
const Transform & pose = iter->second;
NodeItem * item = new NodeItem(iter->first, -1, pose, _nodeRadius, -1, _viewPlane, _linkWidth);
this->scene()->addItem(item);
item->setZValue(20);
item->setColor(_gtPathColor);
item->setParentItem(_gtGraphRoot);
item->setVisible(_nodeVisible);
_gtNodeItems.insert(iter->first, item);
QMap<int, NodeItem*>::iterator itemIter = _gtNodeItems.find(iter->first);
if(itemIter != _gtNodeItems.end())
{
itemIter.value()->setPose(iter->second, _viewPlane);
itemIter.value()->show();
}
else
{
// create node item
const Transform & pose = iter->second;
NodeItem * item = new NodeItem(iter->first, -1, pose, _nodeRadius, -1, _viewPlane, _linkWidth);
this->scene()->addItem(item);
item->setZValue(20);
item->setColor(_gtPathColor);
item->setParentItem(_gtGraphRoot);
item->setVisible(_nodeVisible);
_gtNodeItems.insert(iter->first, item);
}
}
if(iter!=poses.begin())
@@ -913,20 +948,6 @@ void GraphViewer::updateGTGraph(const std::map<int, Transform> & poses)
++iter;
}
}
if(_gtNodeItems.size() || _gtLinkItems.size())
{
this->scene()->setSceneRect(this->scene()->itemsBoundingRect()); // Re-shrink the scene to it's bounding contents
if(wasEmpty)
{
QRectF rect = this->scene()->itemsBoundingRect();
this->fitInView(rect.adjusted(-rect.width()/2.0f, -rect.height()/2.0f, rect.width()/2.0f, rect.height()/2.0f), Qt::KeepAspectRatio);
}
}
_gtGraphRoot->setVisible(wasVisible);
UDEBUG("_gtNodeItems=%d, _gtLinkItems=%d timer=%fs", _gtNodeItems.size(), _gtLinkItems.size(), timer.ticks());
}
@@ -934,10 +955,11 @@ void GraphViewer::updateGPSGraph(
const std::map<int, Transform> & poses,
const std::map<int, GPS> & gpsValues)
{
if(!_gpsGraphRoot->isVisible()) {
UDEBUG("Ignoring updating gps graph, the graph root is not visible.");
return;
}
UTimer timer;
bool wasVisible = _gpsGraphRoot->isVisible();
_gpsGraphRoot->show();
bool wasEmpty = _gpsNodeItems.size() == 0 && _gpsNodeItems.size() == 0;
UDEBUG("poses=%d", (int)poses.size());
//Hide nodes and links
for(QMap<int, NodeItem*>::iterator iter = _gpsNodeItems.begin(); iter!=_gpsNodeItems.end(); ++iter)
@@ -954,24 +976,27 @@ void GraphViewer::updateGPSGraph(
{
if(!iter->second.isNull())
{
QMap<int, NodeItem*>::iterator itemIter = _gpsNodeItems.find(iter->first);
if(itemIter != _gpsNodeItems.end())
if(_nodeVisible)
{
itemIter.value()->setPose(iter->second, _viewPlane);
itemIter.value()->show();
}
else
{
// create node item
const Transform & pose = iter->second;
UASSERT(gpsValues.find(iter->first) != gpsValues.end());
NodeItem * item = new NodeGPSItem(iter->first, -1, pose, _nodeRadius, gpsValues.at(iter->first), _viewPlane, _linkWidth);
this->scene()->addItem(item);
item->setZValue(20);
item->setColor(_gpsPathColor);
item->setParentItem(_gpsGraphRoot);
item->setVisible(_nodeVisible);
_gpsNodeItems.insert(iter->first, item);
QMap<int, NodeItem*>::iterator itemIter = _gpsNodeItems.find(iter->first);
if(itemIter != _gpsNodeItems.end())
{
itemIter.value()->setPose(iter->second, _viewPlane);
itemIter.value()->show();
}
else
{
// create node item
const Transform & pose = iter->second;
UASSERT(gpsValues.find(iter->first) != gpsValues.end());
NodeItem * item = new NodeGPSItem(iter->first, -1, pose, _nodeRadius, gpsValues.at(iter->first), _viewPlane, _linkWidth);
this->scene()->addItem(item);
item->setZValue(20);
item->setColor(_gpsPathColor);
item->setParentItem(_gpsGraphRoot);
item->setVisible(_nodeVisible);
_gpsNodeItems.insert(iter->first, item);
}
}
if(iter!=poses.begin())
@@ -1043,20 +1068,6 @@ void GraphViewer::updateGPSGraph(
++iter;
}
}
if(_gpsNodeItems.size() || _gpsLinkItems.size())
{
this->scene()->setSceneRect(this->scene()->itemsBoundingRect()); // Re-shrink the scene to it's bounding contents
if(wasEmpty)
{
QRectF rect = this->scene()->itemsBoundingRect();
this->fitInView(rect.adjusted(-rect.width()/2.0f, -rect.height()/2.0f, rect.width()/2.0f, rect.height()/2.0f), Qt::KeepAspectRatio);
}
}
_gpsGraphRoot->setVisible(wasVisible);
UDEBUG("_gpsNodeItems=%d, _gpsLinkItems=%d timer=%fs", _gpsNodeItems.size(), _gpsLinkItems.size(), timer.ticks());
}
@@ -1085,6 +1096,7 @@ void GraphViewer::updateMap(const cv::Mat & map8U, float resolution, float xMin,
UASSERT(map8U.empty() || (!map8U.empty() && resolution > 0.0f));
if(!map8U.empty())
{
bool wasEmpty = _nodeItems.size() <= 1 && _linkItems.size() == 0 && _gridMap->pixmap().isNull();
_gridCellSize = resolution;
QImage image = uCvMat2QImage(map8U, false);
_gridMap->resetTransform();
@@ -1092,8 +1104,11 @@ void GraphViewer::updateMap(const cv::Mat & map8U, float resolution, float xMin,
_gridMap->setRotation(90);
_gridMap->setPixmap(QPixmap::fromImage(image));
_gridMap->setPos(-yMin*100.0f, -xMin*100.0f);
// Re-shrink the scene to it's bounding contents
this->scene()->setSceneRect(this->scene()->itemsBoundingRect());
if(wasEmpty)
{
this->fitInView(this->scene()->sceneRect(), Qt::KeepAspectRatio);
}
}
else
{
@@ -1134,6 +1149,66 @@ void GraphViewer::updateNodeColorByValue(const std::string & valueName, const st
}
}
void GraphViewer::updateNodeColorByValue(
const std::string & valueName,
const std::map<int, float> & values,
float min,
float max,
bool invertedColorScale,
unsigned short hueMin,
unsigned short hueMax,
int zValueOffset)
{
hueMax = hueMax > 360 ? 360 : hueMax;
//find min/max
if(min >= max)
{
bool firstValueSet = false;
for(std::map<int, float>::const_iterator iter = values.begin(); iter!=values.end(); ++iter)
{
if(iter->first > 0)
{
if(!firstValueSet) {
min = max = iter->second;
firstValueSet = true;
}
else if(iter->second>max)
{
max = iter->second;
}
else if(iter->second<min)
{
min = iter->second;
}
}
}
}
if(min < max && hueMin < hueMax)
{
float range = max - min;
float hueRange = float(hueMax - hueMin);
for(QMap<int, NodeItem*>::iterator iter = _nodeItems.begin(); iter!=_nodeItems.end(); ++iter)
{
std::map<int,float>::const_iterator jter = values.find(iter.key());
if(jter != values.end())
{
float v = jter->second;
v = std::min(v, max);
v = std::max(v, min);
iter.value()->setColor(QColor::fromHsvF(( invertedColorScale ? (v-min)/range : 1-(v-min)/range )*hueRange/360.0f + hueMin/360.0f, 1, 1, 1), valueName.c_str(), jter->second);
iter.value()->setZValue(iter.value()->zValue()+zValueOffset);
}
}
}
else if(min >= max) {
UWARN("min (%f) is not less than max (%f), cannot change color of the graph.", min, max);
}
else if(hueMin >= hueMax) {
UWARN("Hue min (%d) is not less than hue max (%d), cannot change color of the graph. The hue values should be set between 0 (red) and 360(pink).", (int)hueMin, (int)hueMax);
}
}
void GraphViewer::setGlobalPath(const std::vector<std::pair<int, Transform> > & globalPath)
{
UDEBUG("Set global path size=%d", (int)globalPath.size());
@@ -1200,6 +1275,11 @@ void GraphViewer::setNodeInfo(int id, const QString & info)
void GraphViewer::setLocalRadius(float radius)
{
_localRadius->setRect(-radius*100, -radius*100, radius*200, radius*200);
if(_nodeItems.empty() && _linkItems.empty() && _gridMap->pixmap().isNull())
{
QRectF rect = this->scene()->sceneRect();
this->fitInView(rect.adjusted(-rect.width()/2.0f, -rect.height()/2.0f, rect.width()/2.0f, rect.height()/2.0f), Qt::KeepAspectRatio);
}
}
void GraphViewer::updateLocalPath(const std::vector<int> & localPath)
@@ -1324,14 +1404,17 @@ void GraphViewer::clearGraph()
_worldMapRotation = 0.0f;
_referential->resetTransform();
_localRadius->resetTransform();
this->scene()->setSceneRect(this->scene()->itemsBoundingRect()); // Re-shrink the scene to it's bounding contents
}
void GraphViewer::clearMap()
{
_gridMap->setPixmap(QPixmap());
_gridCellSize = 0.0f;
this->scene()->setSceneRect(this->scene()->itemsBoundingRect()); // Re-shrink the scene to it's bounding contents
if(_gridMap->pixmap().isNull())
{
// there is no grid map, just return
return;
}
_gridMap->setPixmap(QPixmap());
}
void GraphViewer::clearPosterior()
@@ -1351,6 +1434,14 @@ void GraphViewer::clearAll()
{
clearMap();
clearGraph();
// The only way to re-shrink the dynamic scene rect is to re-create the QGraphicsScene.
QSettings tmp;
saveSettings(tmp);
QRectF localRadiusRectF = _localRadius->rect();
setupGraphicsScene();
loadSettings(tmp); // restore previous state
_localRadius->setRect(localRadiusRectF);
}
void GraphViewer::saveSettings(QSettings & settings, const QString & group) const
@@ -1387,8 +1478,9 @@ void GraphViewer::saveSettings(QSettings & settings, const QString & group) cons
settings.setValue("referential_visible", this->isReferentialVisible());
settings.setValue("local_radius_visible", this->isLocalRadiusVisible());
settings.setValue("loop_closure_outlier_thr", this->getLoopClosureOutlierThr());
settings.setValue("max_link_length", this->getMaxLinkLength());
settings.setValue("min_link_length", this->getMinLinkLength());
settings.setValue("graph_visible", this->isGraphVisible());
settings.setValue("node_visible", this->isNodeVisible());
settings.setValue("global_path_visible", this->isGlobalPathVisible());
settings.setValue("local_path_visible", this->isLocalPathVisible());
settings.setValue("gt_graph_visible", this->isGtGraphVisible());
@@ -1437,8 +1529,9 @@ void GraphViewer::loadSettings(QSettings & settings, const QString & group)
this->setLocalRadiusVisible(settings.value("local_radius_visible", this->isLocalRadiusVisible()).toBool());
this->setIntraInterSessionColorsEnabled(settings.value("intra_inter_session_colors_enabled", this->isIntraInterSessionColorsEnabled()).toBool());
this->setLoopClosureOutlierThr(settings.value("loop_closure_outlier_thr", this->getLoopClosureOutlierThr()).toDouble());
this->setMaxLinkLength(settings.value("max_link_length", this->getMaxLinkLength()).toDouble());
this->setMinLinkLength(settings.value("min_link_length", this->getMinLinkLength()).toDouble());
this->setGraphVisible(settings.value("graph_visible", this->isGraphVisible()).toBool());
this->setNodeVisible(settings.value("node_visible", this->isNodeVisible()).toBool());
this->setGlobalPathVisible(settings.value("global_path_visible", this->isGlobalPathVisible()).toBool());
this->setLocalPathVisible(settings.value("local_path_visible", this->isLocalPathVisible()).toBool());
this->setGtGraphVisible(settings.value("gt_graph_visible", this->isGtGraphVisible()).toBool());
@@ -1473,6 +1566,10 @@ bool GraphViewer::isGraphVisible() const
{
return _graphRoot->isVisible();
}
bool GraphViewer::isNodeVisible() const
{
return _nodeVisible;
}
bool GraphViewer::isGlobalPathVisible() const
{
return _globalPathRoot->isVisible();
@@ -1795,9 +1892,9 @@ void GraphViewer::setLoopClosureOutlierThr(float value)
{
_loopClosureOutlierThr = value;
}
void GraphViewer::setMaxLinkLength(float value)
void GraphViewer::setMinLinkLength(float value)
{
_maxLinkLength = value;
_minLinkLength = value;
}
void GraphViewer::setGraphVisible(bool visible)
{
@@ -1838,10 +1935,6 @@ void GraphViewer::setOrientationENU(bool enabled)
QTransform t;
t.rotateRadians(_worldMapRotation);
_root->setTransform(t);
if(_nodeItems.size() || _linkItems.size())
{
this->scene()->setSceneRect(this->scene()->itemsBoundingRect()); // Re-shrink the scene to it's bounding contents
}
}
void GraphViewer::setViewPlane(ViewPlane plane)
@@ -1868,11 +1961,6 @@ void GraphViewer::setViewPlane(ViewPlane plane)
_referentialXY->setVisible(plane==XY);
_referentialXZ->setVisible(plane==XZ);
_referentialYZ->setVisible(plane==YZ);
if(_nodeItems.size() || _linkItems.size())
{
this->scene()->setSceneRect(this->scene()->itemsBoundingRect()); // Re-shrink the scene to it's bounding contents
}
}
void GraphViewer::setEnsureFrameVisible(bool visible)
{
@@ -2063,7 +2151,7 @@ void GraphViewer::contextMenuEvent(QContextMenuEvent * event)
menu.addSeparator();
QAction * aSetNodeSize = menu.addAction(tr("Set node radius..."));
QAction * aSetLinkSize = menu.addAction(tr("Set link width..."));
QAction * aChangeMaxLinkLength = menu.addAction(tr("Set maximum link length..."));
QAction * aChangeMinLinkLength = menu.addAction(tr("Set minimum link length..."));
menu.addSeparator();
QAction * aEnsureFrameVisible;
QAction * aShowHideGridMap;
@@ -2181,12 +2269,12 @@ void GraphViewer::contextMenuEvent(QContextMenuEvent * event)
aMouseTracking->setCheckable(true);
aMouseTracking->setChecked(_mouseTracking);
aMouseTracking->setEnabled(_viewPlane == XY);
aShowHideGraph->setEnabled(_nodeItems.size() && _viewPlane == XY);
aShowHideGraphNodes->setEnabled(_nodeItems.size() && _graphRoot->isVisible());
aShowHideGraph->setEnabled(_viewPlane == XY);
aShowHideGraphNodes->setEnabled(_graphRoot->isVisible());
aShowHideGlobalPath->setEnabled(_globalPathLinkItems.size());
aShowHideLocalPath->setEnabled(_localPathLinkItems.size());
aShowHideGtGraph->setEnabled(_gtNodeItems.size());
aShowHideGPSGraph->setEnabled(_gpsNodeItems.size());
aShowHideGtGraph->setEnabled(_gtGraphRoot->isVisible());
aShowHideGPSGraph->setEnabled(_gpsGraphRoot->isVisible());
aShowHideOdomCacheOverlay->setEnabled(_odomCacheOverlay->rect().width()>0);
QMenu * viewPlaneMenu = menu.addMenu("View Plane...");
@@ -2303,8 +2391,7 @@ void GraphViewer::contextMenuEvent(QContextMenuEvent * event)
//reset scale
_root->setScale(1.0f);
this->scene()->setSceneRect(this->scene()->itemsBoundingRect()); // Re-shrink the scene to it's bounding contents
this->scene()->setSceneRect(QRectF());
QDesktopServices::openUrl(QUrl::fromLocalFile(filePath));
}
@@ -2366,13 +2453,13 @@ void GraphViewer::contextMenuEvent(QContextMenuEvent * event)
setLoopClosureOutlierThr(value);
}
}
else if(r == aChangeMaxLinkLength)
else if(r == aChangeMinLinkLength)
{
bool ok;
double value = QInputDialog::getDouble(this, tr("Maximum link length to be shown"), tr("Value (m)"), _maxLinkLength, 0.0, 1000.0, 3, &ok);
double value = QInputDialog::getDouble(this, tr("Minimum link length to be shown"), tr("Value (m)"), _minLinkLength, 0.0, 1000.0, 3, &ok);
if(ok)
{
setMaxLinkLength(value);
setMinLinkLength(value);
}
}
else if(r == aChangeNodeColor ||
+1
View File
@@ -44,6 +44,7 @@
<file>images/oakd.png</file>
<file>images/oakd_lite.png</file>
<file>images/astra.png</file>
<file>images/astra2.png</file>
<file>images/oakdpro.png</file>
<file>images/seer_sense_DS80.png</file>
</qresource>
+92 -11
View File
@@ -266,14 +266,16 @@ ImageView::ImageView(QWidget * parent) :
_colorMapBlueToRed = colorMap->addAction(tr("Blue to red"));
_colorMapBlueToRed->setCheckable(true);
_colorMapBlueToRed->setChecked(false);
_colorMapMinRange = colorMap->addAction(tr("Min Range..."));
_colorMapMaxRange = colorMap->addAction(tr("Max Range..."));
_colorMapInCameraFrame = colorMap->addAction(tr("Camera Frame"));
_colorMapInCameraFrame->setCheckable(true);
_colorMapInCameraFrame->setChecked(true);
_colorMapMinRange = colorMap->addAction(tr("Min Z..."));
_colorMapMaxRange = colorMap->addAction(tr("Max Z..."));
group = new QActionGroup(this);
group->addAction(_colorMapWhiteToBlack);
group->addAction(_colorMapBlackToWhite);
group->addAction(_colorMapRedToBlue);
group->addAction(_colorMapBlueToRed);
group->addAction(_colorMapMaxRange);
_mouseTracking = _menu->addAction(tr("Show pixel depth"));
_mouseTracking->setCheckable(true);
_mouseTracking->setChecked(false);
@@ -311,6 +313,7 @@ void ImageView::saveSettings(QSettings & settings, const QString & group) const
settings.setValue("graphics_view_scale", this->isGraphicsViewScaled());
settings.setValue("graphics_view_scale_to_height", this->isGraphicsViewScaledToHeight());
settings.setValue("colormap", _colorMapWhiteToBlack->isChecked()?0:_colorMapBlackToWhite->isChecked()?1:_colorMapRedToBlue->isChecked()?2:3);
settings.setValue("colormap_camera_frame", this->isDepthColorMapInCameraFrame());
settings.setValue("colormap_min_range", this->getDepthColorMapMinRange());
settings.setValue("colormap_max_range", this->getDepthColorMapMaxRange());
if(!group.isEmpty())
@@ -345,6 +348,7 @@ void ImageView::loadSettings(QSettings & settings, const QString & group)
_colorMapBlackToWhite->setChecked(colorMap==1);
_colorMapRedToBlue->setChecked(colorMap==2);
_colorMapBlueToRed->setChecked(colorMap==3);
this->setDepthColorMapInCameraFrame(settings.value("colormap_camera_frame", this->isDepthColorMapInCameraFrame()).toBool());
this->setDepthColorMapRange(
settings.value("colormap_min_range", this->getDepthColorMapMinRange()).toFloat(),
settings.value("colormap_max_range", settings.value("colormap_range" /*backward compatibility*/, this->getDepthColorMapMaxRange())).toFloat());
@@ -763,13 +767,20 @@ void ImageView::setBackgroundColor(const QColor & color)
}
}
void ImageView::setDepthColorMapInCameraFrame(bool enabled) {
_colorMapInCameraFrame->setChecked(enabled);
}
bool ImageView::isDepthColorMapInCameraFrame() const {
return _colorMapInCameraFrame->isChecked();
}
void ImageView::setDepthColorMapRange(float min, float max)
{
_depthColorMapMinRange = min;
_depthColorMapMaxRange = max;
}
void ImageView::computeScaleOffsets(const QRect & targetRect, float & scale, float & offsetX, float & offsetY) const
{
scale = 1.0f;
@@ -1054,10 +1065,17 @@ void ImageView::contextMenuEvent(QContextMenuEvent * e)
}
Q_EMIT configChanged();
}
else if(action == _colorMapInCameraFrame)
{
if(!_imageDepthCv.empty()) {
this->setImageDepth(_imageDepthCv, _imageDepthConfidenceCv);
}
Q_EMIT configChanged();
}
else if(action == _colorMapMinRange)
{
bool ok = false;
double value = QInputDialog::getDouble(this, tr("Set depth colormap min range"), tr("Range (m), 0=no limit"), _depthColorMapMinRange, 0, 9999, 1, &ok);
double value = QInputDialog::getDouble(this, tr("Set depth colormap min range"), tr("Range (m), 0=no limit"), _depthColorMapMinRange, -9999, 9999, 2, &ok);
if(ok)
{
this->setDepthColorMapRange(value, _depthColorMapMaxRange);
@@ -1070,7 +1088,7 @@ void ImageView::contextMenuEvent(QContextMenuEvent * e)
else if(action == _colorMapMaxRange)
{
bool ok = false;
double value = QInputDialog::getDouble(this, tr("Set depth colormap max range"), tr("Range (m), 0=no limit"), _depthColorMapMaxRange, 0, 9999, 1, &ok);
double value = QInputDialog::getDouble(this, tr("Set depth colormap max range"), tr("Range (m), 0=no limit"), _depthColorMapMaxRange, -9999, 9999, 2, &ok);
if(ok)
{
this->setDepthColorMapRange(_depthColorMapMinRange, value);
@@ -1123,14 +1141,14 @@ void ImageView::mouseMoveEvent(QMouseEvent * event)
if(_mouseTracking->isChecked() &&
!_graphicsView->scene()->sceneRect().isNull() &&
!_image.isNull() &&
!_imageDepthCv.empty() &&(_imageDepthCv.type() == CV_16UC1 || _imageDepthCv.type() == CV_32FC1))
!_imageDepthCv.empty() && (_imageDepthCv.type() == CV_16UC1 || _imageDepthCv.type() == CV_32FC1))
{
float scale, offsetX, offsetY;
computeScaleOffsets(this->rect(), scale, offsetX, offsetY);
float u = (event->pos().x() - offsetX) / scale;
float v = (event->pos().y() - offsetY) / scale;
float depthScale = 1;
if(_image.width() > _imageDepthCv.cols)
if(_image.width() != _imageDepthCv.cols)
{
depthScale = float(_imageDepthCv.cols) / float(_image.width());
}
@@ -1350,8 +1368,71 @@ void ImageView::setImageDepth(const cv::Mat & imageDepth, const cv::Mat & imageD
{
_imageDepthCv = imageDepth;
_imageDepthConfidenceCv = imageDepthConfidence;
QImage depth;
if(!_imageDepthCv.empty() && (_imageDepthCv.type() == CV_16UC1 || _imageDepthCv.type() == CV_32FC1)) {
if(_colorMapInCameraFrame->isChecked() || _models.empty() || !_models[0].isValidForProjection()) {
depth = uCvMat2QImage(_imageDepthCv, true, getDepthColorMap(), _depthColorMapMinRange, _depthColorMapMaxRange);
if(!_colorMapInCameraFrame->isChecked()) {
UWARN("Trying to set depth color map in base frame but the the camera model "
"is not valid for projection, showing depth in camera frame instead.");
}
}
else {
// convert the depth values in height values
cv::Mat depthInBaseFrame = _imageDepthCv.clone();
int subImageWidth = _imageDepthCv.cols / _models.size();
std::vector<CameraModel> models; // scale model to size of depth image if needed
for(const auto & model: _models) {
UASSERT(subImageWidth <= model.imageWidth());
if(subImageWidth < model.imageWidth()) {
models.push_back(model.scaled(float(subImageWidth)/float(model.imageWidth())));
}
else {
models.push_back(model);
}
}
if(depthInBaseFrame.type() == CV_16UC1) {
for(int v=0; v<depthInBaseFrame.rows; ++v){
unsigned short * rowPtr = depthInBaseFrame.ptr<unsigned short>(v);
for(int u=0; u<depthInBaseFrame.cols; ++u){
unsigned short & val = rowPtr[u];
if(val > 0) {
cv::Point3f pt;
int cameraIndex = u/subImageWidth;
UASSERT(cameraIndex>=0 && cameraIndex < (int)models.size() && subImageWidth == models[cameraIndex].imageWidth());
models[cameraIndex].project(u,v,float(val)/1000.0f, pt.x, pt.y, pt.z);
pt = util3d::transformPoint(pt, models[cameraIndex].localTransform());
val = (unsigned short)(pt.z*1000.0f);
}
}
}
}
else { // CV_32FC1
for(int v=0; v<depthInBaseFrame.rows; ++v){
float * rowPtr = depthInBaseFrame.ptr<float>(v);
for(int u=0; u<depthInBaseFrame.cols; ++u){
float & val = rowPtr[u];
if(val > 0) {
cv::Point3f pt;
int cameraIndex = u/subImageWidth;
UASSERT(cameraIndex>=0 && cameraIndex < (int)models.size() && subImageWidth == models[cameraIndex].imageWidth());
models[cameraIndex].project(u,v,val, pt.x, pt.y, pt.z);
pt = util3d::transformPoint(pt, models[cameraIndex].localTransform());
val = pt.z;
}
}
}
}
depth = uCvMat2QImage(depthInBaseFrame, true, getDepthColorMap(), _depthColorMapMinRange, _depthColorMapMaxRange);
}
}
else {
// right image grayscale or color
depth = uCvMat2QImage(_imageDepthCv, true, uCvQtDepthBlackToWhite);
}
setImageDepth(
uCvMat2QImage(_imageDepthCv, true, _imageDepthCv.type()==CV_8UC1?uCvQtDepthBlackToWhite:getDepthColorMap(), _depthColorMapMinRange, _depthColorMapMaxRange),
depth,
uCvMat2QImage(_imageDepthConfidenceCv, true, getDepthColorMap()));
}
@@ -1367,8 +1448,8 @@ void ImageView::setImageDepth(const QImage & imageDepth, const QImage & imageDep
UASSERT(_imageDepth.width() && _imageDepth.height());
if( _image.width() > 0 &&
_image.width() > _imageDepth.width() &&
_image.height() > _imageDepth.height())
_image.width() != _imageDepth.width() &&
_image.height() != _imageDepth.height())
{
// scale depth to rgb
_imageDepth = _imageDepth.scaled(_image.size());
+339 -274
View File
@@ -470,6 +470,7 @@ MainWindow::MainWindow(PreferencesDialog * prefDialog, QWidget * parent, bool sh
connect(_ui->actionDepthAI_oakdlite, SIGNAL(triggered()), this, SLOT(selectDepthAIOAKDLite()));
connect(_ui->actionDepthAI_oakdpro, SIGNAL(triggered()), this, SLOT(selectDepthAIOAKDPro()));
connect(_ui->actionXvisio_SeerSense, SIGNAL(triggered()), this, SLOT(selectXvisioSeerSense()));
connect(_ui->actionOrbbecSDK_astra2, SIGNAL(triggered()), this, SLOT(selectOrbbecSDK()));
connect(_ui->actionVelodyne_VLP_16, SIGNAL(triggered()), this, SLOT(selectVLP16()));
_ui->actionFreenect->setEnabled(CameraFreenect::available());
_ui->actionOpenNI_PCL->setEnabled(CameraOpenni::available());
@@ -499,6 +500,7 @@ MainWindow::MainWindow(PreferencesDialog * prefDialog, QWidget * parent, bool sh
_ui->actionDepthAI_oakdlite->setEnabled(CameraDepthAI::available());
_ui->actionDepthAI_oakdpro->setEnabled(CameraDepthAI::available());
_ui->actionXvisio_SeerSense->setEnabled(CameraSeerSense::available());
_ui->actionOrbbecSDK_astra2->setEnabled(CameraOrbbecSDK::available());
this->updateSelectSourceMenu();
connect(_ui->actionPreferences, SIGNAL(triggered()), this, SLOT(openPreferences()));
@@ -753,7 +755,7 @@ void MainWindow::setupMainLayout(bool vertical)
std::map<int, Transform> MainWindow::currentVisiblePosesMap() const
{
return _ui->widget_mapVisibility->getVisiblePoses();
return !_ui->widget_mapVisibility->isEmpty()?_ui->widget_mapVisibility->getVisiblePoses():_currentPosesMap;
}
void MainWindow::setCloudViewer(rtabmap::CloudViewer * cloudViewer)
@@ -1586,63 +1588,61 @@ void MainWindow::processOdometry(const rtabmap::OdometryEvent & odom, bool dataI
{
_odometryReceived = true;
// update camera position
if(data->cameraModels().size() && data->cameraModels()[0].isValidForProjection())
if(_cloudViewer->isVisible())
{
_cloudViewer->updateCameraFrustums(_odometryCorrection*odom.pose(), data->cameraModels());
}
else if(data->stereoCameraModels().size() && data->stereoCameraModels()[0].isValidForProjection())
{
_cloudViewer->updateCameraFrustums(_odometryCorrection*odom.pose(), data->stereoCameraModels());
}
else if(!data->laserScanRaw().isEmpty() ||
!data->laserScanCompressed().isEmpty())
{
Transform scanLocalTransform;
if(!data->laserScanRaw().isEmpty())
if(data->cameraModels().size() && data->cameraModels()[0].isValidForProjection())
{
scanLocalTransform = data->laserScanRaw().localTransform();
_cloudViewer->updateCameraFrustums(_odometryCorrection*odom.pose(), data->cameraModels());
}
else if(data->stereoCameraModels().size() && data->stereoCameraModels()[0].isValidForProjection())
{
_cloudViewer->updateCameraFrustums(_odometryCorrection*odom.pose(), data->stereoCameraModels());
}
else if(!data->laserScanRaw().isEmpty() ||
!data->laserScanCompressed().isEmpty())
{
Transform scanLocalTransform;
if(!data->laserScanRaw().isEmpty())
{
scanLocalTransform = data->laserScanRaw().localTransform();
}
else
{
scanLocalTransform = data->laserScanCompressed().localTransform();
}
//fake frustum
CameraModel model(
2,
2,
2,
1.5,
scanLocalTransform*CameraModel::opticalRotation(),
0,
cv::Size(4,3));
_cloudViewer->updateCameraFrustum(_odometryCorrection*odom.pose(), model);
}
#if PCL_VERSION_COMPARE(>=, 1, 7, 2)
if(_preferencesDialog->isFramesShown())
{
_cloudViewer->addOrUpdateLine("odom_to_base_link", _odometryCorrection, _odometryCorrection*odom.pose(), qRgb(255, 128, 0), true, false);
}
else
{
scanLocalTransform = data->laserScanCompressed().localTransform();
_cloudViewer->removeLine("odom_to_base_link");
}
//fake frustum
CameraModel model(
2,
2,
2,
1.5,
scanLocalTransform*CameraModel::opticalRotation(),
0,
cv::Size(4,3));
_cloudViewer->updateCameraFrustum(_odometryCorrection*odom.pose(), model);
}
#if PCL_VERSION_COMPARE(>=, 1, 7, 2)
if(_preferencesDialog->isFramesShown())
{
_cloudViewer->addOrUpdateLine("odom_to_base_link", _odometryCorrection, _odometryCorrection*odom.pose(), qRgb(255, 128, 0), true, false);
}
else
{
_cloudViewer->removeLine("odom_to_base_link");
}
#endif
_cloudViewer->updateCameraTargetPosition(_odometryCorrection*odom.pose());
UDEBUG("Time Update Pose: %fs", time.ticks());
}
_cloudViewer->refreshView();
if(_ui->graphicsView_graphView->isVisible())
{
if(!pose.isNull() && !odom.pose().isNull())
_cloudViewer->updateCameraTargetPosition(_odometryCorrection*odom.pose());
UDEBUG("Time Update Pose: %fs", time.ticks());
_cloudViewer->refreshView();
}
if(_ui->graphicsView_graphView->isVisible())
{
_ui->graphicsView_graphView->updateReferentialPosition(_odometryCorrection*odom.pose());
_ui->graphicsView_graphView->update();
UDEBUG("Time Update graphview: %fs", time.ticks());
}
}
}
if(_ui->dockWidget_odometry->isVisible() &&
!data->imageRaw().empty())
@@ -1675,7 +1675,7 @@ void MainWindow::processOdometry(const rtabmap::OdometryEvent & odom, bool dataI
odom.info().type == (int)Odometry::kTypeViso2 ||
odom.info().type == (int)Odometry::kTypeFovis ||
odom.info().type == (int)Odometry::kTypeMSCKF ||
odom.info().type == (int)Odometry::kTypeVINS ||
odom.info().type == (int)Odometry::kTypeVINSFusion ||
odom.info().type == (int)Odometry::kTypeOpenVINS)
{
std::vector<cv::KeyPoint> kpts;
@@ -1725,7 +1725,6 @@ void MainWindow::processOdometry(const rtabmap::OdometryEvent & odom, bool dataI
if( odom.info().type == (int)Odometry::kTypeF2M ||
odom.info().type == (int)Odometry::kTypeORBSLAM ||
odom.info().type == (int)Odometry::kTypeMSCKF ||
odom.info().type == (int)Odometry::kTypeVINS ||
odom.info().type == (int)Odometry::kTypeOpenVINS)
{
if(_ui->imageView_odometry->isFeaturesShown() && !_preferencesDialog->isOdomOnlyInliersShown())
@@ -1742,6 +1741,7 @@ void MainWindow::processOdometry(const rtabmap::OdometryEvent & odom, bool dataI
}
if((odom.info().type == (int)Odometry::kTypeF2F ||
odom.info().type == (int)Odometry::kTypeViso2 ||
odom.info().type == (int)Odometry::kTypeVINSFusion ||
odom.info().type == (int)Odometry::kTypeFovis) && odom.info().refCorners.size())
{
if(_ui->imageView_odometry->isFeaturesShown() || _ui->imageView_odometry->isLinesShown())
@@ -1795,6 +1795,7 @@ void MainWindow::processOdometry(const rtabmap::OdometryEvent & odom, bool dataI
//Process info
if(_preferencesDialog->isCacheSavedInFigures() || _ui->statsToolBox->isVisible())
{
UASSERT(odom.info().reg.covariance.total() == 36 && odom.info().reg.covariance.type() == CV_64FC1);
double linVar = uMax3(odom.info().reg.covariance.at<double>(0,0), odom.info().reg.covariance.at<double>(1,1)>=9999?0:odom.info().reg.covariance.at<double>(1,1), odom.info().reg.covariance.at<double>(2,2)>=9999?0:odom.info().reg.covariance.at<double>(2,2));
double angVar = uMax3(odom.info().reg.covariance.at<double>(3,3)>=9999?0:odom.info().reg.covariance.at<double>(3,3), odom.info().reg.covariance.at<double>(4,4)>=9999?0:odom.info().reg.covariance.at<double>(4,4), odom.info().reg.covariance.at<double>(5,5));
_ui->statsToolBox->updateStat("Odometry/Inliers/", _preferencesDialog->isTimeUsedInFigures()?data->stamp()-_firstStamp:(float)data->id(), (float)odom.info().reg.inliers, _preferencesDialog->isCacheSavedInFigures());
@@ -2028,13 +2029,14 @@ void MainWindow::processStats(const rtabmap::Statistics & stat)
{
// make sure data are uncompressed
// We don't need to uncompress images if we don't show them
bool uncompressImages = !signature.sensorData().imageCompressed().empty() && (
_ui->imageView_source->isVisible() ||
(_loopClosureViewer->isVisible() &&
!signature.sensorData().depthOrRightCompressed().empty()) ||
(_cloudViewer->isVisible() &&
_preferencesDialog->isCloudsShown(0) &&
!signature.sensorData().depthOrRightCompressed().empty()));
bool uncompressImages = (!signature.sensorData().imageCompressed().empty() &&
((_ui->imageView_source->isVisible() && _ui->imageView_source->isImageShown()) ||
_loopClosureViewer->isVisible()))
||
(!signature.sensorData().depthOrRightCompressed().empty() &&
((_ui->imageView_loopClosure->isVisible() && _ui->imageView_loopClosure->isImageShown()) ||
(_cloudViewer->isVisible() && _preferencesDialog->isCloudsShown(0))));
bool uncompressScan = !signature.sensorData().laserScanCompressed().isEmpty() && (
_loopClosureViewer->isVisible() ||
(_cloudViewer->isVisible() && _preferencesDialog->isScansShown(0)));
@@ -2113,11 +2115,19 @@ void MainWindow::processStats(const rtabmap::Statistics & stat)
_ui->imageView_source->clear();
_ui->imageView_loopClosure->clear();
if(signature.sensorData().imageRaw().empty() && signature.getWords().empty())
// To see colors
QRect rect(0,0,640,480); // default
if(signature.sensorData().cameraModels().size() && signature.sensorData().cameraModels().at(0).imageSize()!=cv::Size())
{
// To see colors
_ui->imageView_source->setSceneRect(QRect(0,0,640,480));
rect.setWidth(signature.sensorData().cameraModels().at(0).imageWidth()*signature.sensorData().cameraModels().size());
rect.setHeight(signature.sensorData().cameraModels().at(0).imageHeight());
}
else if(signature.sensorData().stereoCameraModels().size() && signature.sensorData().stereoCameraModels().at(0).left().imageSize()!=cv::Size())
{
rect.setWidth(signature.sensorData().stereoCameraModels().at(0).left().imageWidth()*signature.sensorData().stereoCameraModels().size());
rect.setHeight(signature.sensorData().stereoCameraModels().at(0).left().imageHeight());
}
_ui->imageView_source->setSceneRect(rect);
_ui->imageView_source->setBackgroundColor(_ui->imageView_source->getDefaultBackgroundColor());
_ui->imageView_loopClosure->setBackgroundColor(_ui->imageView_loopClosure->getDefaultBackgroundColor());
@@ -2258,22 +2268,27 @@ void MainWindow::processStats(const rtabmap::Statistics & stat)
QMap<int, Signature>::iterator iter = _cachedSignatures.find(shownLoopId);
if(iter != _cachedSignatures.end())
{
// uncompress after copy to avoid keeping uncompressed data in memory
loopSignature = iter.value();
bool uncompressImages = !loopSignature.sensorData().imageCompressed().empty() && (
_ui->imageView_source->isVisible() ||
(_loopClosureViewer->isVisible() &&
!loopSignature.sensorData().depthOrRightCompressed().empty()));
bool uncompressScan = _loopClosureViewer->isVisible() &&
!loopSignature.sensorData().laserScanCompressed().isEmpty();
if(uncompressImages || uncompressScan)
if((_ui->imageView_loopClosure->isVisible() && (_ui->imageView_loopClosure->isImageShown() || _ui->imageView_loopClosure->isImageDepthShown())) ||
_loopClosureViewer->isVisible())
{
cv::Mat tmpRGB, tmpDepth;
LaserScan tmpScan;
loopSignature.sensorData().uncompressData(
uncompressImages?&tmpRGB:0,
uncompressImages?&tmpDepth:0,
uncompressScan?&tmpScan:0);
// uncompress after copy to avoid keeping uncompressed data in memory
bool uncompressImages = !loopSignature.sensorData().imageCompressed().empty() && (
(_ui->imageView_loopClosure->isVisible() && (_ui->imageView_loopClosure->isImageShown() || _ui->imageView_loopClosure->isImageDepthShown())) ||
(_loopClosureViewer->isVisible() &&
!loopSignature.sensorData().depthOrRightCompressed().empty()));
bool uncompressScan = _loopClosureViewer->isVisible() &&
!loopSignature.sensorData().laserScanCompressed().isEmpty();
if(uncompressImages || uncompressScan)
{
cv::Mat tmpRGB, tmpDepth;
LaserScan tmpScan;
loopSignature.sensorData().uncompressData(
uncompressImages?&tmpRGB:0,
uncompressImages?&tmpDepth:0,
uncompressScan?&tmpScan:0);
}
}
}
}
@@ -2291,14 +2306,14 @@ void MainWindow::processStats(const rtabmap::Statistics & stat)
!loopSignature.sensorData().imageRaw().empty() ||
signature.getWords().size())
{
cv::Mat refImage = signature.sensorData().imageRaw();
cv::Mat loopImage = loopSignature.sensorData().imageRaw();
cv::Mat refImage = _ui->imageView_source->isImageShown()?signature.sensorData().imageRaw():cv::Mat();
cv::Mat loopImage = _ui->imageView_loopClosure->isImageShown()?loopSignature.sensorData().imageRaw():cv::Mat();
if( _preferencesDialog->isMarkerDetection() &&
_preferencesDialog->isLandmarksShown())
{
//draw markers
if(!signature.getLandmarks().empty())
if(!signature.getLandmarks().empty() && !refImage.empty())
{
if(refImage.channels() == 1)
{
@@ -2312,7 +2327,7 @@ void MainWindow::processStats(const rtabmap::Statistics & stat)
}
drawLandmarks(refImage, signature);
}
if(!loopSignature.getLandmarks().empty())
if(!loopSignature.getLandmarks().empty() && !loopImage.empty())
{
if(loopImage.channels() == 1)
{
@@ -2342,42 +2357,37 @@ void MainWindow::processStats(const rtabmap::Statistics & stat)
{
_ui->imageView_source->setImage(img);
}
if(!signature.sensorData().depthOrRightRaw().empty())
if(!signature.sensorData().depthOrRightRaw().empty() && _ui->imageView_source->isImageDepthShown())
{
_ui->imageView_source->setImageDepth(signature.sensorData().depthOrRightRaw(), signature.sensorData().depthConfidenceRaw());
}
if(img.isNull() && signature.sensorData().depthOrRightRaw().empty())
{
QRect sceneRect;
if(signature.sensorData().cameraModels().size())
{
for(unsigned int i=0; i<signature.sensorData().cameraModels().size(); ++i)
{
sceneRect.setWidth(sceneRect.width()+signature.sensorData().cameraModels()[i].imageWidth());
sceneRect.setHeight(std::max((int)sceneRect.height(), signature.sensorData().cameraModels()[i].imageHeight()));
}
}
else if(signature.sensorData().stereoCameraModels().size())
{
for(unsigned int i=0; i<signature.sensorData().cameraModels().size(); ++i)
{
sceneRect.setWidth(sceneRect.width()+signature.sensorData().stereoCameraModels()[i].left().imageWidth());
sceneRect.setHeight(std::max((int)sceneRect.height(), signature.sensorData().stereoCameraModels()[i].left().imageHeight()));
}
}
if(sceneRect.isValid())
{
_ui->imageView_source->setSceneRect(sceneRect);
}
}
if(!lcImg.isNull())
{
_ui->imageView_loopClosure->setImage(lcImg);
}
if(!loopSignature.sensorData().depthOrRightRaw().empty())
if(!loopSignature.sensorData().depthOrRightRaw().empty() && _ui->imageView_loopClosure->isImageDepthShown())
{
_ui->imageView_loopClosure->setImageDepth(loopSignature.sensorData().depthOrRightRaw(), loopSignature.sensorData().depthConfidenceRaw());
}
if(lcImg.isNull())
{
QRect sceneRect;
if(loopSignature.sensorData().cameraModels().size() && loopSignature.sensorData().cameraModels().at(0).imageSize()!=cv::Size())
{
rect.setWidth(loopSignature.sensorData().cameraModels().at(0).imageWidth()*loopSignature.sensorData().cameraModels().size());
rect.setHeight(loopSignature.sensorData().cameraModels().at(0).imageHeight());
}
else if(loopSignature.sensorData().stereoCameraModels().size() && loopSignature.sensorData().stereoCameraModels().at(0).left().imageSize()!=cv::Size())
{
rect.setWidth(loopSignature.sensorData().stereoCameraModels().at(0).left().imageWidth()*loopSignature.sensorData().stereoCameraModels().size());
rect.setHeight(loopSignature.sensorData().stereoCameraModels().at(0).left().imageHeight());
}
if(sceneRect.isValid())
{
_ui->imageView_loopClosure->setSceneRect(sceneRect);
}
}
if(_ui->imageView_loopClosure->sceneRect().isNull())
{
_ui->imageView_loopClosure->setSceneRect(_ui->imageView_source->sceneRect());
@@ -2391,18 +2401,37 @@ void MainWindow::processStats(const rtabmap::Statistics & stat)
UDEBUG("time= %d ms (update detection imageviews)", time.restart());
// do it after scaling
std::multimap<int, cv::KeyPoint> wordsA;
std::multimap<int, cv::KeyPoint> wordsB;
for(std::map<int, int>::const_iterator iter=signature.getWords().begin(); iter!=signature.getWords().end(); ++iter)
if(_ui->imageView_source->isFeaturesShown() || _ui->imageView_loopClosure->isFeaturesShown() ||
(_ui->imageView_source->isLinesShown() && _ui->imageView_loopClosure->isLinesShown()))
{
wordsA.insert(wordsA.end(), std::make_pair(iter->first, signature.getWordsKpts()[iter->second]));
// do it after scaling
std::multimap<int, cv::KeyPoint> wordsA;
std::multimap<int, cv::KeyPoint> wordsB;
if(signature.getWords().size() == signature.getWordsKpts().size() &&
(_ui->imageView_source->isFeaturesShown() || (_ui->imageView_source->isLinesShown() && _ui->imageView_loopClosure->isLinesShown())))
{
for(std::map<int, int>::const_iterator iter=signature.getWords().begin(); iter!=signature.getWords().end(); ++iter)
{
wordsA.insert(wordsA.end(), std::make_pair(iter->first, signature.getWordsKpts()[iter->second]));
}
}
if(loopSignature.getWords().size() == loopSignature.getWordsKpts().size() &&
(_ui->imageView_loopClosure->isFeaturesShown() || (_ui->imageView_source->isLinesShown() && _ui->imageView_loopClosure->isLinesShown())))
{
for(std::map<int, int>::const_iterator iter=loopSignature.getWords().begin(); iter!=loopSignature.getWords().end(); ++iter)
{
wordsB.insert(wordsB.end(), std::make_pair(iter->first, loopSignature.getWordsKpts()[iter->second]));
}
}
this->drawKeypoints(wordsA, wordsB);
}
for(std::map<int, int>::const_iterator iter=loopSignature.getWords().begin(); iter!=loopSignature.getWords().end(); ++iter)
{
wordsB.insert(wordsB.end(), std::make_pair(iter->first, loopSignature.getWordsKpts()[iter->second]));
else {
_ui->imageView_source->clearFeatures();
_ui->imageView_loopClosure->clearFeatures();
_ui->imageView_source->clearLines();
_ui->imageView_loopClosure->clearLines();
_lastIds.clear();
}
this->drawKeypoints(wordsA, wordsB);
UDEBUG("time= %d ms (draw keypoints)", time.restart());
@@ -2511,43 +2540,45 @@ void MainWindow::processStats(const rtabmap::Statistics & stat)
UDEBUG("%d %d %d", poses.size(), poses.size()?poses.rbegin()->first:0, stat.refImageId());
if(!_odometryReceived && poses.size() && poses.rbegin()->first == stat.refImageId())
{
if(poses.rbegin()->first == stat.getLastSignatureData().id())
if(_cloudViewer->isVisible())
{
if(stat.getLastSignatureData().sensorData().cameraModels().size() && stat.getLastSignatureData().sensorData().cameraModels()[0].isValidForProjection())
if(poses.rbegin()->first == stat.getLastSignatureData().id())
{
_cloudViewer->updateCameraFrustums(poses.rbegin()->second, stat.getLastSignatureData().sensorData().cameraModels());
}
else if(stat.getLastSignatureData().sensorData().stereoCameraModels().size() && stat.getLastSignatureData().sensorData().stereoCameraModels()[0].isValidForProjection())
{
_cloudViewer->updateCameraFrustums(poses.rbegin()->second, stat.getLastSignatureData().sensorData().stereoCameraModels());
}
else if(!stat.getLastSignatureData().sensorData().laserScanRaw().isEmpty() ||
!stat.getLastSignatureData().sensorData().laserScanCompressed().isEmpty())
{
Transform scanLocalTransform;
if(!stat.getLastSignatureData().sensorData().laserScanRaw().isEmpty())
if(stat.getLastSignatureData().sensorData().cameraModels().size() && stat.getLastSignatureData().sensorData().cameraModels()[0].isValidForProjection())
{
scanLocalTransform = stat.getLastSignatureData().sensorData().laserScanRaw().localTransform();
_cloudViewer->updateCameraFrustums(poses.rbegin()->second, stat.getLastSignatureData().sensorData().cameraModels());
}
else
else if(stat.getLastSignatureData().sensorData().stereoCameraModels().size() && stat.getLastSignatureData().sensorData().stereoCameraModels()[0].isValidForProjection())
{
scanLocalTransform = stat.getLastSignatureData().sensorData().laserScanCompressed().localTransform();
_cloudViewer->updateCameraFrustums(poses.rbegin()->second, stat.getLastSignatureData().sensorData().stereoCameraModels());
}
else if(!stat.getLastSignatureData().sensorData().laserScanRaw().isEmpty() ||
!stat.getLastSignatureData().sensorData().laserScanCompressed().isEmpty())
{
Transform scanLocalTransform;
if(!stat.getLastSignatureData().sensorData().laserScanRaw().isEmpty())
{
scanLocalTransform = stat.getLastSignatureData().sensorData().laserScanRaw().localTransform();
}
else
{
scanLocalTransform = stat.getLastSignatureData().sensorData().laserScanCompressed().localTransform();
}
//fake frustum
CameraModel model(
2,
2,
2,
1.5,
scanLocalTransform*CameraModel::opticalRotation(),
0,
cv::Size(4,3));
_cloudViewer->updateCameraFrustum(poses.rbegin()->second, model);
}
//fake frustum
CameraModel model(
2,
2,
2,
1.5,
scanLocalTransform*CameraModel::opticalRotation(),
0,
cv::Size(4,3));
_cloudViewer->updateCameraFrustum(poses.rbegin()->second, model);
}
_cloudViewer->updateCameraTargetPosition(poses.rbegin()->second);
}
_cloudViewer->updateCameraTargetPosition(poses.rbegin()->second);
if(_ui->graphicsView_graphView->isVisible())
{
_ui->graphicsView_graphView->updateReferentialPosition(poses.rbegin()->second);
@@ -2842,6 +2873,7 @@ void MainWindow::updateMapCloud(
_progressDialog->appendText(tr("Map update: %1 nodes shown of %2 (cloud filtering is on)").arg(poses.size()).arg(nodePoses.size()));
QApplication::processEvents();
}
UDEBUG("Filtered poses");
}
else
{
@@ -2849,27 +2881,33 @@ void MainWindow::updateMapCloud(
mapIds = mapIdsIn;
}
std::map<int, bool> posesMask;
for(std::map<int, Transform>::const_iterator iter = nodePoses.begin(); iter!=nodePoses.end(); ++iter)
if(_ui->widget_mapVisibility->isVisible())
{
posesMask.insert(posesMask.end(), std::make_pair(iter->first, poses.find(iter->first) != poses.end()));
std::map<int, bool> posesMask;
for(std::map<int, Transform>::const_iterator iter = nodePoses.begin(); iter!=nodePoses.end(); ++iter)
{
posesMask.insert(posesMask.end(), std::make_pair(iter->first, poses.find(iter->first) != poses.end()));
}
_ui->widget_mapVisibility->setMap(nodePoses, posesMask);
UDEBUG("Updated map visibility with %ld poses", nodePoses.size());
}
else {
_ui->widget_mapVisibility->clear();
}
_ui->widget_mapVisibility->setMap(nodePoses, posesMask);
if(groundTruths.size() && _ui->actionAnchor_clouds_to_ground_truth->isChecked())
{
int anchored = 0;
for(std::map<int, Transform>::iterator iter = poses.begin(); iter!=poses.end(); ++iter)
{
std::map<int, Transform>::const_iterator gtIter = groundTruths.find(iter->first);
if(gtIter!=groundTruths.end())
{
iter->second = gtIter->second;
}
else
{
UWARN("Not found ground truth pose for node %d", iter->first);
++anchored;
}
}
UDEBUG("Anchored %d/%ld poses to ground truth", anchored, poses.size());
}
else if(_currentGTPosesMap.size() == 0)
{
@@ -3041,7 +3079,9 @@ void MainWindow::updateMapCloud(
cv::Mat obstacles;
cv::Mat empty;
UTimer decompressionTime;
jter->sensorData().uncompressDataConst(0, 0, 0, 0, &ground, &obstacles, &empty);
UDEBUG("Uncompressed local occupancy grid of node %d (%f s)", jter->id(), decompressionTime.ticks());
double resolution = jter->sensorData().gridCellSize();
if(_preferencesDialog->getGridUIResolution() > jter->sensorData().gridCellSize())
@@ -3210,6 +3250,7 @@ void MainWindow::updateMapCloud(
if(_preferencesDialog->isGroundTruthAligned() && _currentGTPosesMap.size())
{
mapToGt = alignPosesToGroundTruth(_currentPosesMap, _currentGTPosesMap).inverse();
UDEBUG("Aligned poses to ground truth (%ld poses %ld gt poses)", _currentPosesMap.size(), _currentGTPosesMap.size());
}
std::map<int, Transform> posesWithOdomCache;
@@ -3224,7 +3265,9 @@ void MainWindow::updateMapCloud(
}
}
if((_preferencesDialog->isGraphsShown() || _preferencesDialog->isFrustumsShown(0)) && _currentPosesMap.size())
if( _cloudViewer->isVisible() &&
(_preferencesDialog->isGraphsShown() || _preferencesDialog->isFrustumsShown(0)) &&
_currentPosesMap.size())
{
UTimer timerGraph;
// Find all graphs
@@ -3327,7 +3370,7 @@ void MainWindow::updateMapCloud(
}
}
UDEBUG("timerGraph=%fs", timerGraph.ticks());
UDEBUG("timerGraph (CloudViewer)=%fs", timerGraph.ticks());
}
UDEBUG("labels.size()=%d", (int)labels.size());
@@ -4363,7 +4406,7 @@ void MainWindow::createAndAddFeaturesToMap(int nodeId, const Transform & pose, i
UASSERT(iter->getWords().size() == iter->getWords3().size());
float maxDepth = _preferencesDialog->getCloudMaxDepth(0);
UDEBUG("rgb.channels()=%d");
if(!iter->getWords3().empty() && !iter->getWordsKpts().empty())
if(!iter->getWords3().empty() && iter->getWords3().size() == iter->getWordsKpts().size())
{
Transform invLocalTransform = Transform::getIdentity();
if(iter.value().sensorData().cameraModels().size() == 1 &&
@@ -5012,96 +5055,113 @@ void MainWindow::drawKeypoints(const std::multimap<int, cv::KeyPoint> & refWords
timer.start();
ULOGGER_DEBUG("refWords.size() = %d", refWords.size());
if(refWords.size())
_ui->imageView_source->clearFeatures();
if(_ui->imageView_source->isFeaturesShown())
{
_ui->imageView_source->clearFeatures();
for(std::multimap<int, cv::KeyPoint>::const_iterator iter = refWords.begin(); iter != refWords.end(); ++iter )
{
int id = iter->first;
QColor color;
if(id<0)
{
// GRAY = NOT QUANTIZED
color = Qt::gray;
}
else if(uContains(loopWords, id))
{
// PINK = FOUND IN LOOP SIGNATURE
color = Qt::magenta;
}
else if(_lastIds.contains(id))
{
// BLUE = FOUND IN LAST SIGNATURE
color = Qt::blue;
}
else if(id<=_lastId)
{
// RED = ALREADY EXISTS
color = Qt::red;
}
else if(refWords.count(id) > 1)
{
// YELLOW = NEW and multiple times
color = Qt::yellow;
}
else
{
// GREEN = NEW
color = Qt::green;
}
_ui->imageView_source->addFeature(iter->first, iter->second, 0, color);
}
}
for(std::multimap<int, cv::KeyPoint>::const_iterator iter = refWords.begin(); iter != refWords.end(); ++iter )
{
int id = iter->first;
QColor color;
if(id<0)
{
// GRAY = NOT QUANTIZED
color = Qt::gray;
}
else if(uContains(loopWords, id))
{
// PINK = FOUND IN LOOP SIGNATURE
color = Qt::magenta;
}
else if(_lastIds.contains(id))
{
// BLUE = FOUND IN LAST SIGNATURE
color = Qt::blue;
}
else if(id<=_lastId)
{
// RED = ALREADY EXISTS
color = Qt::red;
}
else if(refWords.count(id) > 1)
{
// YELLOW = NEW and multiple times
color = Qt::yellow;
}
else
{
// GREEN = NEW
color = Qt::green;
}
_ui->imageView_source->addFeature(iter->first, iter->second, 0, color);
}
ULOGGER_DEBUG("source time = %f s", timer.ticks());
ULOGGER_DEBUG("source time (shown=%d) = %f s", _ui->imageView_source->isFeaturesShown()?1:0, timer.ticks());
timer.start();
ULOGGER_DEBUG("loopWords.size() = %d", loopWords.size());
QList<QPair<cv::Point2f, cv::Point2f> > uniqueCorrespondences;
if(loopWords.size())
_ui->imageView_loopClosure->clearFeatures();
if(_ui->imageView_loopClosure->isFeaturesShown())
{
_ui->imageView_loopClosure->clearFeatures();
}
for(std::multimap<int, cv::KeyPoint>::const_iterator iter = loopWords.begin(); iter != loopWords.end(); ++iter )
{
int id = iter->first;
QColor color;
if(id<0)
for(std::multimap<int, cv::KeyPoint>::const_iterator iter = loopWords.begin(); iter != loopWords.end(); ++iter )
{
// GRAY = NOT QUANTIZED
color = Qt::gray;
}
else if(uContains(refWords, id))
{
// PINK = FOUND IN LOOP SIGNATURE
color = Qt::magenta;
//To draw lines... get only unique correspondences
if(uValues(refWords, id).size() == 1 && uValues(loopWords, id).size() == 1)
int id = iter->first;
QColor color;
if(id<0)
{
const cv::KeyPoint & a = refWords.find(id)->second;
const cv::KeyPoint & b = iter->second;
uniqueCorrespondences.push_back(QPair<cv::Point2f, cv::Point2f>(a.pt, b.pt));
// GRAY = NOT QUANTIZED
color = Qt::gray;
}
else if(uContains(refWords, id))
{
// PINK = FOUND IN LOOP SIGNATURE
color = Qt::magenta;
//To draw lines... get only unique correspondences
if(uValues(refWords, id).size() == 1 && uValues(loopWords, id).size() == 1)
{
const cv::KeyPoint & a = refWords.find(id)->second;
const cv::KeyPoint & b = iter->second;
uniqueCorrespondences.push_back(QPair<cv::Point2f, cv::Point2f>(a.pt, b.pt));
}
}
else if(id<=_lastId)
{
// RED = ALREADY EXISTS
color = Qt::red;
}
else if(refWords.count(id) > 1)
{
// YELLOW = NEW and multiple times
color = Qt::yellow;
}
else
{
// GREEN = NEW
color = Qt::green;
}
_ui->imageView_loopClosure->addFeature(iter->first, iter->second, 0, color);
}
}
else if(_ui->imageView_source->isLinesShown() && _ui->imageView_loopClosure->isLinesShown())
{
for(std::multimap<int, cv::KeyPoint>::const_iterator iter = loopWords.begin(); iter != loopWords.end(); ++iter )
{
int id = iter->first;
if(id>=0 && uContains(refWords, id))
{
//To draw lines... get only unique correspondences
if(uValues(refWords, id).size() == 1 && uValues(loopWords, id).size() == 1)
{
const cv::KeyPoint & a = refWords.find(id)->second;
const cv::KeyPoint & b = iter->second;
uniqueCorrespondences.push_back(QPair<cv::Point2f, cv::Point2f>(a.pt, b.pt));
}
}
}
else if(id<=_lastId)
{
// RED = ALREADY EXISTS
color = Qt::red;
}
else if(refWords.count(id) > 1)
{
// YELLOW = NEW and multiple times
color = Qt::yellow;
}
else
{
// GREEN = NEW
color = Qt::green;
}
_ui->imageView_loopClosure->addFeature(iter->first, iter->second, 0, color);
}
ULOGGER_DEBUG("loop closure time (shown=%d) = %f s", _ui->imageView_loopClosure->isFeaturesShown()?1:0, timer.ticks());
ULOGGER_DEBUG("loop closure time = %f s", timer.ticks());
_lastIds.clear();
if(refWords.size()>0)
{
if((*refWords.rbegin()).first > _lastId)
@@ -5116,52 +5176,51 @@ void MainWindow::drawKeypoints(const std::multimap<int, cv::KeyPoint> & refWords
#endif
}
// Draw lines between corresponding features...
float scaleSource = _ui->imageView_source->viewScale();
float scaleLoop = _ui->imageView_loopClosure->viewScale();
UDEBUG("scale source=%f loop=%f", scaleSource, scaleLoop);
// Delta in actual window pixels
float sourceMarginX = (_ui->imageView_source->width() - _ui->imageView_source->sceneRect().width()*scaleSource)/2.0f;
float sourceMarginY = (_ui->imageView_source->height() - _ui->imageView_source->sceneRect().height()*scaleSource)/2.0f;
float loopMarginX = (_ui->imageView_loopClosure->width() - _ui->imageView_loopClosure->sceneRect().width()*scaleLoop)/2.0f;
float loopMarginY = (_ui->imageView_loopClosure->height() - _ui->imageView_loopClosure->sceneRect().height()*scaleLoop)/2.0f;
float deltaX = 0;
float deltaY = 0;
if(_preferencesDialog->isVerticalLayoutUsed())
_ui->imageView_source->clearLines();
_ui->imageView_loopClosure->clearLines();
if(_ui->imageView_source->isLinesShown() && _ui->imageView_loopClosure->isLinesShown())
{
deltaY = _ui->label_matchId->height() + _ui->imageView_source->height();
}
else
{
deltaX = _ui->imageView_source->width();
}
// Draw lines between corresponding features...
float scaleSource = _ui->imageView_source->viewScale();
float scaleLoop = _ui->imageView_loopClosure->viewScale();
UDEBUG("scale source=%f loop=%f", scaleSource, scaleLoop);
// Delta in actual window pixels
float sourceMarginX = (_ui->imageView_source->width() - _ui->imageView_source->sceneRect().width()*scaleSource)/2.0f;
float sourceMarginY = (_ui->imageView_source->height() - _ui->imageView_source->sceneRect().height()*scaleSource)/2.0f;
float loopMarginX = (_ui->imageView_loopClosure->width() - _ui->imageView_loopClosure->sceneRect().width()*scaleLoop)/2.0f;
float loopMarginY = (_ui->imageView_loopClosure->height() - _ui->imageView_loopClosure->sceneRect().height()*scaleLoop)/2.0f;
if(refWords.size() && loopWords.size())
{
_ui->imageView_source->clearLines();
_ui->imageView_loopClosure->clearLines();
}
float deltaX = 0;
float deltaY = 0;
for(QList<QPair<cv::Point2f, cv::Point2f> >::iterator iter = uniqueCorrespondences.begin();
iter!=uniqueCorrespondences.end();
++iter)
{
if(_preferencesDialog->isVerticalLayoutUsed())
{
deltaY = _ui->label_matchId->height() + _ui->imageView_source->height();
}
else
{
deltaX = _ui->imageView_source->width();
}
_ui->imageView_source->addLine(
iter->first.x,
iter->first.y,
(iter->second.x*scaleLoop+loopMarginX+deltaX-sourceMarginX)/scaleSource,
(iter->second.y*scaleLoop+loopMarginY+deltaY-sourceMarginY)/scaleSource,
_ui->imageView_source->getDefaultMatchingLineColor());
for(QList<QPair<cv::Point2f, cv::Point2f> >::iterator iter = uniqueCorrespondences.begin();
iter!=uniqueCorrespondences.end();
++iter)
{
_ui->imageView_loopClosure->addLine(
(iter->first.x*scaleSource+sourceMarginX-deltaX-loopMarginX)/scaleLoop,
(iter->first.y*scaleSource+sourceMarginY-deltaY-loopMarginY)/scaleLoop,
iter->second.x,
iter->second.y,
_ui->imageView_loopClosure->getDefaultMatchingLineColor());
_ui->imageView_source->addLine(
iter->first.x,
iter->first.y,
(iter->second.x*scaleLoop+loopMarginX+deltaX-sourceMarginX)/scaleSource,
(iter->second.y*scaleLoop+loopMarginY+deltaY-sourceMarginY)/scaleSource,
_ui->imageView_source->getDefaultMatchingLineColor());
_ui->imageView_loopClosure->addLine(
(iter->first.x*scaleSource+sourceMarginX-deltaX-loopMarginX)/scaleLoop,
(iter->first.y*scaleSource+sourceMarginY-deltaY-loopMarginY)/scaleLoop,
iter->second.x,
iter->second.y,
_ui->imageView_loopClosure->getDefaultMatchingLineColor());
}
}
_ui->imageView_source->update();
_ui->imageView_loopClosure->update();
@@ -5331,6 +5390,7 @@ void MainWindow::updateSelectSourceMenu()
_ui->actionDepthAI_oakdlite->setChecked(_preferencesDialog->getSourceDriver() == PreferencesDialog::kSrcStereoDepthAI);
_ui->actionDepthAI_oakdpro->setChecked(_preferencesDialog->getSourceDriver() == PreferencesDialog::kSrcStereoDepthAI);
_ui->actionXvisio_SeerSense->setChecked(_preferencesDialog->getSourceDriver() == PreferencesDialog::kSrcSeerSense);
_ui->actionOrbbecSDK_astra2->setChecked(_preferencesDialog->getSourceDriver() == PreferencesDialog::kSrcOrbbecSDK);
_ui->actionVelodyne_VLP_16->setChecked(_preferencesDialog->getLidarSourceDriver() == PreferencesDialog::kSrcLidarVLP16);
}
@@ -5989,7 +6049,7 @@ void MainWindow::startDetection()
_imuThread = 0;
}
if(!_sensorCapture->odomProvided() && !_preferencesDialog->isOdomDisabled())
if((!_sensorCapture->odomProvided() || _preferencesDialog->isOdomAsGuessEnabled()) && !_preferencesDialog->isOdomDisabled())
{
ParametersMap odomParameters = parameters;
if(_preferencesDialog->getOdomRegistrationApproach() < 3)
@@ -6047,7 +6107,7 @@ void MainWindow::startDetection()
}
}
if(_dataRecorder && _sensorCapture && _odomThread)
if(_dataRecorder && _sensorCapture)
{
UEventsManager::createPipe(_sensorCapture, _dataRecorder, "SensorEvent");
}
@@ -7207,6 +7267,11 @@ void MainWindow::selectK4A()
_preferencesDialog->selectSourceDriver(PreferencesDialog::kSrcK4A);
}
void MainWindow::selectOrbbecSDK()
{
_preferencesDialog->selectSourceDriver(PreferencesDialog::kSrcOrbbecSDK);
}
void MainWindow::selectRealSense()
{
_preferencesDialog->selectSourceDriver(PreferencesDialog::kSrcRealSense);
@@ -7981,7 +8046,7 @@ void MainWindow::exportClouds()
return;
}
std::map<int, Transform> poses = _ui->widget_mapVisibility->getVisiblePoses();
std::map<int, Transform> poses = !_ui->widget_mapVisibility->isEmpty()?_ui->widget_mapVisibility->getVisiblePoses():_currentPosesMap;
// Use ground truth poses if current clouds are using them
if(_currentGTPosesMap.size() && _ui->actionAnchor_clouds_to_ground_truth->isChecked())
@@ -8018,7 +8083,7 @@ void MainWindow::viewClouds()
return;
}
std::map<int, Transform> poses = _ui->widget_mapVisibility->getVisiblePoses();
std::map<int, Transform> poses = !_ui->widget_mapVisibility->isEmpty()?_ui->widget_mapVisibility->getVisiblePoses():_currentPosesMap;
// Use ground truth poses if current clouds are using them
if(_currentGTPosesMap.size() && _ui->actionAnchor_clouds_to_ground_truth->isChecked())
@@ -8094,7 +8159,7 @@ void MainWindow::exportImages()
QMessageBox::warning(this, tr("Export images..."), tr("Cannot export images, the cache is empty!"));
return;
}
std::map<int, Transform> poses = _ui->widget_mapVisibility->getVisiblePoses();
std::map<int, Transform> poses = !_ui->widget_mapVisibility->isEmpty()?_ui->widget_mapVisibility->getVisiblePoses():_currentPosesMap;
if(poses.empty())
{
@@ -8311,7 +8376,7 @@ void MainWindow::exportBundlerFormat()
return;
}
std::map<int, Transform> posesIn = _ui->widget_mapVisibility->getVisiblePoses();
std::map<int, Transform> posesIn = !_ui->widget_mapVisibility->isEmpty()?_ui->widget_mapVisibility->getVisiblePoses():_currentPosesMap;
// Use ground truth poses if current clouds are using them
if(_currentGTPosesMap.size() && _ui->actionAnchor_clouds_to_ground_truth->isChecked())
+6 -4
View File
@@ -149,11 +149,13 @@ void MultiSessionLocWidget::updateView(
Link link = loopLinks.find(nodeId) != loopLinks.end()?loopLinks.find(nodeId)->second:Link();
std::multimap<int, cv::KeyPoint> keypoints;
for(std::multimap<int, int>::const_iterator jter=s.getWords().begin(); jter!=s.getWords().end(); ++jter)
{
if(jter->first>0 && lastSignature.getWords().find(jter->first) != lastSignature.getWords().end())
if(s.getWords().size() == s.getWordsKpts().size()) {
for(std::multimap<int, int>::const_iterator jter=s.getWords().begin(); jter!=s.getWords().end(); ++jter)
{
keypoints.insert(std::make_pair(jter->first, s.getWordsKpts()[jter->second]));
if(jter->first>0 && lastSignature.getWords().find(jter->first) != lastSignature.getWords().end())
{
keypoints.insert(std::make_pair(jter->first, s.getWordsKpts()[jter->second]));
}
}
}
+156 -23
View File
@@ -226,7 +226,7 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
#ifndef RTABMAP_MSCKF_VIO
_ui->odom_strategy->setItemData(8, 0, Qt::UserRole - 1);
#endif
#ifndef RTABMAP_VINS
#ifndef RTABMAP_VINS_FUSION
_ui->odom_strategy->setItemData(9, 0, Qt::UserRole - 1);
#endif
#ifndef RTABMAP_OPENVINS
@@ -238,6 +238,9 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
#ifndef RTABMAP_OPEN3D
_ui->odom_strategy->setItemData(12, 0, Qt::UserRole - 1);
#endif
#ifndef RTABMAP_CUVSLAM
_ui->odom_strategy->setItemData(13, 0, Qt::UserRole - 1);
#endif
#if CV_MAJOR_VERSION < 3
_ui->stereosgbm_mode->setItemData(2, 0, Qt::UserRole - 1);
@@ -291,6 +294,10 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
_ui->comboBox_detector_strategy->setItemData(11, 0, Qt::UserRole - 1);
_ui->vis_feature_detector->setItemData(11, 0, Qt::UserRole - 1);
#endif
#if !defined(RTABMAP_TORCH) || !defined(RTABMAP_PYTHON)
_ui->comboBox_detector_strategy->setItemData(16, 0, Qt::UserRole - 1);
_ui->vis_feature_detector->setItemData(16, 0, Qt::UserRole - 1);
#endif
#ifndef RTABMAP_PYTHON
_ui->comboBox_detector_strategy->setItemData(15, 0, Qt::UserRole - 1);
@@ -398,6 +405,10 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
{
_ui->comboBox_cameraRGBD->setItemData(kSrcK4A - kSrcRGBD, 0, Qt::UserRole - 1);
}
if (!CameraOrbbecSDK::available())
{
_ui->comboBox_cameraRGBD->setItemData(kSrcOrbbecSDK - kSrcRGBD, 0, Qt::UserRole - 1);
}
if (!CameraRealSense::available())
{
_ui->comboBox_cameraRGBD->setItemData(kSrcRealSense - kSrcRGBD, 0, Qt::UserRole - 1);
@@ -767,19 +778,39 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
connect(_ui->openni2_hshift, SIGNAL(valueChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->openni2_vshift, SIGNAL(valueChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->openni2_depth_decimation, SIGNAL(valueChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->comboBox_freenect2Format, SIGNAL(currentIndexChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->doubleSpinBox_freenect2MinDepth, SIGNAL(valueChanged(double)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->doubleSpinBox_freenect2MaxDepth, SIGNAL(valueChanged(double)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->checkBox_freenect2BilateralFiltering, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->checkBox_freenect2EdgeAwareFiltering, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->checkBox_freenect2NoiseFiltering, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->lineEdit_freenect2Pipeline, SIGNAL(textChanged(const QString &)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->comboBox_k4w2Format, SIGNAL(currentIndexChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->comboBox_k4a_rgb_resolution, SIGNAL(currentIndexChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->comboBox_k4a_framerate, SIGNAL(currentIndexChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->comboBox_k4a_depth_resolution, SIGNAL(currentIndexChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->checkbox_k4a_irDepth, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->lineEdit_k4a_mkv, SIGNAL(textChanged(const QString &)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->source_checkBox_useMKVStamps, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->spinBox_orbbec_sdk_color_width, SIGNAL(valueChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->spinBox_orbbec_sdk_color_height, SIGNAL(valueChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->spinBox_orbbec_sdk_depth_width, SIGNAL(valueChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->spinBox_orbbec_sdk_depth_height, SIGNAL(valueChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->checkBox_orbbec_sdk_color_rectification, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->checkBox_orbbec_sdk_imu, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->checkBox_orbbec_sdk_depth_mm, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->comboBox_realsensePresetRGB, SIGNAL(currentIndexChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->comboBox_realsensePresetDepth, SIGNAL(currentIndexChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->checkbox_realsenseOdom, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->checkbox_realsenseDepthScaledToRGBSize, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->comboBox_realsenseRGBSource, SIGNAL(currentIndexChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->checkbox_rs2_emitter, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->checkbox_rs2_irMode, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->checkbox_rs2_irDepth, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
@@ -918,6 +949,7 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
connect(_ui->doubleSpinBox_odom_sensor_scale_factor, SIGNAL(valueChanged(double)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->doubleSpinBox_odom_sensor_wait_time, SIGNAL(valueChanged(double)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->checkBox_odom_sensor_use_as_gt, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->checkbox_passthrough_source_odom, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->comboBox_imuFilter_strategy, SIGNAL(currentIndexChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->comboBox_imuFilter_strategy, SIGNAL(currentIndexChanged(int)), _ui->stackedWidget_imuFilter, SLOT(setCurrentIndex(int)));
@@ -1005,6 +1037,7 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
_ui->lineEdit_rgbCompressionFormat->setObjectName(Parameters::kMemImageCompressionFormat().c_str());
_ui->lineEdit_depthCompressionFormat->setObjectName(Parameters::kMemDepthCompressionFormat().c_str());
_ui->general_checkBox_keepDescriptors->setObjectName(Parameters::kMemRawDescriptorsKept().c_str());
_ui->general_checkBox_loadVisualLocalFeaturesOnInit->setObjectName(Parameters::kMemLoadVisualLocalFeaturesOnInit().c_str());
_ui->general_checkBox_saveDepth16bits->setObjectName(Parameters::kMemSaveDepth16Format().c_str());
_ui->general_checkBox_compressionParallelized->setObjectName(Parameters::kMemCompressionParallelized().c_str());
_ui->general_checkBox_reduceGraph->setObjectName(Parameters::kMemReduceGraph().c_str());
@@ -1079,6 +1112,8 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
_ui->lineEdit_dictionaryPath->setObjectName(Parameters::kKpDictionaryPath().c_str());
connect(_ui->toolButton_dictionaryPath, SIGNAL(clicked()), this, SLOT(changeDictionaryPath()));
_ui->checkBox_kp_newWordsComparedTogether->setObjectName(Parameters::kKpNewWordsComparedTogether().c_str());
_ui->checkBox_kp_flannIndexSaved->setObjectName(Parameters::kKpFlannIndexSaved().c_str());
_ui->checkBox_kp_serializeWithChecksum->setObjectName(Parameters::kKpSerializeWithChecksum().c_str());
_ui->subpix_winSize_kp->setObjectName(Parameters::kKpSubPixWinSize().c_str());
_ui->subpix_iterations_kp->setObjectName(Parameters::kKpSubPixIterations().c_str());
_ui->subpix_eps_kp->setObjectName(Parameters::kKpSubPixEps().c_str());
@@ -1166,6 +1201,16 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
_ui->spinBox_sptorch_minDistance->setObjectName(Parameters::kSuperPointNMSRadius().c_str());
_ui->checkBox_sptorch_cuda->setObjectName(Parameters::kSuperPointCuda().c_str());
// SuperPoint Rpautrat
_ui->lineEdit_sprpautrat_weights_path->setObjectName(Parameters::kSuperPointRpautratWeightsPath().c_str());
connect(_ui->toolButton_sprpautrat_weights_path, SIGNAL(clicked()), this, SLOT(changeSuperPointRpautratWeightsPath()));
_ui->lineEdit_sprpautrat_model_path->setObjectName(Parameters::kSuperPointRpautratModelPath().c_str());
connect(_ui->toolButton_sprpautrat_model_path, SIGNAL(clicked()), this, SLOT(changeSuperPointRpautratModelPath()));
_ui->doubleSpinBox_sprpautrat_threshold->setObjectName(Parameters::kSuperPointRpautratThreshold().c_str());
_ui->checkBox_sprpautrat_nms->setObjectName(Parameters::kSuperPointRpautratNMS().c_str());
_ui->spinBox_sprpautrat_minDistance->setObjectName(Parameters::kSuperPointRpautratNMSRadius().c_str());
_ui->checkBox_sprpautrat_cuda->setObjectName(Parameters::kSuperPointRpautratCuda().c_str());
// PyMatcher
_ui->lineEdit_pymatcher_path->setObjectName(Parameters::kPyMatcherPath().c_str());
connect(_ui->toolButton_pymatcher_path, SIGNAL(clicked()), this, SLOT(changePyMatcherPath()));
@@ -1553,8 +1598,8 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
_ui->OdomMSCKFInitCovExTrans->setObjectName(Parameters::kOdomMSCKFInitCovExTrans().c_str());
// Odometry VINS
_ui->lineEdit_OdomVinsPath->setObjectName(Parameters::kOdomVINSConfigPath().c_str());
connect(_ui->toolButton_OdomVinsPath, SIGNAL(clicked()), this, SLOT(changeOdometryVINSConfigPath()));
_ui->lineEdit_OdomVinsFusionPath->setObjectName(Parameters::kOdomVINSFusionConfigPath().c_str());
connect(_ui->toolButton_OdomVinsFusionPath, SIGNAL(clicked()), this, SLOT(changeOdometryVINSFusionConfigPath()));
// Odometry OpenVINS
_ui->checkBox_OdomOpenVINSUseStereo->setObjectName(Parameters::kOdomOpenVINSUseStereo().c_str());
@@ -1631,12 +1676,14 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
_ui->stereo_flow_eps->setObjectName(Parameters::kStereoEps().c_str());
_ui->stereo_opticalFlow->setObjectName(Parameters::kStereoOpticalFlow().c_str());
_ui->stereo_flow_gpu->setObjectName(Parameters::kStereoGpu().c_str());
// Odometry Open3D
_ui->odom_open3d_method->setObjectName(Parameters::kOdomOpen3DMethod().c_str());
_ui->odom_open3d_max_depth->setObjectName(Parameters::kOdomOpen3DMaxDepth().c_str());
// Odometry CuVSLAM
_ui->odom_cuvslam_multicam_mode->setObjectName(Parameters::kOdomCuVSLAMMulticamMode().c_str());
//StereoDense
_ui->comboBox_stereoDense_strategy->setObjectName(Parameters::kStereoDenseStrategy().c_str());
connect(_ui->comboBox_stereoDense_strategy, SIGNAL(currentIndexChanged(int)), _ui->stackedWidget_stereoDense, SLOT(setCurrentIndex(int)));
@@ -2228,6 +2275,13 @@ void PreferencesDialog::resetSettings(QGroupBox * groupBox)
_ui->comboBox_k4a_depth_resolution->setCurrentIndex(2);
_ui->checkbox_k4a_irDepth->setChecked(false);
_ui->lineEdit_k4a_mkv->clear();
_ui->spinBox_orbbec_sdk_color_width->setValue(800);
_ui->spinBox_orbbec_sdk_color_height->setValue(600);
_ui->spinBox_orbbec_sdk_depth_width->setValue(800);
_ui->spinBox_orbbec_sdk_depth_height->setValue(600);
_ui->checkBox_orbbec_sdk_color_rectification->setChecked(false);
_ui->checkBox_orbbec_sdk_imu->setChecked(true);
_ui->checkBox_orbbec_sdk_depth_mm->setChecked(true);
_ui->source_checkBox_useMKVStamps->setChecked(true);
_ui->lineEdit_cameraRGBDImages_path_rgb->setText("");
_ui->lineEdit_cameraRGBDImages_path_depth->setText("");
@@ -2306,6 +2360,7 @@ void PreferencesDialog::resetSettings(QGroupBox * groupBox)
_ui->doubleSpinBox_odom_sensor_scale_factor->setValue(1);
_ui->doubleSpinBox_odom_sensor_wait_time->setValue(100);
_ui->checkBox_odom_sensor_use_as_gt->setChecked(false);
_ui->checkbox_passthrough_source_odom->setChecked(false);
_ui->comboBox_imuFilter_strategy->setCurrentIndex(2);
_ui->doubleSpinBox_imuFilterMadgwickGain->setValue(Parameters::defaultImuFilterMadgwickGain());
@@ -2713,6 +2768,16 @@ void PreferencesDialog::readCameraSettings(const QString & filePath)
_ui->source_checkBox_useMKVStamps->setChecked(settings.value("useMkvStamps", _ui->source_checkBox_useMKVStamps->isChecked()).toBool());
settings.endGroup(); // K4A
settings.beginGroup("OrbbecSDK");
_ui->spinBox_orbbec_sdk_color_width->setValue(settings.value("color_width", _ui->spinBox_orbbec_sdk_color_width->value()).toInt());
_ui->spinBox_orbbec_sdk_color_height->setValue(settings.value("color_height", _ui->spinBox_orbbec_sdk_color_height->value()).toInt());
_ui->spinBox_orbbec_sdk_depth_width->setValue(settings.value("depth_width", _ui->spinBox_orbbec_sdk_depth_width->value()).toInt());
_ui->spinBox_orbbec_sdk_depth_height->setValue(settings.value("depth_height", _ui->spinBox_orbbec_sdk_depth_height->value()).toInt());
_ui->checkBox_orbbec_sdk_color_rectification->setChecked(settings.value("rectify_color", _ui->checkBox_orbbec_sdk_color_rectification->isChecked()).toBool());
_ui->checkBox_orbbec_sdk_imu->setChecked(settings.value("enable_imu", _ui->checkBox_orbbec_sdk_imu->isChecked()).toBool());
_ui->checkBox_orbbec_sdk_depth_mm->setChecked(settings.value("depth_mm", _ui->checkBox_orbbec_sdk_depth_mm->isChecked()).toBool());
settings.endGroup(); // Orbbec SDK
settings.beginGroup("RealSense");
_ui->comboBox_realsensePresetRGB->setCurrentIndex(settings.value("presetRGB", _ui->comboBox_realsensePresetRGB->currentIndex()).toInt());
_ui->comboBox_realsensePresetDepth->setCurrentIndex(settings.value("presetDepth", _ui->comboBox_realsensePresetDepth->currentIndex()).toInt());
@@ -2832,6 +2897,7 @@ void PreferencesDialog::readCameraSettings(const QString & filePath)
_ui->doubleSpinBox_odom_sensor_scale_factor->setValue(settings.value("odom_sensor_scale_factor", _ui->doubleSpinBox_odom_sensor_scale_factor->value()).toDouble());
_ui->doubleSpinBox_odom_sensor_wait_time->setValue(settings.value("odom_sensor_wait_time", _ui->doubleSpinBox_odom_sensor_wait_time->value()).toDouble());
_ui->checkBox_odom_sensor_use_as_gt->setChecked(settings.value("odom_sensor_odom_as_gt", _ui->checkBox_odom_sensor_use_as_gt->isChecked()).toBool());
_ui->checkbox_passthrough_source_odom->setChecked(settings.value("odom_sensor_as_guess", _ui->checkbox_passthrough_source_odom->isChecked()).toBool());
settings.endGroup(); // OdomSensor
settings.beginGroup("UsbCam");
@@ -3319,6 +3385,16 @@ void PreferencesDialog::writeCameraSettings(const QString & filePath) const
settings.setValue("useMkvStamps", _ui->source_checkBox_useMKVStamps->isChecked());
settings.endGroup(); // K4A
settings.beginGroup("OrbbecSDK");
settings.setValue("color_width", _ui->spinBox_orbbec_sdk_color_width->value());
settings.setValue("color_height", _ui->spinBox_orbbec_sdk_color_height->value());
settings.setValue("depth_width", _ui->spinBox_orbbec_sdk_depth_width->value());
settings.setValue("depth_height", _ui->spinBox_orbbec_sdk_depth_height->value());
settings.setValue("rectify_color", _ui->checkBox_orbbec_sdk_color_rectification->isChecked());
settings.setValue("enable_imu", _ui->checkBox_orbbec_sdk_imu->isChecked());
settings.setValue("depth_mm", _ui->checkBox_orbbec_sdk_depth_mm->isChecked());
settings.endGroup(); // Orbbec SDK
settings.beginGroup("RealSense");
settings.setValue("presetRGB", _ui->comboBox_realsensePresetRGB->currentIndex());
settings.setValue("presetDepth", _ui->comboBox_realsensePresetDepth->currentIndex());
@@ -3436,6 +3512,7 @@ void PreferencesDialog::writeCameraSettings(const QString & filePath) const
settings.setValue("odom_sensor_scale_factor", _ui->doubleSpinBox_odom_sensor_scale_factor->value());
settings.setValue("odom_sensor_wait_time", _ui->doubleSpinBox_odom_sensor_wait_time->value());
settings.setValue("odom_sensor_odom_as_gt", _ui->checkBox_odom_sensor_use_as_gt->isChecked());
settings.setValue("odom_sensor_as_guess", _ui->checkbox_passthrough_source_odom->isChecked());
settings.endGroup(); // OdomSensor
settings.beginGroup("UsbCam");
@@ -3730,15 +3807,6 @@ bool PreferencesDialog::validateForm()
_ui->odom_f2m_bundleStrategy->setCurrentIndex(0);
}
// verify that Robust and Reject threshold are not set at the same time
if(_ui->graphOptimization_robust->isChecked() && _ui->graphOptimization_maxError->value()>0.0)
{
QMessageBox::warning(this, tr("Parameter warning"),
tr("Robust graph optimization and maximum optimization error threshold cannot be "
"both used at the same time. Disabling robust optimization."));
_ui->graphOptimization_robust->setChecked(false);
}
//verify binary features and nearest neighbor
// BOW dictionary type
if(_ui->comboBox_dictionary_strategy->currentIndex() == VWDictionary::kNNFlannLSH && _ui->comboBox_detector_strategy->currentIndex() <= 1)
@@ -5473,9 +5541,10 @@ void PreferencesDialog::updateOdometryStackedIndex(int index)
_ui->groupBox_odomOKVIS->setVisible(index==6);
_ui->groupBox_odomLOAM->setVisible(index==7);
_ui->groupBox_odomMSCKF->setVisible(index==8);
_ui->groupBox_odomVINS->setVisible(index==9);
_ui->groupBox_odomVINSFusion->setVisible(index==9);
_ui->groupBox_odomOpenVINS->setVisible(index==10);
_ui->groupBox_odomOpen3D->setVisible(index==12);
_ui->groupBox_odomCuvslam->setVisible(index==13);
}
void PreferencesDialog::useOdomFeatures()
@@ -5564,20 +5633,20 @@ void PreferencesDialog::changeOdometryOKVISConfigPath()
}
}
void PreferencesDialog::changeOdometryVINSConfigPath()
void PreferencesDialog::changeOdometryVINSFusionConfigPath()
{
QString path;
if(_ui->lineEdit_OdomVinsPath->text().isEmpty())
if(_ui->lineEdit_OdomVinsFusionPath->text().isEmpty())
{
path = QFileDialog::getOpenFileName(this, tr("VINS-Fusion Config"), this->getWorkingDirectory(), tr("VINS-Fusion config (*.yaml)"));
}
else
{
path = QFileDialog::getOpenFileName(this, tr("VINS-Fusion Config"), _ui->lineEdit_OdomVinsPath->text(), tr("VINS-Fusion config (*.yaml)"));
path = QFileDialog::getOpenFileName(this, tr("VINS-Fusion Config"), _ui->lineEdit_OdomVinsFusionPath->text(), tr("VINS-Fusion config (*.yaml)"));
}
if(!path.isEmpty())
{
_ui->lineEdit_OdomVinsPath->setText(path);
_ui->lineEdit_OdomVinsFusionPath->setText(path);
}
}
@@ -5649,6 +5718,41 @@ void PreferencesDialog::changeSuperPointModelPath()
}
}
void PreferencesDialog::changeSuperPointRpautratWeightsPath()
{
QString path;
if(_ui->lineEdit_sprpautrat_weights_path->text().isEmpty())
{
path = QFileDialog::getOpenFileName(this, tr("Select SuperPoint weights"), this->getWorkingDirectory(), tr("SuperPoint weights (*.pth)"));
}
else
{
path = QFileDialog::getOpenFileName(this, tr("Select SuperPoint weights"), _ui->lineEdit_sprpautrat_weights_path->text(), tr("SuperPoint weights (*.pth)"));
}
if(!path.isEmpty())
{
_ui->lineEdit_sprpautrat_weights_path->setText(path);
}
}
void PreferencesDialog::changeSuperPointRpautratModelPath()
{
QString path;
if(_ui->lineEdit_sprpautrat_model_path->text().isEmpty())
{
path = QFileDialog::getOpenFileName(this, tr("Select SuperPoint Python Model"), this->getWorkingDirectory(), tr("SuperPoint Python Model (*.py)"));
}
else
{
path = QFileDialog::getOpenFileName(this, tr("Select SuperPoint Python Model"), _ui->lineEdit_sprpautrat_model_path->text(), tr("SuperPoint Python Model (*.py)"));
}
if(!path.isEmpty())
{
_ui->lineEdit_sprpautrat_model_path->setText(path);
}
}
void PreferencesDialog::changePyMatcherPath()
{
QString path;
@@ -5731,6 +5835,7 @@ void PreferencesDialog::updateSourceGrpVisibility()
_ui->comboBox_cameraRGBD->currentIndex() == kSrcFreenect2-kSrcRGBD ||
_ui->comboBox_cameraRGBD->currentIndex() == kSrcK4W2 - kSrcRGBD ||
_ui->comboBox_cameraRGBD->currentIndex() == kSrcK4A - kSrcRGBD ||
_ui->comboBox_cameraRGBD->currentIndex() == kSrcOrbbecSDK - kSrcRGBD ||
_ui->comboBox_cameraRGBD->currentIndex() == kSrcRealSense - kSrcRGBD ||
_ui->comboBox_cameraRGBD->currentIndex() == kSrcRGBDImages-kSrcRGBD ||
_ui->comboBox_cameraRGBD->currentIndex() == kSrcOpenNI_PCL-kSrcRGBD ||
@@ -5740,6 +5845,7 @@ void PreferencesDialog::updateSourceGrpVisibility()
_ui->groupBox_freenect2->setVisible(_ui->comboBox_sourceType->currentIndex() == 0 && _ui->comboBox_cameraRGBD->currentIndex() == kSrcFreenect2-kSrcRGBD);
_ui->groupBox_k4w2->setVisible(_ui->comboBox_sourceType->currentIndex() == 0 && _ui->comboBox_cameraRGBD->currentIndex() == kSrcK4W2 - kSrcRGBD);
_ui->groupBox_k4a->setVisible(_ui->comboBox_sourceType->currentIndex() == 0 && _ui->comboBox_cameraRGBD->currentIndex() == kSrcK4A - kSrcRGBD);
_ui->groupBox_orbbec_sdk->setVisible(_ui->comboBox_sourceType->currentIndex() == 0 && _ui->comboBox_cameraRGBD->currentIndex() == kSrcOrbbecSDK - kSrcRGBD);
_ui->groupBox_realsense->setVisible(_ui->comboBox_sourceType->currentIndex() == 0 && _ui->comboBox_cameraRGBD->currentIndex() == kSrcRealSense - kSrcRGBD);
_ui->groupBox_realsense2->setVisible(_ui->comboBox_sourceType->currentIndex() == 0 && _ui->comboBox_cameraRGBD->currentIndex() == kSrcRealSense2 - kSrcRGBD);
_ui->groupBox_cameraRGBDImages->setVisible(_ui->comboBox_sourceType->currentIndex() == 0 && _ui->comboBox_cameraRGBD->currentIndex() == kSrcRGBDImages-kSrcRGBD);
@@ -5783,7 +5889,7 @@ void PreferencesDialog::updateSourceGrpVisibility()
// Odom Sensor Group
_ui->frame_visual_odometry_sensor->setVisible(getOdomSourceDriver() != kSrcUndef); // Not Lidar None
_ui->groupBox_odom_sensor->setVisible(_ui->comboBox_sourceType->currentIndex() != 3); // Don't show when database is selected
_ui->comboBox_odom_sensor->setEnabled(_ui->comboBox_sourceType->currentIndex() != 3); // Don't enable when database is selected
// Lidar Sensor Group
_ui->comboBox_lidar_src->setEnabled(_ui->comboBox_sourceType->currentIndex() != 3); // Disable if database input
@@ -5809,6 +5915,7 @@ void PreferencesDialog::updateSourceGrpVisibility()
(_ui->comboBox_sourceType->currentIndex() == 2 && _ui->source_comboBox_image_type->currentIndex() == kSrcImages-kSrcRGB) ||
(_ui->comboBox_sourceType->currentIndex() == 0 && _ui->comboBox_cameraRGBD->currentIndex() == kSrcFreenect - kSrcRGBD) || //Kinect360
(_ui->comboBox_sourceType->currentIndex() == 0 && _ui->comboBox_cameraRGBD->currentIndex() == kSrcK4A - kSrcRGBD) || //K4A
(_ui->comboBox_sourceType->currentIndex() == 0 && _ui->comboBox_cameraRGBD->currentIndex() == kSrcOrbbecSDK - kSrcRGBD) || //Orbbec SDK
(_ui->comboBox_sourceType->currentIndex() == 0 && _ui->comboBox_cameraRGBD->currentIndex() == kSrcRealSense2 - kSrcRGBD) || //D435i
(_ui->comboBox_sourceType->currentIndex() == 0 && _ui->comboBox_cameraRGBD->currentIndex() == kSrcSeerSense - kSrcRGBD) ||
(_ui->comboBox_sourceType->currentIndex() == 1 && _ui->comboBox_cameraStereo->currentIndex() == kSrcStereoRealSense2 - kSrcStereo) || //T265
@@ -5816,7 +5923,6 @@ void PreferencesDialog::updateSourceGrpVisibility()
(_ui->comboBox_sourceType->currentIndex() == 1 && _ui->comboBox_cameraStereo->currentIndex() == kSrcStereoMyntEye - kSrcStereo) || // MYNT EYE S
(_ui->comboBox_sourceType->currentIndex() == 1 && _ui->comboBox_cameraStereo->currentIndex() == kSrcStereoZedOC - kSrcStereo) ||
(_ui->comboBox_sourceType->currentIndex() == 1 && _ui->comboBox_cameraStereo->currentIndex() == kSrcStereoDepthAI - kSrcStereo));
_ui->frame_imu_filtering->setVisible(getIMUFilteringStrategy() > 0); // Not None
_ui->stackedWidget_imuFilter->setVisible(_ui->comboBox_imuFilter_strategy->currentIndex() > 0);
_ui->groupBox_madgwickfilter->setVisible(_ui->comboBox_imuFilter_strategy->currentIndex() == 1);
_ui->groupBox_complementaryfilter->setVisible(_ui->comboBox_imuFilter_strategy->currentIndex() == 2);
@@ -5917,6 +6023,10 @@ bool PreferencesDialog::isOdomDisabled() const
{
return _ui->checkbox_odomDisabled->isChecked();
}
bool PreferencesDialog::isOdomAsGuessEnabled() const
{
return _ui->checkbox_passthrough_source_odom->isChecked();
}
bool PreferencesDialog::isOdomSensorAsGt() const
{
return _ui->checkBox_odom_sensor_use_as_gt->isChecked();
@@ -6637,6 +6747,26 @@ Camera * PreferencesDialog::createCamera(
_ui->comboBox_k4a_framerate->currentIndex(),
_ui->comboBox_k4a_depth_resolution->currentIndex());
}
else if (driver == kSrcOrbbecSDK)
{
camera = new CameraOrbbecSDK(
device.toStdString(),
_ui->spinBox_orbbec_sdk_color_width->value(),
_ui->spinBox_orbbec_sdk_color_height->value(),
_ui->spinBox_orbbec_sdk_depth_width->value(),
_ui->spinBox_orbbec_sdk_depth_height->value(),
this->getGeneralInputRate(),
this->getSourceLocalTransform());
((CameraOrbbecSDK*)camera)->enableColorRectification(_ui->checkBox_orbbec_sdk_color_rectification->isChecked());
((CameraOrbbecSDK*)camera)->enableImu(_ui->checkBox_orbbec_sdk_imu->isChecked());
((CameraOrbbecSDK*)camera)->enableDepthMM(_ui->checkBox_orbbec_sdk_depth_mm->isChecked());
camera->setInterIMUPublishing(
_ui->checkbox_publishInterIMU->isChecked(),
_ui->checkbox_publishInterIMU->isChecked() && getIMUFilteringStrategy()>0?
IMUFilter::create((IMUFilter::Type)(getIMUFilteringStrategy()-1), this->getAllParameters()):0,
getIMUFilteringBaseFrameConversion());
}
else if (driver == kSrcRealSense)
{
if(useRawImages && _ui->comboBox_realsenseRGBSource->currentIndex()!=2)
@@ -6677,7 +6807,8 @@ Camera * PreferencesDialog::createCamera(
camera->setInterIMUPublishing(
_ui->checkbox_publishInterIMU->isChecked(),
_ui->checkbox_publishInterIMU->isChecked() && getIMUFilteringStrategy()>0?
IMUFilter::create((IMUFilter::Type)(getIMUFilteringStrategy()-1), this->getAllParameters()):0);
IMUFilter::create((IMUFilter::Type)(getIMUFilteringStrategy()-1), this->getAllParameters()):0,
getIMUFilteringBaseFrameConversion());
if(driver == kSrcStereoRealSense2)
{
((CameraRealSense2*)camera)->setImagesRectified((_ui->checkBox_stereo_rectify->isEnabled() && _ui->checkBox_stereo_rectify->isChecked()) && !useRawImages);
@@ -6895,7 +7026,8 @@ Camera * PreferencesDialog::createCamera(
camera->setInterIMUPublishing(
_ui->checkbox_publishInterIMU->isChecked(),
_ui->checkbox_publishInterIMU->isChecked() && getIMUFilteringStrategy()>0?
IMUFilter::create((IMUFilter::Type)(getIMUFilteringStrategy()-1), this->getAllParameters()):0);
IMUFilter::create((IMUFilter::Type)(getIMUFilteringStrategy()-1), this->getAllParameters()):0,
getIMUFilteringBaseFrameConversion());
((CameraStereoZed*)camera)->setRightGrayScale(_ui->checkBox_stereo_rightGrayScale->isChecked());
}
else if (driver == kSrcStereoZedOC)
@@ -6944,7 +7076,8 @@ Camera * PreferencesDialog::createCamera(
camera->setInterIMUPublishing(
_ui->checkbox_publishInterIMU->isChecked(),
_ui->checkbox_publishInterIMU->isChecked() && getIMUFilteringStrategy()>0?
IMUFilter::create((IMUFilter::Type)(getIMUFilteringStrategy()-1), this->getAllParameters()):0);
IMUFilter::create((IMUFilter::Type)(getIMUFilteringStrategy()-1), this->getAllParameters()):0,
getIMUFilteringBaseFrameConversion());
}
else if(driver == kSrcUsbDevice)
{
+1 -1
View File
@@ -101,7 +101,7 @@ void ProgressDialog::setCancelButtonVisible(bool visible)
void ProgressDialog::appendText(const QString & text, const QColor & color)
{
UDEBUG(text.toStdString().c_str());
//UDEBUG(text.toStdString().c_str());
_text->setText(text);
QString html = tr("<html><font color=\"#999999\">%1 </font><font color=\"%2\">%3</font></html>").arg(QTime::currentTime().toString("HH:mm:ss")).arg(color.name()).arg(text);
_detailedText->append(html);
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

+436 -357
View File
@@ -17,7 +17,7 @@
<enum>Qt::LeftToRight</enum>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout_6" stretch="1,0,0">
<layout class="QVBoxLayout" name="verticalLayout_15" stretch="1,0,0">
<property name="spacing">
<number>0</number>
</property>
@@ -44,7 +44,7 @@
</layout>
</item>
<item>
<layout class="QGridLayout" name="gridLayout_11" rowstretch="1,0">
<layout class="QGridLayout" name="gridLayout_11">
<property name="spacing">
<number>0</number>
</property>
@@ -776,71 +776,90 @@
</layout>
</item>
<item row="1" column="1">
<widget class="QWidget" name="widget_imageControls_B">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="leftMargin">
<number>12</number>
</property>
<property name="topMargin">
<number>12</number>
</property>
<property name="rightMargin">
<number>12</number>
</property>
<property name="bottomMargin">
<number>12</number>
</property>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>Index :</string>
</property>
<widget class="QWidget" name="widget_imageControls_B" native="true">
<layout class="QVBoxLayout" name="verticalLayout_6">
<property name="spacing">
<number>0</number>
</property>
<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>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="leftMargin">
<number>12</number>
</property>
<property name="topMargin">
<number>12</number>
</property>
<property name="rightMargin">
<number>12</number>
</property>
<property name="bottomMargin">
<number>12</number>
</property>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>Index :</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>Id :</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QSpinBox" name="spinBox_indexB">
<property name="frame">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_idB">
<property name="text">
<string>idB</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QSlider" name="horizontalSlider_B">
<property name="focusPolicy">
<enum>Qt::ClickFocus</enum>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="tickPosition">
<enum>QSlider::TicksAbove</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>Id :</string>
</property>
</widget>
</item>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QSpinBox" name="spinBox_indexB">
<property name="frame">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_idB">
<property name="text">
<string>idB</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QSlider" name="horizontalSlider_B">
<property name="focusPolicy">
<enum>Qt::ClickFocus</enum>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="tickPosition">
<enum>QSlider::TicksAbove</enum>
</property>
</widget>
</item>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</item>
@@ -1252,322 +1271,382 @@
<widget class="rtabmap::GraphViewer" name="graphViewer"/>
</item>
<item>
<widget class="QWidget" name="widget_graphControl">
<layout class="QVBoxLayout" name="verticalLayout_91">
<widget class="QWidget" name="widget_graphControl" native="true">
<layout class="QVBoxLayout" name="verticalLayout_61">
<property name="spacing">
<number>0</number>
</property>
<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>
<layout class="QHBoxLayout" name="horizontalLayout_15">
<layout class="QVBoxLayout" name="verticalLayout_91">
<item>
<widget class="QLabel" name="label_rotation">
<property name="text">
<string>0.0 deg</string>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="horizontalSlider_rotation">
<property name="focusPolicy">
<enum>Qt::ClickFocus</enum>
</property>
<property name="minimum">
<number>-1799</number>
</property>
<property name="maximum">
<number>1800</number>
</property>
<property name="sliderPosition">
<number>0</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="tickPosition">
<enum>QSlider::TicksAbove</enum>
</property>
<property name="tickInterval">
<number>100</number>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_applyRotation">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The rotation will be applied temporary to optimized global graph. To save it to database, do File-&amp;gt;&amp;quot;Regenerate optimized 2D map...&amp;quot;.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Apply Rotation</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLabel" name="label_iterations">
<property name="text">
<string>#</string>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="horizontalSlider_iterations">
<property name="focusPolicy">
<enum>Qt::ClickFocus</enum>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="tickPosition">
<enum>QSlider::TicksAbove</enum>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBox_optimizationFlavor">
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_15">
<item>
<widget class="QLabel" name="label_rotation">
<property name="text">
<string>Global Iterative</string>
<string>0.0 deg</string>
</property>
</widget>
</item>
<item>
<property name="text">
<string>Global Full</string>
<widget class="QSlider" name="horizontalSlider_rotation">
<property name="focusPolicy">
<enum>Qt::ClickFocus</enum>
</property>
<property name="minimum">
<number>-1799</number>
</property>
<property name="maximum">
<number>1800</number>
</property>
<property name="sliderPosition">
<number>0</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="tickPosition">
<enum>QSlider::TicksAbove</enum>
</property>
<property name="tickInterval">
<number>100</number>
</property>
</widget>
</item>
<item>
<property name="text">
<string>Local Optimized</string>
<widget class="QPushButton" name="pushButton_applyRotation">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The rotation will be applied temporary to optimized global graph. To save it to database, do File-&amp;gt;&amp;quot;Regenerate optimized 2D map...&amp;quot;.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Apply Rotation</string>
</property>
</widget>
</item>
</widget>
</layout>
</item>
</layout>
</item>
<item>
<layout class="QGridLayout" name="gridLayout_5" columnstretch="0,1">
<item row="2" column="1">
<widget class="QLabel" name="label_alignPosesWithGroundTruth">
<property name="text">
<string>Align poses with ground truth</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="checkBox_ignoreIntermediateNodes">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="0" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_7" stretch="0,0,1">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLabel" name="label_optimizeFrom">
<widget class="QLabel" name="label_iterations">
<property name="text">
<string>Root</string>
<string>#</string>
</property>
</widget>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBox_spanAllMaps">
<widget class="QSlider" name="horizontalSlider_iterations">
<property name="focusPolicy">
<enum>Qt::ClickFocus</enum>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="tickPosition">
<enum>QSlider::TicksAbove</enum>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBox_optimizationFlavor">
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum>
</property>
<item>
<property name="text">
<string>Global Iterative</string>
</property>
</item>
<item>
<property name="text">
<string>Global Full</string>
</property>
</item>
<item>
<property name="text">
<string>Local Optimized</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QGridLayout" name="gridLayout_5" columnstretch="0,1">
<item row="1" column="1">
<widget class="QLabel" name="label_alignPosesWithGPS">
<property name="text">
<string>Span to all maps</string>
<string>Align poses with GPS</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QLabel" name="label_45">
<property name="text">
<string>Time grid (s)</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QLabel" name="label_39">
<property name="text">
<string>Time optimization (s)</string>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_timeOptimization">
<property name="text">
<string/>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="checkBox_alignPosesWithGPS">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>true</bool>
<bool>true</bool>
</property>
</widget>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBox_wmState">
<item row="3" column="0">
<widget class="QCheckBox" name="checkBox_alignScansCloudsWithGroundTruth">
<property name="text">
<string>WM</string>
<string/>
</property>
</widget>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
<item row="9" column="0">
<widget class="QLabel" name="label_rmse">
<property name="text">
<string/>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="label_alignPosesWithGroundTruth">
<property name="text">
<string>Align poses with ground truth</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="QLabel" name="label_rmse_title">
<property name="text">
<string>RMSE (m)</string>
</property>
</widget>
</item>
<item row="0" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_7" stretch="0,0,1">
<item>
<widget class="QLabel" name="label_optimizeFrom">
<property name="text">
<string>Root</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBox_spanAllMaps">
<property name="text">
<string>Span to all maps</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBox_wmState">
<property name="text">
<string>WM</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="0">
<widget class="QSpinBox" name="spinBox_optimizationsFrom"/>
</item>
<item row="11" column="0">
<widget class="QLabel" name="label_loopClosures">
<property name="text">
<string/>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="10" column="0">
<widget class="QLabel" name="label_poses">
<property name="text">
<string/>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLabel" name="label_ignoreINtermediateNdoes">
<property name="text">
<string>Ignore intermediate nodes</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_pathLength">
<property name="text">
<string/>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="10" column="1">
<widget class="QLabel" name="label_52">
<property name="text">
<string>Poses</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Path length (m)</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="label_alignScansCloudsWithGroundTruth">
<property name="text">
<string>Align scans/clouds with ground truth</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="11" column="1">
<widget class="QLabel" name="label_41">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;N: Neighbor&lt;/p&gt;&lt;p&gt;NM: Neighbor Merged&lt;/p&gt;&lt;p&gt;G: Global&lt;/p&gt;&lt;p&gt;LS: Local by Space (Proximity)&lt;/p&gt;&lt;p&gt;LT: Local by Time (Proximity)&lt;/p&gt;&lt;p&gt;U: User&lt;/p&gt;&lt;p&gt;P: Prior&lt;/p&gt;&lt;p&gt;LM: Landmark&lt;/p&gt;&lt;p&gt;GR: Gravity&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Links (N, NM, G, LS, LT, U, P, LM, GR)</string>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="label_timeGrid">
<property name="text">
<string/>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="checkBox_ignoreIntermediateNodes">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="checkBox_alignPosesWithGroundTruth">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLabel" name="label_21">
<property name="text">
<string>Env Sensor Colormap</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QComboBox" name="comboBox_env_sensor_graph_colormap">
<item>
<property name="text">
<string>Disabled</string>
</property>
</item>
<item>
<property name="text">
<string>Wifi</string>
</property>
</item>
<item>
<property name="text">
<string>Temperature</string>
</property>
</item>
<item>
<property name="text">
<string>Air Pressure</string>
</property>
</item>
<item>
<property name="text">
<string>Light</string>
</property>
</item>
<item>
<property name="text">
<string>Relative Humidity</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item row="7" column="1">
<widget class="QLabel" name="label_45">
<property name="text">
<string>Time grid (s)</string>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QLabel" name="label_rmse_title">
<property name="text">
<string>RMSE (m)</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="checkBox_alignScansCloudsWithGroundTruth">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QLabel" name="label_poses">
<property name="text">
<string/>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_timeOptimization">
<property name="text">
<string/>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="label_alignScansCloudsWithGroundTruth">
<property name="text">
<string>Align scans/clouds with ground truth</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="label_rmse">
<property name="text">
<string/>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_timeGrid">
<property name="text">
<string/>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="10" column="1">
<widget class="QLabel" name="label_41">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;N: Neighbor&lt;/p&gt;&lt;p&gt;NM: Neighbor Merged&lt;/p&gt;&lt;p&gt;G: Global&lt;/p&gt;&lt;p&gt;LS: Local by Space (Proximity)&lt;/p&gt;&lt;p&gt;LT: Local by Time (Proximity)&lt;/p&gt;&lt;p&gt;U: User&lt;/p&gt;&lt;p&gt;P: Prior&lt;/p&gt;&lt;p&gt;LM: Landmark&lt;/p&gt;&lt;p&gt;GR: Gravity&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Links (N, NM, G, LS, LT, U, P, LM, GR)</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Path length (m)</string>
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="QLabel" name="label_52">
<property name="text">
<string>Poses</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_pathLength">
<property name="text">
<string/>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QSpinBox" name="spinBox_optimizationsFrom"/>
</item>
<item row="10" column="0">
<widget class="QLabel" name="label_loopClosures">
<property name="text">
<string/>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLabel" name="label_ignoreINtermediateNdoes">
<property name="text">
<string>Ignore intermediate nodes</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLabel" name="label_39">
<property name="text">
<string>Time optimization (s)</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="checkBox_alignPosesWithGroundTruth">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_alignPosesWithGPS">
<property name="text">
<string>Align poses with GPS</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="checkBox_alignPosesWithGPS">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</layout>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
@@ -1805,7 +1884,7 @@
<property name="geometry">
<rect>
<x>0</x>
<y>-316</y>
<y>0</y>
<width>518</width>
<height>1071</height>
</rect>
@@ -1815,7 +1894,7 @@
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_16">
<item>
<layout class="QGridLayout" name="gridLayout_9" columnstretch="0,0">
<layout class="QGridLayout" name="gridLayout_9" columnstretch="0,1">
<item row="3" column="1">
<widget class="QLabel" name="label_octomap_empty_3">
<property name="text">
@@ -2526,8 +2605,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>296</width>
<height>272</height>
<width>222</width>
<height>306</height>
</rect>
</property>
<attribute name="label">
@@ -2700,8 +2779,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>428</width>
<height>196</height>
<width>181</width>
<height>485</height>
</rect>
</property>
<attribute name="label">
+1313 -1226
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -360,7 +360,7 @@
<bool>false</bool>
</property>
<property name="minimum">
<number>2</number>
<number>3</number>
</property>
<property name="value">
<number>8</number>
@@ -373,7 +373,7 @@
<bool>false</bool>
</property>
<property name="minimum">
<number>2</number>
<number>3</number>
</property>
<property name="value">
<number>6</number>
+1 -1
View File
@@ -35,7 +35,7 @@
<number>99999</number>
</property>
<property name="value">
<number>100</number>
<number>500</number>
</property>
</widget>
</item>
+19
View File
@@ -239,9 +239,20 @@
</property>
<addaction name="actionXvisio_SeerSense"/>
</widget>
<widget class="QMenu" name="menuOrbbec_Astra_2">
<property name="title">
<string>Orbbec Astra 2</string>
</property>
<property name="icon">
<iconset resource="../GuiLib.qrc">
<normaloff>:/images/astra2.png</normaloff>:/images/astra2.png</iconset>
</property>
<addaction name="actionOrbbecSDK_astra2"/>
</widget>
<addaction name="menuKinect_for_Xbox_360"/>
<addaction name="menuXtion_PRO_LIVE"/>
<addaction name="menuOrbbec_Astra"/>
<addaction name="menuOrbbec_Astra_2"/>
<addaction name="menuSense_3D_scanner"/>
<addaction name="menuKinect_v2"/>
<addaction name="menuKinect_K4A"/>
@@ -1749,6 +1760,14 @@
<string>Xvisio</string>
</property>
</action>
<action name="actionOrbbecSDK_astra2">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Orbbec SDK</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>
File diff suppressed because it is too large Load Diff