Added GainCompensator class. GUI/3D Rendering: added texturing option.

This commit is contained in:
matlabbe
2016-09-07 12:15:44 -04:00
parent 3b25fef852
commit ff4300d525
18 changed files with 1458 additions and 541 deletions
+1 -1
View File
@@ -66,7 +66,7 @@ PointCloudDrawable::PointCloudDrawable(
if(!textures_)
{
vertex_buffers_ = 0;
LOGE("OpenGL: could not generate vertex buffers\n");
LOGE("OpenGL: could not generate texture buffers\n");
return;
}
}
@@ -0,0 +1,104 @@
/*
Copyright (c) 2010-2016, 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 CORELIB_SRC_GAINCOMPENSATOR_H_
#define CORELIB_SRC_GAINCOMPENSATOR_H_
#include "rtabmap/core/RtabmapExp.h" // DLL export/import defines
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
#include <pcl/pcl_base.h>
#include <opencv2/opencv.hpp>
#include <rtabmap/core/Link.h>
namespace rtabmap {
/**
* Works like cv::GainCompensator but with point clouds
*/
class RTABMAP_EXP GainCompensator {
public:
GainCompensator(double maxCorrespondenceDistance = 0.02, double minOverlap = 0.05, double alpha = 0.01, double beta = 10);
virtual ~GainCompensator();
void feed(
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloudA, // should not contain NaNs
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloudB, // should not contain NaNs
const Transform & transformB);
void feed(
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloudA,
const pcl::IndicesPtr & indicesA,
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloudB,
const pcl::IndicesPtr & indicesB,
const Transform & transformB);
void feed(
const std::map<int, pcl::PointCloud<pcl::PointXYZRGB>::Ptr> & clouds, // should not contain NaNs
const std::multimap<int, Link> & links);
void feed(
const std::map<int, pcl::PointCloud<pcl::PointXYZRGB>::Ptr> & clouds,
const std::map<int, pcl::IndicesPtr> & indices,
const std::multimap<int, Link> & links);
void feed(
const std::map<int, pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr> & clouds,
const std::map<int, pcl::IndicesPtr> & indices,
const std::multimap<int, Link> & links);
void feed(
const std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr, pcl::IndicesPtr> > & clouds,
const std::multimap<int, Link> & links);
void apply(
int id,
pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud);
void apply(
int id,
pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
const pcl::IndicesPtr & indices);
void apply(
int id,
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr & cloud,
const pcl::IndicesPtr & indices);
void apply(
int id,
cv::Mat & image);
double getGain(int id) const;
int getIndex(int id) const;
private:
cv::Mat_<double> gains_;
std::map<int, int> idToIndex_;
double maxCorrespondenceDistance_;
double minOverlap_;
double alpha_;
double beta_;
};
} /* namespace rtabmap */
#endif /* CORELIB_SRC_GAINCOMPENSATOR_H_ */
@@ -14,7 +14,7 @@ namespace util3d {
template<typename pointT>
std::vector<pcl::Vertices> normalizePolygonsSide(
const pcl::PointCloud<pointT> & cloud,
const typename pcl::PointCloud<pointT> & cloud,
const std::vector<pcl::Vertices> & polygons,
const pcl::PointXYZ & viewPoint)
{
@@ -433,13 +433,6 @@ pcl::IndicesPtr RTABMAP_EXP normalFiltering(
int normalKSearch,
const Eigen::Vector4f & viewpoint);
void RTABMAP_EXP colorMeanFiltering(
pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
const pcl::IndicesPtr & indices,
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloudRef,
const pcl::IndicesPtr & indicesRef,
float radiusSearch);
/**
* For convenience.
*/
+2
View File
@@ -66,6 +66,8 @@ SET(SRC_FILES
StereoCameraModel.cpp
OccupancyGrid.cpp
GainCompensator.cpp
rtflann/ext/lz4.c
rtflann/ext/lz4hc.c
+314
View File
@@ -0,0 +1,314 @@
/*
Copyright (c) 2010-2016, 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.
*/
#include "rtabmap/core/GainCompensator.h"
#include <rtabmap/utilite/ULogger.h>
#include <rtabmap/utilite/UStl.h>
#include <rtabmap/utilite/UConversion.h>
#include <rtabmap/core/util3d_transforms.h>
#include <pcl/registration/correspondence_estimation.h>
namespace rtabmap {
double sqr(uchar v)
{
return double(v)*double(v);
}
GainCompensator::GainCompensator(double maxCorrespondenceDistance, double minOverlap, double alpha, double beta) :
maxCorrespondenceDistance_(maxCorrespondenceDistance),
minOverlap_(minOverlap),
alpha_(alpha),
beta_(beta)
{
}
GainCompensator::~GainCompensator() {
}
void GainCompensator::feed(
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloudA,
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloudB,
const Transform & transformB)
{
std::multimap<int, Link> links;
links.insert(std::make_pair(0, Link(0,1,Link::kUserClosure, transformB)));
std::map<int, pcl::PointCloud<pcl::PointXYZRGB>::Ptr> clouds;
clouds.insert(std::make_pair(0, cloudA));
clouds.insert(std::make_pair(1, cloudB));
feed(clouds, links);
}
void GainCompensator::feed(
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloudA,
const pcl::IndicesPtr & indicesA,
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloudB,
const pcl::IndicesPtr & indicesB,
const Transform & transformB)
{
std::multimap<int, Link> links;
links.insert(std::make_pair(0, Link(0,1,Link::kUserClosure, transformB)));
std::map<int, pcl::PointCloud<pcl::PointXYZRGB>::Ptr> clouds;
clouds.insert(std::make_pair(0, cloudA));
clouds.insert(std::make_pair(1, cloudB));
std::map<int, pcl::IndicesPtr> indices;
indices.insert(std::make_pair(0, indicesA));
indices.insert(std::make_pair(1, indicesB));
feed(clouds, indices, links);
}
void GainCompensator::feed(
const std::map<int, pcl::PointCloud<pcl::PointXYZRGB>::Ptr> & clouds,
const std::multimap<int, Link> & links)
{
std::map<int, pcl::IndicesPtr> indices;
feed(clouds, indices, links);
}
/**
* @see https://github.com/opencv/opencv/blob/master/modules/stitching/src/exposure_compensate.cpp
*/
template<typename PointT>
void feedImpl(
const std::map<int, typename pcl::PointCloud<PointT>::Ptr> & clouds,
const std::map<int, pcl::IndicesPtr> & indices,
const std::multimap<int, Link> & links,
float maxCorrespondenceDistance,
double minOverlap,
double alpha,
double beta,
cv::Mat_<double> & gains,
std::map<int, int> & idToIndex)
{
UDEBUG("Exposure compensation...");
UASSERT(maxCorrespondenceDistance > 0.0f);
UASSERT(indices.size() == 0 || clouds.size() == indices.size());
const int num_images = static_cast<int>(clouds.size());
cv::Mat_<int> N(num_images, num_images); N.setTo(0);
cv::Mat_<double> I(num_images, num_images); I.setTo(0);
// make id to index map
idToIndex.clear();
int oi=0;
for(typename std::map<int, typename pcl::PointCloud<PointT>::Ptr>::const_iterator iter=clouds.begin(); iter!=clouds.end(); ++iter)
{
idToIndex.insert(std::make_pair(iter->first, oi));
UASSERT(indices.empty() || uContains(indices, iter->first));
N(oi,oi) = iter->second->size();
++oi;
}
typename pcl::registration::CorrespondenceEstimation<PointT, PointT>::Ptr est;
est.reset(new pcl::registration::CorrespondenceEstimation<PointT, PointT>);
for(std::multimap<int, Link>::const_iterator iter=links.begin(); iter!=links.end(); ++iter)
{
if(uContains(idToIndex, iter->second.from()) && uContains(idToIndex, iter->second.to()))
{
UDEBUG("estimate...%d %d", iter->second.from(), iter->second.to());
const typename pcl::PointCloud<PointT>::Ptr & cloudFrom = clouds.at(iter->second.from());
const typename pcl::PointCloud<PointT>::Ptr & cloudTo = clouds.at(iter->second.to());
if(cloudFrom->size() && cloudTo->size())
{
est->setInputTarget(cloudFrom); //match
if(iter->second.transform().isIdentity() || iter->second.transform().isNull())
{
est->setInputSource(cloudTo); //query
}
else
{
est->setInputSource(util3d::transformPointCloud(cloudTo, iter->second.transform())); //query
}
if(indices.size())
{
if(indices.at(iter->second.from())->size())
{
est->setIndicesTarget(indices.at(iter->second.from()));
}
if(indices.at(iter->second.to())->size())
{
est->setIndicesSource(indices.at(iter->second.to()));
}
}
pcl::Correspondences correspondences;
est->determineCorrespondences(correspondences, maxCorrespondenceDistance);
UDEBUG("correspondences = %d", (int)correspondences.size());
if((minOverlap <= 0.0 && correspondences.size()) ||
(double(correspondences.size()) / double(clouds.at(iter->second.from())->size()) >= minOverlap &&
double(correspondences.size()) / double(clouds.at(iter->second.to())->size()) >= minOverlap))
{
int i = idToIndex.at(iter->second.from());
int j = idToIndex.at(iter->second.to());
N(i, j) = N(j, i) = correspondences.size();
double Isum1 = 0, Isum2 = 0;
for (unsigned int c = 0; c < correspondences.size(); ++c)
{
const PointT & pt1 = cloudFrom->at(correspondences.at(c).index_match);
const PointT & pt2 = cloudTo->at(correspondences.at(c).index_query);
Isum1 += std::sqrt(static_cast<double>(sqr(pt1.r) + sqr(pt1.g) + sqr(pt1.b)));
Isum2 += std::sqrt(static_cast<double>(sqr(pt2.r) + sqr(pt2.g) + sqr(pt2.b)));
}
I(i, j) = Isum1 / N(i, j);
I(j, i) = Isum2 / N(i, j);
}
}
}
}
cv::Mat_<double> A(num_images, num_images); A.setTo(0);
cv::Mat_<double> b(num_images, 1); b.setTo(0);
for (int i = 0; i < num_images; ++i)
{
for (int j = 0; j < num_images; ++j)
{
b(i, 0) += beta * N(i, j);
A(i, i) += beta * N(i, j);
if (j == i) continue;
A(i, i) += 2 * alpha * I(i, j) * I(i, j) * N(i, j);
A(i, j) -= 2 * alpha * I(i, j) * I(j, i) * N(i, j);
}
}
gains = cv::Mat_<double>();
cv::solve(A, b, gains);
}
void GainCompensator::feed(
const std::map<int, pcl::PointCloud<pcl::PointXYZRGB>::Ptr> & clouds,
const std::map<int, pcl::IndicesPtr> & indices,
const std::multimap<int, Link> & links)
{
feedImpl<pcl::PointXYZRGB>(clouds, indices, links, maxCorrespondenceDistance_, minOverlap_, alpha_, beta_, gains_, idToIndex_);
}
void GainCompensator::feed(
const std::map<int, pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr> & clouds,
const std::map<int, pcl::IndicesPtr> & indices,
const std::multimap<int, Link> & links)
{
feedImpl<pcl::PointXYZRGBNormal>(clouds, indices, links, maxCorrespondenceDistance_, minOverlap_, alpha_, beta_, gains_, idToIndex_);
}
void GainCompensator::feed(
const std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr, pcl::IndicesPtr> > & cloudsIndices,
const std::multimap<int, Link> & links)
{
std::map<int, pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr> clouds;
std::map<int, pcl::IndicesPtr> indices;
for(std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr, pcl::IndicesPtr> >::const_iterator iter=cloudsIndices.begin(); iter!=cloudsIndices.end(); ++iter)
{
clouds.insert(std::make_pair(iter->first, iter->second.first));
indices.insert(std::make_pair(iter->first, iter->second.second));
}
feedImpl<pcl::PointXYZRGBNormal>(clouds, indices, links, maxCorrespondenceDistance_, minOverlap_, alpha_, beta_, gains_, idToIndex_);
}
template<typename PointT>
void applyImpl(
int index,
typename pcl::PointCloud<PointT>::Ptr & cloud,
const pcl::IndicesPtr & indices,
const cv::Mat_<double> & gains)
{
double gain = gains(index, 0);
UDEBUG("index=%d gain=%f", index, gain);
if(indices->size())
{
for(unsigned int i=0; i<indices->size(); ++i)
{
PointT & pt = cloud->at(indices->at(i));
pt.r = uchar(std::max(0.0, std::min(255.0, double(pt.r) * gain)));
pt.g = uchar(std::max(0.0, std::min(255.0, double(pt.g) * gain)));
pt.b = uchar(std::max(0.0, std::min(255.0, double(pt.b) * gain)));
}
}
else
{
for(unsigned int i=0; i<cloud->size(); ++i)
{
PointT & pt = cloud->at(i);
pt.r = uchar(std::max(0.0, std::min(255.0, double(pt.r) * gain)));
pt.g = uchar(std::max(0.0, std::min(255.0, double(pt.g) * gain)));
pt.b = uchar(std::max(0.0, std::min(255.0, double(pt.b) * gain)));
}
}
}
void GainCompensator::apply(
int id,
pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud)
{
pcl::IndicesPtr indices(new std::vector<int>);
UASSERT_MSG(uContains(idToIndex_, id), uFormat("id=%d idToIndex_.size()=%d", id, (int)idToIndex_.size()).c_str());
apply(idToIndex_.at(id), cloud, indices);
}
void GainCompensator::apply(
int id,
pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
const pcl::IndicesPtr & indices)
{
UASSERT_MSG(uContains(idToIndex_, id), uFormat("id=%d idToIndex_.size()=%d", id, (int)idToIndex_.size()).c_str());
applyImpl<pcl::PointXYZRGB>(idToIndex_.at(id), cloud, indices, gains_);
}
void GainCompensator::apply(
int id,
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr & cloud,
const pcl::IndicesPtr & indices)
{
UASSERT_MSG(uContains(idToIndex_, id), uFormat("id=%d idToIndex_.size()=%d", id, (int)idToIndex_.size()).c_str());
applyImpl<pcl::PointXYZRGBNormal>(idToIndex_.at(id), cloud, indices, gains_);
}
void GainCompensator::apply(
int id,
cv::Mat & image)
{
UASSERT_MSG(uContains(idToIndex_, id), uFormat("id=%d idToIndex_.size()=%d", id, (int)idToIndex_.size()).c_str());
cv::multiply(image, gains_(idToIndex_.at(id), 0), image);
}
double GainCompensator::getGain(int id) const
{
UASSERT_MSG(uContains(idToIndex_, id), uFormat("id=%d idToIndex_.size()=%d", id, (int)idToIndex_.size()).c_str());
return gains_(idToIndex_.at(id), 0);
}
int GainCompensator::getIndex(int id) const
{
if(uContains(idToIndex_, id))
{
return idToIndex_.at(id);
}
return -1;
}
} /* namespace rtabmap */
-39
View File
@@ -1555,45 +1555,6 @@ pcl::IndicesPtr normalFiltering(
return output;
}
void colorMeanFiltering(
pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
const pcl::IndicesPtr & indices,
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloudRef,
const pcl::IndicesPtr & indicesRef,
float radiusSearch)
{
UASSERT(radiusSearch>0.0f);
pcl::search::KdTree<pcl::PointXYZRGB>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZRGB>(false));
if(indicesRef->size())
{
tree->setInputCloud(cloudRef, indicesRef);
}
else
{
tree->setInputCloud(cloudRef);
}
for(unsigned int i=0; i<indices->size(); ++i)
{
std::vector<int> kIndices;
std::vector<float> kDistances;
pcl::PointXYZRGB & pt = cloud->at(indices->at(i));
if(tree->radiusSearch(pt, radiusSearch, kIndices, kDistances))
{
UASSERT(kIndices.size());
int r=0,g=0,b=0;
for(unsigned int j=0; j<kIndices.size(); ++j)
{
r+=cloudRef->at(kIndices.at(j)).r;
g+=cloudRef->at(kIndices.at(j)).g;
b+=cloudRef->at(kIndices.at(j)).b;
}
pt.r = (unsigned char)(r/kIndices.size());
pt.g = (unsigned char)(g/kIndices.size());
pt.b = (unsigned char)(b/kIndices.size());
}
}
}
std::vector<pcl::IndicesPtr> extractClusters(
const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud,
float clusterTolerance,
@@ -183,6 +183,7 @@ public:
double getSubtractFilteringRadius() const;
double getSubtractFilteringAngle() const;
int getNormalKSearch() const;
bool gainCompensation() const;
bool getGridMapShown() const;
double getGridMapResolution() const;;
@@ -201,6 +202,7 @@ public:
bool isCloudMeshing() const;
double getCloudMeshingAngle() const;
bool isCloudMeshingQuad() const;
bool isCloudMeshingTexture() const;
int getCloudMeshingTriangleSize();
QString getWorkingDirectory() const;
+13 -6
View File
@@ -642,22 +642,29 @@ bool CloudViewer::addCloudTextureMesh(
const pcl::TextureMesh::Ptr & textureMesh,
const Transform & pose)
{
#if PCL_VERSION_COMPARE(>=, 1, 7, 2)
if(_addedClouds.contains(id))
{
this->removeCloud(id);
}
UDEBUG("Adding %s", id.c_str());
if(_visualizer->addTextureMesh(*textureMesh, id))
if(this->addTextureMesh(*textureMesh, id))
{
_visualizer->getCloudActorMap()->find(id)->second.actor->GetProperty()->LightingOff();
if(_backfaceCulling)
{
_visualizer->getCloudActorMap()->find(id)->second.actor->GetProperty()->BackfaceCullingOn();
}
if(_frontfaceCulling)
{
_visualizer->getCloudActorMap()->find(id)->second.actor->GetProperty()->FrontfaceCullingOn();
}
_visualizer->getCloudActorMap()->find(id)->second.actor->GetTexture()->SetInterpolate(1);
_visualizer->getCloudActorMap()->find(id)->second.actor->GetTexture()->SetBlendingMode(vtkTexture::VTK_TEXTURE_BLENDING_MODE_REPLACE);
_visualizer->updatePointCloudPose(id, pose.toEigen3f());
_addedClouds.insert(id, pose);
return true;
}
#endif
// not implemented on lower version of PCL
return false;
}
@@ -895,7 +902,7 @@ bool CloudViewer::addTextureMesh (
int viewport)
{
#if PCL_VERSION_COMPARE(>=, 1, 7, 2)
return addTextureMesh(mesh, id, viewport);
return _visualizer->addTextureMesh(mesh, id, viewport);
#else
// Copied from PCL 1.8
+27 -3
View File
@@ -68,6 +68,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "rtabmap/core/OccupancyGrid.h"
#include "rtabmap/gui/DataRecorder.h"
#include "rtabmap/core/SensorData.h"
#include "rtabmap/core/GainCompensator.h"
#include "ExportDialog.h"
#include "rtabmap/gui/ProgressDialog.h"
#include "ParametersToolBox.h"
@@ -253,6 +254,7 @@ DatabaseViewer::DatabaseViewer(const QString & ini, QWidget * parent) :
connect(ui_->checkBox_ignoreUserLoop, SIGNAL(stateChanged(int)), this, SLOT(updateGraphView()));
connect(ui_->spinBox_optimizationDepth, SIGNAL(editingFinished()), this, SLOT(updateGraphView()));
connect(ui_->checkBox_gridErode, SIGNAL(stateChanged(int)), this, SLOT(updateGrid()));
connect(ui_->doubleSpinBox_gainCompensationRadius, SIGNAL(valueChanged(double)), this, SLOT(updateConstraintView()));
connect(ui_->groupBox_posefiltering, SIGNAL(clicked(bool)), this, SLOT(updateGraphView()));
connect(ui_->doubleSpinBox_posefilteringRadius, SIGNAL(editingFinished()), this, SLOT(updateGraphView()));
connect(ui_->doubleSpinBox_posefilteringAngle, SIGNAL(editingFinished()), this, SLOT(updateGraphView()));
@@ -280,6 +282,7 @@ DatabaseViewer::DatabaseViewer(const QString & ini, QWidget * parent) :
connect(ui_->checkBox_ignoreUserLoop, SIGNAL(stateChanged(int)), this, SLOT(configModified()));
connect(ui_->spinBox_optimizationDepth, SIGNAL(valueChanged(int)), this, SLOT(configModified()));
connect(ui_->checkBox_gridErode, SIGNAL(stateChanged(int)), this, SLOT(configModified()));
connect(ui_->doubleSpinBox_gainCompensationRadius, SIGNAL(valueChanged(double)), this, SLOT(configModified()));
connect(ui_->doubleSpinBox_gridCellSize, SIGNAL(valueChanged(double)), this, SLOT(configModified()));
connect(ui_->groupBox_posefiltering, SIGNAL(clicked(bool)), this, SLOT(configModified()));
connect(ui_->doubleSpinBox_posefilteringRadius, SIGNAL(valueChanged(double)), this, SLOT(configModified()));
@@ -392,6 +395,7 @@ void DatabaseViewer::readSettings()
ui_->checkBox_ignoreUserLoop->setChecked(settings.value("ignoreUserLoop", ui_->checkBox_ignoreUserLoop->isChecked()).toBool());
ui_->spinBox_optimizationDepth->setValue(settings.value("depth", ui_->spinBox_optimizationDepth->value()).toInt());
ui_->checkBox_gridErode->setChecked(settings.value("erode", ui_->checkBox_gridErode->isChecked()).toBool());
ui_->doubleSpinBox_gainCompensationRadius->setValue(settings.value("gainCompensationRadius", ui_->doubleSpinBox_gainCompensationRadius->value()).toDouble());
settings.endGroup();
settings.beginGroup("grid");
@@ -473,6 +477,7 @@ void DatabaseViewer::writeSettings()
//settings.setValue("slam2d", ui_->checkBox_2dslam->isChecked());
settings.setValue("depth", ui_->spinBox_optimizationDepth->value());
settings.setValue("erode", ui_->checkBox_gridErode->isChecked());
settings.setValue("gainCompensationRadius", ui_->doubleSpinBox_gainCompensationRadius->value());
settings.endGroup();
// save Grid settings
@@ -3285,13 +3290,33 @@ void DatabaseViewer::updateConstraintView(
if(ui_->checkBox_show3Dclouds->isChecked())
{
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloudFrom, cloudTo;
pcl::IndicesPtr indicesFrom(new std::vector<int>);
pcl::IndicesPtr indicesTo(new std::vector<int>);
if(!dataFrom.imageRaw().empty() && !dataFrom.depthOrRightRaw().empty())
{
cloudFrom=util3d::cloudRGBFromSensorData(dataFrom, 1, 0, 0, 0, ui_->parameters_toolbox->getParameters());
cloudFrom=util3d::cloudRGBFromSensorData(dataFrom, 1, 0, 0, indicesFrom.get(), ui_->parameters_toolbox->getParameters());
}
if(!dataTo.imageRaw().empty() && !dataTo.depthOrRightRaw().empty())
{
cloudTo=util3d::cloudRGBFromSensorData(dataTo, 1, 0, 0, 0, ui_->parameters_toolbox->getParameters());
cloudTo=util3d::cloudRGBFromSensorData(dataTo, 1, 0, 0, indicesTo.get(), ui_->parameters_toolbox->getParameters());
}
if(cloudTo.get() && cloudTo->size())
{
cloudTo = rtabmap::util3d::transformPointCloud(cloudTo, t);
}
// Gain compensation
if(ui_->doubleSpinBox_gainCompensationRadius->value()>0.0 &&
cloudFrom.get() && cloudFrom->size() &&
cloudTo.get() && cloudTo->size())
{
UTimer t;
GainCompensator compensator(ui_->doubleSpinBox_gainCompensationRadius->value());
compensator.feed(cloudFrom, indicesFrom, cloudTo, indicesTo, Transform::getIdentity());
compensator.apply(0, cloudFrom, indicesFrom);
compensator.apply(1, cloudTo, indicesTo);
UINFO("Gain compensation time = %fs", t.ticks());
}
if(cloudFrom.get() && cloudFrom->size())
@@ -3300,7 +3325,6 @@ void DatabaseViewer::updateConstraintView(
}
if(cloudTo.get() && cloudTo->size())
{
cloudTo = rtabmap::util3d::transformPointCloud(cloudTo, t);
constraintsViewer_->addCloud("cloud1", cloudTo, Transform::getIdentity(), Qt::cyan);
}
}
+197 -54
View File
@@ -40,6 +40,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "rtabmap/core/util3d_transforms.h"
#include "rtabmap/core/util3d.h"
#include "rtabmap/core/Graph.h"
#include "rtabmap/core/GainCompensator.h"
#include <pcl/conversions.h>
#include <pcl/io/pcd_io.h>
@@ -82,6 +83,7 @@ ExportCloudsDialog::ExportCloudsDialog(QWidget *parent) :
connect(_ui->spinBox_filteringMinNeighbors, SIGNAL(valueChanged(int)), this, SIGNAL(configChanged()));
connect(_ui->checkBox_assemble, SIGNAL(clicked(bool)), this, SIGNAL(configChanged()));
connect(_ui->checkBox_assemble, SIGNAL(clicked(bool)), this, SLOT(updateTexturingAvailability()));
connect(_ui->doubleSpinBox_voxelSize_assembled, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
connect(_ui->groupBox_subtraction, SIGNAL(clicked(bool)), this, SIGNAL(configChanged()));
@@ -100,13 +102,19 @@ ExportCloudsDialog::ExportCloudsDialog(QWidget *parent) :
_ui->stackedWidget_upsampling->setCurrentIndex(_ui->comboBox_upsamplingMethod->currentIndex());
connect(_ui->comboBox_upsamplingMethod, SIGNAL(currentIndexChanged(int)), _ui->stackedWidget_upsampling, SLOT(setCurrentIndex(int)));
connect(_ui->comboBox_upsamplingMethod, SIGNAL(currentIndexChanged(int)), this, SLOT(updateMLSGrpVisibility()));
updateMLSGrpVisibility();
connect(_ui->groupBox_gain, SIGNAL(clicked(bool)), this, SIGNAL(configChanged()));
connect(_ui->doubleSpinBox_gainRadius, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
connect(_ui->doubleSpinBox_gainOverlap, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
connect(_ui->doubleSpinBox_gainAlpha, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
connect(_ui->doubleSpinBox_gainBeta, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
connect(_ui->groupBox_meshing, SIGNAL(clicked(bool)), this, SIGNAL(configChanged()));
connect(_ui->doubleSpinBox_gp3Radius, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
connect(_ui->doubleSpinBox_gp3Mu, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
connect(_ui->doubleSpinBox_meshDecimationFactor, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
connect(_ui->checkBox_textureMapping, SIGNAL(stateChanged(int)), this, SIGNAL(configChanged()));
connect(_ui->checkBox_textureMapping, SIGNAL(stateChanged(int)), this, SLOT(updateTexturingAvailability()));
_progressDialog = new ProgressDialog(this);
_progressDialog->setVisible(false);
@@ -132,6 +140,14 @@ void ExportCloudsDialog::updateMLSGrpVisibility()
_ui->groupBox_5->setVisible(_ui->comboBox_upsamplingMethod->currentIndex() == 4);
}
void ExportCloudsDialog::updateTexturingAvailability()
{
_ui->checkBox_textureMapping->setEnabled(!_ui->checkBox_assemble->isChecked() || _ui->checkBox_binary->isVisible());
_ui->label_textureMapping->setEnabled(_ui->checkBox_textureMapping->isEnabled());
_ui->doubleSpinBox_meshDecimationFactor->setEnabled(!_ui->checkBox_textureMapping->isEnabled() || !_ui->checkBox_textureMapping->isChecked());
_ui->label_meshDecimation->setEnabled(_ui->doubleSpinBox_meshDecimationFactor->isEnabled());
}
void ExportCloudsDialog::saveSettings(QSettings & settings, const QString & group) const
{
if(!group.isEmpty())
@@ -170,6 +186,12 @@ void ExportCloudsDialog::saveSettings(QSettings & settings, const QString & grou
settings.setValue("mls_dilation_voxel_size", _ui->doubleSpinBox_dilationVoxelSize->value());
settings.setValue("mls_dilation_iterations", _ui->spinBox_dilationSteps->value());
settings.setValue("gain", _ui->groupBox_gain->isChecked());
settings.setValue("gain_radius", _ui->doubleSpinBox_gainRadius->value());
settings.setValue("gain_overlap", _ui->doubleSpinBox_gainOverlap->value());
settings.setValue("gain_alpha", _ui->doubleSpinBox_gainAlpha->value());
settings.setValue("gain_beta", _ui->doubleSpinBox_gainBeta->value());
settings.setValue("mesh", _ui->groupBox_meshing->isChecked());
settings.setValue("mesh_radius", _ui->doubleSpinBox_gp3Radius->value());
settings.setValue("mesh_mu", _ui->doubleSpinBox_gp3Mu->value());
@@ -226,6 +248,12 @@ void ExportCloudsDialog::loadSettings(QSettings & settings, const QString & grou
_ui->doubleSpinBox_dilationVoxelSize->setValue(settings.value("mls_dilation_voxel_size", _ui->doubleSpinBox_dilationVoxelSize->value()).toDouble());
_ui->spinBox_dilationSteps->setValue(settings.value("mls_dilation_iterations", _ui->spinBox_dilationSteps->value()).toInt());
_ui->groupBox_gain->setChecked(settings.value("gain", _ui->groupBox_gain->isChecked()).toBool());
_ui->doubleSpinBox_gainRadius->setValue(settings.value("gain_radius", _ui->doubleSpinBox_gainRadius->value()).toDouble());
_ui->doubleSpinBox_gainOverlap->setValue(settings.value("gain_overlap", _ui->doubleSpinBox_gainOverlap->value()).toDouble());
_ui->doubleSpinBox_gainAlpha->setValue(settings.value("gain_alpha", _ui->doubleSpinBox_gainAlpha->value()).toDouble());
_ui->doubleSpinBox_gainBeta->setValue(settings.value("gain_beta", _ui->doubleSpinBox_gainBeta->value()).toDouble());
_ui->groupBox_meshing->setChecked(settings.value("mesh", _ui->groupBox_meshing->isChecked()).toBool());
_ui->doubleSpinBox_gp3Radius->setValue(settings.value("mesh_radius", _ui->doubleSpinBox_gp3Radius->value()).toDouble());
_ui->doubleSpinBox_gp3Mu->setValue(settings.value("mesh_mu", _ui->doubleSpinBox_gp3Mu->value()).toDouble());
@@ -238,6 +266,10 @@ void ExportCloudsDialog::loadSettings(QSettings & settings, const QString & grou
_ui->checkBox_mesh_quad->setChecked(settings.value("mesh_quad", _ui->checkBox_mesh_quad->isChecked()).toBool());
_ui->spinBox_mesh_triangleSize->setValue(settings.value("mesh_triangle_size", _ui->spinBox_mesh_triangleSize->value()).toInt());
updateReconstructionFlavor();
updateTexturingAvailability();
updateMLSGrpVisibility();
if(!group.isEmpty())
{
settings.endGroup();
@@ -276,6 +308,12 @@ void ExportCloudsDialog::restoreDefaults()
_ui->doubleSpinBox_dilationVoxelSize->setValue(0.01);
_ui->spinBox_dilationSteps->setValue(0);
_ui->groupBox_gain->setChecked(true);
_ui->doubleSpinBox_gainRadius->setValue(0.02);
_ui->doubleSpinBox_gainOverlap->setValue(0.05);
_ui->doubleSpinBox_gainAlpha->setValue(0.01);
_ui->doubleSpinBox_gainBeta->setValue(10);
_ui->groupBox_meshing->setChecked(false);
_ui->doubleSpinBox_gp3Radius->setValue(0.04);
_ui->doubleSpinBox_gp3Mu->setValue(2.5);
@@ -288,6 +326,8 @@ void ExportCloudsDialog::restoreDefaults()
_ui->spinBox_mesh_triangleSize->setValue(2);
updateReconstructionFlavor();
updateTexturingAvailability();
updateMLSGrpVisibility();
this->update();
}
@@ -305,12 +345,10 @@ void ExportCloudsDialog::setSaveButton()
_ui->buttonBox->button(QDialogButtonBox::Save)->setVisible(true);
_ui->checkBox_binary->setVisible(true);
_ui->label_binaryFile->setVisible(true);
_ui->checkBox_textureMapping->setVisible(true);
_ui->checkBox_textureMapping->setEnabled(true);
_ui->label_textureMapping->setVisible(true);
_ui->checkBox_mesh_quad->setVisible(false);
_ui->checkBox_mesh_quad->setEnabled(false);
_ui->label_quad->setVisible(false);
updateTexturingAvailability();
}
void ExportCloudsDialog::setOkButton()
@@ -319,12 +357,10 @@ void ExportCloudsDialog::setOkButton()
_ui->buttonBox->button(QDialogButtonBox::Save)->setVisible(false);
_ui->checkBox_binary->setVisible(false);
_ui->label_binaryFile->setVisible(false);
_ui->checkBox_textureMapping->setVisible(false);
_ui->checkBox_textureMapping->setEnabled(false);
_ui->label_textureMapping->setVisible(false);
_ui->checkBox_mesh_quad->setVisible(true);
_ui->checkBox_mesh_quad->setEnabled(true);
_ui->label_quad->setVisible(true);
updateTexturingAvailability();
}
void ExportCloudsDialog::enableRegeneration(bool enabled)
@@ -338,6 +374,7 @@ void ExportCloudsDialog::enableRegeneration(bool enabled)
void ExportCloudsDialog::exportClouds(
const std::map<int, Transform> & poses,
const std::multimap<int, Link> & links,
const std::map<int, int> & mapIds,
const QMap<int, Signature> & cachedSignatures,
const std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGB>::Ptr, pcl::IndicesPtr> > & cachedClouds,
@@ -352,6 +389,7 @@ void ExportCloudsDialog::exportClouds(
if(getExportedClouds(
poses,
links,
mapIds,
cachedSignatures,
cachedClouds,
@@ -384,12 +422,17 @@ void ExportCloudsDialog::exportClouds(
{
saveClouds(workingDirectory, poses, clouds, _ui->checkBox_binary->isChecked());
}
_progressDialog->setValue(_progressDialog->maximumSteps());
}
else
{
_progressDialog->setAutoClose(false);
}
_progressDialog->setValue(_progressDialog->maximumSteps());
}
void ExportCloudsDialog::viewClouds(
const std::map<int, Transform> & poses,
const std::multimap<int, Link> & links,
const std::map<int, int> & mapIds,
const QMap<int, Signature> & cachedSignatures,
const std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGB>::Ptr, pcl::IndicesPtr> > & cachedClouds,
@@ -404,6 +447,7 @@ void ExportCloudsDialog::viewClouds(
if(getExportedClouds(
poses,
links,
mapIds,
cachedSignatures,
cachedClouds,
@@ -442,7 +486,34 @@ void ExportCloudsDialog::viewClouds(
uSleep(500);
if(meshes.size())
if(textureMeshes.size())
{
for(std::map<int, pcl::TextureMesh::Ptr>::iterator iter = textureMeshes.begin(); iter!=textureMeshes.end(); ++iter)
{
_progressDialog->appendText(tr("Viewing the mesh %1 (%2 polygons)...").arg(iter->first).arg(iter->second->tex_polygons.size()?iter->second->tex_polygons[0].size():0));
_progressDialog->incrementStep();
bool isRGB = false;
for(unsigned int i=0; i<iter->second->cloud.fields.size(); ++i)
{
if(iter->second->cloud.fields[i].name.compare("rgb") == 0)
{
isRGB=true;
break;
}
}
if(isRGB)
{
viewer->addCloudTextureMesh(uFormat("mesh%d",iter->first), iter->second, iter->first>0?poses.at(iter->first):Transform::getIdentity());
}
else
{
viewer->addCloudTextureMesh(uFormat("mesh%d",iter->first), iter->second, iter->first>0?poses.at(iter->first):Transform::getIdentity());
}
_progressDialog->appendText(tr("Viewing the mesh %1 (%2 polygons)... done.").arg(iter->first).arg(iter->second->tex_polygons.size()?iter->second->tex_polygons[0].size():0));
QApplication::processEvents();
}
}
else if(meshes.size())
{
for(std::map<int, pcl::PolygonMesh::Ptr>::iterator iter = meshes.begin(); iter!=meshes.end(); ++iter)
{
@@ -490,13 +561,16 @@ void ExportCloudsDialog::viewClouds(
_progressDialog->appendText(tr("Viewing the cloud %1 (%2 points)... done.").arg(iter->first).arg(iter->second->size()));
}
}
_progressDialog->setValue(_progressDialog->maximumSteps());
viewer->update();
}
else
{
_progressDialog->setAutoClose(false);
}
_progressDialog->setValue(_progressDialog->maximumSteps());
}
bool removeDirRecursively(const QString & dirName)
bool ExportCloudsDialog::removeDirRecursively(const QString & dirName)
{
bool result = true;
QDir dir(dirName);
@@ -521,6 +595,7 @@ bool removeDirRecursively(const QString & dirName)
bool ExportCloudsDialog::getExportedClouds(
const std::map<int, Transform> & poses,
const std::multimap<int, Link> & links,
const std::map<int, int> & mapIds,
const QMap<int, Signature> & cachedSignatures,
const std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGB>::Ptr, pcl::IndicesPtr> > & cachedClouds,
@@ -533,6 +608,11 @@ bool ExportCloudsDialog::getExportedClouds(
enableRegeneration(cachedSignatures.size());
if(this->exec() == QDialog::Accepted)
{
if(poses.empty())
{
QMessageBox::critical(this, tr("Creating clouds..."), tr("Poses are null! Cannot export/view clouds."));
return false;
}
_progressDialog->resetProgress();
_progressDialog->show();
int mul = 1;
@@ -554,6 +634,14 @@ bool ExportCloudsDialog::getExportedClouds(
{
mul+=1;
}
if(_ui->groupBox_gain->isChecked())
{
mul+=1;
}
if(_ui->checkBox_mesh_quad->isEnabled()) // when enabled we are viewing the clouds
{
mul+=1;
}
_progressDialog->setMaximumSteps(int(poses.size())*mul+1);
std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr, pcl::IndicesPtr> > clouds = this->getClouds(
@@ -562,6 +650,46 @@ bool ExportCloudsDialog::getExportedClouds(
cachedClouds,
parameters);
if(clouds.empty())
{
_progressDialog->setAutoClose(false);
if(_ui->groupBox_regenerate->isEnabled() && !_ui->groupBox_regenerate->isChecked())
{
QMessageBox::warning(this, tr("Creating clouds..."), tr("Could create clouds for %1 node(s). You "
"may want to activate clouds regeneration option.").arg(poses.size()));
}
else
{
QMessageBox::warning(this, tr("Creating clouds..."), tr("Could not create clouds for %1 "
"node(s). The cache may not contain point cloud data. Try re-downloading the map.").arg(poses.size()));
}
return false;
}
GainCompensator compensator(_ui->doubleSpinBox_gainRadius->value(), _ui->doubleSpinBox_gainOverlap->value(), _ui->doubleSpinBox_gainAlpha->value(), _ui->doubleSpinBox_gainBeta->value());
if(_ui->groupBox_gain->isChecked() && clouds.size() > 1)
{
_progressDialog->appendText(tr("Gain compensation of %1 clouds...").arg(clouds.size()));
QApplication::processEvents();
QApplication::processEvents();
compensator.feed(clouds, links);
_progressDialog->appendText(tr("Applying gain compensation..."));
for(std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr, pcl::IndicesPtr> >::iterator jter=clouds.begin();jter!=clouds.end(); ++jter)
{
if(jter!=clouds.end())
{
double gain = compensator.getGain(jter->first);;
compensator.apply(jter->first, jter->second.first, jter->second.second);
_progressDialog->appendText(tr("Cloud %1 has gain %2").arg(jter->first).arg(gain));
_progressDialog->incrementStep();
QApplication::processEvents();
}
}
}
pcl::PointCloud<pcl::PointXYZ>::Ptr rawAssembledCloud(new pcl::PointCloud<pcl::PointXYZ>);
std::vector<int> rawCameraIndices;
if(_ui->checkBox_assemble->isChecked() &&
@@ -707,7 +835,8 @@ bool ExportCloudsDialog::getExportedClouds(
}
//used for organized texturing below
std::map<int, std::pair<std::map<int, int>, std::pair<int, int> > > organizedIndices;
std::map<int, std::map<int, int> > organizedIndices;
std::map<int, cv::Size> organizedCloudSizes;
//mesh
UDEBUG("Meshing=%d", _ui->groupBox_meshing->isChecked()?1:0);
@@ -808,7 +937,8 @@ bool ExportCloudsDialog::getExportedClouds(
}
else
{
organizedIndices.insert(std::make_pair(iter->first, std::make_pair(newToOldIndices, std::make_pair(iter->second->width, iter->second->height))));
organizedIndices.insert(std::make_pair(iter->first, newToOldIndices));
organizedCloudSizes.insert(std::make_pair(iter->first, cv::Size(iter->second->width, iter->second->height)));
}
meshes.insert(std::make_pair(iter->first, mesh));
}
@@ -995,6 +1125,10 @@ bool ExportCloudsDialog::getExportedClouds(
{
cameraPoses.insert(std::make_pair(jter->first, jter->second));
cameraModels.insert(std::make_pair(jter->first, model));
if(_ui->groupBox_gain->isChecked() && compensator.getIndex(jter->first) >= 0)
{
compensator.apply(jter->first, image);
}
images.insert(std::make_pair(jter->first, image));
}
}
@@ -1002,34 +1136,57 @@ bool ExportCloudsDialog::getExportedClouds(
if(cameraPoses.size())
{
pcl::TextureMesh::Ptr textureMesh(new pcl::TextureMesh);
std::map<int, std::pair<std::map<int, int>, std::pair<int, int> > >::iterator oter = organizedIndices.find(iter->first);
std::map<int, std::map<int, int> >::iterator oter = organizedIndices.find(iter->first);
std::map<int, cv::Size>::iterator ster = organizedCloudSizes.find(iter->first);
if(iter->first != 0 && oter != organizedIndices.end())
{
UASSERT(ster!=organizedCloudSizes.end()&&ster->first == oter->first);
UDEBUG("Texture by pixels");
textureMesh->cloud = iter->second->cloud;
textureMesh->tex_polygons.push_back(iter->second->polygons);
int w = oter->second.second.first;
int h = oter->second.second.second;
int w = ster->second.width;
int h = ster->second.height;
UASSERT(w > 1 && h > 1);
UASSERT(textureMesh->tex_polygons.size() && textureMesh->tex_polygons[0].size());
textureMesh->tex_coordinates.resize(1);
int polygonSize = textureMesh->tex_polygons[0][0].vertices.size();
textureMesh->tex_coordinates[0].resize(polygonSize*textureMesh->tex_polygons[0].size());
for(unsigned int i=0; i<textureMesh->tex_polygons[0].size(); ++i)
if(!_ui->checkBox_mesh_quad->isEnabled()) // disabled -> we are exporting to file
{
const pcl::Vertices & vertices = textureMesh->tex_polygons[0][i];
UASSERT(polygonSize == (int)vertices.vertices.size());
for(int k=0; k<polygonSize; ++k)
// When saving to file, tex_coordinates should be linked to polygon vertices, not points
int polygonSize = textureMesh->tex_polygons[0][0].vertices.size();
textureMesh->tex_coordinates[0].resize(polygonSize*textureMesh->tex_polygons[0].size());
for(unsigned int i=0; i<textureMesh->tex_polygons[0].size(); ++i)
{
const pcl::Vertices & vertices = textureMesh->tex_polygons[0][i];
UASSERT(polygonSize == (int)vertices.vertices.size());
for(int k=0; k<polygonSize; ++k)
{
//uv
std::map<int, int>::iterator vter = oter->second.find(vertices.vertices[k]);
UASSERT(vter != oter->second.end());
int originalVertex = vter->second;
textureMesh->tex_coordinates[0][i*polygonSize+k] = Eigen::Vector2f(
float(originalVertex % w) / float(w), // u
float(h - originalVertex / w) / float(h)); // v
}
}
}
else
{
int nPoints = textureMesh->cloud.data.size()/textureMesh->cloud.point_step;
textureMesh->tex_coordinates[0].resize(nPoints);
for(int i=0; i<nPoints; ++i)
{
//uv
std::map<int, int>::iterator vter = oter->second.first.find(vertices.vertices[k]);
UASSERT(vter != oter->second.first.end());
std::map<int, int>::iterator vter = oter->second.find(i);
UASSERT(vter != oter->second.end());
int originalVertex = vter->second;
textureMesh->tex_coordinates[0][i*polygonSize+k] = Eigen::Vector2f(
float(originalVertex % w) / float(w), // u
textureMesh->tex_coordinates[0][i] = Eigen::Vector2f(
float(originalVertex % w) / float(w), // u
float(h - originalVertex / w) / float(h)); // v
}
}
pcl::TexMaterial mesh_material;
mesh_material.tex_d = 1.0f;
mesh_material.tex_Ns = 75.0f;
@@ -1101,11 +1258,11 @@ std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr, pcl::Indic
const ParametersMap & parameters) const
{
std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr, pcl::IndicesPtr> > clouds;
int i=0;
int index=1;
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr previousCloud;
pcl::IndicesPtr previousIndices;
Transform previousPose;
for(std::map<int, Transform>::const_iterator iter = poses.begin(); iter!=poses.end(); ++iter)
for(std::map<int, Transform>::const_iterator iter = poses.begin(); iter!=poses.end(); ++iter, ++index)
{
int points = 0;
int totalIndices = 0;
@@ -1134,7 +1291,7 @@ std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr, pcl::Indic
parameters);
// Don't voxelize if we create organized mesh
if(!(_ui->comboBox_pipeline->currentIndex()==0 && _ui->groupBox_meshing->isChecked()))
if(!(_ui->comboBox_pipeline->currentIndex()==0 && _ui->groupBox_meshing->isChecked()) && _ui->doubleSpinBox_voxelSize_assembled->value()>0.0)
{
cloudWithoutNormals = util3d::voxelize(cloudWithoutNormals, indices, _ui->doubleSpinBox_voxelSize_assembled->value());
indices->resize(cloudWithoutNormals->size());
@@ -1187,23 +1344,6 @@ std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr, pcl::Indic
previousIndices = beforeSubtractionIndices;
previousPose = iter->second;
}
}
else if(s.getWords3().size())
{
cloud->resize(s.getWords3().size());
int oi=0;
indices->resize(cloud->size());
for(std::multimap<int, cv::Point3f>::const_iterator jter=s.getWords3().begin(); jter!=s.getWords3().end(); ++jter)
{
indices->at(oi) = oi;
(*cloud)[oi].x = jter->second.x;
(*cloud)[oi].y = jter->second.y;
(*cloud)[oi].z = jter->second.z;
(*cloud)[oi].r = 255;
(*cloud)[oi].g = 255;
(*cloud)[oi++].b = 255;
}
}
}
else
@@ -1256,7 +1396,7 @@ std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr, pcl::Indic
}
else
{
_progressDialog->appendText(tr("Cached cloud %1 is not found in cached data, the view point for normal computation will not be set (%2/%3).").arg(iter->first).arg(++i).arg(poses.size()));
_progressDialog->appendText(tr("Cached cloud %1 is not found in cached data, the view point for normal computation will not be set (%2/%3).").arg(iter->first).arg(index).arg(poses.size()), Qt::darkYellow);
}
pcl::PointCloud<pcl::Normal>::Ptr normals = util3d::computeNormals(cloudWithoutNormals, indices, _ui->spinBox_normalKSearch->value(), viewPoint);
@@ -1264,7 +1404,7 @@ std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr, pcl::Indic
}
else
{
_progressDialog->appendText(tr("Cached cloud %1 not found. You may want to regenerate the clouds (%2/%3).").arg(iter->first).arg(++i).arg(poses.size()));
_progressDialog->appendText(tr("Cached cloud %1 not found. You may want to regenerate the clouds (%2/%3).").arg(iter->first).arg(index).arg(poses.size()), Qt::darkYellow);
}
if(indices->size())
@@ -1291,17 +1431,17 @@ std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr, pcl::Indic
if(_ui->groupBox_regenerate->isChecked())
{
_progressDialog->appendText(tr("Generated cloud %1 with %2 points and %3 indices (%4/%5).")
.arg(iter->first).arg(points).arg(totalIndices).arg(++i).arg(poses.size()));
.arg(iter->first).arg(points).arg(totalIndices).arg(index).arg(poses.size()));
}
else
{
_progressDialog->appendText(tr("Copied cloud %1 from cache with %2 points and %3 indices (%4/%5).")
.arg(iter->first).arg(points).arg(totalIndices).arg(++i).arg(poses.size()));
.arg(iter->first).arg(points).arg(totalIndices).arg(index).arg(poses.size()));
}
}
else
{
_progressDialog->appendText(tr("Ignored cloud %1 (%2/%3).").arg(iter->first).arg(++i).arg(poses.size()));
_progressDialog->appendText(tr("Ignored cloud %1 (%2/%3).").arg(iter->first).arg(index).arg(poses.size()));
}
_progressDialog->incrementStep();
QApplication::processEvents();
@@ -1407,7 +1547,8 @@ void ExportCloudsDialog::saveClouds(
}
else
{
_progressDialog->appendText(tr("Failed saving cloud %1 (%2 points) to %3.").arg(iter->first).arg(iter->second->size()).arg(pathFile));
_progressDialog->appendText(tr("Failed saving cloud %1 (%2 points) to %3.").arg(iter->first).arg(iter->second->size()).arg(pathFile), Qt::darkRed);
_progressDialog->setAutoClose(false);
}
}
else
@@ -1559,7 +1700,8 @@ void ExportCloudsDialog::saveMeshes(
else
{
_progressDialog->appendText(tr("Failed saving mesh %1 (%2 polygons) to %3.")
.arg(iter->first).arg(iter->second->polygons.size()).arg(pathFile));
.arg(iter->first).arg(iter->second->polygons.size()).arg(pathFile), Qt::darkRed);
_progressDialog->setAutoClose(false);
}
}
else
@@ -1698,6 +1840,7 @@ void ExportCloudsDialog::saveTextureMeshes(
{
_progressDialog->appendText(tr("Failed saving mesh %1 (%2 textures) to %3.")
.arg(iter->first).arg(iter->second->tex_materials.size()-1).arg(pathFile), Qt::darkRed);
_progressDialog->setAutoClose(false);
}
}
else
+6
View File
@@ -61,6 +61,7 @@ public:
void exportClouds(
const std::map<int, Transform> & poses,
const std::multimap<int, Link> & links,
const std::map<int, int> & mapIds,
const QMap<int, Signature> & cachedSignatures,
const std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGB>::Ptr, pcl::IndicesPtr> > & cachedClouds,
@@ -69,12 +70,15 @@ public:
void viewClouds(
const std::map<int, Transform> & poses,
const std::multimap<int, Link> & links,
const std::map<int, int> & mapIds,
const QMap<int, Signature> & cachedSignatures,
const std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGB>::Ptr, pcl::IndicesPtr> > & cachedClouds,
const QString & workingDirectory,
const ParametersMap & parameters);
static bool removeDirRecursively(const QString & dirName);
signals:
void configChanged();
@@ -84,6 +88,7 @@ public slots:
private slots:
void updateReconstructionFlavor();
void updateMLSGrpVisibility();
void updateTexturingAvailability();
private:
std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr, pcl::IndicesPtr> > getClouds(
@@ -93,6 +98,7 @@ private:
const ParametersMap & parameters) const;
bool getExportedClouds(
const std::map<int, Transform> & poses,
const std::multimap<int, Link> & links,
const std::map<int, int> & mapIds,
const QMap<int, Signature> & cachedSignatures,
const std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGB>::Ptr, pcl::IndicesPtr> > & cachedClouds,
+171 -46
View File
@@ -41,6 +41,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "rtabmap/core/DBDriver.h"
#include "rtabmap/core/RegistrationVis.h"
#include "rtabmap/core/OccupancyGrid.h"
#include "rtabmap/core/GainCompensator.h"
#include "rtabmap/gui/ImageView.h"
#include "rtabmap/gui/KeypointItem.h"
@@ -984,7 +985,55 @@ void MainWindow::processOdometry(const rtabmap::OdometryEvent & odom, bool dataI
Eigen::Vector3f(pose.x(), pose.y(), pose.z()) + viewpoint);
if(polygons.size())
{
if(!_cloudViewer->addCloudMesh("cloudOdom", output, polygons, _odometryCorrection))
if(_preferencesDialog->isCloudMeshingTexture() && !odom.data().imageRaw().empty())
{
pcl::TextureMesh::Ptr textureMesh(new pcl::TextureMesh);
pcl::toPCLPointCloud2(*cloud, textureMesh->cloud);
textureMesh->tex_polygons.push_back(polygons);
int w = cloud->width;
int h = cloud->height;
UASSERT(w > 1 && h > 1);
textureMesh->tex_coordinates.resize(1);
int nPoints = textureMesh->cloud.data.size()/textureMesh->cloud.point_step;
textureMesh->tex_coordinates[0].resize(nPoints);
for(int i=0; i<nPoints; ++i)
{
//uv
textureMesh->tex_coordinates[0][i] = Eigen::Vector2f(
float(i % w) / float(w), // u
float(h - i / w) / float(h)); // v
}
pcl::TexMaterial mesh_material;
mesh_material.tex_d = 1.0f;
mesh_material.tex_Ns = 75.0f;
mesh_material.tex_illum = 1;
mesh_material.tex_name = "material_odom";
QDir dir(_preferencesDialog->getWorkingDirectory());
ExportCloudsDialog::removeDirRecursively(_preferencesDialog->getWorkingDirectory()+QDir::separator()+"tmp_textures");
dir.mkdir("tmp_textures");
std::string tmpDirectory = dir.filePath("tmp_textures").toStdString();
mesh_material.tex_file = uFormat("%s/%s.png", tmpDirectory.c_str(), "texture_odom");
if(!cv::imwrite(mesh_material.tex_file, odom.data().imageRaw()))
{
UERROR("Cannot save texture of image odom");
}
else
{
UINFO("Saved temporary texture: \"%s\"", mesh_material.tex_file.c_str());
}
textureMesh->tex_materials.push_back(mesh_material);
if(!_cloudViewer->addCloudTextureMesh("cloudOdom", textureMesh, _odometryCorrection))
{
UERROR("Adding cloudOdom to viewer failed!");
}
}
else if(!_cloudViewer->addCloudMesh("cloudOdom", output, polygons, _odometryCorrection))
{
UERROR("Adding cloudOdom to viewer failed!");
}
@@ -2477,8 +2526,10 @@ std::pair<pcl::PointCloud<pcl::PointXYZRGB>::Ptr, pcl::IndicesPtr> MainWindow::c
}
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr cloudWithNormals(new pcl::PointCloud<pcl::PointXYZRGBNormal>);
if(_preferencesDialog->isSubtractFiltering() &&
_preferencesDialog->getSubtractFilteringRadius() > 0.0)
GainCompensator compensator;
if((_preferencesDialog->isSubtractFiltering() &&
_preferencesDialog->getSubtractFilteringRadius() > 0.0) ||
_preferencesDialog->gainCompensation())
{
pcl::IndicesPtr beforeFiltering = indices;
if( cloud->size() &&
@@ -2496,53 +2547,63 @@ std::pair<pcl::PointCloud<pcl::PointXYZRGB>::Ptr, pcl::IndicesPtr> MainWindow::c
//pcl::io::savePCDFile("new.pcd", *cloud, *indices);
//pcl::io::savePCDFile("old.pcd", *previousCloud, *_previousCloud.second.second);
if(_preferencesDialog->getSubtractFilteringAngle() > 0.0f)
if(_preferencesDialog->gainCompensation())
{
//normals required
if(_preferencesDialog->getNormalKSearch() > 0)
compensator.feed(cloud, indices, _previousCloud.second.first.first, _previousCloud.second.second, t);
compensator.apply(0, cloud, indices);
UINFO("Time gain compensation = %fs", time.ticks());
}
if(_preferencesDialog->isSubtractFiltering())
{
if(_preferencesDialog->getSubtractFilteringAngle() > 0.0f)
{
pcl::PointCloud<pcl::Normal>::Ptr normals = util3d::computeNormals(cloud, indices, _preferencesDialog->getNormalKSearch(), viewPoint);
pcl::concatenateFields(*cloud, *normals, *cloudWithNormals);
//normals required
if(_preferencesDialog->getNormalKSearch() > 0)
{
pcl::PointCloud<pcl::Normal>::Ptr normals = util3d::computeNormals(cloud, indices, _preferencesDialog->getNormalKSearch(), viewPoint);
pcl::concatenateFields(*cloud, *normals, *cloudWithNormals);
}
else
{
UWARN("Cloud subtraction with angle filtering is activated but "
"cloud normal K search is 0. Subtraction is done with angle.");
}
}
if(cloudWithNormals->size() &&
_previousCloud.second.first.second.get() &&
_previousCloud.second.first.second->size())
{
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr previousCloud = rtabmap::util3d::transformPointCloud(_previousCloud.second.first.second, t);
indices = rtabmap::util3d::subtractFiltering(
cloudWithNormals,
indices,
previousCloud,
_previousCloud.second.second,
_preferencesDialog->getSubtractFilteringRadius(),
_preferencesDialog->getSubtractFilteringAngle(),
_preferencesDialog->getSubtractFilteringMinPts());
}
else
{
UWARN("Cloud subtraction with angle filtering is activated but "
"cloud normal K search is 0. Subtraction is done with angle.");
pcl::PointCloud<pcl::PointXYZRGB>::Ptr previousCloud = rtabmap::util3d::transformPointCloud(_previousCloud.second.first.first, t);
indices = rtabmap::util3d::subtractFiltering(
cloud,
indices,
previousCloud,
_previousCloud.second.second,
_preferencesDialog->getSubtractFilteringRadius(),
_preferencesDialog->getSubtractFilteringMinPts());
}
}
if(cloudWithNormals->size() &&
_previousCloud.second.first.second.get() &&
_previousCloud.second.first.second->size())
{
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr previousCloud = rtabmap::util3d::transformPointCloud(_previousCloud.second.first.second, t);
indices = rtabmap::util3d::subtractFiltering(
cloudWithNormals,
indices,
previousCloud,
_previousCloud.second.second,
_preferencesDialog->getSubtractFilteringRadius(),
_preferencesDialog->getSubtractFilteringAngle(),
_preferencesDialog->getSubtractFilteringMinPts());
}
else
{
pcl::PointCloud<pcl::PointXYZRGB>::Ptr previousCloud = rtabmap::util3d::transformPointCloud(_previousCloud.second.first.first, t);
indices = rtabmap::util3d::subtractFiltering(
cloud,
indices,
previousCloud,
_previousCloud.second.second,
_preferencesDialog->getSubtractFilteringRadius(),
_preferencesDialog->getSubtractFilteringMinPts());
}
UINFO("Time subtract filtering %d from %d -> %d (%fs)",
(int)_previousCloud.second.second->size(),
(int)beforeFiltering->size(),
(int)indices->size(),
time.ticks());
UINFO("Time subtract filtering %d from %d -> %d (%fs)",
(int)_previousCloud.second.second->size(),
(int)beforeFiltering->size(),
(int)indices->size(),
time.ticks());
}
}
// keep all indices for next subtraction
_previousCloud.first = nodeId;
@@ -2571,8 +2632,70 @@ std::pair<pcl::PointCloud<pcl::PointXYZRGB>::Ptr, pcl::IndicesPtr> MainWindow::c
// remove unused vertices to save memory
pcl::PointCloud<pcl::PointXYZRGB>::Ptr outputFiltered(new pcl::PointCloud<pcl::PointXYZRGB>);
std::vector<pcl::Vertices> outputPolygons;
util3d::filterNotUsedVerticesFromMesh(*output, polygons, *outputFiltered, outputPolygons);
if(!_cloudViewer->addCloudMesh(cloudName, outputFiltered, outputPolygons, pose))
std::map<int, int> newToOldIndices = util3d::filterNotUsedVerticesFromMesh(*output, polygons, *outputFiltered, outputPolygons);
if(_preferencesDialog->isCloudMeshingTexture() && !image.empty())
{
pcl::TextureMesh::Ptr textureMesh(new pcl::TextureMesh);
pcl::toPCLPointCloud2(*outputFiltered, textureMesh->cloud);
textureMesh->tex_polygons.push_back(outputPolygons);
int w = cloud->width;
int h = cloud->height;
UASSERT(w > 1 && h > 1);
textureMesh->tex_coordinates.resize(1);
int nPoints = textureMesh->cloud.data.size()/textureMesh->cloud.point_step;
textureMesh->tex_coordinates[0].resize(nPoints);
for(int i=0; i<nPoints; ++i)
{
//uv
std::map<int, int>::iterator vter = newToOldIndices.find(i);
UASSERT(vter != newToOldIndices.end());
int originalVertex = vter->second;
textureMesh->tex_coordinates[0][i] = Eigen::Vector2f(
float(originalVertex % w) / float(w), // u
float(h - originalVertex / w) / float(h)); // v
}
pcl::TexMaterial mesh_material;
mesh_material.tex_d = 1.0f;
mesh_material.tex_Ns = 75.0f;
mesh_material.tex_illum = 1;
std::stringstream tex_name;
tex_name << "material_" << nodeId;
tex_name >> mesh_material.tex_name;
QDir dir(_preferencesDialog->getWorkingDirectory());
ExportCloudsDialog::removeDirRecursively(_preferencesDialog->getWorkingDirectory()+QDir::separator()+"tmp_textures");
dir.mkdir("tmp_textures");
std::string tmpDirectory = dir.filePath("tmp_textures").toStdString();
mesh_material.tex_file = uFormat("%s/%s%d.png", tmpDirectory.c_str(), "texture_", nodeId);
if(_preferencesDialog->gainCompensation() && compensator.getIndex(0) >= 0)
{
compensator.apply(0, image);
}
if(!cv::imwrite(mesh_material.tex_file, image))
{
UERROR("Cannot save texture of image %d", nodeId);
}
else
{
UINFO("Saved temporary texture: \"%s\"", mesh_material.tex_file.c_str());
}
textureMesh->tex_materials.push_back(mesh_material);
if(!_cloudViewer->addCloudTextureMesh(cloudName, textureMesh, pose))
{
UERROR("Adding texture mesh %d to viewer failed!", nodeId);
}
else
{
added = true;
}
}
else if(!_cloudViewer->addCloudMesh(cloudName, outputFiltered, outputPolygons, pose))
{
UERROR("Adding mesh cloud %d to viewer failed!", nodeId);
}
@@ -3036,7 +3159,7 @@ void MainWindow::processRtabmapEventInit(int status, const QString & info)
{
UINFO("Deleted temporary database \"%s\".", _newDatabasePath.toStdString().c_str());
}
else
else if(!uStr2Bool(_preferencesDialog->getAllParameters().at(Parameters::kDbSqlite3InMemory())))
{
UERROR("Temporary database \"%s\" could not be deleted.", _newDatabasePath.toStdString().c_str());
}
@@ -5435,6 +5558,7 @@ void MainWindow::exportClouds()
_exportCloudsDialog->exportClouds(
_ui->widget_mapVisibility->getVisiblePoses(),
_currentLinksMap,
_currentMapIds,
_cachedSignatures,
_cachedClouds,
@@ -5450,7 +5574,8 @@ void MainWindow::viewClouds()
}
_exportCloudsDialog->viewClouds(
_currentPosesMap,
_ui->widget_mapVisibility->getVisiblePoses(),
_currentLinksMap,
_currentMapIds,
_cachedSignatures,
_cachedClouds,
+1 -1
View File
@@ -141,7 +141,7 @@ void PostProcessingDialog::restoreDefaults()
setDetectMoreLoopClosures(true);
setClusterRadius(0.5);
setClusterAngle(30);
setIterations(1);
setIterations(3);
setRefineNeighborLinks(false);
setRefineLoopClosureLinks(false);
setSBA(false);
+27 -3
View File
@@ -365,6 +365,7 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
connect(_ui->doubleSpinBox_subtractFilteringRadius, SIGNAL(valueChanged(double)), this, SLOT(makeObsoleteCloudRenderingPanel()));
connect(_ui->doubleSpinBox_subtractFilteringAngle, SIGNAL(valueChanged(double)), this, SLOT(makeObsoleteCloudRenderingPanel()));
connect(_ui->spinBox_normalKSearch, SIGNAL(valueChanged(int)), this, SLOT(makeObsoleteCloudRenderingPanel()));
connect(_ui->checkBox_gainCompensation, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteCloudRenderingPanel()));
connect(_ui->checkBox_map_shown, SIGNAL(clicked(bool)), this, SLOT(makeObsoleteCloudRenderingPanel()));
connect(_ui->doubleSpinBox_map_resolution, SIGNAL(valueChanged(double)), this, SLOT(makeObsoleteCloudRenderingPanel()));
@@ -380,6 +381,7 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
connect(_ui->groupBox_organized, SIGNAL(toggled(bool)), this, SLOT(makeObsoleteCloudRenderingPanel()));
connect(_ui->doubleSpinBox_mesh_angleTolerance, SIGNAL(valueChanged(double)), this, SLOT(makeObsoleteCloudRenderingPanel()));
connect(_ui->checkBox_mesh_quad, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteCloudRenderingPanel()));
connect(_ui->checkBox_mesh_texture, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteCloudRenderingPanel()));
connect(_ui->spinBox_mesh_triangleSize, SIGNAL(valueChanged(int)), this, SLOT(makeObsoleteCloudRenderingPanel()));
//Logging panel
@@ -1210,15 +1212,16 @@ void PreferencesDialog::resetSettings(QGroupBox * groupBox)
_ui->checkBox_showLabels->setChecked(false);
_ui->spinBox_normalKSearch->setValue(10);
_ui->checkBox_gainCompensation->setChecked(false);
_ui->doubleSpinBox_mesh_angleTolerance->setValue(15.0);
#if PCL_VERSION_COMPARE(>=, 1, 7, 2)
_ui->groupBox_organized->setChecked(false);
#if PCL_VERSION_COMPARE(>=, 1, 7, 2)
_ui->checkBox_mesh_quad->setChecked(true);
#else
_ui->groupBox_organized->setChecked(false);
_ui->checkBox_mesh_quad->setChecked(false);
#endif
_ui->checkBox_mesh_texture->setChecked(false);
_ui->spinBox_mesh_triangleSize->setValue(2);
}
else if(groupBox->objectName() == _ui->groupBox_filtering2->objectName())
@@ -1585,6 +1588,7 @@ void PreferencesDialog::readGuiSettings(const QString & filePath)
_ui->doubleSpinBox_subtractFilteringRadius->setValue(settings.value("subtractFilteringRadius", _ui->doubleSpinBox_subtractFilteringRadius->value()).toDouble());
_ui->doubleSpinBox_subtractFilteringAngle->setValue(settings.value("subtractFilteringAngle", _ui->doubleSpinBox_subtractFilteringAngle->value()).toDouble());
_ui->spinBox_normalKSearch->setValue(settings.value("normalKSearch", _ui->spinBox_normalKSearch->value()).toInt());
_ui->checkBox_gainCompensation->setChecked(settings.value("gainCompensation", _ui->checkBox_gainCompensation->isChecked()).toBool());
_ui->checkBox_map_shown->setChecked(settings.value("gridMapShown", _ui->checkBox_map_shown->isChecked()).toBool());
_ui->doubleSpinBox_map_resolution->setValue(settings.value("gridMapResolution", _ui->doubleSpinBox_map_resolution->value()).toDouble());
@@ -1602,6 +1606,7 @@ void PreferencesDialog::readGuiSettings(const QString & filePath)
_ui->groupBox_organized->setChecked(settings.value("meshing", _ui->groupBox_organized->isChecked()).toBool());
_ui->doubleSpinBox_mesh_angleTolerance->setValue(settings.value("meshing_angle", _ui->doubleSpinBox_mesh_angleTolerance->value()).toDouble());
_ui->checkBox_mesh_quad->setChecked(settings.value("meshing_quad", _ui->checkBox_mesh_quad->isChecked()).toBool());
_ui->checkBox_mesh_texture->setChecked(settings.value("meshing_texture", _ui->checkBox_mesh_texture->isChecked()).toBool());
_ui->spinBox_mesh_triangleSize->setValue(settings.value("meshing_triangle_size", _ui->spinBox_mesh_triangleSize->value()).toInt());
settings.endGroup(); // General
@@ -1925,7 +1930,16 @@ void PreferencesDialog::writeSettings(const QString & filePath)
for(ParametersMap::iterator iter = _modifiedParameters.begin(); iter!=_modifiedParameters.end(); ++iter)
{
if( _parameters.at(iter->first).compare(iter->second) != 0)
bool different = true;
if(Parameters::getType(iter->first).compare("double") ==0 ||
Parameters::getType(iter->first).compare("float") == 0)
{
if(uStr2Double(_parameters.at(iter->first)) == uStr2Double(iter->second))
{
different = false;
}
}
if(different)
{
UINFO("modified %s = %s->%s", iter->first.c_str(), _parameters.at(iter->first).c_str(), iter->second.c_str());
}
@@ -1998,6 +2012,7 @@ void PreferencesDialog::writeGuiSettings(const QString & filePath) const
settings.setValue("subtractFilteringRadius", _ui->doubleSpinBox_subtractFilteringRadius->value());
settings.setValue("subtractFilteringAngle", _ui->doubleSpinBox_subtractFilteringAngle->value());
settings.setValue("normalKSearch", _ui->spinBox_normalKSearch->value());
settings.setValue("gainCompensation", _ui->checkBox_gainCompensation->isChecked());
settings.setValue("gridMapShown", _ui->checkBox_map_shown->isChecked());
settings.setValue("gridMapResolution", _ui->doubleSpinBox_map_resolution->value());
@@ -2016,6 +2031,7 @@ void PreferencesDialog::writeGuiSettings(const QString & filePath) const
settings.setValue("meshing", _ui->groupBox_organized->isChecked());
settings.setValue("meshing_angle", _ui->doubleSpinBox_mesh_angleTolerance->value());
settings.setValue("meshing_quad", _ui->checkBox_mesh_quad->isChecked());
settings.setValue("meshing_texture", _ui->checkBox_mesh_texture->isChecked());
settings.setValue("meshing_triangle_size", _ui->spinBox_mesh_triangleSize->value());
settings.endGroup(); // General
@@ -3759,6 +3775,10 @@ bool PreferencesDialog::isCloudMeshingQuad() const
{
return _ui->checkBox_mesh_quad->isChecked();
}
bool PreferencesDialog::isCloudMeshingTexture() const
{
return _ui->checkBox_mesh_texture->isChecked();
}
int PreferencesDialog::getCloudMeshingTriangleSize()
{
return _ui->spinBox_mesh_triangleSize->value();
@@ -3858,6 +3878,10 @@ int PreferencesDialog::getNormalKSearch() const
{
return _ui->spinBox_normalKSearch->value();
}
bool PreferencesDialog::gainCompensation() const
{
return _ui->checkBox_gainCompensation->isChecked();
}
bool PreferencesDialog::getGridMapShown() const
{
return _ui->checkBox_map_shown->isChecked();
+39 -7
View File
@@ -52,7 +52,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>205</width>
<width>204</width>
<height>208</height>
</rect>
</property>
@@ -210,7 +210,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>203</width>
<width>202</width>
<height>208</height>
</rect>
</property>
@@ -1125,9 +1125,9 @@
<property name="geometry">
<rect>
<x>0</x>
<y>-225</y>
<y>-32</y>
<width>280</width>
<height>465</height>
<height>584</height>
</rect>
</property>
<attribute name="label">
@@ -1170,6 +1170,38 @@
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="label_51">
<property name="text">
<string>Gain compensation radius (Constraints view)</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_gainCompensationRadius">
<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>10.000000000000000</double>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item>
@@ -1411,8 +1443,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>265</width>
<height>126</height>
<width>282</width>
<height>163</height>
</rect>
</property>
<attribute name="label">
@@ -1511,7 +1543,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>265</width>
<width>267</width>
<height>168</height>
</rect>
</property>
+201 -61
View File
@@ -23,24 +23,14 @@
<property name="geometry">
<rect>
<x>0</x>
<y>-860</y>
<y>0</y>
<width>773</width>
<height>1463</height>
<height>1648</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_13">
<item>
<layout class="QGridLayout" name="gridLayout_8" columnstretch="0,1">
<item row="2" column="1">
<widget class="QLabel" name="label_binaryFile_2">
<property name="text">
<string>Assemble clouds/meshes to a single output cloud/mesh.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QSpinBox" name="spinBox_normalKSearch">
<property name="minimum">
@@ -51,10 +41,17 @@
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_binaryFile">
<item row="2" column="0">
<widget class="QCheckBox" name="checkBox_assemble">
<property name="text">
<string>Binary file.</string>
<string/>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="label_binaryFile_2">
<property name="text">
<string>Assemble clouds/meshes to a single output cloud/mesh.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
@@ -71,23 +68,6 @@
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="checkBox_assemble">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLabel" name="label_voxel">
<property name="text">
<string>Voxel size. Set 0 to disable. When organized meshes are assembled, this is the radius in which the vertices of the polygons are merged.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_voxelSize_assembled">
<property name="suffix">
@@ -138,6 +118,26 @@
</item>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_binaryFile">
<property name="text">
<string>Binary file.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLabel" name="label_voxel">
<property name="text">
<string>Voxel size. Set 0 to disable. When organized meshes are assembled, this is the radius in which the vertices of the polygons are merged.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
@@ -782,6 +782,146 @@ Guidelines: 4 times the voxel size, 0.025 for voxel=0.</string>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_gain">
<property name="title">
<string>Gain Compensation</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<layout class="QGridLayout" name="gridLayout_12" columnstretch="0,1">
<item row="0" column="1">
<widget class="QLabel" name="label_binaryFile_3">
<property name="text">
<string>Correspondence radius</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="label_binaryFile_5">
<property name="text">
<string>Beta</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_gainRadius">
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>3</number>
</property>
<property name="minimum">
<double>0.001000000000000</double>
</property>
<property name="maximum">
<double>10.000000000000000</double>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
<property name="value">
<double>0.020000000000000</double>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="label_binaryFile_4">
<property name="text">
<string>Alpha</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_gainAlpha">
<property name="suffix">
<string/>
</property>
<property name="decimals">
<number>3</number>
</property>
<property name="minimum">
<double>0.001000000000000</double>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
<property name="value">
<double>0.010000000000000</double>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_gainBeta">
<property name="suffix">
<string/>
</property>
<property name="decimals">
<number>0</number>
</property>
<property name="minimum">
<double>1.000000000000000</double>
</property>
<property name="maximum">
<double>1000.000000000000000</double>
</property>
<property name="singleStep">
<double>1.000000000000000</double>
</property>
<property name="value">
<double>100.000000000000000</double>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_binaryFile_6">
<property name="text">
<string>Min overlap (%)</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_gainOverlap">
<property name="suffix">
<string/>
</property>
<property name="decimals">
<number>2</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.050000000000000</double>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_meshing">
<property name="title">
@@ -793,34 +933,7 @@ Guidelines: 4 times the voxel size, 0.025 for voxel=0.</string>
<layout class="QVBoxLayout" name="verticalLayout_15">
<item>
<layout class="QGridLayout" name="gridLayout_10" columnstretch="0,1">
<item row="0" column="1">
<widget class="QLabel" name="label_170">
<property name="text">
<string>Mesh quadric decimation factor (0=no decimation). Used to reduce the number of polygons.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="checkBox_textureMapping">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_textureMapping">
<property name="text">
<string>Texture mapping. Images of the cameras will be projected on the mesh(es). Output is a *.obj format.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_meshDecimationFactor">
<property name="decimals">
<number>2</number>
@@ -839,20 +952,47 @@ Guidelines: 4 times the voxel size, 0.025 for voxel=0.</string>
</property>
</widget>
</item>
<item row="2" column="1">
<item row="3" column="1">
<widget class="QLabel" name="label_16">
<property name="text">
<string>Min polygon cluster size</string>
</property>
</widget>
</item>
<item row="2" column="0">
<item row="3" column="0">
<widget class="QSpinBox" name="spinBox_mesh_minClusterSize">
<property name="maximum">
<number>999</number>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_meshDecimation">
<property name="text">
<string>Mesh quadric decimation factor (0=no decimation). Used to reduce the number of polygons. Cannot be used if texturing is on and organized mesh flavor is selected.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="checkBox_textureMapping">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_textureMapping">
<property name="text">
<string>Texture mapping. Images of the cameras will be projected on the mesh(es). Output is a *.obj format.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
+352 -312
View File
@@ -64,8 +64,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>678</width>
<height>2417</height>
<width>673</width>
<height>2496</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_16">
@@ -86,7 +86,7 @@
<enum>QFrame::Raised</enum>
</property>
<property name="currentIndex">
<number>3</number>
<number>1</number>
</property>
<widget class="QWidget" name="page_22">
<layout class="QVBoxLayout" name="verticalLayout_29" stretch="0,1">
@@ -414,19 +414,6 @@ Show a yellow background when the number of odometry inliers goes under this thr
<layout class="QVBoxLayout" name="verticalLayout_98">
<item>
<layout class="QGridLayout" name="gridLayout_2" columnstretch="0,0,1">
<item row="0" column="1">
<widget class="QLabel" name="label_137">
<property name="text">
<string>Odometry</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_154">
<property name="text">
@@ -459,51 +446,6 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property>
</widget>
</item>
<item row="4" column="2">
<widget class="QLabel" name="label_150">
<property name="text">
<string>3D cloud minimum depth.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="5" column="2">
<widget class="QLabel" name="label_171">
<property name="text">
<string>3D cloud voxel filtering size (0=disabled).</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_noiseRadius">
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>3</number>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="singleStep">
<double>0.050000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
<item row="6" column="2">
<widget class="QLabel" name="label_168">
<property name="text">
@@ -517,19 +459,6 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QSpinBox" name="spinBox_noiseMinNeighbors">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>1000</number>
</property>
<property name="value">
<number>5</number>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QDoubleSpinBox" name="doubleSpinBox_maxDepth_odom">
<property name="suffix">
@@ -549,19 +478,6 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QLabel" name="label_132">
<property name="text">
<string>3D cloud maximum depth (0 means no limit).</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_minDepth">
<property name="suffix">
@@ -581,7 +497,7 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property>
</widget>
</item>
<item row="16" column="1">
<item row="17" column="1">
<widget class="QCheckBox" name="checkBox_showOdomFeatures">
<property name="text">
<string/>
@@ -591,7 +507,7 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property>
</widget>
</item>
<item row="16" column="2">
<item row="17" column="2">
<widget class="QLabel" name="label_123">
<property name="text">
<string>Show 3D features.</string>
@@ -604,30 +520,7 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property>
</widget>
</item>
<item row="17" column="0">
<widget class="QSpinBox" name="spinBox_ptsize_features">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>64</number>
</property>
</widget>
</item>
<item row="8" column="2">
<widget class="QLabel" name="label_210">
<property name="text">
<string>3D cloud normal K search. If not 0, normals will be computed and added to created cloud for visualization (keys 7, 8 and 9).</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="11" column="0">
<item row="12" column="0">
<widget class="QCheckBox" name="checkBox_showScans">
<property name="text">
<string/>
@@ -637,7 +530,7 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property>
</widget>
</item>
<item row="11" column="1">
<item row="12" column="1">
<widget class="QCheckBox" name="checkBox_showOdomScans">
<property name="text">
<string/>
@@ -647,7 +540,7 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property>
</widget>
</item>
<item row="11" column="2">
<item row="12" column="2">
<widget class="QLabel" name="label_110">
<property name="text">
<string>Show scans.</string>
@@ -660,7 +553,7 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property>
</widget>
</item>
<item row="12" column="0">
<item row="13" column="0">
<widget class="QSpinBox" name="spinBox_downsamplingScan">
<property name="minimum">
<number>1</number>
@@ -670,17 +563,7 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property>
</widget>
</item>
<item row="12" column="1">
<widget class="QSpinBox" name="spinBox_downsamplingScan_odom">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>9999</number>
</property>
</widget>
</item>
<item row="12" column="2">
<item row="13" column="2">
<widget class="QLabel" name="label_273">
<property name="text">
<string>Scan downsampling step size.</string>
@@ -693,7 +576,7 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property>
</widget>
</item>
<item row="13" column="0">
<item row="14" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_voxelSizeScan">
<property name="suffix">
<string> m</string>
@@ -712,7 +595,7 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property>
</widget>
</item>
<item row="13" column="1">
<item row="14" column="1">
<widget class="QDoubleSpinBox" name="doubleSpinBox_voxelSizeScan_odom">
<property name="suffix">
<string> m</string>
@@ -731,39 +614,7 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property>
</widget>
</item>
<item row="13" column="2">
<widget class="QLabel" name="label_271">
<property name="text">
<string>Scan voxel size.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="14" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_opacity_scan">
<property name="suffix">
<string/>
</property>
<property name="decimals">
<number>2</number>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>1.000000000000000</double>
</property>
</widget>
</item>
<item row="14" column="1">
<item row="15" column="1">
<widget class="QDoubleSpinBox" name="doubleSpinBox_opacity_odom_scan">
<property name="suffix">
<string/>
@@ -782,19 +633,6 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property>
</widget>
</item>
<item row="14" column="2">
<widget class="QLabel" name="label_156">
<property name="text">
<string>Scan opacity.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="7" column="2">
<widget class="QLabel" name="label_169">
<property name="text">
@@ -808,20 +646,7 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QSpinBox" name="spinBox_normalKSearch">
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>1000</number>
</property>
<property name="value">
<number>10</number>
</property>
</widget>
</item>
<item row="17" column="1">
<item row="18" column="1">
<widget class="QSpinBox" name="spinBox_ptsize_odom_features">
<property name="minimum">
<number>1</number>
@@ -831,7 +656,7 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property>
</widget>
</item>
<item row="17" column="2">
<item row="18" column="2">
<widget class="QLabel" name="label_166">
<property name="text">
<string>Feature point size.</string>
@@ -844,7 +669,7 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property>
</widget>
</item>
<item row="9" column="0">
<item row="10" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_opacity">
<property name="suffix">
<string/>
@@ -863,39 +688,7 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="QDoubleSpinBox" name="doubleSpinBox_opacity_odom">
<property name="suffix">
<string/>
</property>
<property name="decimals">
<number>2</number>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>1.000000000000000</double>
</property>
</widget>
</item>
<item row="9" column="2">
<widget class="QLabel" name="label_155">
<property name="text">
<string>3D cloud opacity.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="10" column="0">
<item row="11" column="0">
<widget class="QSpinBox" name="spinBox_ptsize">
<property name="minimum">
<number>1</number>
@@ -908,20 +701,7 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property>
</widget>
</item>
<item row="10" column="1">
<widget class="QSpinBox" name="spinBox_ptsize_odom">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>64</number>
</property>
<property name="value">
<number>2</number>
</property>
</widget>
</item>
<item row="10" column="2">
<item row="11" column="2">
<widget class="QLabel" name="label_157">
<property name="text">
<string>3D cloud point size (1..64).</string>
@@ -934,17 +714,7 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property>
</widget>
</item>
<item row="15" column="0">
<widget class="QSpinBox" name="spinBox_ptsize_scan">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>64</number>
</property>
</widget>
</item>
<item row="15" column="1">
<item row="16" column="1">
<widget class="QSpinBox" name="spinBox_ptsize_odom_scan">
<property name="minimum">
<number>1</number>
@@ -954,20 +724,7 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property>
</widget>
</item>
<item row="15" column="2">
<widget class="QLabel" name="label_158">
<property name="text">
<string>Scan point size (1..64).</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="16" column="0">
<item row="17" column="0">
<widget class="QCheckBox" name="checkBox_showFeatures">
<property name="text">
<string/>
@@ -977,19 +734,6 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="spinBox_decimation_odom">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>32</number>
</property>
<property name="value">
<number>2</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="checkBox_showClouds">
<property name="text">
@@ -1045,16 +789,6 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="checkBox_showOdomClouds">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QDoubleSpinBox" name="doubleSpinBox_minDepth_odom">
<property name="suffix">
@@ -1077,6 +811,285 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property>
</widget>
</item>
<item row="19" column="2">
<widget class="QLabel" name="label_213">
<property name="text">
<string>Show graphs.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_137">
<property name="text">
<string>Odometry</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="2">
<widget class="QLabel" name="label_150">
<property name="text">
<string>3D cloud minimum depth.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="5" column="2">
<widget class="QLabel" name="label_171">
<property name="text">
<string>3D cloud voxel filtering size (0=disabled).</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_noiseRadius">
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>3</number>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="singleStep">
<double>0.050000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QSpinBox" name="spinBox_noiseMinNeighbors">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>1000</number>
</property>
<property name="value">
<number>5</number>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QLabel" name="label_132">
<property name="text">
<string>3D cloud maximum depth (0 means no limit).</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="18" column="0">
<widget class="QSpinBox" name="spinBox_ptsize_features">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>64</number>
</property>
</widget>
</item>
<item row="8" column="2">
<widget class="QLabel" name="label_210">
<property name="text">
<string>3D cloud normal K search. If not 0, normals will be computed and added to created cloud for visualization (keys 7, 8 and 9).</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="13" column="1">
<widget class="QSpinBox" name="spinBox_downsamplingScan_odom">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>9999</number>
</property>
</widget>
</item>
<item row="14" column="2">
<widget class="QLabel" name="label_271">
<property name="text">
<string>Scan voxel size.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="15" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_opacity_scan">
<property name="suffix">
<string/>
</property>
<property name="decimals">
<number>2</number>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>1.000000000000000</double>
</property>
</widget>
</item>
<item row="15" column="2">
<widget class="QLabel" name="label_156">
<property name="text">
<string>Scan opacity.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QSpinBox" name="spinBox_normalKSearch">
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>1000</number>
</property>
<property name="value">
<number>10</number>
</property>
</widget>
</item>
<item row="10" column="1">
<widget class="QDoubleSpinBox" name="doubleSpinBox_opacity_odom">
<property name="suffix">
<string/>
</property>
<property name="decimals">
<number>2</number>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>1.000000000000000</double>
</property>
</widget>
</item>
<item row="10" column="2">
<widget class="QLabel" name="label_155">
<property name="text">
<string>3D cloud opacity.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="11" column="1">
<widget class="QSpinBox" name="spinBox_ptsize_odom">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>64</number>
</property>
<property name="value">
<number>2</number>
</property>
</widget>
</item>
<item row="16" column="0">
<widget class="QSpinBox" name="spinBox_ptsize_scan">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>64</number>
</property>
</widget>
</item>
<item row="16" column="2">
<widget class="QLabel" name="label_158">
<property name="text">
<string>Scan point size (1..64).</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="spinBox_decimation_odom">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>32</number>
</property>
<property name="value">
<number>2</number>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="checkBox_showOdomClouds">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLabel" name="label_119">
<property name="text">
@@ -1090,20 +1103,7 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property>
</widget>
</item>
<item row="18" column="2">
<widget class="QLabel" name="label_213">
<property name="text">
<string>Show graphs.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="19" column="2">
<item row="20" column="2">
<widget class="QLabel" name="label_243">
<property name="text">
<string>Show labels.</string>
@@ -1116,7 +1116,7 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property>
</widget>
</item>
<item row="18" column="0">
<item row="19" column="0">
<widget class="QCheckBox" name="checkBox_showGraphs">
<property name="text">
<string/>
@@ -1126,7 +1126,7 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property>
</widget>
</item>
<item row="19" column="0">
<item row="20" column="0">
<widget class="QCheckBox" name="checkBox_showLabels">
<property name="text">
<string/>
@@ -1136,6 +1136,29 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property>
</widget>
</item>
<item row="9" column="2">
<widget class="QLabel" name="label_338">
<property name="text">
<string>Gain compensation.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QCheckBox" name="checkBox_gainCompensation">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
@@ -1156,16 +1179,6 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="checkBox_mesh_quad">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_quad">
<property name="text">
@@ -1193,6 +1206,16 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="checkBox_mesh_quad">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_mesh_angleTolerance">
<property name="suffix">
@@ -1212,6 +1235,23 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="label_337">
<property name="text">
<string>Texture</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="checkBox_mesh_texture">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>