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_) if(!textures_)
{ {
vertex_buffers_ = 0; vertex_buffers_ = 0;
LOGE("OpenGL: could not generate vertex buffers\n"); LOGE("OpenGL: could not generate texture buffers\n");
return; 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> template<typename pointT>
std::vector<pcl::Vertices> normalizePolygonsSide( std::vector<pcl::Vertices> normalizePolygonsSide(
const pcl::PointCloud<pointT> & cloud, const typename pcl::PointCloud<pointT> & cloud,
const std::vector<pcl::Vertices> & polygons, const std::vector<pcl::Vertices> & polygons,
const pcl::PointXYZ & viewPoint) const pcl::PointXYZ & viewPoint)
{ {
@@ -433,13 +433,6 @@ pcl::IndicesPtr RTABMAP_EXP normalFiltering(
int normalKSearch, int normalKSearch,
const Eigen::Vector4f & viewpoint); 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. * For convenience.
*/ */
+2
View File
@@ -66,6 +66,8 @@ SET(SRC_FILES
StereoCameraModel.cpp StereoCameraModel.cpp
OccupancyGrid.cpp OccupancyGrid.cpp
GainCompensator.cpp
rtflann/ext/lz4.c rtflann/ext/lz4.c
rtflann/ext/lz4hc.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; 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( std::vector<pcl::IndicesPtr> extractClusters(
const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud, const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud,
float clusterTolerance, float clusterTolerance,
@@ -183,6 +183,7 @@ public:
double getSubtractFilteringRadius() const; double getSubtractFilteringRadius() const;
double getSubtractFilteringAngle() const; double getSubtractFilteringAngle() const;
int getNormalKSearch() const; int getNormalKSearch() const;
bool gainCompensation() const;
bool getGridMapShown() const; bool getGridMapShown() const;
double getGridMapResolution() const;; double getGridMapResolution() const;;
@@ -201,6 +202,7 @@ public:
bool isCloudMeshing() const; bool isCloudMeshing() const;
double getCloudMeshingAngle() const; double getCloudMeshingAngle() const;
bool isCloudMeshingQuad() const; bool isCloudMeshingQuad() const;
bool isCloudMeshingTexture() const;
int getCloudMeshingTriangleSize(); int getCloudMeshingTriangleSize();
QString getWorkingDirectory() const; QString getWorkingDirectory() const;
+13 -6
View File
@@ -642,22 +642,29 @@ bool CloudViewer::addCloudTextureMesh(
const pcl::TextureMesh::Ptr & textureMesh, const pcl::TextureMesh::Ptr & textureMesh,
const Transform & pose) const Transform & pose)
{ {
#if PCL_VERSION_COMPARE(>=, 1, 7, 2)
if(_addedClouds.contains(id)) if(_addedClouds.contains(id))
{ {
this->removeCloud(id); this->removeCloud(id);
} }
UDEBUG("Adding %s", id.c_str()); 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()); _visualizer->updatePointCloudPose(id, pose.toEigen3f());
_addedClouds.insert(id, pose); _addedClouds.insert(id, pose);
return true; return true;
} }
#endif
// not implemented on lower version of PCL
return false; return false;
} }
@@ -895,7 +902,7 @@ bool CloudViewer::addTextureMesh (
int viewport) int viewport)
{ {
#if PCL_VERSION_COMPARE(>=, 1, 7, 2) #if PCL_VERSION_COMPARE(>=, 1, 7, 2)
return addTextureMesh(mesh, id, viewport); return _visualizer->addTextureMesh(mesh, id, viewport);
#else #else
// Copied from PCL 1.8 // 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/core/OccupancyGrid.h"
#include "rtabmap/gui/DataRecorder.h" #include "rtabmap/gui/DataRecorder.h"
#include "rtabmap/core/SensorData.h" #include "rtabmap/core/SensorData.h"
#include "rtabmap/core/GainCompensator.h"
#include "ExportDialog.h" #include "ExportDialog.h"
#include "rtabmap/gui/ProgressDialog.h" #include "rtabmap/gui/ProgressDialog.h"
#include "ParametersToolBox.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_->checkBox_ignoreUserLoop, SIGNAL(stateChanged(int)), this, SLOT(updateGraphView()));
connect(ui_->spinBox_optimizationDepth, SIGNAL(editingFinished()), this, SLOT(updateGraphView())); connect(ui_->spinBox_optimizationDepth, SIGNAL(editingFinished()), this, SLOT(updateGraphView()));
connect(ui_->checkBox_gridErode, SIGNAL(stateChanged(int)), this, SLOT(updateGrid())); 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_->groupBox_posefiltering, SIGNAL(clicked(bool)), this, SLOT(updateGraphView()));
connect(ui_->doubleSpinBox_posefilteringRadius, SIGNAL(editingFinished()), this, SLOT(updateGraphView())); connect(ui_->doubleSpinBox_posefilteringRadius, SIGNAL(editingFinished()), this, SLOT(updateGraphView()));
connect(ui_->doubleSpinBox_posefilteringAngle, 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_->checkBox_ignoreUserLoop, SIGNAL(stateChanged(int)), this, SLOT(configModified()));
connect(ui_->spinBox_optimizationDepth, SIGNAL(valueChanged(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_->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_->doubleSpinBox_gridCellSize, SIGNAL(valueChanged(double)), this, SLOT(configModified()));
connect(ui_->groupBox_posefiltering, SIGNAL(clicked(bool)), this, SLOT(configModified())); connect(ui_->groupBox_posefiltering, SIGNAL(clicked(bool)), this, SLOT(configModified()));
connect(ui_->doubleSpinBox_posefilteringRadius, SIGNAL(valueChanged(double)), 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_->checkBox_ignoreUserLoop->setChecked(settings.value("ignoreUserLoop", ui_->checkBox_ignoreUserLoop->isChecked()).toBool());
ui_->spinBox_optimizationDepth->setValue(settings.value("depth", ui_->spinBox_optimizationDepth->value()).toInt()); 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_->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.endGroup();
settings.beginGroup("grid"); settings.beginGroup("grid");
@@ -473,6 +477,7 @@ void DatabaseViewer::writeSettings()
//settings.setValue("slam2d", ui_->checkBox_2dslam->isChecked()); //settings.setValue("slam2d", ui_->checkBox_2dslam->isChecked());
settings.setValue("depth", ui_->spinBox_optimizationDepth->value()); settings.setValue("depth", ui_->spinBox_optimizationDepth->value());
settings.setValue("erode", ui_->checkBox_gridErode->isChecked()); settings.setValue("erode", ui_->checkBox_gridErode->isChecked());
settings.setValue("gainCompensationRadius", ui_->doubleSpinBox_gainCompensationRadius->value());
settings.endGroup(); settings.endGroup();
// save Grid settings // save Grid settings
@@ -3285,13 +3290,33 @@ void DatabaseViewer::updateConstraintView(
if(ui_->checkBox_show3Dclouds->isChecked()) if(ui_->checkBox_show3Dclouds->isChecked())
{ {
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloudFrom, cloudTo; 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()) 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()) 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()) if(cloudFrom.get() && cloudFrom->size())
@@ -3300,7 +3325,6 @@ void DatabaseViewer::updateConstraintView(
} }
if(cloudTo.get() && cloudTo->size()) if(cloudTo.get() && cloudTo->size())
{ {
cloudTo = rtabmap::util3d::transformPointCloud(cloudTo, t);
constraintsViewer_->addCloud("cloud1", cloudTo, Transform::getIdentity(), Qt::cyan); 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_transforms.h"
#include "rtabmap/core/util3d.h" #include "rtabmap/core/util3d.h"
#include "rtabmap/core/Graph.h" #include "rtabmap/core/Graph.h"
#include "rtabmap/core/GainCompensator.h"
#include <pcl/conversions.h> #include <pcl/conversions.h>
#include <pcl/io/pcd_io.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->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, 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->doubleSpinBox_voxelSize_assembled, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
connect(_ui->groupBox_subtraction, SIGNAL(clicked(bool)), 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()); _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)), _ui->stackedWidget_upsampling, SLOT(setCurrentIndex(int)));
connect(_ui->comboBox_upsamplingMethod, SIGNAL(currentIndexChanged(int)), this, SLOT(updateMLSGrpVisibility())); 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->groupBox_meshing, SIGNAL(clicked(bool)), this, SIGNAL(configChanged()));
connect(_ui->doubleSpinBox_gp3Radius, SIGNAL(valueChanged(double)), 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_gp3Mu, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
connect(_ui->doubleSpinBox_meshDecimationFactor, 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, SIGNAL(configChanged()));
connect(_ui->checkBox_textureMapping, SIGNAL(stateChanged(int)), this, SLOT(updateTexturingAvailability()));
_progressDialog = new ProgressDialog(this); _progressDialog = new ProgressDialog(this);
_progressDialog->setVisible(false); _progressDialog->setVisible(false);
@@ -132,6 +140,14 @@ void ExportCloudsDialog::updateMLSGrpVisibility()
_ui->groupBox_5->setVisible(_ui->comboBox_upsamplingMethod->currentIndex() == 4); _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 void ExportCloudsDialog::saveSettings(QSettings & settings, const QString & group) const
{ {
if(!group.isEmpty()) 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_voxel_size", _ui->doubleSpinBox_dilationVoxelSize->value());
settings.setValue("mls_dilation_iterations", _ui->spinBox_dilationSteps->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", _ui->groupBox_meshing->isChecked());
settings.setValue("mesh_radius", _ui->doubleSpinBox_gp3Radius->value()); settings.setValue("mesh_radius", _ui->doubleSpinBox_gp3Radius->value());
settings.setValue("mesh_mu", _ui->doubleSpinBox_gp3Mu->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->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->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->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_gp3Radius->setValue(settings.value("mesh_radius", _ui->doubleSpinBox_gp3Radius->value()).toDouble());
_ui->doubleSpinBox_gp3Mu->setValue(settings.value("mesh_mu", _ui->doubleSpinBox_gp3Mu->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->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()); _ui->spinBox_mesh_triangleSize->setValue(settings.value("mesh_triangle_size", _ui->spinBox_mesh_triangleSize->value()).toInt());
updateReconstructionFlavor();
updateTexturingAvailability();
updateMLSGrpVisibility();
if(!group.isEmpty()) if(!group.isEmpty())
{ {
settings.endGroup(); settings.endGroup();
@@ -276,6 +308,12 @@ void ExportCloudsDialog::restoreDefaults()
_ui->doubleSpinBox_dilationVoxelSize->setValue(0.01); _ui->doubleSpinBox_dilationVoxelSize->setValue(0.01);
_ui->spinBox_dilationSteps->setValue(0); _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->groupBox_meshing->setChecked(false);
_ui->doubleSpinBox_gp3Radius->setValue(0.04); _ui->doubleSpinBox_gp3Radius->setValue(0.04);
_ui->doubleSpinBox_gp3Mu->setValue(2.5); _ui->doubleSpinBox_gp3Mu->setValue(2.5);
@@ -288,6 +326,8 @@ void ExportCloudsDialog::restoreDefaults()
_ui->spinBox_mesh_triangleSize->setValue(2); _ui->spinBox_mesh_triangleSize->setValue(2);
updateReconstructionFlavor(); updateReconstructionFlavor();
updateTexturingAvailability();
updateMLSGrpVisibility();
this->update(); this->update();
} }
@@ -305,12 +345,10 @@ void ExportCloudsDialog::setSaveButton()
_ui->buttonBox->button(QDialogButtonBox::Save)->setVisible(true); _ui->buttonBox->button(QDialogButtonBox::Save)->setVisible(true);
_ui->checkBox_binary->setVisible(true); _ui->checkBox_binary->setVisible(true);
_ui->label_binaryFile->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->setVisible(false);
_ui->checkBox_mesh_quad->setEnabled(false); _ui->checkBox_mesh_quad->setEnabled(false);
_ui->label_quad->setVisible(false); _ui->label_quad->setVisible(false);
updateTexturingAvailability();
} }
void ExportCloudsDialog::setOkButton() void ExportCloudsDialog::setOkButton()
@@ -319,12 +357,10 @@ void ExportCloudsDialog::setOkButton()
_ui->buttonBox->button(QDialogButtonBox::Save)->setVisible(false); _ui->buttonBox->button(QDialogButtonBox::Save)->setVisible(false);
_ui->checkBox_binary->setVisible(false); _ui->checkBox_binary->setVisible(false);
_ui->label_binaryFile->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->setVisible(true);
_ui->checkBox_mesh_quad->setEnabled(true); _ui->checkBox_mesh_quad->setEnabled(true);
_ui->label_quad->setVisible(true); _ui->label_quad->setVisible(true);
updateTexturingAvailability();
} }
void ExportCloudsDialog::enableRegeneration(bool enabled) void ExportCloudsDialog::enableRegeneration(bool enabled)
@@ -338,6 +374,7 @@ void ExportCloudsDialog::enableRegeneration(bool enabled)
void ExportCloudsDialog::exportClouds( void ExportCloudsDialog::exportClouds(
const std::map<int, Transform> & poses, const std::map<int, Transform> & poses,
const std::multimap<int, Link> & links,
const std::map<int, int> & mapIds, const std::map<int, int> & mapIds,
const QMap<int, Signature> & cachedSignatures, const QMap<int, Signature> & cachedSignatures,
const std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGB>::Ptr, pcl::IndicesPtr> > & cachedClouds, const std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGB>::Ptr, pcl::IndicesPtr> > & cachedClouds,
@@ -352,6 +389,7 @@ void ExportCloudsDialog::exportClouds(
if(getExportedClouds( if(getExportedClouds(
poses, poses,
links,
mapIds, mapIds,
cachedSignatures, cachedSignatures,
cachedClouds, cachedClouds,
@@ -384,12 +422,17 @@ void ExportCloudsDialog::exportClouds(
{ {
saveClouds(workingDirectory, poses, clouds, _ui->checkBox_binary->isChecked()); saveClouds(workingDirectory, poses, clouds, _ui->checkBox_binary->isChecked());
} }
_progressDialog->setValue(_progressDialog->maximumSteps());
} }
else
{
_progressDialog->setAutoClose(false);
}
_progressDialog->setValue(_progressDialog->maximumSteps());
} }
void ExportCloudsDialog::viewClouds( void ExportCloudsDialog::viewClouds(
const std::map<int, Transform> & poses, const std::map<int, Transform> & poses,
const std::multimap<int, Link> & links,
const std::map<int, int> & mapIds, const std::map<int, int> & mapIds,
const QMap<int, Signature> & cachedSignatures, const QMap<int, Signature> & cachedSignatures,
const std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGB>::Ptr, pcl::IndicesPtr> > & cachedClouds, const std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGB>::Ptr, pcl::IndicesPtr> > & cachedClouds,
@@ -404,6 +447,7 @@ void ExportCloudsDialog::viewClouds(
if(getExportedClouds( if(getExportedClouds(
poses, poses,
links,
mapIds, mapIds,
cachedSignatures, cachedSignatures,
cachedClouds, cachedClouds,
@@ -442,7 +486,34 @@ void ExportCloudsDialog::viewClouds(
uSleep(500); 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) 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->appendText(tr("Viewing the cloud %1 (%2 points)... done.").arg(iter->first).arg(iter->second->size()));
} }
} }
_progressDialog->setValue(_progressDialog->maximumSteps());
viewer->update(); viewer->update();
} }
else
{
_progressDialog->setAutoClose(false);
}
_progressDialog->setValue(_progressDialog->maximumSteps());
} }
bool removeDirRecursively(const QString & dirName) bool ExportCloudsDialog::removeDirRecursively(const QString & dirName)
{ {
bool result = true; bool result = true;
QDir dir(dirName); QDir dir(dirName);
@@ -521,6 +595,7 @@ bool removeDirRecursively(const QString & dirName)
bool ExportCloudsDialog::getExportedClouds( bool ExportCloudsDialog::getExportedClouds(
const std::map<int, Transform> & poses, const std::map<int, Transform> & poses,
const std::multimap<int, Link> & links,
const std::map<int, int> & mapIds, const std::map<int, int> & mapIds,
const QMap<int, Signature> & cachedSignatures, const QMap<int, Signature> & cachedSignatures,
const std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGB>::Ptr, pcl::IndicesPtr> > & cachedClouds, const std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGB>::Ptr, pcl::IndicesPtr> > & cachedClouds,
@@ -533,6 +608,11 @@ bool ExportCloudsDialog::getExportedClouds(
enableRegeneration(cachedSignatures.size()); enableRegeneration(cachedSignatures.size());
if(this->exec() == QDialog::Accepted) 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->resetProgress();
_progressDialog->show(); _progressDialog->show();
int mul = 1; int mul = 1;
@@ -554,6 +634,14 @@ bool ExportCloudsDialog::getExportedClouds(
{ {
mul+=1; 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); _progressDialog->setMaximumSteps(int(poses.size())*mul+1);
std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr, pcl::IndicesPtr> > clouds = this->getClouds( std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr, pcl::IndicesPtr> > clouds = this->getClouds(
@@ -562,6 +650,46 @@ bool ExportCloudsDialog::getExportedClouds(
cachedClouds, cachedClouds,
parameters); 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>); pcl::PointCloud<pcl::PointXYZ>::Ptr rawAssembledCloud(new pcl::PointCloud<pcl::PointXYZ>);
std::vector<int> rawCameraIndices; std::vector<int> rawCameraIndices;
if(_ui->checkBox_assemble->isChecked() && if(_ui->checkBox_assemble->isChecked() &&
@@ -707,7 +835,8 @@ bool ExportCloudsDialog::getExportedClouds(
} }
//used for organized texturing below //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 //mesh
UDEBUG("Meshing=%d", _ui->groupBox_meshing->isChecked()?1:0); UDEBUG("Meshing=%d", _ui->groupBox_meshing->isChecked()?1:0);
@@ -808,7 +937,8 @@ bool ExportCloudsDialog::getExportedClouds(
} }
else 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)); meshes.insert(std::make_pair(iter->first, mesh));
} }
@@ -995,6 +1125,10 @@ bool ExportCloudsDialog::getExportedClouds(
{ {
cameraPoses.insert(std::make_pair(jter->first, jter->second)); cameraPoses.insert(std::make_pair(jter->first, jter->second));
cameraModels.insert(std::make_pair(jter->first, model)); 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)); images.insert(std::make_pair(jter->first, image));
} }
} }
@@ -1002,34 +1136,57 @@ bool ExportCloudsDialog::getExportedClouds(
if(cameraPoses.size()) if(cameraPoses.size())
{ {
pcl::TextureMesh::Ptr textureMesh(new pcl::TextureMesh); 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()) if(iter->first != 0 && oter != organizedIndices.end())
{ {
UASSERT(ster!=organizedCloudSizes.end()&&ster->first == oter->first);
UDEBUG("Texture by pixels"); UDEBUG("Texture by pixels");
textureMesh->cloud = iter->second->cloud; textureMesh->cloud = iter->second->cloud;
textureMesh->tex_polygons.push_back(iter->second->polygons); textureMesh->tex_polygons.push_back(iter->second->polygons);
int w = oter->second.second.first; int w = ster->second.width;
int h = oter->second.second.second; int h = ster->second.height;
UASSERT(w > 1 && h > 1); UASSERT(w > 1 && h > 1);
UASSERT(textureMesh->tex_polygons.size() && textureMesh->tex_polygons[0].size()); UASSERT(textureMesh->tex_polygons.size() && textureMesh->tex_polygons[0].size());
textureMesh->tex_coordinates.resize(1); textureMesh->tex_coordinates.resize(1);
int polygonSize = textureMesh->tex_polygons[0][0].vertices.size(); if(!_ui->checkBox_mesh_quad->isEnabled()) // disabled -> we are exporting to file
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]; // When saving to file, tex_coordinates should be linked to polygon vertices, not points
UASSERT(polygonSize == (int)vertices.vertices.size()); int polygonSize = textureMesh->tex_polygons[0][0].vertices.size();
for(int k=0; k<polygonSize; ++k) 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 //uv
std::map<int, int>::iterator vter = oter->second.first.find(vertices.vertices[k]); std::map<int, int>::iterator vter = oter->second.find(i);
UASSERT(vter != oter->second.first.end()); UASSERT(vter != oter->second.end());
int originalVertex = vter->second; int originalVertex = vter->second;
textureMesh->tex_coordinates[0][i*polygonSize+k] = Eigen::Vector2f( textureMesh->tex_coordinates[0][i] = Eigen::Vector2f(
float(originalVertex % w) / float(w), // u float(originalVertex % w) / float(w), // u
float(h - originalVertex / w) / float(h)); // v float(h - originalVertex / w) / float(h)); // v
} }
} }
pcl::TexMaterial mesh_material; pcl::TexMaterial mesh_material;
mesh_material.tex_d = 1.0f; mesh_material.tex_d = 1.0f;
mesh_material.tex_Ns = 75.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 const ParametersMap & parameters) const
{ {
std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr, pcl::IndicesPtr> > clouds; 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::PointCloud<pcl::PointXYZRGBNormal>::Ptr previousCloud;
pcl::IndicesPtr previousIndices; pcl::IndicesPtr previousIndices;
Transform previousPose; 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 points = 0;
int totalIndices = 0; int totalIndices = 0;
@@ -1134,7 +1291,7 @@ std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr, pcl::Indic
parameters); parameters);
// Don't voxelize if we create organized mesh // 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()); cloudWithoutNormals = util3d::voxelize(cloudWithoutNormals, indices, _ui->doubleSpinBox_voxelSize_assembled->value());
indices->resize(cloudWithoutNormals->size()); indices->resize(cloudWithoutNormals->size());
@@ -1187,23 +1344,6 @@ std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr, pcl::Indic
previousIndices = beforeSubtractionIndices; previousIndices = beforeSubtractionIndices;
previousPose = iter->second; 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 else
@@ -1256,7 +1396,7 @@ std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr, pcl::Indic
} }
else 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); 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 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()) if(indices->size())
@@ -1291,17 +1431,17 @@ std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr, pcl::Indic
if(_ui->groupBox_regenerate->isChecked()) if(_ui->groupBox_regenerate->isChecked())
{ {
_progressDialog->appendText(tr("Generated cloud %1 with %2 points and %3 indices (%4/%5).") _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 else
{ {
_progressDialog->appendText(tr("Copied cloud %1 from cache with %2 points and %3 indices (%4/%5).") _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 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(); _progressDialog->incrementStep();
QApplication::processEvents(); QApplication::processEvents();
@@ -1407,7 +1547,8 @@ void ExportCloudsDialog::saveClouds(
} }
else 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 else
@@ -1559,7 +1700,8 @@ void ExportCloudsDialog::saveMeshes(
else else
{ {
_progressDialog->appendText(tr("Failed saving mesh %1 (%2 polygons) to %3.") _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 else
@@ -1698,6 +1840,7 @@ void ExportCloudsDialog::saveTextureMeshes(
{ {
_progressDialog->appendText(tr("Failed saving mesh %1 (%2 textures) to %3.") _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); .arg(iter->first).arg(iter->second->tex_materials.size()-1).arg(pathFile), Qt::darkRed);
_progressDialog->setAutoClose(false);
} }
} }
else else
+6
View File
@@ -61,6 +61,7 @@ public:
void exportClouds( void exportClouds(
const std::map<int, Transform> & poses, const std::map<int, Transform> & poses,
const std::multimap<int, Link> & links,
const std::map<int, int> & mapIds, const std::map<int, int> & mapIds,
const QMap<int, Signature> & cachedSignatures, const QMap<int, Signature> & cachedSignatures,
const std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGB>::Ptr, pcl::IndicesPtr> > & cachedClouds, const std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGB>::Ptr, pcl::IndicesPtr> > & cachedClouds,
@@ -69,12 +70,15 @@ public:
void viewClouds( void viewClouds(
const std::map<int, Transform> & poses, const std::map<int, Transform> & poses,
const std::multimap<int, Link> & links,
const std::map<int, int> & mapIds, const std::map<int, int> & mapIds,
const QMap<int, Signature> & cachedSignatures, const QMap<int, Signature> & cachedSignatures,
const std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGB>::Ptr, pcl::IndicesPtr> > & cachedClouds, const std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGB>::Ptr, pcl::IndicesPtr> > & cachedClouds,
const QString & workingDirectory, const QString & workingDirectory,
const ParametersMap & parameters); const ParametersMap & parameters);
static bool removeDirRecursively(const QString & dirName);
signals: signals:
void configChanged(); void configChanged();
@@ -84,6 +88,7 @@ public slots:
private slots: private slots:
void updateReconstructionFlavor(); void updateReconstructionFlavor();
void updateMLSGrpVisibility(); void updateMLSGrpVisibility();
void updateTexturingAvailability();
private: private:
std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr, pcl::IndicesPtr> > getClouds( std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr, pcl::IndicesPtr> > getClouds(
@@ -93,6 +98,7 @@ private:
const ParametersMap & parameters) const; const ParametersMap & parameters) const;
bool getExportedClouds( bool getExportedClouds(
const std::map<int, Transform> & poses, const std::map<int, Transform> & poses,
const std::multimap<int, Link> & links,
const std::map<int, int> & mapIds, const std::map<int, int> & mapIds,
const QMap<int, Signature> & cachedSignatures, const QMap<int, Signature> & cachedSignatures,
const std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGB>::Ptr, pcl::IndicesPtr> > & cachedClouds, 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/DBDriver.h"
#include "rtabmap/core/RegistrationVis.h" #include "rtabmap/core/RegistrationVis.h"
#include "rtabmap/core/OccupancyGrid.h" #include "rtabmap/core/OccupancyGrid.h"
#include "rtabmap/core/GainCompensator.h"
#include "rtabmap/gui/ImageView.h" #include "rtabmap/gui/ImageView.h"
#include "rtabmap/gui/KeypointItem.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); Eigen::Vector3f(pose.x(), pose.y(), pose.z()) + viewpoint);
if(polygons.size()) 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!"); 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>); pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr cloudWithNormals(new pcl::PointCloud<pcl::PointXYZRGBNormal>);
if(_preferencesDialog->isSubtractFiltering() && GainCompensator compensator;
_preferencesDialog->getSubtractFilteringRadius() > 0.0) if((_preferencesDialog->isSubtractFiltering() &&
_preferencesDialog->getSubtractFilteringRadius() > 0.0) ||
_preferencesDialog->gainCompensation())
{ {
pcl::IndicesPtr beforeFiltering = indices; pcl::IndicesPtr beforeFiltering = indices;
if( cloud->size() && 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("new.pcd", *cloud, *indices);
//pcl::io::savePCDFile("old.pcd", *previousCloud, *_previousCloud.second.second); //pcl::io::savePCDFile("old.pcd", *previousCloud, *_previousCloud.second.second);
if(_preferencesDialog->getSubtractFilteringAngle() > 0.0f) if(_preferencesDialog->gainCompensation())
{ {
//normals required compensator.feed(cloud, indices, _previousCloud.second.first.first, _previousCloud.second.second, t);
if(_preferencesDialog->getNormalKSearch() > 0) 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); //normals required
pcl::concatenateFields(*cloud, *normals, *cloudWithNormals); 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 else
{ {
UWARN("Cloud subtraction with angle filtering is activated but " pcl::PointCloud<pcl::PointXYZRGB>::Ptr previousCloud = rtabmap::util3d::transformPointCloud(_previousCloud.second.first.first, t);
"cloud normal K search is 0. Subtraction is done with angle."); 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)", UINFO("Time subtract filtering %d from %d -> %d (%fs)",
(int)_previousCloud.second.second->size(), (int)_previousCloud.second.second->size(),
(int)beforeFiltering->size(), (int)beforeFiltering->size(),
(int)indices->size(), (int)indices->size(),
time.ticks()); time.ticks());
}
} }
// keep all indices for next subtraction // keep all indices for next subtraction
_previousCloud.first = nodeId; _previousCloud.first = nodeId;
@@ -2571,8 +2632,70 @@ std::pair<pcl::PointCloud<pcl::PointXYZRGB>::Ptr, pcl::IndicesPtr> MainWindow::c
// remove unused vertices to save memory // remove unused vertices to save memory
pcl::PointCloud<pcl::PointXYZRGB>::Ptr outputFiltered(new pcl::PointCloud<pcl::PointXYZRGB>); pcl::PointCloud<pcl::PointXYZRGB>::Ptr outputFiltered(new pcl::PointCloud<pcl::PointXYZRGB>);
std::vector<pcl::Vertices> outputPolygons; std::vector<pcl::Vertices> outputPolygons;
util3d::filterNotUsedVerticesFromMesh(*output, polygons, *outputFiltered, outputPolygons); std::map<int, int> newToOldIndices = util3d::filterNotUsedVerticesFromMesh(*output, polygons, *outputFiltered, outputPolygons);
if(!_cloudViewer->addCloudMesh(cloudName, outputFiltered, outputPolygons, pose))
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); 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()); 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()); UERROR("Temporary database \"%s\" could not be deleted.", _newDatabasePath.toStdString().c_str());
} }
@@ -5435,6 +5558,7 @@ void MainWindow::exportClouds()
_exportCloudsDialog->exportClouds( _exportCloudsDialog->exportClouds(
_ui->widget_mapVisibility->getVisiblePoses(), _ui->widget_mapVisibility->getVisiblePoses(),
_currentLinksMap,
_currentMapIds, _currentMapIds,
_cachedSignatures, _cachedSignatures,
_cachedClouds, _cachedClouds,
@@ -5450,7 +5574,8 @@ void MainWindow::viewClouds()
} }
_exportCloudsDialog->viewClouds( _exportCloudsDialog->viewClouds(
_currentPosesMap, _ui->widget_mapVisibility->getVisiblePoses(),
_currentLinksMap,
_currentMapIds, _currentMapIds,
_cachedSignatures, _cachedSignatures,
_cachedClouds, _cachedClouds,
+1 -1
View File
@@ -141,7 +141,7 @@ void PostProcessingDialog::restoreDefaults()
setDetectMoreLoopClosures(true); setDetectMoreLoopClosures(true);
setClusterRadius(0.5); setClusterRadius(0.5);
setClusterAngle(30); setClusterAngle(30);
setIterations(1); setIterations(3);
setRefineNeighborLinks(false); setRefineNeighborLinks(false);
setRefineLoopClosureLinks(false); setRefineLoopClosureLinks(false);
setSBA(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_subtractFilteringRadius, SIGNAL(valueChanged(double)), this, SLOT(makeObsoleteCloudRenderingPanel()));
connect(_ui->doubleSpinBox_subtractFilteringAngle, 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->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->checkBox_map_shown, SIGNAL(clicked(bool)), this, SLOT(makeObsoleteCloudRenderingPanel()));
connect(_ui->doubleSpinBox_map_resolution, SIGNAL(valueChanged(double)), 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->groupBox_organized, SIGNAL(toggled(bool)), this, SLOT(makeObsoleteCloudRenderingPanel()));
connect(_ui->doubleSpinBox_mesh_angleTolerance, SIGNAL(valueChanged(double)), 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_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())); connect(_ui->spinBox_mesh_triangleSize, SIGNAL(valueChanged(int)), this, SLOT(makeObsoleteCloudRenderingPanel()));
//Logging panel //Logging panel
@@ -1210,15 +1212,16 @@ void PreferencesDialog::resetSettings(QGroupBox * groupBox)
_ui->checkBox_showLabels->setChecked(false); _ui->checkBox_showLabels->setChecked(false);
_ui->spinBox_normalKSearch->setValue(10); _ui->spinBox_normalKSearch->setValue(10);
_ui->checkBox_gainCompensation->setChecked(false);
_ui->doubleSpinBox_mesh_angleTolerance->setValue(15.0); _ui->doubleSpinBox_mesh_angleTolerance->setValue(15.0);
#if PCL_VERSION_COMPARE(>=, 1, 7, 2)
_ui->groupBox_organized->setChecked(false); _ui->groupBox_organized->setChecked(false);
#if PCL_VERSION_COMPARE(>=, 1, 7, 2)
_ui->checkBox_mesh_quad->setChecked(true); _ui->checkBox_mesh_quad->setChecked(true);
#else #else
_ui->groupBox_organized->setChecked(false);
_ui->checkBox_mesh_quad->setChecked(false); _ui->checkBox_mesh_quad->setChecked(false);
#endif #endif
_ui->checkBox_mesh_texture->setChecked(false);
_ui->spinBox_mesh_triangleSize->setValue(2); _ui->spinBox_mesh_triangleSize->setValue(2);
} }
else if(groupBox->objectName() == _ui->groupBox_filtering2->objectName()) 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_subtractFilteringRadius->setValue(settings.value("subtractFilteringRadius", _ui->doubleSpinBox_subtractFilteringRadius->value()).toDouble());
_ui->doubleSpinBox_subtractFilteringAngle->setValue(settings.value("subtractFilteringAngle", _ui->doubleSpinBox_subtractFilteringAngle->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->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->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()); _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->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->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_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()); _ui->spinBox_mesh_triangleSize->setValue(settings.value("meshing_triangle_size", _ui->spinBox_mesh_triangleSize->value()).toInt());
settings.endGroup(); // General settings.endGroup(); // General
@@ -1925,7 +1930,16 @@ void PreferencesDialog::writeSettings(const QString & filePath)
for(ParametersMap::iterator iter = _modifiedParameters.begin(); iter!=_modifiedParameters.end(); ++iter) 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()); 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("subtractFilteringRadius", _ui->doubleSpinBox_subtractFilteringRadius->value());
settings.setValue("subtractFilteringAngle", _ui->doubleSpinBox_subtractFilteringAngle->value()); settings.setValue("subtractFilteringAngle", _ui->doubleSpinBox_subtractFilteringAngle->value());
settings.setValue("normalKSearch", _ui->spinBox_normalKSearch->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("gridMapShown", _ui->checkBox_map_shown->isChecked());
settings.setValue("gridMapResolution", _ui->doubleSpinBox_map_resolution->value()); 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", _ui->groupBox_organized->isChecked());
settings.setValue("meshing_angle", _ui->doubleSpinBox_mesh_angleTolerance->value()); settings.setValue("meshing_angle", _ui->doubleSpinBox_mesh_angleTolerance->value());
settings.setValue("meshing_quad", _ui->checkBox_mesh_quad->isChecked()); 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.setValue("meshing_triangle_size", _ui->spinBox_mesh_triangleSize->value());
settings.endGroup(); // General settings.endGroup(); // General
@@ -3759,6 +3775,10 @@ bool PreferencesDialog::isCloudMeshingQuad() const
{ {
return _ui->checkBox_mesh_quad->isChecked(); return _ui->checkBox_mesh_quad->isChecked();
} }
bool PreferencesDialog::isCloudMeshingTexture() const
{
return _ui->checkBox_mesh_texture->isChecked();
}
int PreferencesDialog::getCloudMeshingTriangleSize() int PreferencesDialog::getCloudMeshingTriangleSize()
{ {
return _ui->spinBox_mesh_triangleSize->value(); return _ui->spinBox_mesh_triangleSize->value();
@@ -3858,6 +3878,10 @@ int PreferencesDialog::getNormalKSearch() const
{ {
return _ui->spinBox_normalKSearch->value(); return _ui->spinBox_normalKSearch->value();
} }
bool PreferencesDialog::gainCompensation() const
{
return _ui->checkBox_gainCompensation->isChecked();
}
bool PreferencesDialog::getGridMapShown() const bool PreferencesDialog::getGridMapShown() const
{ {
return _ui->checkBox_map_shown->isChecked(); return _ui->checkBox_map_shown->isChecked();
+39 -7
View File
@@ -52,7 +52,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>205</width> <width>204</width>
<height>208</height> <height>208</height>
</rect> </rect>
</property> </property>
@@ -210,7 +210,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>203</width> <width>202</width>
<height>208</height> <height>208</height>
</rect> </rect>
</property> </property>
@@ -1125,9 +1125,9 @@
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>0</x> <x>0</x>
<y>-225</y> <y>-32</y>
<width>280</width> <width>280</width>
<height>465</height> <height>584</height>
</rect> </rect>
</property> </property>
<attribute name="label"> <attribute name="label">
@@ -1170,6 +1170,38 @@
</property> </property>
</widget> </widget>
</item> </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> </layout>
</item> </item>
<item> <item>
@@ -1411,8 +1443,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>265</width> <width>282</width>
<height>126</height> <height>163</height>
</rect> </rect>
</property> </property>
<attribute name="label"> <attribute name="label">
@@ -1511,7 +1543,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>265</width> <width>267</width>
<height>168</height> <height>168</height>
</rect> </rect>
</property> </property>
+201 -61
View File
@@ -23,24 +23,14 @@
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>0</x> <x>0</x>
<y>-860</y> <y>0</y>
<width>773</width> <width>773</width>
<height>1463</height> <height>1648</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_13"> <layout class="QVBoxLayout" name="verticalLayout_13">
<item> <item>
<layout class="QGridLayout" name="gridLayout_8" columnstretch="0,1"> <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"> <item row="3" column="0">
<widget class="QSpinBox" name="spinBox_normalKSearch"> <widget class="QSpinBox" name="spinBox_normalKSearch">
<property name="minimum"> <property name="minimum">
@@ -51,10 +41,17 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="1"> <item row="2" column="0">
<widget class="QLabel" name="label_binaryFile"> <widget class="QCheckBox" name="checkBox_assemble">
<property name="text"> <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>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -71,23 +68,6 @@
</property> </property>
</widget> </widget>
</item> </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"> <item row="4" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_voxelSize_assembled"> <widget class="QDoubleSpinBox" name="doubleSpinBox_voxelSize_assembled">
<property name="suffix"> <property name="suffix">
@@ -138,6 +118,26 @@
</item> </item>
</widget> </widget>
</item> </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> </layout>
</item> </item>
<item> <item>
@@ -782,6 +782,146 @@ Guidelines: 4 times the voxel size, 0.025 for voxel=0.</string>
</layout> </layout>
</widget> </widget>
</item> </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> <item>
<widget class="QGroupBox" name="groupBox_meshing"> <widget class="QGroupBox" name="groupBox_meshing">
<property name="title"> <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"> <layout class="QVBoxLayout" name="verticalLayout_15">
<item> <item>
<layout class="QGridLayout" name="gridLayout_10" columnstretch="0,1"> <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"> <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"> <widget class="QDoubleSpinBox" name="doubleSpinBox_meshDecimationFactor">
<property name="decimals"> <property name="decimals">
<number>2</number> <number>2</number>
@@ -839,20 +952,47 @@ Guidelines: 4 times the voxel size, 0.025 for voxel=0.</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="1"> <item row="3" column="1">
<widget class="QLabel" name="label_16"> <widget class="QLabel" name="label_16">
<property name="text"> <property name="text">
<string>Min polygon cluster size</string> <string>Min polygon cluster size</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="0"> <item row="3" column="0">
<widget class="QSpinBox" name="spinBox_mesh_minClusterSize"> <widget class="QSpinBox" name="spinBox_mesh_minClusterSize">
<property name="maximum"> <property name="maximum">
<number>999</number> <number>999</number>
</property> </property>
</widget> </widget>
</item> </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> </layout>
</item> </item>
<item> <item>
+352 -312
View File
@@ -64,8 +64,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>678</width> <width>673</width>
<height>2417</height> <height>2496</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_16"> <layout class="QVBoxLayout" name="verticalLayout_16">
@@ -86,7 +86,7 @@
<enum>QFrame::Raised</enum> <enum>QFrame::Raised</enum>
</property> </property>
<property name="currentIndex"> <property name="currentIndex">
<number>3</number> <number>1</number>
</property> </property>
<widget class="QWidget" name="page_22"> <widget class="QWidget" name="page_22">
<layout class="QVBoxLayout" name="verticalLayout_29" stretch="0,1"> <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"> <layout class="QVBoxLayout" name="verticalLayout_98">
<item> <item>
<layout class="QGridLayout" name="gridLayout_2" columnstretch="0,0,1"> <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"> <item row="0" column="0">
<widget class="QLabel" name="label_154"> <widget class="QLabel" name="label_154">
<property name="text"> <property name="text">
@@ -459,51 +446,6 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property> </property>
</widget> </widget>
</item> </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"> <item row="6" column="2">
<widget class="QLabel" name="label_168"> <widget class="QLabel" name="label_168">
<property name="text"> <property name="text">
@@ -517,19 +459,6 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property> </property>
</widget> </widget>
</item> </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"> <item row="3" column="1">
<widget class="QDoubleSpinBox" name="doubleSpinBox_maxDepth_odom"> <widget class="QDoubleSpinBox" name="doubleSpinBox_maxDepth_odom">
<property name="suffix"> <property name="suffix">
@@ -549,19 +478,6 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property> </property>
</widget> </widget>
</item> </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"> <item row="4" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_minDepth"> <widget class="QDoubleSpinBox" name="doubleSpinBox_minDepth">
<property name="suffix"> <property name="suffix">
@@ -581,7 +497,7 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property> </property>
</widget> </widget>
</item> </item>
<item row="16" column="1"> <item row="17" column="1">
<widget class="QCheckBox" name="checkBox_showOdomFeatures"> <widget class="QCheckBox" name="checkBox_showOdomFeatures">
<property name="text"> <property name="text">
<string/> <string/>
@@ -591,7 +507,7 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property> </property>
</widget> </widget>
</item> </item>
<item row="16" column="2"> <item row="17" column="2">
<widget class="QLabel" name="label_123"> <widget class="QLabel" name="label_123">
<property name="text"> <property name="text">
<string>Show 3D features.</string> <string>Show 3D features.</string>
@@ -604,30 +520,7 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property> </property>
</widget> </widget>
</item> </item>
<item row="17" column="0"> <item row="12" 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">
<widget class="QCheckBox" name="checkBox_showScans"> <widget class="QCheckBox" name="checkBox_showScans">
<property name="text"> <property name="text">
<string/> <string/>
@@ -637,7 +530,7 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property> </property>
</widget> </widget>
</item> </item>
<item row="11" column="1"> <item row="12" column="1">
<widget class="QCheckBox" name="checkBox_showOdomScans"> <widget class="QCheckBox" name="checkBox_showOdomScans">
<property name="text"> <property name="text">
<string/> <string/>
@@ -647,7 +540,7 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property> </property>
</widget> </widget>
</item> </item>
<item row="11" column="2"> <item row="12" column="2">
<widget class="QLabel" name="label_110"> <widget class="QLabel" name="label_110">
<property name="text"> <property name="text">
<string>Show scans.</string> <string>Show scans.</string>
@@ -660,7 +553,7 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property> </property>
</widget> </widget>
</item> </item>
<item row="12" column="0"> <item row="13" column="0">
<widget class="QSpinBox" name="spinBox_downsamplingScan"> <widget class="QSpinBox" name="spinBox_downsamplingScan">
<property name="minimum"> <property name="minimum">
<number>1</number> <number>1</number>
@@ -670,17 +563,7 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property> </property>
</widget> </widget>
</item> </item>
<item row="12" column="1"> <item row="13" column="2">
<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">
<widget class="QLabel" name="label_273"> <widget class="QLabel" name="label_273">
<property name="text"> <property name="text">
<string>Scan downsampling step size.</string> <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> </property>
</widget> </widget>
</item> </item>
<item row="13" column="0"> <item row="14" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_voxelSizeScan"> <widget class="QDoubleSpinBox" name="doubleSpinBox_voxelSizeScan">
<property name="suffix"> <property name="suffix">
<string> m</string> <string> m</string>
@@ -712,7 +595,7 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property> </property>
</widget> </widget>
</item> </item>
<item row="13" column="1"> <item row="14" column="1">
<widget class="QDoubleSpinBox" name="doubleSpinBox_voxelSizeScan_odom"> <widget class="QDoubleSpinBox" name="doubleSpinBox_voxelSizeScan_odom">
<property name="suffix"> <property name="suffix">
<string> m</string> <string> m</string>
@@ -731,39 +614,7 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property> </property>
</widget> </widget>
</item> </item>
<item row="13" column="2"> <item row="15" column="1">
<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">
<widget class="QDoubleSpinBox" name="doubleSpinBox_opacity_odom_scan"> <widget class="QDoubleSpinBox" name="doubleSpinBox_opacity_odom_scan">
<property name="suffix"> <property name="suffix">
<string/> <string/>
@@ -782,19 +633,6 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property> </property>
</widget> </widget>
</item> </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"> <item row="7" column="2">
<widget class="QLabel" name="label_169"> <widget class="QLabel" name="label_169">
<property name="text"> <property name="text">
@@ -808,20 +646,7 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property> </property>
</widget> </widget>
</item> </item>
<item row="8" column="0"> <item row="18" column="1">
<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">
<widget class="QSpinBox" name="spinBox_ptsize_odom_features"> <widget class="QSpinBox" name="spinBox_ptsize_odom_features">
<property name="minimum"> <property name="minimum">
<number>1</number> <number>1</number>
@@ -831,7 +656,7 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property> </property>
</widget> </widget>
</item> </item>
<item row="17" column="2"> <item row="18" column="2">
<widget class="QLabel" name="label_166"> <widget class="QLabel" name="label_166">
<property name="text"> <property name="text">
<string>Feature point size.</string> <string>Feature point size.</string>
@@ -844,7 +669,7 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property> </property>
</widget> </widget>
</item> </item>
<item row="9" column="0"> <item row="10" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_opacity"> <widget class="QDoubleSpinBox" name="doubleSpinBox_opacity">
<property name="suffix"> <property name="suffix">
<string/> <string/>
@@ -863,39 +688,7 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property> </property>
</widget> </widget>
</item> </item>
<item row="9" column="1"> <item row="11" column="0">
<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">
<widget class="QSpinBox" name="spinBox_ptsize"> <widget class="QSpinBox" name="spinBox_ptsize">
<property name="minimum"> <property name="minimum">
<number>1</number> <number>1</number>
@@ -908,20 +701,7 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property> </property>
</widget> </widget>
</item> </item>
<item row="10" column="1"> <item row="11" column="2">
<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">
<widget class="QLabel" name="label_157"> <widget class="QLabel" name="label_157">
<property name="text"> <property name="text">
<string>3D cloud point size (1..64).</string> <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> </property>
</widget> </widget>
</item> </item>
<item row="15" column="0"> <item row="16" column="1">
<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">
<widget class="QSpinBox" name="spinBox_ptsize_odom_scan"> <widget class="QSpinBox" name="spinBox_ptsize_odom_scan">
<property name="minimum"> <property name="minimum">
<number>1</number> <number>1</number>
@@ -954,20 +724,7 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property> </property>
</widget> </widget>
</item> </item>
<item row="15" column="2"> <item row="17" column="0">
<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">
<widget class="QCheckBox" name="checkBox_showFeatures"> <widget class="QCheckBox" name="checkBox_showFeatures">
<property name="text"> <property name="text">
<string/> <string/>
@@ -977,19 +734,6 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property> </property>
</widget> </widget>
</item> </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"> <item row="1" column="0">
<widget class="QCheckBox" name="checkBox_showClouds"> <widget class="QCheckBox" name="checkBox_showClouds">
<property name="text"> <property name="text">
@@ -1045,16 +789,6 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property> </property>
</widget> </widget>
</item> </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"> <item row="4" column="1">
<widget class="QDoubleSpinBox" name="doubleSpinBox_minDepth_odom"> <widget class="QDoubleSpinBox" name="doubleSpinBox_minDepth_odom">
<property name="suffix"> <property name="suffix">
@@ -1077,6 +811,285 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property> </property>
</widget> </widget>
</item> </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"> <item row="1" column="2">
<widget class="QLabel" name="label_119"> <widget class="QLabel" name="label_119">
<property name="text"> <property name="text">
@@ -1090,20 +1103,7 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property> </property>
</widget> </widget>
</item> </item>
<item row="18" column="2"> <item row="20" 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">
<widget class="QLabel" name="label_243"> <widget class="QLabel" name="label_243">
<property name="text"> <property name="text">
<string>Show labels.</string> <string>Show labels.</string>
@@ -1116,7 +1116,7 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property> </property>
</widget> </widget>
</item> </item>
<item row="18" column="0"> <item row="19" column="0">
<widget class="QCheckBox" name="checkBox_showGraphs"> <widget class="QCheckBox" name="checkBox_showGraphs">
<property name="text"> <property name="text">
<string/> <string/>
@@ -1126,7 +1126,7 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property> </property>
</widget> </widget>
</item> </item>
<item row="19" column="0"> <item row="20" column="0">
<widget class="QCheckBox" name="checkBox_showLabels"> <widget class="QCheckBox" name="checkBox_showLabels">
<property name="text"> <property name="text">
<string/> <string/>
@@ -1136,6 +1136,29 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property> </property>
</widget> </widget>
</item> </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> </layout>
</item> </item>
<item> <item>
@@ -1156,16 +1179,6 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property> </property>
</widget> </widget>
</item> </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"> <item row="1" column="1">
<widget class="QLabel" name="label_quad"> <widget class="QLabel" name="label_quad">
<property name="text"> <property name="text">
@@ -1193,6 +1206,16 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property> </property>
</widget> </widget>
</item> </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"> <item row="0" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_mesh_angleTolerance"> <widget class="QDoubleSpinBox" name="doubleSpinBox_mesh_angleTolerance">
<property name="suffix"> <property name="suffix">
@@ -1212,6 +1235,23 @@ Show a yellow background when the number of odometry inliers goes under this thr
</property> </property>
</widget> </widget>
</item> </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> </layout>
</item> </item>
</layout> </layout>