mirror of
https://github.com/introlab/rtabmap.git
synced 2026-09-02 17:40:23 +08:00
added subtractFiltering() method to filter point clouds by subtracting the previous cloud
This commit is contained in:
@@ -156,6 +156,14 @@ std::multimap<int, int>::iterator RTABMAP_EXP findLink(
|
|||||||
std::multimap<int, int> & links,
|
std::multimap<int, int> & links,
|
||||||
int from,
|
int from,
|
||||||
int to);
|
int to);
|
||||||
|
std::multimap<int, Link>::const_iterator RTABMAP_EXP findLink(
|
||||||
|
const std::multimap<int, Link> & links,
|
||||||
|
int from,
|
||||||
|
int to);
|
||||||
|
std::multimap<int, int>::const_iterator RTABMAP_EXP findLink(
|
||||||
|
const std::multimap<int, int> & links,
|
||||||
|
int from,
|
||||||
|
int to);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get only the the most recent or older poses in the defined radius.
|
* Get only the the most recent or older poses in the defined radius.
|
||||||
|
|||||||
@@ -115,6 +115,33 @@ pcl::IndicesPtr RTABMAP_EXP radiusFiltering(
|
|||||||
float radiusSearch,
|
float radiusSearch,
|
||||||
int minNeighborsInRadius);
|
int minNeighborsInRadius);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For convenience.
|
||||||
|
*/
|
||||||
|
pcl::PointCloud<pcl::PointXYZRGB>::Ptr RTABMAP_EXP subtractFiltering(
|
||||||
|
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
|
||||||
|
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & substractCloud,
|
||||||
|
float radiusSearch,
|
||||||
|
int minNeighborsInRadius = 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subtract a cloud from another one using radius filtering.
|
||||||
|
* @param cloud the input cloud.
|
||||||
|
* @param indices the input indices of the cloud to check, if empty, all points in the cloud are checked.
|
||||||
|
* @param cloud the input cloud to subtract.
|
||||||
|
* @param indices the input indices of the subtracted cloud to check, if empty, all points in the cloud are checked.
|
||||||
|
* @param radiusSearch the radius in meter.
|
||||||
|
* @return the indices of the points satisfying the parameters.
|
||||||
|
*/
|
||||||
|
pcl::IndicesPtr RTABMAP_EXP subtractFiltering(
|
||||||
|
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
|
||||||
|
const pcl::IndicesPtr & indices,
|
||||||
|
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & substractCloud,
|
||||||
|
const pcl::IndicesPtr & substractIndices,
|
||||||
|
float radiusSearch,
|
||||||
|
int minNeighborsInRadius = 0);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For convenience.
|
* For convenience.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -947,6 +947,61 @@ std::multimap<int, int>::iterator findLink(
|
|||||||
}
|
}
|
||||||
return links.end();
|
return links.end();
|
||||||
}
|
}
|
||||||
|
std::multimap<int, Link>::const_iterator findLink(
|
||||||
|
const std::multimap<int, Link> & links,
|
||||||
|
int from,
|
||||||
|
int to)
|
||||||
|
{
|
||||||
|
std::multimap<int, Link>::const_iterator iter = links.find(from);
|
||||||
|
while(iter != links.end() && iter->first == from)
|
||||||
|
{
|
||||||
|
if(iter->second.to() == to)
|
||||||
|
{
|
||||||
|
return iter;
|
||||||
|
}
|
||||||
|
++iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
// let's try to -> from
|
||||||
|
iter = links.find(to);
|
||||||
|
while(iter != links.end() && iter->first == to)
|
||||||
|
{
|
||||||
|
if(iter->second.to() == from)
|
||||||
|
{
|
||||||
|
return iter;
|
||||||
|
}
|
||||||
|
++iter;
|
||||||
|
}
|
||||||
|
return links.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::multimap<int, int>::const_iterator findLink(
|
||||||
|
const std::multimap<int, int> & links,
|
||||||
|
int from,
|
||||||
|
int to)
|
||||||
|
{
|
||||||
|
std::multimap<int, int>::const_iterator iter = links.find(from);
|
||||||
|
while(iter != links.end() && iter->first == from)
|
||||||
|
{
|
||||||
|
if(iter->second == to)
|
||||||
|
{
|
||||||
|
return iter;
|
||||||
|
}
|
||||||
|
++iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
// let's try to -> from
|
||||||
|
iter = links.find(to);
|
||||||
|
while(iter != links.end() && iter->first == to)
|
||||||
|
{
|
||||||
|
if(iter->second == from)
|
||||||
|
{
|
||||||
|
return iter;
|
||||||
|
}
|
||||||
|
++iter;
|
||||||
|
}
|
||||||
|
return links.end();
|
||||||
|
}
|
||||||
|
|
||||||
std::map<int, Transform> radiusPosesFiltering(
|
std::map<int, Transform> radiusPosesFiltering(
|
||||||
const std::map<int, Transform> & poses,
|
const std::map<int, Transform> & poses,
|
||||||
|
|||||||
@@ -281,6 +281,82 @@ pcl::IndicesPtr radiusFiltering(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pcl::PointCloud<pcl::PointXYZRGB>::Ptr subtractFiltering(
|
||||||
|
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
|
||||||
|
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & substractCloud,
|
||||||
|
float radiusSearch,
|
||||||
|
int minNeighborsInRadius)
|
||||||
|
{
|
||||||
|
pcl::IndicesPtr indices(new std::vector<int>);
|
||||||
|
pcl::IndicesPtr indicesOut = subtractFiltering(cloud, indices, substractCloud, indices, radiusSearch, minNeighborsInRadius);
|
||||||
|
pcl::PointCloud<pcl::PointXYZRGB>::Ptr out(new pcl::PointCloud<pcl::PointXYZRGB>);
|
||||||
|
pcl::copyPointCloud(*cloud, *indicesOut, *out);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pcl::IndicesPtr subtractFiltering(
|
||||||
|
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
|
||||||
|
const pcl::IndicesPtr & indices,
|
||||||
|
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & substractCloud,
|
||||||
|
const pcl::IndicesPtr & substractIndices,
|
||||||
|
float radiusSearch,
|
||||||
|
int minNeighborsInRadius)
|
||||||
|
{
|
||||||
|
pcl::search::KdTree<pcl::PointXYZRGB>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZRGB>(false));
|
||||||
|
|
||||||
|
if(indices->size())
|
||||||
|
{
|
||||||
|
pcl::IndicesPtr output(new std::vector<int>(indices->size()));
|
||||||
|
int oi = 0; // output iterator
|
||||||
|
if(substractIndices->size())
|
||||||
|
{
|
||||||
|
tree->setInputCloud(substractCloud, substractIndices);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tree->setInputCloud(substractCloud);
|
||||||
|
}
|
||||||
|
for(unsigned int i=0; i<indices->size(); ++i)
|
||||||
|
{
|
||||||
|
std::vector<int> kIndices;
|
||||||
|
std::vector<float> kDistances;
|
||||||
|
int k = tree->radiusSearch(cloud->at(indices->at(i)), radiusSearch, kIndices, kDistances);
|
||||||
|
if(k <= minNeighborsInRadius)
|
||||||
|
{
|
||||||
|
output->at(oi++) = indices->at(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
output->resize(oi);
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pcl::IndicesPtr output(new std::vector<int>(cloud->size()));
|
||||||
|
int oi = 0; // output iterator
|
||||||
|
if(substractIndices->size())
|
||||||
|
{
|
||||||
|
tree->setInputCloud(substractCloud, substractIndices);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tree->setInputCloud(substractCloud);
|
||||||
|
}
|
||||||
|
for(unsigned int i=0; i<cloud->size(); ++i)
|
||||||
|
{
|
||||||
|
std::vector<int> kIndices;
|
||||||
|
std::vector<float> kDistances;
|
||||||
|
int k = tree->radiusSearch(cloud->at(i), radiusSearch, kIndices, kDistances);
|
||||||
|
if(k <= minNeighborsInRadius)
|
||||||
|
{
|
||||||
|
output->at(oi++) = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
output->resize(oi);
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
pcl::IndicesPtr normalFiltering(
|
pcl::IndicesPtr normalFiltering(
|
||||||
const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud,
|
const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud,
|
||||||
|
|||||||
@@ -206,7 +206,7 @@ signals:
|
|||||||
private:
|
private:
|
||||||
void update3DMapVisibility(bool cloudsShown, bool scansShown);
|
void update3DMapVisibility(bool cloudsShown, bool scansShown);
|
||||||
void updateMapCloud(const std::map<int, Transform> & poses, const Transform & pose, const std::multimap<int, Link> & constraints, const std::map<int, int> & mapIds, bool verboseProgress = false);
|
void updateMapCloud(const std::map<int, Transform> & poses, const Transform & pose, const std::multimap<int, Link> & constraints, const std::map<int, int> & mapIds, bool verboseProgress = false);
|
||||||
void createAndAddCloudToMap(int nodeId, const Transform & pose, int mapId);
|
void createAndAddCloudToMap(int nodeId, const Transform & pose, int mapId);
|
||||||
void createAndAddScanToMap(int nodeId, const Transform & pose, int mapId);
|
void createAndAddScanToMap(int nodeId, const Transform & pose, int mapId);
|
||||||
void drawKeypoints(const std::multimap<int, cv::KeyPoint> & refWords, const std::multimap<int, cv::KeyPoint> & loopWords);
|
void drawKeypoints(const std::multimap<int, cv::KeyPoint> & refWords, const std::multimap<int, cv::KeyPoint> & loopWords);
|
||||||
void setupMainLayout(bool vertical);
|
void setupMainLayout(bool vertical);
|
||||||
|
|||||||
@@ -157,8 +157,10 @@ public:
|
|||||||
double getMeshSmoothingRadius() const;
|
double getMeshSmoothingRadius() const;
|
||||||
|
|
||||||
bool isCloudFiltering() const;
|
bool isCloudFiltering() const;
|
||||||
|
bool isSubtractFiltering() const;
|
||||||
double getCloudFilteringRadius() const;
|
double getCloudFilteringRadius() const;
|
||||||
double getCloudFilteringAngle() const;
|
double getCloudFilteringAngle() const;
|
||||||
|
int getSubstractFilteringMinPts() const;
|
||||||
|
|
||||||
bool getGridMapShown() const;
|
bool getGridMapShown() const;
|
||||||
double getGridMapResolution() const;
|
double getGridMapResolution() const;
|
||||||
|
|||||||
@@ -94,7 +94,6 @@ public:
|
|||||||
|
|
||||||
CloudViewer::CloudViewer(QWidget *parent) :
|
CloudViewer::CloudViewer(QWidget *parent) :
|
||||||
QVTKWidget(parent),
|
QVTKWidget(parent),
|
||||||
_visualizer(new pcl::visualization::PCLVisualizer("PCLVisualizer", false)),
|
|
||||||
_aLockCamera(0),
|
_aLockCamera(0),
|
||||||
_aFollowCamera(0),
|
_aFollowCamera(0),
|
||||||
_aResetCamera(0),
|
_aResetCamera(0),
|
||||||
@@ -119,13 +118,15 @@ CloudViewer::CloudViewer(QWidget *parent) :
|
|||||||
{
|
{
|
||||||
this->setMinimumSize(200, 200);
|
this->setMinimumSize(200, 200);
|
||||||
|
|
||||||
|
int argc = 0;
|
||||||
|
_visualizer = new pcl::visualization::PCLVisualizer(argc, 0, "PCLVisualizer", vtkSmartPointer<MyInteractorStyle>(new MyInteractorStyle()), false);
|
||||||
|
|
||||||
this->SetRenderWindow(_visualizer->getRenderWindow());
|
this->SetRenderWindow(_visualizer->getRenderWindow());
|
||||||
|
|
||||||
// Replaced by the second line, to avoid a crash in Mac OS X on close, as well as
|
// Replaced by the second line, to avoid a crash in Mac OS X on close, as well as
|
||||||
// the "Invalid drawable" warning when the view is not visible.
|
// the "Invalid drawable" warning when the view is not visible.
|
||||||
//_visualizer->setupInteractor(this->GetInteractor(), this->GetRenderWindow());
|
//_visualizer->setupInteractor(this->GetInteractor(), this->GetRenderWindow());
|
||||||
vtkSmartPointer<MyInteractorStyle> interactor(new MyInteractorStyle());
|
this->GetInteractor()->SetInteractorStyle (_visualizer->getInteractorStyle());
|
||||||
this->GetInteractor()->SetInteractorStyle (interactor);
|
|
||||||
|
|
||||||
_visualizer->setCameraPosition(
|
_visualizer->setCameraPosition(
|
||||||
-1, 0, 0,
|
-1, 0, 0,
|
||||||
|
|||||||
@@ -1645,6 +1645,7 @@ void MainWindow::createAndAddCloudToMap(int nodeId, const Transform & pose, int
|
|||||||
_preferencesDialog->getCloudDecimation(0),
|
_preferencesDialog->getCloudDecimation(0),
|
||||||
_preferencesDialog->getCloudMaxDepth(0),
|
_preferencesDialog->getCloudMaxDepth(0),
|
||||||
_preferencesDialog->getCloudVoxelSize(0));
|
_preferencesDialog->getCloudVoxelSize(0));
|
||||||
|
_createdClouds.insert(std::make_pair(nodeId, cloud));
|
||||||
|
|
||||||
if(cloud->size() && _preferencesDialog->isGridMapFrom3DCloud())
|
if(cloud->size() && _preferencesDialog->isGridMapFrom3DCloud())
|
||||||
{
|
{
|
||||||
@@ -1654,7 +1655,7 @@ void MainWindow::createAndAddCloudToMap(int nodeId, const Transform & pose, int
|
|||||||
int minClusterSize = 20;
|
int minClusterSize = 20;
|
||||||
cv::Mat ground, obstacles;
|
cv::Mat ground, obstacles;
|
||||||
pcl::PointCloud<pcl::PointXYZRGB>::Ptr voxelizedCloud = cloud;
|
pcl::PointCloud<pcl::PointXYZRGB>::Ptr voxelizedCloud = cloud;
|
||||||
if(voxelizedCloud->size())
|
if(voxelizedCloud->size() && cellSize > _preferencesDialog->getCloudVoxelSize(0))
|
||||||
{
|
{
|
||||||
voxelizedCloud = util3d::voxelize(cloud, cellSize);
|
voxelizedCloud = util3d::voxelize(cloud, cellSize);
|
||||||
}
|
}
|
||||||
@@ -1671,19 +1672,60 @@ void MainWindow::createAndAddCloudToMap(int nodeId, const Transform & pose, int
|
|||||||
UDEBUG("time gridMapFrom2DCloud = %f s", timer.ticks());
|
UDEBUG("time gridMapFrom2DCloud = %f s", timer.ticks());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloudFiltered = cloud;
|
||||||
|
if(_preferencesDialog->isSubtractFiltering() &&
|
||||||
|
_preferencesDialog->getCloudVoxelSize(0) > 0.0 &&
|
||||||
|
cloud->size() &&
|
||||||
|
_createdClouds.size() &&
|
||||||
|
_currentPosesMap.size() &&
|
||||||
|
_currentLinksMap.size())
|
||||||
|
{
|
||||||
|
// find link to previous neighbor
|
||||||
|
std::map<int, Transform>::const_iterator previousIter = _currentPosesMap.find(nodeId);
|
||||||
|
Link link;
|
||||||
|
if(previousIter != _currentPosesMap.begin())
|
||||||
|
{
|
||||||
|
--previousIter;
|
||||||
|
std::multimap<int, Link>::const_iterator linkIter = graph::findLink(_currentLinksMap, nodeId, previousIter->first);
|
||||||
|
if(linkIter != _currentLinksMap.end())
|
||||||
|
{
|
||||||
|
link = linkIter->second;
|
||||||
|
if(link.from() != nodeId)
|
||||||
|
{
|
||||||
|
link = link.inverse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(link.isValid())
|
||||||
|
{
|
||||||
|
std::map<int, pcl::PointCloud<pcl::PointXYZRGB>::Ptr>::iterator iter = _createdClouds.find(link.to());
|
||||||
|
if(iter!=_createdClouds.end() && iter->second->size())
|
||||||
|
{
|
||||||
|
pcl::PointCloud<pcl::PointXYZRGB>::Ptr previousCloud = util3d::transformPointCloud(iter->second, link.transform());
|
||||||
|
cloudFiltered = util3d::subtractFiltering(
|
||||||
|
cloud,
|
||||||
|
previousCloud,
|
||||||
|
_preferencesDialog->getCloudVoxelSize(0),
|
||||||
|
_preferencesDialog->getSubstractFilteringMinPts());
|
||||||
|
UDEBUG("Filtering %d from %d -> %d", (int)previousCloud->size(), (int)cloud->size(), (int)cloudFiltered->size());
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(_preferencesDialog->isCloudMeshing())
|
if(_preferencesDialog->isCloudMeshing())
|
||||||
{
|
{
|
||||||
pcl::PolygonMesh::Ptr mesh(new pcl::PolygonMesh);
|
pcl::PolygonMesh::Ptr mesh(new pcl::PolygonMesh);
|
||||||
if(cloud->size())
|
if(cloudFiltered->size())
|
||||||
{
|
{
|
||||||
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr cloudWithNormals;
|
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr cloudWithNormals;
|
||||||
if(_preferencesDialog->getMeshSmoothing())
|
if(_preferencesDialog->getMeshSmoothing())
|
||||||
{
|
{
|
||||||
cloudWithNormals = util3d::computeNormalsSmoothed(cloud, (float)_preferencesDialog->getMeshSmoothingRadius());
|
cloudWithNormals = util3d::computeNormalsSmoothed(cloudFiltered, (float)_preferencesDialog->getMeshSmoothingRadius());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cloudWithNormals = util3d::computeNormals(cloud, _preferencesDialog->getMeshNormalKSearch());
|
cloudWithNormals = util3d::computeNormals(cloudFiltered, _preferencesDialog->getMeshNormalKSearch());
|
||||||
}
|
}
|
||||||
mesh = util3d::createMesh(cloudWithNormals, _preferencesDialog->getMeshGP3Radius());
|
mesh = util3d::createMesh(cloudWithNormals, _preferencesDialog->getMeshGP3Radius());
|
||||||
}
|
}
|
||||||
@@ -1696,10 +1738,6 @@ void MainWindow::createAndAddCloudToMap(int nodeId, const Transform & pose, int
|
|||||||
{
|
{
|
||||||
UERROR("Adding mesh cloud %d to viewer failed!", nodeId);
|
UERROR("Adding mesh cloud %d to viewer failed!", nodeId);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
_createdClouds.insert(std::make_pair(nodeId, tmp));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -1707,23 +1745,19 @@ void MainWindow::createAndAddCloudToMap(int nodeId, const Transform & pose, int
|
|||||||
if(_preferencesDialog->getMeshSmoothing())
|
if(_preferencesDialog->getMeshSmoothing())
|
||||||
{
|
{
|
||||||
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr cloudWithNormals;
|
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr cloudWithNormals;
|
||||||
cloudWithNormals = util3d::computeNormalsSmoothed(cloud, (float)_preferencesDialog->getMeshSmoothingRadius());
|
cloudWithNormals = util3d::computeNormalsSmoothed(cloudFiltered, (float)_preferencesDialog->getMeshSmoothingRadius());
|
||||||
cloud->clear();
|
cloudFiltered.reset(new pcl::PointCloud<pcl::PointXYZRGB>);
|
||||||
pcl::copyPointCloud(*cloudWithNormals, *cloud);
|
pcl::copyPointCloud(*cloudWithNormals, *cloudFiltered);
|
||||||
}
|
}
|
||||||
QColor color = Qt::gray;
|
QColor color = Qt::gray;
|
||||||
if(mapId >= 0)
|
if(mapId >= 0)
|
||||||
{
|
{
|
||||||
color = (Qt::GlobalColor)(mapId+3 % 12 + 7 );
|
color = (Qt::GlobalColor)(mapId+3 % 12 + 7 );
|
||||||
}
|
}
|
||||||
if(!_ui->widget_cloudViewer->addOrUpdateCloud(cloudName, cloud, pose, color))
|
if(!_ui->widget_cloudViewer->addOrUpdateCloud(cloudName, cloudFiltered, pose, color))
|
||||||
{
|
{
|
||||||
UERROR("Adding cloud %d to viewer failed!", nodeId);
|
UERROR("Adding cloud %d to viewer failed!", nodeId);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
_createdClouds.insert(std::make_pair(nodeId, cloud));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(iter->getWords3().size())
|
else if(iter->getWords3().size())
|
||||||
|
|||||||
@@ -295,9 +295,11 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
|
|||||||
connect(_ui->checkBox_mls, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteCloudRenderingPanel()));
|
connect(_ui->checkBox_mls, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteCloudRenderingPanel()));
|
||||||
connect(_ui->doubleSpinBox_mlsRadius, SIGNAL(valueChanged(double)), this, SLOT(makeObsoleteCloudRenderingPanel()));
|
connect(_ui->doubleSpinBox_mlsRadius, SIGNAL(valueChanged(double)), this, SLOT(makeObsoleteCloudRenderingPanel()));
|
||||||
|
|
||||||
connect(_ui->groupBox_poseFiltering, SIGNAL(clicked(bool)), this, SLOT(makeObsoleteCloudRenderingPanel()));
|
connect(_ui->checkBox_nodeFiltering, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteCloudRenderingPanel()));
|
||||||
|
connect(_ui->checkBox_subtractFiltering, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteCloudRenderingPanel()));
|
||||||
connect(_ui->doubleSpinBox_cloudFilterRadius, SIGNAL(valueChanged(double)), this, SLOT(makeObsoleteCloudRenderingPanel()));
|
connect(_ui->doubleSpinBox_cloudFilterRadius, SIGNAL(valueChanged(double)), this, SLOT(makeObsoleteCloudRenderingPanel()));
|
||||||
connect(_ui->doubleSpinBox_cloudFilterAngle, SIGNAL(valueChanged(double)), this, SLOT(makeObsoleteCloudRenderingPanel()));
|
connect(_ui->doubleSpinBox_cloudFilterAngle, SIGNAL(valueChanged(double)), this, SLOT(makeObsoleteCloudRenderingPanel()));
|
||||||
|
connect(_ui->spinBox_substractFilteringMinPts, SIGNAL(valueChanged(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()));
|
||||||
@@ -999,9 +1001,11 @@ void PreferencesDialog::resetSettings(QGroupBox * groupBox)
|
|||||||
_ui->checkBox_mls->setChecked(false);
|
_ui->checkBox_mls->setChecked(false);
|
||||||
_ui->doubleSpinBox_mlsRadius->setValue(0.04);
|
_ui->doubleSpinBox_mlsRadius->setValue(0.04);
|
||||||
|
|
||||||
_ui->groupBox_poseFiltering->setChecked(true);
|
_ui->checkBox_nodeFiltering->setChecked(true);
|
||||||
|
_ui->checkBox_subtractFiltering->setChecked(false);
|
||||||
_ui->doubleSpinBox_cloudFilterRadius->setValue(0.1);
|
_ui->doubleSpinBox_cloudFilterRadius->setValue(0.1);
|
||||||
_ui->doubleSpinBox_cloudFilterAngle->setValue(30);
|
_ui->doubleSpinBox_cloudFilterAngle->setValue(30);
|
||||||
|
_ui->spinBox_substractFilteringMinPts->setValue(0);
|
||||||
|
|
||||||
_ui->checkBox_map_shown->setChecked(false);
|
_ui->checkBox_map_shown->setChecked(false);
|
||||||
_ui->doubleSpinBox_map_resolution->setValue(0.05);
|
_ui->doubleSpinBox_map_resolution->setValue(0.05);
|
||||||
@@ -1261,9 +1265,11 @@ void PreferencesDialog::readGuiSettings(const QString & filePath)
|
|||||||
_ui->checkBox_mls->setChecked(settings.value("meshSmoothing", _ui->checkBox_mls->isChecked()).toBool());
|
_ui->checkBox_mls->setChecked(settings.value("meshSmoothing", _ui->checkBox_mls->isChecked()).toBool());
|
||||||
_ui->doubleSpinBox_mlsRadius->setValue(settings.value("meshSmoothingRadius", _ui->doubleSpinBox_mlsRadius->value()).toDouble());
|
_ui->doubleSpinBox_mlsRadius->setValue(settings.value("meshSmoothingRadius", _ui->doubleSpinBox_mlsRadius->value()).toDouble());
|
||||||
|
|
||||||
_ui->groupBox_poseFiltering->setChecked(settings.value("cloudFiltering", _ui->groupBox_poseFiltering->isChecked()).toBool());
|
_ui->checkBox_nodeFiltering->setChecked(settings.value("cloudFiltering", _ui->checkBox_nodeFiltering->isChecked()).toBool());
|
||||||
|
_ui->checkBox_subtractFiltering->setChecked(settings.value("subtractFiltering", _ui->checkBox_subtractFiltering->isChecked()).toBool());
|
||||||
_ui->doubleSpinBox_cloudFilterRadius->setValue(settings.value("cloudFilteringRadius", _ui->doubleSpinBox_cloudFilterRadius->value()).toDouble());
|
_ui->doubleSpinBox_cloudFilterRadius->setValue(settings.value("cloudFilteringRadius", _ui->doubleSpinBox_cloudFilterRadius->value()).toDouble());
|
||||||
_ui->doubleSpinBox_cloudFilterAngle->setValue(settings.value("cloudFilteringAngle", _ui->doubleSpinBox_cloudFilterAngle->value()).toDouble());
|
_ui->doubleSpinBox_cloudFilterAngle->setValue(settings.value("cloudFilteringAngle", _ui->doubleSpinBox_cloudFilterAngle->value()).toDouble());
|
||||||
|
_ui->spinBox_substractFilteringMinPts->setValue(settings.value("cloudFilteringAngleMinPts", _ui->spinBox_substractFilteringMinPts->value()).toDouble());
|
||||||
|
|
||||||
_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());
|
||||||
@@ -1551,9 +1557,11 @@ void PreferencesDialog::writeGuiSettings(const QString & filePath) const
|
|||||||
settings.setValue("meshSmoothing", _ui->checkBox_mls->isChecked());
|
settings.setValue("meshSmoothing", _ui->checkBox_mls->isChecked());
|
||||||
settings.setValue("meshSmoothingRadius", _ui->doubleSpinBox_mlsRadius->value());
|
settings.setValue("meshSmoothingRadius", _ui->doubleSpinBox_mlsRadius->value());
|
||||||
|
|
||||||
settings.setValue("cloudFiltering", _ui->groupBox_poseFiltering->isChecked());
|
settings.setValue("cloudFiltering", _ui->checkBox_nodeFiltering->isChecked());
|
||||||
|
settings.setValue("subtractFiltering", _ui->checkBox_subtractFiltering->isChecked());
|
||||||
settings.setValue("cloudFilteringRadius", _ui->doubleSpinBox_cloudFilterRadius->value());
|
settings.setValue("cloudFilteringRadius", _ui->doubleSpinBox_cloudFilterRadius->value());
|
||||||
settings.setValue("cloudFilteringAngle", _ui->doubleSpinBox_cloudFilterAngle->value());
|
settings.setValue("cloudFilteringAngle", _ui->doubleSpinBox_cloudFilterAngle->value());
|
||||||
|
settings.setValue("subtractFilteringMinPts", _ui->spinBox_substractFilteringMinPts->value());
|
||||||
|
|
||||||
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());
|
||||||
@@ -3069,7 +3077,11 @@ double PreferencesDialog::getMeshSmoothingRadius() const
|
|||||||
}
|
}
|
||||||
bool PreferencesDialog::isCloudFiltering() const
|
bool PreferencesDialog::isCloudFiltering() const
|
||||||
{
|
{
|
||||||
return _ui->groupBox_poseFiltering->isChecked();
|
return _ui->checkBox_nodeFiltering->isChecked();
|
||||||
|
}
|
||||||
|
bool PreferencesDialog::isSubtractFiltering() const
|
||||||
|
{
|
||||||
|
return _ui->checkBox_subtractFiltering->isChecked();
|
||||||
}
|
}
|
||||||
double PreferencesDialog::getCloudFilteringRadius() const
|
double PreferencesDialog::getCloudFilteringRadius() const
|
||||||
{
|
{
|
||||||
@@ -3079,6 +3091,10 @@ double PreferencesDialog::getCloudFilteringAngle() const
|
|||||||
{
|
{
|
||||||
return _ui->doubleSpinBox_cloudFilterAngle->value();
|
return _ui->doubleSpinBox_cloudFilterAngle->value();
|
||||||
}
|
}
|
||||||
|
int PreferencesDialog::getSubstractFilteringMinPts() const
|
||||||
|
{
|
||||||
|
return _ui->spinBox_substractFilteringMinPts->value();
|
||||||
|
}
|
||||||
bool PreferencesDialog::getGridMapShown() const
|
bool PreferencesDialog::getGridMapShown() const
|
||||||
{
|
{
|
||||||
return _ui->checkBox_map_shown->isChecked();
|
return _ui->checkBox_map_shown->isChecked();
|
||||||
|
|||||||
@@ -86,7 +86,7 @@
|
|||||||
<enum>QFrame::Raised</enum>
|
<enum>QFrame::Raised</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="currentIndex">
|
<property name="currentIndex">
|
||||||
<number>20</number>
|
<number>1</number>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QWidget" name="page_22">
|
<widget class="QWidget" name="page_22">
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_29">
|
<layout class="QVBoxLayout" name="verticalLayout_29">
|
||||||
@@ -346,21 +346,21 @@ Show a yellow background when the number of odometry inliers goes under this thr
|
|||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_31">
|
<layout class="QVBoxLayout" name="verticalLayout_31">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QGroupBox" name="groupBox_poseFiltering">
|
<widget class="QGroupBox" name="groupBox_filtering">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>Cloud filtering</string>
|
<string>Cloud filtering</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="checkable">
|
<property name="checkable">
|
||||||
<bool>true</bool>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
<property name="checked">
|
<property name="checked">
|
||||||
<bool>true</bool>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_37">
|
<layout class="QVBoxLayout" name="verticalLayout_37">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="label_33">
|
<widget class="QLabel" name="label_160">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>For visualization, superposed clouds are not shown. By comparing poses in the same area, only one cloud in a fixed radius and angle is kept.</string>
|
<string>For visualization purpose, superposed clouds can be filtered by one or both approaches below.</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="wordWrap">
|
<property name="wordWrap">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
@@ -368,50 +368,108 @@ Show a yellow background when the number of odometry inliers goes under this thr
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QGridLayout" name="gridLayout_17" rowstretch="0,0" columnstretch="0,1">
|
<layout class="QGridLayout" name="gridLayout_64" columnstretch="0,1">
|
||||||
<item row="0" column="0">
|
|
||||||
<widget class="QDoubleSpinBox" name="doubleSpinBox_cloudFilterRadius">
|
|
||||||
<property name="suffix">
|
|
||||||
<string> m</string>
|
|
||||||
</property>
|
|
||||||
<property name="minimum">
|
|
||||||
<double>0.010000000000000</double>
|
|
||||||
</property>
|
|
||||||
<property name="value">
|
|
||||||
<double>0.100000000000000</double>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="1">
|
<item row="0" column="1">
|
||||||
<widget class="QLabel" name="label_37">
|
<widget class="QLabel" name="label_33">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Radius.</string>
|
<string>Node filtering. By comparing poses in the same area, only one cloud in a fixed radius and angle is shown.</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
<property name="wordWrap">
|
||||||
</item>
|
<bool>true</bool>
|
||||||
<item row="1" column="0">
|
|
||||||
<widget class="QDoubleSpinBox" name="doubleSpinBox_cloudFilterAngle">
|
|
||||||
<property name="suffix">
|
|
||||||
<string> degrees</string>
|
|
||||||
</property>
|
|
||||||
<property name="decimals">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="maximum">
|
|
||||||
<double>180.000000000000000</double>
|
|
||||||
</property>
|
|
||||||
<property name="value">
|
|
||||||
<double>30.000000000000000</double>
|
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="1">
|
<item row="1" column="1">
|
||||||
<widget class="QLabel" name="label_48">
|
<layout class="QGridLayout" name="gridLayout_17" columnstretch="0,1">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QDoubleSpinBox" name="doubleSpinBox_cloudFilterRadius">
|
||||||
|
<property name="suffix">
|
||||||
|
<string> m</string>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<double>0.010000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<double>0.100000000000000</double>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QLabel" name="label_37">
|
||||||
|
<property name="text">
|
||||||
|
<string>Radius.</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QDoubleSpinBox" name="doubleSpinBox_cloudFilterAngle">
|
||||||
|
<property name="suffix">
|
||||||
|
<string> degrees</string>
|
||||||
|
</property>
|
||||||
|
<property name="decimals">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<double>180.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<double>30.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QLabel" name="label_48">
|
||||||
|
<property name="text">
|
||||||
|
<string>Angle.</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QCheckBox" name="checkBox_nodeFiltering">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Angle.</string>
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QLabel" name="label_161">
|
||||||
|
<property name="text">
|
||||||
|
<string>Cloud subtraction filtering. When a new cloud is added to the map, the previous cloud is subtracted from the new cloud. Using "Node filtering" at the same time may generate large "holes" in the map (so better to use without "Node filtering"). Voxel size of the map below is used for the radius search of the close points to filter between the two clouds.</string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QCheckBox" name="checkBox_subtractFiltering">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="1">
|
||||||
|
<layout class="QGridLayout" name="gridLayout_65" columnstretch="0,1">
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QLabel" name="label_174">
|
||||||
|
<property name="text">
|
||||||
|
<string>Minimum number of previous cloud's points in the fixed radius in order to substract the point in the new cloud (radius is the voxel size). Increasing this value reduces the black contours between clouds.</string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QSpinBox" name="spinBox_substractFilteringMinPts"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
|
|||||||
Reference in New Issue
Block a user