Compare commits

...
19 Commits
Author SHA1 Message Date
matlabbe 85112c2cdf add pull request template 2024-03-16 21:45:05 -07:00
matlabbe 8657e18bda update config 2024-03-16 21:27:50 -07:00
matlabbe 578bf0ed8f Try with pre-commit default usage 2024-03-16 21:06:00 -07:00
matlabbe 9f230f5b28 Adding pre-commit checks 2024-03-16 20:26:56 -07:00
matlabbe 264c560a2c reverted 87faea7a85 for #783 (just don't include OptimizerCeres if -DWITH_CERES=OFF even if floam or okvis did include it) 2024-03-16 17:10:34 -07:00
matlabbe 4ce36ef245 Updated appveyor gdown version 2024-03-13 23:27:47 -07:00
matlabbe d0227694c5 small fix for qt6 2024-03-13 22:52:44 -07:00
matlabbe a6d9425bce DBViewer: support doubleclick on node or link in graphview to update correpsonding image view and constraints view, also added "Show pixel depth" menu option in ImageView to show pixel depth and pixel coordinate in map frame. 2024-03-13 22:42:47 -07:00
matlabbe e299505a64 Fixed ORB_SLAM3 config for stereo mode 2024-03-12 23:13:06 -07:00
matlabbe 57b4954cb3 Update README.md 2024-03-10 15:24:48 -07:00
matlabbe 2577c47e77 Fixed #1232 2024-03-09 15:14:01 -08:00
matlabbe 52e1b01597 Fixed assert when exporting textured mesh with both multiband and blending enabled with grayscale images 2024-03-04 17:05:17 -08:00
matlabbe 8019a2dc49 Fixed #1227 2024-03-02 16:17:10 -08:00
matlabbe 33b875ecbf GraphView: fixed mouse cursor tracking inverted x-y values 2024-03-01 10:13:53 -08:00
matlabbe c24f95a8d9 ExportCloudsDialog: added option to filter off-axis points 2024-02-29 16:19:57 -08:00
matlabbe 6f7e5cc97b Removed RGB option from main menu (#640) 2024-02-26 19:06:39 -08:00
matlabbe fccf33dd96 GraphViewer: added "Show mouse cursor position (m)" context menu option. 2024-02-26 17:13:50 -08:00
Long VuongandLong Vuong 752ca76cf5 not limitKps inside Feature2D::generateKeypoints when using pyDetector (#1223)
* not limitKps when using pyDetector

* update with upstream

---------

Co-authored-by: Long Vuong <vuong@wheel.me>
2024-02-26 15:21:15 -08:00
matlabbe 81e249b56c Update README.md 2024-02-18 19:02:40 -08:00
24 changed files with 733 additions and 313 deletions
+1 -1
View File
@@ -19,7 +19,7 @@ init:
install:
# To download from google drive
- set PATH=C:\Python38-x64;C:\Python38-x64\Scripts;%PATH%
- ps: py -m pip --disable-pip-version-check install gdown==4.6.0
- ps: py -m pip --disable-pip-version-check install gdown>=5.1.0
# Qt
- set QTDIR=C:\Qt\5.10.1\msvc2015_64
# make sure Qt bin path is before cmake bin path to avoid copying qt5 dlls from cmake before qt installation
+7
View File
@@ -0,0 +1,7 @@
## Description
Please include a summary of the change and which issue is fixed (if any).
## Checklist:
- [ ] Did `pre-commit run --all-files` locally to fix any pre-commit failures on CI.
+16
View File
@@ -0,0 +1,16 @@
name: pre-commit
on:
pull_request:
branches:
- '**'
push:
branches: [master]
jobs:
pre-commit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v3
- uses: pre-commit/action@v3.0.1
+31
View File
@@ -0,0 +1,31 @@
# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
exclude: '^build/|^data/|^app/|^archive/|^cmake_modules/|^\..*'
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.2.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-added-large-files
- repo: https://github.com/cheshirekow/cmake-format-precommit
rev: v0.6.10
hooks:
- id: cmake-format
- id: cmake-lint
- repo: https://github.com/pryorda/dockerfilelint-precommit-hooks
rev: v0.1.0
hooks:
- id: dockerfilelint
- repo: https://github.com/pre-commit/mirrors-clang-format
rev: v18.1.1
hooks:
- id: clang-format
args: ["-style=Google", "-i"]
+3 -7
View File
@@ -892,9 +892,9 @@ ENDIF()
IF(NOT MRPT_FOUND)
SET(MRPT "//")
ENDIF(NOT MRPT_FOUND)
IF(NOT CERES_FOUND)
IF(NOT WITH_CERES OR NOT CERES_FOUND)
SET(CERES "//")
ENDIF(NOT CERES_FOUND)
ENDIF(NOT WITH_CERES OR NOT CERES_FOUND)
IF(NOT WITH_TORO)
SET(TORO "//")
ENDIF(NOT WITH_TORO)
@@ -1406,12 +1406,8 @@ ELSE()
MESSAGE(STATUS " *With GTSAM = NO (GTSAM not found)")
ENDIF()
IF(CERES_FOUND)
IF(WITH_CERES)
IF(WITH_CERES AND CERES_FOUND)
MESSAGE(STATUS " *With Ceres ${Ceres_VERSION} = YES (License: BSD)")
ELSE()
MESSAGE(STATUS " *With Ceres ${Ceres_VERSION} = YES (License: BSD, WITH_CERES=OFF but it is enabled by okvis or floam dependencies)")
ENDIF()
ELSEIF(NOT WITH_CERES)
MESSAGE(STATUS " *With Ceres = NO (WITH_CERES=OFF)")
ELSE()
+1 -1
View File
@@ -7,7 +7,7 @@ rtabmap
[![Downloads][downloads-image]][downloads]
[![License][license-image]][license]
[release-image]: https://img.shields.io/badge/release-0.21.0-green.svg?style=flat
[release-image]: https://img.shields.io/badge/release-0.21.4-green.svg?style=flat
[releases]: https://github.com/introlab/rtabmap/releases
[downloads-image]: https://img.shields.io/github/downloads/introlab/rtabmap/total?label=downloads
+2 -2
View File
@@ -25,13 +25,13 @@ The following image shows when we do the same localization experiment at differe
We provide two formats: the first one is more general and the second one is used to produce the results in this paper with RTAB-Map. Please open issue if the links are outdated.
* [Images](https://usherbrooke-my.sharepoint.com/:u:/g/personal/labm2414_usherbrooke_ca/EV8F4PZUxOxLhwAyEehlzKwBjF-9xNuxR32Q4mUjx5u-rA?e=eCJ3TW):
* [Images](https://drive.google.com/file/d/1fUm1m8oW6q8qlThx7BjrBH2vrVbNQ9bQ/view?usp=drive_link):
* `rgb`: folder containing *.jpg color camera images
* `depth`: folder containing *.png 16bits mm depth images
* `calib`: folder containing calibration for each color image. Each calibration contains also the transform between `device` and `camera` frames as `local_transform`.
* `device_poses.txt`: VIO poses of each image in `device` frame
* `camera_poses.txt`: VIO poses of each image in `camera` frame
* [RTAB-Map Databases](https://usherbrooke-my.sharepoint.com/:u:/g/personal/labm2414_usherbrooke_ca/EU5fb0jEKzlGhPK3OWjMGLUBnDo1BRAoZwtB2czyeVLE_A?e=Y0JyXY)
* [RTAB-Map Databases](https://drive.google.com/file/d/1TklUcTKFSrcg8b0t0U80G_IpFRMVRlY5/view?usp=drive_link)
@@ -49,7 +49,7 @@ public:
private:
virtual Transform computeTransform(SensorData & image, const Transform & guess = Transform(), OdometryInfo * info = 0);
bool init(const rtabmap::CameraModel & model, double stamp, bool stereo, double baseline);
bool init(const rtabmap::CameraModel & model1, const rtabmap::CameraModel & model2, double stamp, bool stereo, double baseline);
private:
#if defined(RTABMAP_ORB_SLAM) and RTABMAP_ORB_SLAM == 3
ORB_SLAM3::System * orbslam_;
+4 -1
View File
@@ -734,7 +734,10 @@ std::vector<cv::KeyPoint> Feature2D::generateKeypoints(const cv::Mat & image, co
cv::Rect roi(globalRoi.x + j*colSize, globalRoi.y + i*rowSize, colSize, rowSize);
std::vector<cv::KeyPoint> subKeypoints;
subKeypoints = this->generateKeypointsImpl(image, roi, mask);
limitKeypoints(subKeypoints, maxFeatures);
if (this->getType() != Feature2D::Type::kFeaturePyDetector)
{
limitKeypoints(subKeypoints, maxFeatures);
}
if(roi.x || roi.y)
{
// Adjust keypoint position to raw image
+1 -1
View File
@@ -86,7 +86,7 @@ Odometry * Odometry::create(Odometry::Type & type, const ParametersMap & paramet
break;
case Odometry::kTypeORBSLAM:
#if defined(RTABMAP_ORB_SLAM) and RTABMAP_ORB_SLAM == 2
odometry = new OdometryORBSLAM(parameters);
odometry = new OdometryORBSLAM2(parameters);
#else
odometry = new OdometryORBSLAM3(parameters);
#endif
+3 -1
View File
@@ -3027,7 +3027,7 @@ bool Rtabmap::process(
// Landmark
//============================================================
std::map<int, std::set<int> > landmarksDetected; // <Landmark ID, list of nodes that saw this landmark>
if(!signature->getLandmarks().empty())
if(!signature->getLandmarks().empty() && !_graphOptimizer->landmarksIgnored())
{
bool hasGlobalLoopClosuresInOdomCache = !graph::filterLinks(_odomCacheConstraints, Link::kGlobalClosure, true).empty() || _loopClosureHypothesis.first != 0;
UDEBUG("hasGlobalLoopClosuresInOdomCache=%d", hasGlobalLoopClosuresInOdomCache?1:0);
@@ -3527,6 +3527,7 @@ bool Rtabmap::process(
}
// update localization links
UASSERT(uContains(optPoses, signature->id()));
Transform newOptPoseInv = optPoses.at(signature->id()).inverse();
for(std::multimap<int, Link>::iterator iter=localizationLinks.begin(); iter!=localizationLinks.end(); ++iter)
{
@@ -3539,6 +3540,7 @@ bool Rtabmap::process(
else
{
// Adjust with optimized poses, this will smooth the localization
UASSERT(uContains(optPoses, iter->first));
Transform newT = newOptPoseInv * optPoses.at(iter->first);
UDEBUG("Adjusted localization link %d->%d after optimization", iter->second.from(), iter->second.to());
UDEBUG("from %s", iter->second.transform().prettyPrint().c_str());
+55 -37
View File
@@ -103,7 +103,7 @@ bool OdometryORBSLAM3::canProcessAsyncIMU() const
#endif
}
bool OdometryORBSLAM3::init(const rtabmap::CameraModel & model, double stamp, bool stereo, double baseline)
bool OdometryORBSLAM3::init(const rtabmap::CameraModel & model1, const rtabmap::CameraModel & model2, double stamp, bool stereo, double baseline)
{
#if defined(RTABMAP_ORB_SLAM) and RTABMAP_ORB_SLAM == 3
std::string vocabularyPath;
@@ -138,40 +138,45 @@ bool OdometryORBSLAM3::init(const rtabmap::CameraModel & model, double stamp, b
ofs << fixed << setprecision(13);
//# Camera calibration and distortion parameters (OpenCV)
ofs << "Camera1.fx: " << model.fx() << std::endl;
ofs << "Camera1.fy: " << model.fy() << std::endl;
ofs << "Camera1.cx: " << model.cx() << std::endl;
ofs << "Camera1.cy: " << model.cy() << std::endl;
ofs << std::endl;
for(int i=1; i<(stereo?3:2); ++i)
{
const CameraModel & model = i==1?model1:model2;
if(model.D().cols < 4)
{
ofs << "Camera1.k1: " << 0.0 << std::endl;
ofs << "Camera1.k2: " << 0.0 << std::endl;
ofs << "Camera1.p1: " << 0.0 << std::endl;
ofs << "Camera1.p2: " << 0.0 << std::endl;
if(!stereo)
//# Camera calibration and distortion parameters (OpenCV)
ofs << "Camera" << i << ".fx: " << model.fx() << std::endl;
ofs << "Camera" << i << ".fy: " << model.fy() << std::endl;
ofs << "Camera" << i << ".cx: " << model.cx() << std::endl;
ofs << "Camera" << i << ".cy: " << model.cy() << std::endl;
ofs << std::endl;
if(model.D().cols < 4)
{
ofs << "Camera1.k3: " << 0.0 << std::endl;
ofs << "Camera" << i << ".k1: " << 0.0 << std::endl;
ofs << "Camera" << i << ".k2: " << 0.0 << std::endl;
ofs << "Camera" << i << ".p1: " << 0.0 << std::endl;
ofs << "Camera" << i << ".p2: " << 0.0 << std::endl;
if(!stereo)
{
ofs << "Camera" << i << ".k3: " << 0.0 << std::endl;
}
}
if(model.D().cols >= 4)
{
ofs << "Camera" << i << ".k1: " << model.D().at<double>(0,0) << std::endl;
ofs << "Camera" << i << ".k2: " << model.D().at<double>(0,1) << std::endl;
ofs << "Camera" << i << ".p1: " << model.D().at<double>(0,2) << std::endl;
ofs << "Camera" << i << ".p2: " << model.D().at<double>(0,3) << std::endl;
}
if(model.D().cols >= 5)
{
ofs << "Camera" << i << ".k3: " << model.D().at<double>(0,4) << std::endl;
}
if(model.D().cols > 5)
{
UWARN("Unhandled camera distortion size %d, only 5 first coefficients used", model.D().cols);
}
ofs << std::endl;
}
if(model.D().cols >= 4)
{
ofs << "Camera1.k1: " << model.D().at<double>(0,0) << std::endl;
ofs << "Camera1.k2: " << model.D().at<double>(0,1) << std::endl;
ofs << "Camera1.p1: " << model.D().at<double>(0,2) << std::endl;
ofs << "Camera1.p2: " << model.D().at<double>(0,3) << std::endl;
}
if(model.D().cols >= 5)
{
ofs << "Camera1.k3: " << model.D().at<double>(0,4) << std::endl;
}
if(model.D().cols > 5)
{
UWARN("Unhandled camera distortion size %d, only 5 first coefficients used", model.D().cols);
}
ofs << std::endl;
//# IR projector baseline times fx (aprox.)
if(baseline <= 0.0)
@@ -179,15 +184,28 @@ bool OdometryORBSLAM3::init(const rtabmap::CameraModel & model, double stamp, b
baseline = rtabmap::Parameters::defaultOdomORBSLAMBf();
rtabmap::Parameters::parse(parameters_, rtabmap::Parameters::kOdomORBSLAMBf(), baseline);
}
ofs << "Camera.bf: " << model.fx()*baseline << std::endl;
else
{
// # Transformation matrix from right camera to left camera
ofs << "Stereo.T_c1_c2: !!opencv-matrix" << std::endl;
ofs << " rows: 4" << std::endl;
ofs << " cols: 4" << std::endl;
ofs << " dt: f" << std::endl;
ofs << " data: [" << 1 << ", " << 0 << ", " << 0 << ", " << baseline << ", " << std::endl;
ofs << " " << 0 << ", " << 1 << ", " << 0 << ", " << 0 << ", " << std::endl;
ofs << " " << 0 << ", " << 0 << ", " << 1 << ", " << 0 << ", " << std::endl;
ofs << " 0.0, 0.0, 0.0, 1.0]" << std::endl;
ofs << std::endl;
}
ofs << "Camera.bf: " << model1.fx()*baseline << std::endl;
ofs << "Camera.width: " << model.imageWidth() << std::endl;
ofs << "Camera.height: " << model.imageHeight() << std::endl;
ofs << "Camera.width: " << model1.imageWidth() << std::endl;
ofs << "Camera.height: " << model1.imageHeight() << std::endl;
ofs << std::endl;
//# Color order of the images (0: BGR, 1: RGB. It is ignored if images are grayscale)
//Camera.RGB: 1
ofs << "Camera.RGB: 1" << std::endl;
ofs << "Camera.RGB: 0" << std::endl;
ofs << std::endl;
float fps = rtabmap::Parameters::defaultOdomORBSLAMFps();
@@ -222,7 +240,7 @@ bool OdometryORBSLAM3::init(const rtabmap::CameraModel & model, double stamp, b
//# IMU Parameters TODO: hard-coded, not used
//#--------------------------------------------------------------------------------------------
// Transformation from camera 0 to body-frame (imu)
rtabmap::Transform camImuT = model.localTransform()*imuLocalTransform_;
rtabmap::Transform camImuT = model1.localTransform()*imuLocalTransform_;
ofs << "IMU.T_b_c1: !!opencv-matrix" << std::endl;
ofs << " rows: 4" << std::endl;
ofs << " cols: 4" << std::endl;
@@ -418,7 +436,7 @@ Transform OdometryORBSLAM3::computeTransform(
}
CameraModel model = data.cameraModels().size()==1?data.cameraModels()[0]:data.stereoCameraModels()[0].left();
if(!init(model, data.stamp(), stereo, data.cameraModels().size()==1?0.0:data.stereoCameraModels()[0].baseline()))
if(!init(model, !stereo?model:data.stereoCameraModels()[0].right(), data.stamp(), stereo, data.cameraModels().size()==1?0.0:data.stereoCameraModels()[0].baseline()))
{
return t;
}
+29 -13
View File
@@ -2398,7 +2398,7 @@ bool multiBandTexturing(
std::string tmpImageDirectory = outputDirectory+"/rtabmap_tmp_textures";
UDirectory::removeDir(tmpImageDirectory);
UDirectory::makeDir(tmpImageDirectory);
UINFO("Temporary saving images in directory \"%s\"...", tmpImageDirectory.c_str());
UINFO("Temporary saving images from %ld nodes in directory \"%s\"...", cameraPoses.size(), tmpImageDirectory.c_str());
int viewId = 0;
for(std::map<int, Transform>::const_iterator iter = cameraPoses.lower_bound(1); iter!=cameraPoses.end(); ++iter)
{
@@ -2510,28 +2510,45 @@ bool multiBandTexturing(
imageSize.height = image.rows;
imageSize.width = image.cols;
}
UASSERT(image.cols % imageSize.width == 0);
cv::Mat imageRoi = image.colRange(i*imageSize.width, (i+1)*imageSize.width);
if(gains.find(camId) != gains.end() &&
gains.at(camId).find(i) != gains.at(camId).end())
{
const cv::Vec4d & g = gains.at(camId).at(i);
std::vector<cv::Mat> channels;
cv::split(imageRoi, channels);
if(imageRoi.channels() == 1)
{
cv::multiply(imageRoi, g.val[0], imageRoi);
}
else
{
std::vector<cv::Mat> channels;
cv::split(imageRoi, channels);
// assuming BGR
cv::multiply(channels[0], g.val[gainRGB?3:0], channels[0]);
cv::multiply(channels[1], g.val[gainRGB?2:0], channels[1]);
cv::multiply(channels[2], g.val[gainRGB?1:0], channels[2]);
// assuming BGR
cv::multiply(channels[0], g.val[gainRGB?3:0], channels[0]);
cv::multiply(channels[1], g.val[gainRGB?2:0], channels[1]);
cv::multiply(channels[2], g.val[gainRGB?1:0], channels[2]);
cv::Mat output;
cv::merge(channels, output);
imageRoi = output;
cv::Mat output;
cv::merge(channels, output);
imageRoi = output;
}
}
if(blendingGains.find(camId) != blendingGains.end() &&
blendingGains.at(camId).find(i) != blendingGains.at(camId).end())
{
// Should be color for blending options
if(imageRoi.channels() == 1)
{
cv::Mat imageRoiColor;
cv::cvtColor(imageRoi, imageRoiColor, CV_GRAY2BGR);
imageRoi = imageRoiColor;
}
cv::Mat g = blendingGains.at(camId).at(i);
cv::Mat dst;
cv::blur(g, dst, cv::Size(3,3));
@@ -2559,9 +2576,7 @@ bool multiBandTexturing(
sfmData.intrinsics.insert(std::make_pair((IndexT)viewId, camPtr));
std::string imagePath = tmpImageDirectory+uFormat("/%d.jpg", viewId);
cv::imwrite(imagePath, imageRoi);
std::shared_ptr<sfmData::View> viewPtr = std::make_shared<sfmData::View>(
imagePath,
(IndexT)viewId,
@@ -2572,8 +2587,9 @@ bool multiBandTexturing(
sfmData.views.insert(std::make_pair((IndexT)viewId, viewPtr));
++viewId;
}
UDEBUG("camId=%d", camId);
}
UINFO("Temporary saving images in directory \"%s\"... done (%d images). %fs", tmpImageDirectory.c_str(), viewId, (int)cameraPoses.size(), timer.ticks());
UINFO("Temporary saving images in directory \"%s\"... done (%d images of %d nodes). %fs", tmpImageDirectory.c_str(), viewId, (int)cameraPoses.size(), timer.ticks());
mvsUtils::MultiViewParams mp(sfmData);
@@ -128,6 +128,8 @@ private Q_SLOTS:
void updateAllLandmarkCovariances();
void refineLinks();
void resetAllChanges();
void graphNodeSelected(int);
void graphLinkSelected(int, int);
void sliderAValueChanged(int);
void sliderBValueChanged(int);
void sliderAMoved(int);
+5
View File
@@ -166,12 +166,16 @@ public:
Q_SIGNALS:
void configChanged();
void mapShownRequested();
void nodeSelected(int);
void linkSelected(int, int);
public Q_SLOTS:
void restoreDefaults();
protected:
virtual void wheelEvent ( QWheelEvent * event );
virtual void mouseMoveEvent(QMouseEvent * event);
virtual void mouseDoubleClickEvent(QMouseEvent * event);
virtual void contextMenuEvent(QContextMenuEvent * event);
private:
@@ -228,6 +232,7 @@ private:
float _loopClosureOutlierThr;
float _maxLinkLength;
bool _orientationENU;
bool _mouseTracking;
ViewPlane _viewPlane;
bool _ensureFrameVisible;
};
+6 -1
View File
@@ -37,6 +37,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <opencv2/features2d/features2d.hpp>
#include <map>
#include "rtabmap/utilite/UCv2Qt.h"
#include <rtabmap/core/CameraModel.h>
class QAction;
class QMenu;
@@ -96,7 +97,7 @@ public:
void setFeatures(const std::vector<cv::KeyPoint> & features, const cv::Mat & depth = cv::Mat(), const QColor & color = Qt::yellow);
void addFeature(int id, const cv::KeyPoint & kpt, float depth, QColor color);
void addLine(float x1, float y1, float x2, float y2, QColor color, const QString & text = QString());
void setImage(const QImage & image);
void setImage(const QImage & image, const std::vector<CameraModel> & models = std::vector<CameraModel>(), const Transform & pose = Transform());
void setImageDepth(const cv::Mat & imageDepth);
void setImageDepth(const QImage & image);
void setFeatureColor(int id, QColor color);
@@ -121,6 +122,7 @@ protected:
virtual void paintEvent(QPaintEvent *event);
virtual void resizeEvent(QResizeEvent* event);
virtual void contextMenuEvent(QContextMenuEvent * e);
virtual void mouseMoveEvent(QMouseEvent * event);
private Q_SLOTS:
void sceneRectChanged(const QRectF &rect);
@@ -164,6 +166,7 @@ private:
QAction * _colorMapBlueToRed;
QAction * _colorMapMinRange;
QAction * _colorMapMaxRange;
QAction * _mouseTracking;
QMenu * _featureMenu;
QMenu * _scaleMenu;
@@ -175,6 +178,8 @@ private:
QPixmap _image;
QPixmap _imageDepth;
cv::Mat _imageDepthCv;
std::vector<CameraModel> _models;
Transform _pose;
};
}
-1
View File
@@ -170,7 +170,6 @@ protected Q_SLOTS:
void depthCalibration();
void openWorkingDirectory();
void updateEditMenu();
void selectStream();
void selectOpenni();
void selectFreenect();
void selectOpenniCv();
+22 -1
View File
@@ -268,6 +268,8 @@ DatabaseViewer::DatabaseViewer(const QString & ini, QWidget * parent) :
connect(ui_->dockWidget_statistics->toggleViewAction(), SIGNAL(triggered()), this, SLOT(updateStatistics()));
connect(ui_->dockWidget_info->toggleViewAction(), SIGNAL(triggered()), this, SLOT(updateInfo()));
connect(ui_->graphViewer, SIGNAL(nodeSelected(int)), this , SLOT(graphNodeSelected(int)));
connect(ui_->graphViewer, SIGNAL(linkSelected(int,int)), this , SLOT(graphLinkSelected(int,int)));
connect(ui_->parameters_toolbox, SIGNAL(parametersChanged(const QStringList &)), this, SLOT(notifyParametersChanged(const QStringList &)));
@@ -4547,6 +4549,20 @@ void DatabaseViewer::resetAllChanges()
}
}
void DatabaseViewer::graphNodeSelected(int id)
{
if(id>0 && idToIndex_.contains(id))
ui_->horizontalSlider_A->setValue(idToIndex_.value(id));
}
void DatabaseViewer::graphLinkSelected(int from, int to)
{
if(from>0 && idToIndex_.contains(from))
ui_->horizontalSlider_A->setValue(idToIndex_.value(from));
if(to>0 && idToIndex_.contains(to))
ui_->horizontalSlider_B->setValue(idToIndex_.value(to));
}
void DatabaseViewer::sliderAValueChanged(int value)
{
this->update(value,
@@ -4685,7 +4701,12 @@ void DatabaseViewer::update(int value,
QRectF rect;
if(!img.isNull())
{
view->setImage(img);
Transform pose;
if(!graphes_.empty() && graphes_.back().find(data.id())!=graphes_.back().end())
{
pose = graphes_.back().at(data.id());
}
view->setImage(img, data.cameraModels(), pose);
rect = img.rect();
}
else
+63 -1
View File
@@ -129,6 +129,14 @@ ExportCloudsDialog::ExportCloudsDialog(QWidget *parent) :
connect(_ui->doubleSpinBox_minDepth, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
connect(_ui->doubleSpinBox_ceilingHeight, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
connect(_ui->doubleSpinBox_floorHeight, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
connect(_ui->groupBox_offAxisFiltering, SIGNAL(toggled(bool)), this, SIGNAL(configChanged()));
connect(_ui->doubleSpinBox_offAxisFilteringAngle, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
connect(_ui->checkBox_offAxisFilteringPosX, SIGNAL(stateChanged(int)), this, SIGNAL(configChanged()));
connect(_ui->checkBox_offAxisFilteringNegX, SIGNAL(stateChanged(int)), this, SIGNAL(configChanged()));
connect(_ui->checkBox_offAxisFilteringPosY, SIGNAL(stateChanged(int)), this, SIGNAL(configChanged()));
connect(_ui->checkBox_offAxisFilteringNegY, SIGNAL(stateChanged(int)), this, SIGNAL(configChanged()));
connect(_ui->checkBox_offAxisFilteringPosZ, SIGNAL(stateChanged(int)), this, SIGNAL(configChanged()));
connect(_ui->checkBox_offAxisFilteringNegZ, SIGNAL(stateChanged(int)), this, SIGNAL(configChanged()));
connect(_ui->doubleSpinBox_footprintWidth, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
connect(_ui->doubleSpinBox_footprintLength, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
connect(_ui->doubleSpinBox_footprintHeight, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
@@ -370,6 +378,14 @@ void ExportCloudsDialog::saveSettings(QSettings & settings, const QString & grou
settings.setValue("regenerate_min_depth", _ui->doubleSpinBox_minDepth->value());
settings.setValue("regenerate_ceiling", _ui->doubleSpinBox_ceilingHeight->value());
settings.setValue("regenerate_floor", _ui->doubleSpinBox_floorHeight->value());
settings.setValue("regenerate_offaxis_filtering", _ui->groupBox_offAxisFiltering->isChecked());
settings.setValue("regenerate_offaxis_filtering_angle", _ui->doubleSpinBox_offAxisFilteringAngle->value());
settings.setValue("regenerate_offaxis_filtering_pos_x", _ui->checkBox_offAxisFilteringPosX->isChecked());
settings.setValue("regenerate_offaxis_filtering_neg_x", _ui->checkBox_offAxisFilteringNegX->isChecked());
settings.setValue("regenerate_offaxis_filtering_pos_y", _ui->checkBox_offAxisFilteringPosY->isChecked());
settings.setValue("regenerate_offaxis_filtering_neg_y", _ui->checkBox_offAxisFilteringNegY->isChecked());
settings.setValue("regenerate_offaxis_filtering_pos_z", _ui->checkBox_offAxisFilteringPosZ->isChecked());
settings.setValue("regenerate_offaxis_filtering_neg_z", _ui->checkBox_offAxisFilteringNegZ->isChecked());
settings.setValue("regenerate_footprint_height", _ui->doubleSpinBox_footprintHeight->value());
settings.setValue("regenerate_footprint_width", _ui->doubleSpinBox_footprintWidth->value());
settings.setValue("regenerate_footprint_length", _ui->doubleSpinBox_footprintLength->value());
@@ -543,6 +559,14 @@ void ExportCloudsDialog::loadSettings(QSettings & settings, const QString & grou
_ui->doubleSpinBox_minDepth->setValue(settings.value("regenerate_min_depth", _ui->doubleSpinBox_minDepth->value()).toDouble());
_ui->doubleSpinBox_ceilingHeight->setValue(settings.value("regenerate_ceiling", _ui->doubleSpinBox_ceilingHeight->value()).toDouble());
_ui->doubleSpinBox_floorHeight->setValue(settings.value("regenerate_floor", _ui->doubleSpinBox_floorHeight->value()).toDouble());
_ui->groupBox_offAxisFiltering->setChecked(settings.value("regenerate_offaxis_filtering", _ui->groupBox_offAxisFiltering->isChecked()).toBool());
_ui->doubleSpinBox_offAxisFilteringAngle->setValue(settings.value("regenerate_offaxis_filtering_angle", _ui->doubleSpinBox_offAxisFilteringAngle->value()).toDouble());
_ui->checkBox_offAxisFilteringPosX->setChecked(settings.value("regenerate_offaxis_filtering_pos_x", _ui->checkBox_offAxisFilteringPosX->isChecked()).toBool());
_ui->checkBox_offAxisFilteringNegX->setChecked(settings.value("regenerate_offaxis_filtering_neg_x", _ui->checkBox_offAxisFilteringNegX->isChecked()).toBool());
_ui->checkBox_offAxisFilteringPosY->setChecked(settings.value("regenerate_offaxis_filtering_pos_y", _ui->checkBox_offAxisFilteringPosY->isChecked()).toBool());
_ui->checkBox_offAxisFilteringNegY->setChecked(settings.value("regenerate_offaxis_filtering_neg_y", _ui->checkBox_offAxisFilteringNegY->isChecked()).toBool());
_ui->checkBox_offAxisFilteringPosZ->setChecked(settings.value("regenerate_offaxis_filtering_pos_z", _ui->checkBox_offAxisFilteringPosZ->isChecked()).toBool());
_ui->checkBox_offAxisFilteringNegZ->setChecked(settings.value("regenerate_offaxis_filtering_neg_z", _ui->checkBox_offAxisFilteringNegZ->isChecked()).toBool());
_ui->doubleSpinBox_footprintHeight->setValue(settings.value("regenerate_footprint_height", _ui->doubleSpinBox_footprintHeight->value()).toDouble());
_ui->doubleSpinBox_footprintWidth->setValue(settings.value("regenerate_footprint_width", _ui->doubleSpinBox_footprintWidth->value()).toDouble());
_ui->doubleSpinBox_footprintLength->setValue(settings.value("regenerate_footprint_length", _ui->doubleSpinBox_footprintLength->value()).toDouble());
@@ -719,6 +743,14 @@ void ExportCloudsDialog::restoreDefaults()
_ui->doubleSpinBox_minDepth->setValue(0);
_ui->doubleSpinBox_ceilingHeight->setValue(0);
_ui->doubleSpinBox_floorHeight->setValue(0);
_ui->groupBox_offAxisFiltering->setChecked(false);
_ui->doubleSpinBox_offAxisFilteringAngle->setValue(10);
_ui->checkBox_offAxisFilteringPosX->setChecked(true);
_ui->checkBox_offAxisFilteringNegX->setChecked(true);
_ui->checkBox_offAxisFilteringPosY->setChecked(true);
_ui->checkBox_offAxisFilteringNegY->setChecked(true);
_ui->checkBox_offAxisFilteringPosZ->setChecked(true);
_ui->checkBox_offAxisFilteringNegZ->setChecked(true);
_ui->doubleSpinBox_footprintHeight->setValue(0);
_ui->doubleSpinBox_footprintLength->setValue(0);
_ui->doubleSpinBox_footprintWidth->setValue(0);
@@ -3915,6 +3947,36 @@ std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr, pcl::Indic
UWARN("Point cloud %d doesn't have anymore points (had %d points) after radius filtering.", iter->first, (int)cloud->size());
}
}
if( !indices->empty() && _ui->groupBox_offAxisFiltering->isChecked() &&
(_ui->checkBox_offAxisFilteringPosX->isChecked() ||
_ui->checkBox_offAxisFilteringNegX->isChecked() ||
_ui->checkBox_offAxisFilteringPosY->isChecked() ||
_ui->checkBox_offAxisFilteringNegY->isChecked() ||
_ui->checkBox_offAxisFilteringPosZ->isChecked() ||
_ui->checkBox_offAxisFilteringNegZ->isChecked()))
{
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr cloudInMapFrame = util3d::transformPointCloud(cloud, iter->second);
std::vector<pcl::IndicesPtr> indicesVector;
double maxDeltaAngle = _ui->doubleSpinBox_offAxisFilteringAngle->value()*M_PI/180.0;
Eigen::Vector4f viewpoint(iter->second.x(), iter->second.y(), iter->second.z(), 0);
if(_ui->checkBox_offAxisFilteringPosX->isChecked())
indicesVector.push_back(util3d::normalFiltering(cloudInMapFrame, indices, maxDeltaAngle, Eigen::Vector4f(1,0,0,0), 20, viewpoint));
if(_ui->checkBox_offAxisFilteringPosY->isChecked())
indicesVector.push_back(util3d::normalFiltering(cloudInMapFrame, indices, maxDeltaAngle, Eigen::Vector4f(0,1,0,0), 20, viewpoint));
if(_ui->checkBox_offAxisFilteringPosZ->isChecked())
indicesVector.push_back(util3d::normalFiltering(cloudInMapFrame, indices, maxDeltaAngle, Eigen::Vector4f(0,0,1,0), 20, viewpoint));
if(_ui->checkBox_offAxisFilteringNegX->isChecked())
indicesVector.push_back(util3d::normalFiltering(cloudInMapFrame, indices, maxDeltaAngle, Eigen::Vector4f(-1,0,0,0), 20, viewpoint));
if(_ui->checkBox_offAxisFilteringNegY->isChecked())
indicesVector.push_back(util3d::normalFiltering(cloudInMapFrame, indices, maxDeltaAngle, Eigen::Vector4f(0,-1,0,0), 20, viewpoint));
if(_ui->checkBox_offAxisFilteringNegZ->isChecked())
indicesVector.push_back(util3d::normalFiltering(cloudInMapFrame, indices, maxDeltaAngle, Eigen::Vector4f(0,0,-1,0), 20, viewpoint));
indices = util3d::concatenate(indicesVector);
if(indices->empty())
{
UWARN("Point cloud %d doesn't have anymore points (had %d points) after offaxis filtering.", iter->first, (int)cloud->size());
}
}
}
if(!indices->empty())
@@ -4614,7 +4676,7 @@ void ExportCloudsDialog::saveTextureMeshes(
path.toStdString(),
mesh->cloud,
mesh->tex_polygons[0],
poses,
filterNodes(poses),
textureVertexToPixels,
images,
calibrations,
+55
View File
@@ -45,6 +45,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endif
#include <QInputDialog>
#include <QMessageBox>
#include <QToolTip>
#include <QtCore/QDir>
#include <QtCore/QDateTime>
@@ -316,6 +317,7 @@ GraphViewer::GraphViewer(QWidget * parent) :
_loopClosureOutlierThr(0),
_maxLinkLength(0.02f),
_orientationENU(false),
_mouseTracking(false),
_viewPlane(XY),
_ensureFrameVisible(true)
{
@@ -1789,6 +1791,50 @@ void GraphViewer::wheelEvent ( QWheelEvent * event )
}
}
void GraphViewer::mouseMoveEvent(QMouseEvent * event)
{
QPointF scenePoint = mapToScene(event->pos());
if(_mouseTracking && _viewPlane==XY && this->sceneRect().contains(scenePoint))
{
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
QToolTip::showText(event->globalPosition().toPoint(), QString("%1m %2m").arg(-scenePoint.y()/100.0).arg(-scenePoint.x()/100.0));
#else
QToolTip::showText(event->globalPos(), QString("%1m %2m").arg(-scenePoint.y()/100.0).arg(-scenePoint.x()/100.0));
#endif
}
else
{
QToolTip::hideText();
}
QGraphicsView::mouseMoveEvent(event);
}
void GraphViewer::mouseDoubleClickEvent(QMouseEvent * event)
{
QGraphicsItem *item = this->scene()->itemAt(mapToScene(event->pos()), QTransform());
if(item)
{
NodeItem *nodeItem = qgraphicsitem_cast<NodeItem*>(item);
LinkItem *linkItem = qgraphicsitem_cast<LinkItem*>(item);
if(nodeItem && nodeItem->parentItem() == _graphRoot && nodeItem->id() != 0)
{
Q_EMIT nodeSelected(nodeItem->id());
}
else if(linkItem && linkItem->parentItem() == _graphRoot && linkItem->from() != 0 && linkItem->to() != 0)
{
Q_EMIT linkSelected(linkItem->from(), linkItem->to());
}
else
{
QGraphicsView::mouseDoubleClickEvent(event);
}
}
else
{
QGraphicsView::mouseDoubleClickEvent(event);
}
}
QIcon createIcon(const QColor & color)
{
QPixmap pixmap(50, 50);
@@ -1878,6 +1924,7 @@ void GraphViewer::contextMenuEvent(QContextMenuEvent * event)
QAction * aShowHideGPSGraph;
QAction * aShowHideOdomCacheOverlay;
QAction * aOrientationENU;
QAction * aMouseTracking;
QAction * aViewPlaneXY;
QAction * aViewPlaneXZ;
QAction * aViewPlaneYZ;
@@ -1976,6 +2023,10 @@ void GraphViewer::contextMenuEvent(QContextMenuEvent * event)
aOrientationENU = menu.addAction(tr("ENU Orientation"));
aOrientationENU->setCheckable(true);
aOrientationENU->setChecked(_orientationENU);
aMouseTracking = menu.addAction(tr("Show mouse cursor position (m)"));
aMouseTracking->setCheckable(true);
aMouseTracking->setChecked(_mouseTracking);
aMouseTracking->setEnabled(_viewPlane == XY);
aShowHideGraph->setEnabled(_nodeItems.size() && _viewPlane == XY);
aShowHideGraphNodes->setEnabled(_nodeItems.size() && _graphRoot->isVisible());
aShowHideGlobalPath->setEnabled(_globalPathLinkItems.size());
@@ -2405,6 +2456,10 @@ void GraphViewer::contextMenuEvent(QContextMenuEvent * event)
{
this->setOrientationENU(!this->isOrientationENU());
}
else if(r == aMouseTracking)
{
_mouseTracking = aMouseTracking->isChecked();
}
else if(r == aViewPlaneXY)
{
this->setViewPlane(XY);
+71 -1
View File
@@ -40,9 +40,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <QColorDialog>
#include <QPrinter>
#include <QGraphicsRectItem>
#include <QToolTip>
#include "rtabmap/utilite/ULogger.h"
#include "rtabmap/gui/KeypointItem.h"
#include "rtabmap/core/util2d.h"
#include "rtabmap/core/util3d_transforms.h"
#include <QtGlobal>
#if QT_VERSION >= 0x050000
@@ -268,9 +270,14 @@ ImageView::ImageView(QWidget * parent) :
group->addAction(_colorMapRedToBlue);
group->addAction(_colorMapBlueToRed);
group->addAction(_colorMapMaxRange);
_mouseTracking = _menu->addAction(tr("Show pixel depth"));
_mouseTracking->setCheckable(true);
_mouseTracking->setChecked(false);
_saveImage = _menu->addAction(tr("Save picture..."));
_saveImage->setEnabled(false);
setMouseTracking(true);
connect(_graphicsView->scene(), SIGNAL(sceneRectChanged(const QRectF &)), this, SLOT(sceneRectChanged(const QRectF &)));
}
@@ -1047,6 +1054,65 @@ void ImageView::contextMenuEvent(QContextMenuEvent * e)
}
}
void ImageView::mouseMoveEvent(QMouseEvent * event)
{
if(_mouseTracking->isChecked() &&
!_graphicsView->scene()->sceneRect().isNull() &&
!_image.isNull() &&
!_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() > _imageDepth.width())
{
depthScale = _imageDepth.width() / _image.width();
}
int ud = int(u*depthScale);
int vd = int(v*depthScale);
if( ud>=0 && vd>=0 &&
ud < _imageDepthCv.cols &&
vd < _imageDepthCv.rows)
{
float depth = 0;
if(_imageDepthCv.type() == CV_32FC1)
{
depth = _imageDepthCv.at<float>(vd, ud);
}
else
{
depth = float(_imageDepthCv.at<unsigned short>(vd, ud)) / 1000.0f;
}
cv::Point3f pt(0,0,0);
if(depth>0 && !_models.empty() && !_pose.isNull())
{
int subImageWidth = _imageDepthCv.cols / _models.size();
int subImageIndex = ud / subImageWidth;
UASSERT(subImageIndex < (int)_models.size());
float x,y,z;
_models[subImageIndex].project(u, v, depth, x, y, z);
pt = cv::Point3f(x,y,z);
pt = util3d::transformPoint(pt, _pose*_models[subImageIndex].localTransform());
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
QToolTip::showText(event->globalPosition().toPoint(), pt.x!=0?tr("Depth=%1m Map=(%2,%3,%4)").arg(depth).arg(pt.x).arg(pt.y).arg(pt.z):depth > 0?tr("Depth=%1m").arg(depth):tr("Depth=NA"));
#else
QToolTip::showText(event->globalPos(), pt.x!=0?tr("Depth=%1m Map=(%2,%3,%4)").arg(depth).arg(pt.x).arg(pt.y).arg(pt.z):depth > 0?tr("Depth=%1m").arg(depth):tr("Depth=NA"));
#endif
}
else
{
QToolTip::hideText();
}
}
QWidget::mouseMoveEvent(event);
}
void ImageView::updateOpacity()
{
if(_imageItem && _imageDepthItem)
@@ -1166,9 +1232,11 @@ void ImageView::addLine(float x1, float y1, float x2, float y2, QColor color, co
}
}
void ImageView::setImage(const QImage & image)
void ImageView::setImage(const QImage & image, const std::vector<CameraModel> & models, const Transform & pose)
{
_image = QPixmap::fromImage(image);
_models = models;
_pose = pose;
if(_graphicsView->isVisible())
{
if(_imageItem)
@@ -1394,6 +1462,8 @@ void ImageView::clear()
_imageItem = 0;
}
_image = QPixmap();
_models.clear();
_pose.setNull();
if(_imageDepthItem)
{
+1 -8
View File
@@ -435,7 +435,6 @@ MainWindow::MainWindow(PreferencesDialog * prefDialog, QWidget * parent, bool sh
//Settings menu
connect(_ui->actionMore_options, SIGNAL(triggered()), this, SLOT(openPreferencesSource()));
connect(_ui->actionUsbCamera, SIGNAL(triggered()), this, SLOT(selectStream()));
connect(_ui->actionOpenNI_PCL, SIGNAL(triggered()), this, SLOT(selectOpenni()));
connect(_ui->actionOpenNI_PCL_ASUS, SIGNAL(triggered()), this, SLOT(selectOpenni()));
connect(_ui->actionFreenect, SIGNAL(triggered()), this, SLOT(selectFreenect()));
@@ -5228,10 +5227,9 @@ bool MainWindow::eventFilter(QObject *obj, QEvent *event)
void MainWindow::updateSelectSourceMenu()
{
_ui->actionUsbCamera->setChecked(_preferencesDialog->getSourceDriver() == PreferencesDialog::kSrcUsbDevice);
_ui->actionMore_options->setChecked(
_preferencesDialog->getSourceDriver() == PreferencesDialog::kSrcDatabase ||
_preferencesDialog->getSourceDriver() == PreferencesDialog::kSrcUsbDevice ||
_preferencesDialog->getSourceDriver() == PreferencesDialog::kSrcImages ||
_preferencesDialog->getSourceDriver() == PreferencesDialog::kSrcVideo ||
_preferencesDialog->getSourceDriver() == PreferencesDialog::kSrcStereoImages ||
@@ -7061,11 +7059,6 @@ void MainWindow::updateEditMenu()
}
}
void MainWindow::selectStream()
{
_preferencesDialog->selectSourceDriver(PreferencesDialog::kSrcUsbDevice);
}
void MainWindow::selectOpenni()
{
_preferencesDialog->selectSourceDriver(PreferencesDialog::kSrcOpenNI_PCL);
+354 -212
View File
@@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>1032</width>
<width>919</width>
<height>869</height>
</rect>
</property>
@@ -23,9 +23,9 @@
<property name="geometry">
<rect>
<x>0</x>
<y>-2140</y>
<width>998</width>
<height>5850</height>
<y>-1328</y>
<width>885</width>
<height>6169</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_13">
@@ -1086,220 +1086,362 @@
<property name="checkable">
<bool>false</bool>
</property>
<layout class="QGridLayout" name="gridLayout_9" columnstretch="0,1">
<item row="0" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_filteringRadius">
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>3</number>
</property>
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
<property name="value">
<double>0.020000000000000</double>
</property>
</widget>
<layout class="QVBoxLayout" name="verticalLayout_20">
<item>
<layout class="QGridLayout" name="gridLayout_9" columnstretch="0,1">
<item row="3" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_floorHeight">
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>2</number>
</property>
<property name="minimum">
<double>-1000.000000000000000</double>
</property>
<property name="maximum">
<double>1000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_filteringRadius">
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>3</number>
</property>
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
<property name="value">
<double>0.020000000000000</double>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QSpinBox" name="spinBox_filteringMinNeighbors">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>100</number>
</property>
<property name="value">
<number>2</number>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLabel" name="label_144">
<property name="text">
<string>Footprint length.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_footprintWidth">
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>2</number>
</property>
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>1000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_footprintLength">
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>2</number>
</property>
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>1000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLabel" name="label_145">
<property name="text">
<string>Footprint height. If negative, the footprint is filtered between [-height:height] around the base frame, otherwise it is [0:height]</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_ceilingHeight">
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>2</number>
</property>
<property name="minimum">
<double>-1000.000000000000000</double>
</property>
<property name="maximum">
<double>1000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="label_141">
<property name="text">
<string>Floor filtering height. This is done in map frame.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_110">
<property name="text">
<string>Search radius.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLabel" name="label_143">
<property name="text">
<string>Footprint width.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_footprintHeight">
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>2</number>
</property>
<property name="minimum">
<double>-1000.000000000000000</double>
</property>
<property name="maximum">
<double>1000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_112">
<property name="text">
<string>Minimum neighbors in the search radius.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="label_140">
<property name="text">
<string>Ceiling filtering height. This is done in map frame.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_110">
<property name="text">
<string>Search radius.</string>
<item>
<widget class="QGroupBox" name="groupBox_offAxisFiltering">
<property name="title">
<string>Off-Axis Filtering</string>
</property>
<property name="wordWrap">
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QSpinBox" name="spinBox_filteringMinNeighbors">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>100</number>
</property>
<property name="value">
<number>2</number>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_112">
<property name="text">
<string>Minimum neighbors in the search radius.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_ceilingHeight">
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>2</number>
</property>
<property name="minimum">
<double>-1000.000000000000000</double>
</property>
<property name="maximum">
<double>1000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="label_140">
<property name="text">
<string>Ceiling filtering height.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_floorHeight">
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>2</number>
</property>
<property name="minimum">
<double>-1000.000000000000000</double>
</property>
<property name="maximum">
<double>1000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="label_141">
<property name="text">
<string>Floor filtering height.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_footprintWidth">
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>2</number>
</property>
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>1000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLabel" name="label_143">
<property name="text">
<string>Footprint width.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_footprintLength">
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>2</number>
</property>
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>1000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLabel" name="label_144">
<property name="text">
<string>Footprint length.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_footprintHeight">
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>2</number>
</property>
<property name="minimum">
<double>-1000.000000000000000</double>
</property>
<property name="maximum">
<double>1000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLabel" name="label_145">
<property name="text">
<string>Footprint height. If negative, the footprint is filtered between [-height:height] around the base frame, otherwise it is [0:height]</string>
</property>
<property name="wordWrap">
<property name="checked">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_21">
<item>
<widget class="QLabel" name="label_148">
<property name="text">
<string>Keep only points with normals aligned with one/any of the map X-Y-Z axes.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout_24">
<item row="0" column="0">
<widget class="QCheckBox" name="checkBox_offAxisFilteringPosX">
<property name="text">
<string>+X</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QCheckBox" name="checkBox_offAxisFilteringNegY">
<property name="text">
<string>-Y</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="checkBox_offAxisFilteringNegX">
<property name="text">
<string>-X</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QCheckBox" name="checkBox_offAxisFilteringPosY">
<property name="text">
<string>+Y</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="QCheckBox" name="checkBox_offAxisFilteringPosZ">
<property name="text">
<string>+Z</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="5">
<widget class="QCheckBox" name="checkBox_offAxisFilteringNegZ">
<property name="text">
<string>-Z</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="6">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QGridLayout" name="gridLayout_23" columnstretch="0,1">
<item row="0" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_offAxisFilteringAngle">
<property name="suffix">
<string> deg</string>
</property>
<property name="decimals">
<number>1</number>
</property>
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>179.000000000000000</double>
</property>
<property name="singleStep">
<double>1.000000000000000</double>
</property>
<property name="value">
<double>10.000000000000000</double>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_146">
<property name="text">
<string>Max angle error to keep the points. </string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
-23
View File
@@ -105,16 +105,6 @@
<property name="title">
<string>Select source</string>
</property>
<widget class="QMenu" name="menuImage">
<property name="title">
<string>RGB camera</string>
</property>
<property name="icon">
<iconset resource="../GuiLib.qrc">
<normaloff>:/images/webcam.png</normaloff>:/images/webcam.png</iconset>
</property>
<addaction name="actionUsbCamera"/>
</widget>
<widget class="QMenu" name="menuRGB_D_camera">
<property name="title">
<string>RGB-D camera</string>
@@ -342,7 +332,6 @@
</widget>
<addaction name="menuRGB_D_camera"/>
<addaction name="menuStereo_camera"/>
<addaction name="menuImage"/>
<addaction name="actionMore_options"/>
</widget>
<addaction name="menuSelect_source"/>
@@ -1244,18 +1233,6 @@
<string>240p</string>
</property>
</action>
<action name="actionUsbCamera">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="../GuiLib.qrc">
<normaloff>:/images/webcam.png</normaloff>:/images/webcam.png</iconset>
</property>
<property name="text">
<string>Usb camera</string>
</property>
</action>
<action name="actionPrint_loop_closure_IDs_to_console">
<property name="text">
<string>Print loop closure IDs to console</string>