mirror of
https://github.com/introlab/rtabmap.git
synced 2026-09-01 17:10:26 +08:00
Compare commits
2 Commits
0.22.1-rol
...
1045-optim
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0fcf562042 | ||
|
|
d48e2093f5 |
@@ -132,6 +132,7 @@ private:
|
|||||||
bool normalsSegmentation_;
|
bool normalsSegmentation_;
|
||||||
bool grid3D_;
|
bool grid3D_;
|
||||||
bool groundIsObstacle_;
|
bool groundIsObstacle_;
|
||||||
|
bool labelUndergroundObstaclesAsGround_;
|
||||||
float noiseFilteringRadius_;
|
float noiseFilteringRadius_;
|
||||||
int noiseFilteringMinNeighbors_;
|
int noiseFilteringMinNeighbors_;
|
||||||
bool scan2dUnknownSpaceFilled_;
|
bool scan2dUnknownSpaceFilled_;
|
||||||
|
|||||||
@@ -760,6 +760,7 @@ class RTABMAP_CORE_EXPORT Parameters
|
|||||||
RTABMAP_PARAM(Grid, 3D, bool, false, uFormat("A 3D occupancy grid is required if you want an OctoMap (3D ray tracing). Set to false if you want only a 2D map, the cloud will be projected on xy plane. A 2D map can be still generated if checked, but it requires more memory and time to generate it. Ignored if laser scan is 2D and \"%s\" is 0.", kGridSensor().c_str()));
|
RTABMAP_PARAM(Grid, 3D, bool, false, uFormat("A 3D occupancy grid is required if you want an OctoMap (3D ray tracing). Set to false if you want only a 2D map, the cloud will be projected on xy plane. A 2D map can be still generated if checked, but it requires more memory and time to generate it. Ignored if laser scan is 2D and \"%s\" is 0.", kGridSensor().c_str()));
|
||||||
#endif
|
#endif
|
||||||
RTABMAP_PARAM(Grid, GroundIsObstacle, bool, false, uFormat("[%s=true] Ground segmentation (%s) is ignored, all points are obstacles. Use this only if you want an OctoMap with ground identified as an obstacle (e.g., with an UAV).", kGrid3D().c_str(), kGridNormalsSegmentation().c_str()));
|
RTABMAP_PARAM(Grid, GroundIsObstacle, bool, false, uFormat("[%s=true] Ground segmentation (%s) is ignored, all points are obstacles. Use this only if you want an OctoMap with ground identified as an obstacle (e.g., with an UAV).", kGrid3D().c_str(), kGridNormalsSegmentation().c_str()));
|
||||||
|
RTABMAP_PARAM(Grid, UndergroundIsGround, bool, false, uFormat("[%s=true] Label all underground points under largest flat surface detected as ground.", kGridNormalsSegmentation().c_str()));
|
||||||
RTABMAP_PARAM(Grid, NoiseFilteringRadius, float, 0.0, "Noise filtering radius (0=disabled). Done after segmentation.");
|
RTABMAP_PARAM(Grid, NoiseFilteringRadius, float, 0.0, "Noise filtering radius (0=disabled). Done after segmentation.");
|
||||||
RTABMAP_PARAM(Grid, NoiseFilteringMinNeighbors, int, 5, "Noise filtering minimum neighbors.");
|
RTABMAP_PARAM(Grid, NoiseFilteringMinNeighbors, int, 5, "Noise filtering minimum neighbors.");
|
||||||
RTABMAP_PARAM(Grid, Scan2dUnknownSpaceFilled, bool, false, uFormat("Unknown space filled. Only used with 2D laser scans. Use %s to set maximum range if laser scan max range is to set.", kGridRangeMax().c_str()));
|
RTABMAP_PARAM(Grid, Scan2dUnknownSpaceFilled, bool, false, uFormat("Unknown space filled. Only used with 2D laser scans. Use %s to set maximum range if laser scan max range is to set.", kGridRangeMax().c_str()));
|
||||||
|
|||||||
@@ -44,6 +44,8 @@ typename pcl::PointCloud<PointT>::Ptr OccupancyGrid::segmentCloud(
|
|||||||
pcl::IndicesPtr & obstaclesIndices,
|
pcl::IndicesPtr & obstaclesIndices,
|
||||||
pcl::IndicesPtr * flatObstacles) const
|
pcl::IndicesPtr * flatObstacles) const
|
||||||
{
|
{
|
||||||
|
UDEBUG("cloudIn=%dx%d indicesIn=%ld", cloudIn->width, cloudIn->height, indicesIn->size());
|
||||||
|
|
||||||
groundIndices.reset(new std::vector<int>);
|
groundIndices.reset(new std::vector<int>);
|
||||||
obstaclesIndices.reset(new std::vector<int>);
|
obstaclesIndices.reset(new std::vector<int>);
|
||||||
if(flatObstacles)
|
if(flatObstacles)
|
||||||
@@ -54,6 +56,7 @@ typename pcl::PointCloud<PointT>::Ptr OccupancyGrid::segmentCloud(
|
|||||||
typename pcl::PointCloud<PointT>::Ptr cloud(new pcl::PointCloud<PointT>);
|
typename pcl::PointCloud<PointT>::Ptr cloud(new pcl::PointCloud<PointT>);
|
||||||
pcl::IndicesPtr indices(new std::vector<int>);
|
pcl::IndicesPtr indices(new std::vector<int>);
|
||||||
|
|
||||||
|
UDEBUG("preVoxelFiltering=%d", preVoxelFiltering_?1:0);
|
||||||
if(preVoxelFiltering_)
|
if(preVoxelFiltering_)
|
||||||
{
|
{
|
||||||
// voxelize to grid cell size
|
// voxelize to grid cell size
|
||||||
@@ -127,6 +130,9 @@ typename pcl::PointCloud<PointT>::Ptr OccupancyGrid::segmentCloud(
|
|||||||
UDEBUG("flatObstaclesDetected=%d", flatObstaclesDetected_?1:0);
|
UDEBUG("flatObstaclesDetected=%d", flatObstaclesDetected_?1:0);
|
||||||
UDEBUG("maxGroundHeight=%f", maxGroundHeight_);
|
UDEBUG("maxGroundHeight=%f", maxGroundHeight_);
|
||||||
UDEBUG("groundNormalsUp=%f", groundNormalsUp_);
|
UDEBUG("groundNormalsUp=%f", groundNormalsUp_);
|
||||||
|
UDEBUG("labelUndergroundObstaclesAsGround=%d", labelUndergroundObstaclesAsGround_?1:0);
|
||||||
|
UDEBUG("viewPoint=%f,%f,%f", viewPoint.x, viewPoint.y, viewPoint.z+(projMapFrame_?pose.z():0));
|
||||||
|
UDEBUG("cloud=%dx%d indices=%ld", cloud->width, cloud->height, indices->size());
|
||||||
util3d::segmentObstaclesFromGround<PointT>(
|
util3d::segmentObstaclesFromGround<PointT>(
|
||||||
cloud,
|
cloud,
|
||||||
indices,
|
indices,
|
||||||
@@ -140,8 +146,8 @@ typename pcl::PointCloud<PointT>::Ptr OccupancyGrid::segmentCloud(
|
|||||||
maxGroundHeight_,
|
maxGroundHeight_,
|
||||||
flatObstacles,
|
flatObstacles,
|
||||||
Eigen::Vector4f(viewPoint.x, viewPoint.y, viewPoint.z+(projMapFrame_?pose.z():0), 1),
|
Eigen::Vector4f(viewPoint.x, viewPoint.y, viewPoint.z+(projMapFrame_?pose.z():0), 1),
|
||||||
groundNormalsUp_);
|
groundNormalsUp_,
|
||||||
UDEBUG("viewPoint=%f,%f,%f", viewPoint.x, viewPoint.y, viewPoint.z+(projMapFrame_?pose.z():0));
|
labelUndergroundObstaclesAsGround_);
|
||||||
//UWARN("Saving ground.pcd and obstacles.pcd");
|
//UWARN("Saving ground.pcd and obstacles.pcd");
|
||||||
//pcl::io::savePCDFile("ground.pcd", *cloud, *groundIndices);
|
//pcl::io::savePCDFile("ground.pcd", *cloud, *groundIndices);
|
||||||
//pcl::io::savePCDFile("obstacles.pcd", *cloud, *obstaclesIndices);
|
//pcl::io::savePCDFile("obstacles.pcd", *cloud, *obstaclesIndices);
|
||||||
@@ -165,6 +171,42 @@ typename pcl::PointCloud<PointT>::Ptr OccupancyGrid::segmentCloud(
|
|||||||
|
|
||||||
UDEBUG("groundIndices=%d obstaclesIndices=%d", (int)groundIndices->size(), (int)obstaclesIndices->size());
|
UDEBUG("groundIndices=%d obstaclesIndices=%d", (int)groundIndices->size(), (int)obstaclesIndices->size());
|
||||||
|
|
||||||
|
if(!preVoxelFiltering_ && (!groundIndices->empty() || !obstaclesIndices->empty()))
|
||||||
|
{
|
||||||
|
// voxelize to grid cell size
|
||||||
|
typename pcl::PointCloud<PointT>::Ptr cloudWithTransform = cloud;
|
||||||
|
cloud.reset(new pcl::PointCloud<PointT>);
|
||||||
|
if(!groundIndices->empty())
|
||||||
|
{
|
||||||
|
*cloud += *util3d::voxelize(cloudWithTransform, groundIndices, cellSize_);
|
||||||
|
groundIndices->resize(cloud->size());
|
||||||
|
for(size_t i=0; i<groundIndices->size(); ++i)
|
||||||
|
{
|
||||||
|
groundIndices->at(i) = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!obstaclesIndices->empty())
|
||||||
|
{
|
||||||
|
int previousSize = cloud->size();
|
||||||
|
*cloud += *util3d::voxelize(cloudWithTransform, obstaclesIndices, cellSize_);
|
||||||
|
obstaclesIndices->resize(cloud->size()-previousSize);
|
||||||
|
for(size_t i=0; i<obstaclesIndices->size(); ++i)
|
||||||
|
{
|
||||||
|
obstaclesIndices->at(i) = previousSize+i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(flatObstacles && !(*flatObstacles)->empty())
|
||||||
|
{
|
||||||
|
int previousSize = cloud->size();
|
||||||
|
*cloud += *util3d::voxelize(cloudWithTransform, *flatObstacles, cellSize_);
|
||||||
|
(*flatObstacles)->resize(cloud->size()-previousSize);
|
||||||
|
for(size_t i=0; i<(*flatObstacles)->size(); ++i)
|
||||||
|
{
|
||||||
|
(*flatObstacles)->at(i) = previousSize+i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Do radius filtering after voxel filtering ( a lot faster)
|
// Do radius filtering after voxel filtering ( a lot faster)
|
||||||
if(noiseFilteringRadius_ > 0.0 && noiseFilteringMinNeighbors_ > 0)
|
if(noiseFilteringRadius_ > 0.0 && noiseFilteringMinNeighbors_ > 0)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -50,6 +50,79 @@ typename pcl::PointCloud<PointT>::Ptr projectCloudOnXYPlane(
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void clusterIndicesFloodfill(std::vector<int> & cluster,
|
||||||
|
float * visitedIndices,
|
||||||
|
int width,
|
||||||
|
int height,
|
||||||
|
float clusterRadius,
|
||||||
|
int currentIndex,
|
||||||
|
float previousHeight);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Cluster indices of an organized cloud
|
||||||
|
*
|
||||||
|
* @tparam PointT
|
||||||
|
* @param cloud
|
||||||
|
* @param indices
|
||||||
|
* @param minClusterSize
|
||||||
|
* @param maxClusterSize
|
||||||
|
* @param biggestClusterIndex
|
||||||
|
* @return std::vector<pcl::IndicesPtr>
|
||||||
|
*/
|
||||||
|
template<typename PointT>
|
||||||
|
std::vector<pcl::IndicesPtr> clusterIndices(
|
||||||
|
const typename pcl::PointCloud<PointT>::Ptr & cloud,
|
||||||
|
const typename pcl::IndicesPtr & indices,
|
||||||
|
float clusterRadius,
|
||||||
|
int minClusterSize,
|
||||||
|
int maxClusterSize,
|
||||||
|
int * biggestClusterIndex)
|
||||||
|
{
|
||||||
|
std::vector<pcl::IndicesPtr> clusters;
|
||||||
|
if(cloud->empty())
|
||||||
|
{
|
||||||
|
return clusters;
|
||||||
|
}
|
||||||
|
|
||||||
|
UASSERT(cloud->isOrganized());
|
||||||
|
|
||||||
|
cv::Mat visitedIndices = cv::Mat::zeros(cloud->height, cloud->width, CV_32FC1);
|
||||||
|
float * ptr = visitedIndices.ptr<float>();
|
||||||
|
// init search image
|
||||||
|
for(size_t i = 0; i<indices->size(); ++i)
|
||||||
|
{
|
||||||
|
ptr[indices->at(i)] = cloud->at(indices->at(i)).z;
|
||||||
|
}
|
||||||
|
|
||||||
|
int largestCluster = -1;
|
||||||
|
int largestClusterSize = 0;
|
||||||
|
int sum = 0;
|
||||||
|
for(size_t i = 0; i<indices->size(); ++i)
|
||||||
|
{
|
||||||
|
if(ptr[indices->at(i)] != 0.0f)
|
||||||
|
{
|
||||||
|
pcl::IndicesPtr cluster(new pcl::Indices());
|
||||||
|
clusterIndicesFloodfill(*cluster, ptr, visitedIndices.cols, visitedIndices.rows, clusterRadius, indices->at(i), ptr[indices->at(i)]);
|
||||||
|
if(cluster->size()>0 && (int)cluster->size()>=minClusterSize && (int)cluster->size()<=maxClusterSize)
|
||||||
|
{
|
||||||
|
clusters.push_back(cluster);
|
||||||
|
if((int)cluster->size() > largestClusterSize)
|
||||||
|
{
|
||||||
|
sum+=cluster->size();
|
||||||
|
largestCluster = clusters.size()-1;
|
||||||
|
largestClusterSize = cluster->size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(biggestClusterIndex)
|
||||||
|
{
|
||||||
|
*biggestClusterIndex = largestCluster;
|
||||||
|
}
|
||||||
|
|
||||||
|
return clusters;
|
||||||
|
}
|
||||||
|
|
||||||
template<typename PointT>
|
template<typename PointT>
|
||||||
void segmentObstaclesFromGround(
|
void segmentObstaclesFromGround(
|
||||||
const typename pcl::PointCloud<PointT>::Ptr & cloud,
|
const typename pcl::PointCloud<PointT>::Ptr & cloud,
|
||||||
@@ -64,7 +137,8 @@ void segmentObstaclesFromGround(
|
|||||||
float maxGroundHeight,
|
float maxGroundHeight,
|
||||||
pcl::IndicesPtr * flatObstacles,
|
pcl::IndicesPtr * flatObstacles,
|
||||||
const Eigen::Vector4f & viewPoint,
|
const Eigen::Vector4f & viewPoint,
|
||||||
float groundNormalsUp)
|
float groundNormalsUp,
|
||||||
|
bool labelUndergroundObstaclesAsGround)
|
||||||
{
|
{
|
||||||
ground.reset(new std::vector<int>);
|
ground.reset(new std::vector<int>);
|
||||||
obstacles.reset(new std::vector<int>);
|
obstacles.reset(new std::vector<int>);
|
||||||
@@ -75,6 +149,8 @@ void segmentObstaclesFromGround(
|
|||||||
|
|
||||||
if(cloud->size())
|
if(cloud->size())
|
||||||
{
|
{
|
||||||
|
UDEBUG("Normal filtering.... cloud=%ld indices=%ld organized=%d",
|
||||||
|
cloud->size(), indices->size(), cloud->isOrganized()?1:0);
|
||||||
// Find the ground
|
// Find the ground
|
||||||
pcl::IndicesPtr flatSurfaces = normalFiltering(
|
pcl::IndicesPtr flatSurfaces = normalFiltering(
|
||||||
cloud,
|
cloud,
|
||||||
@@ -84,22 +160,40 @@ void segmentObstaclesFromGround(
|
|||||||
normalKSearch,
|
normalKSearch,
|
||||||
viewPoint,
|
viewPoint,
|
||||||
groundNormalsUp);
|
groundNormalsUp);
|
||||||
|
UDEBUG("%ld points on flat surfaces (input indices = %ld, total cloud=%ld)",
|
||||||
|
flatSurfaces->size(), indices->size(), cloud->size());
|
||||||
|
|
||||||
|
Eigen::Vector4f biggestSurfaceMin,biggestSurfaceMax(0,0,0,0);
|
||||||
if(segmentFlatObstacles && flatSurfaces->size())
|
if(segmentFlatObstacles && flatSurfaces->size())
|
||||||
{
|
{
|
||||||
int biggestFlatSurfaceIndex;
|
int biggestFlatSurfaceIndex;
|
||||||
std::vector<pcl::IndicesPtr> clusteredFlatSurfaces = extractClusters(
|
|
||||||
|
std::vector<pcl::IndicesPtr> clusteredFlatSurfaces;
|
||||||
|
if(cloud->isOrganized())
|
||||||
|
{
|
||||||
|
clusteredFlatSurfaces = clusterIndices<PointT>(
|
||||||
cloud,
|
cloud,
|
||||||
flatSurfaces,
|
flatSurfaces,
|
||||||
clusterRadius,
|
clusterRadius,
|
||||||
minClusterSize,
|
minClusterSize,
|
||||||
std::numeric_limits<int>::max(),
|
std::numeric_limits<int>::max(),
|
||||||
&biggestFlatSurfaceIndex);
|
&biggestFlatSurfaceIndex);
|
||||||
|
UDEBUG("clusteredFlatSurfaces=%ld", clusteredFlatSurfaces.size());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
clusteredFlatSurfaces = extractClusters(
|
||||||
|
cloud,
|
||||||
|
flatSurfaces,
|
||||||
|
clusterRadius,
|
||||||
|
minClusterSize,
|
||||||
|
std::numeric_limits<int>::max(),
|
||||||
|
&biggestFlatSurfaceIndex);
|
||||||
|
}
|
||||||
|
|
||||||
// cluster all surfaces for which the centroid is in the Z-range of the bigger surface
|
// cluster all surfaces for which the centroid is in the Z-range of the bigger surface
|
||||||
if(clusteredFlatSurfaces.size())
|
if(clusteredFlatSurfaces.size())
|
||||||
{
|
{
|
||||||
Eigen::Vector4f biggestSurfaceMin,biggestSurfaceMax;
|
|
||||||
if(maxGroundHeight != 0.0f)
|
if(maxGroundHeight != 0.0f)
|
||||||
{
|
{
|
||||||
// Search for biggest surface under max ground height
|
// Search for biggest surface under max ground height
|
||||||
@@ -125,9 +219,12 @@ void segmentObstaclesFromGround(
|
|||||||
if(biggestFlatSurfaceIndex>=0)
|
if(biggestFlatSurfaceIndex>=0)
|
||||||
{
|
{
|
||||||
ground = clusteredFlatSurfaces.at(biggestFlatSurfaceIndex);
|
ground = clusteredFlatSurfaces.at(biggestFlatSurfaceIndex);
|
||||||
|
UDEBUG("Biggest flat surface size = %ld (%d%%) (z min=%f max=%f)",
|
||||||
|
ground->size(), 100*ground->size()/cloud->size(), biggestSurfaceMin[2], biggestSurfaceMax[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!ground->empty() && (maxGroundHeight == 0.0f || biggestSurfaceMin[2] < maxGroundHeight))
|
if(!ground->empty() &&
|
||||||
|
(maxGroundHeight == 0.0f || biggestSurfaceMin[2] < maxGroundHeight))
|
||||||
{
|
{
|
||||||
for(unsigned int i=0; i<clusteredFlatSurfaces.size(); ++i)
|
for(unsigned int i=0; i<clusteredFlatSurfaces.size(); ++i)
|
||||||
{
|
{
|
||||||
@@ -135,7 +232,7 @@ void segmentObstaclesFromGround(
|
|||||||
{
|
{
|
||||||
Eigen::Vector4f centroid(0,0,0,1);
|
Eigen::Vector4f centroid(0,0,0,1);
|
||||||
pcl::compute3DCentroid(*cloud, *clusteredFlatSurfaces.at(i), centroid);
|
pcl::compute3DCentroid(*cloud, *clusteredFlatSurfaces.at(i), centroid);
|
||||||
if(maxGroundHeight==0.0f || centroid[2] <= maxGroundHeight || centroid[2] <= biggestSurfaceMax[2]) // epsilon
|
if(centroid[2] <= biggestSurfaceMax[2]) // relative to ground detected
|
||||||
{
|
{
|
||||||
ground = util3d::concatenate(ground, clusteredFlatSurfaces.at(i));
|
ground = util3d::concatenate(ground, clusteredFlatSurfaces.at(i));
|
||||||
}
|
}
|
||||||
@@ -145,9 +242,46 @@ void segmentObstaclesFromGround(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int groundRatio = 100*ground->size()/cloud->size();
|
||||||
|
int minGroundRatio = 10;
|
||||||
|
if(minGroundRatio != 0 && groundRatio<minGroundRatio)
|
||||||
|
{
|
||||||
|
if(labelUndergroundObstaclesAsGround && maxGroundHeight!=0.0f)
|
||||||
|
{
|
||||||
|
// just do passthrough (e.g. reflective floor)
|
||||||
|
UWARN("Failed normal segmentation (ground ratio=%d%%, ground height=%f), fallback to passThrough (label underground as ground is true).",
|
||||||
|
groundRatio, !ground->empty()?biggestSurfaceMin[2]:0.0f);
|
||||||
|
// passthrough filter
|
||||||
|
ground = rtabmap::util3d::passThrough(cloud, indices, "z",
|
||||||
|
std::numeric_limits<int>::min(),
|
||||||
|
maxGroundHeight!=0.0f?maxGroundHeight:std::numeric_limits<int>::max());
|
||||||
|
|
||||||
|
pcl::IndicesPtr notObstacles = ground;
|
||||||
|
if(indices->size())
|
||||||
|
{
|
||||||
|
notObstacles = util3d::extractIndices(cloud, indices, true);
|
||||||
|
notObstacles = util3d::concatenate(notObstacles, ground);
|
||||||
|
}
|
||||||
|
obstacles = rtabmap::util3d::extractIndices(cloud, notObstacles, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UWARN("Failed normal segmentation, ground surface is too small (ground ratio=%d%%, ground height=%f)!",
|
||||||
|
groundRatio, !ground->empty()?biggestSurfaceMin[2]:0.0f);
|
||||||
|
// reject ground!
|
||||||
|
ground.reset(new std::vector<int>);
|
||||||
|
if(flatObstacles)
|
||||||
|
{
|
||||||
|
*flatObstacles = flatSurfaces;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
UWARN("Failed normal segmentation, could not detect the ground!");
|
||||||
// reject ground!
|
// reject ground!
|
||||||
ground.reset(new std::vector<int>);
|
ground.reset(new std::vector<int>);
|
||||||
if(flatObstacles)
|
if(flatObstacles)
|
||||||
@@ -168,28 +302,49 @@ void segmentObstaclesFromGround(
|
|||||||
pcl::IndicesPtr notObstacles = ground;
|
pcl::IndicesPtr notObstacles = ground;
|
||||||
if(indices->size())
|
if(indices->size())
|
||||||
{
|
{
|
||||||
|
// This will ignore all points not in input indices for obstacles.
|
||||||
notObstacles = util3d::extractIndices(cloud, indices, true);
|
notObstacles = util3d::extractIndices(cloud, indices, true);
|
||||||
notObstacles = util3d::concatenate(notObstacles, ground);
|
notObstacles = util3d::concatenate(notObstacles, ground);
|
||||||
}
|
}
|
||||||
pcl::IndicesPtr otherStuffIndices = util3d::extractIndices(cloud, notObstacles, true);
|
|
||||||
|
|
||||||
// If ground height is set, remove obstacles under it
|
// If ground height is set and if we label obstacles under it as ground
|
||||||
if(maxGroundHeight != 0.0f)
|
if(labelUndergroundObstaclesAsGround)
|
||||||
{
|
{
|
||||||
otherStuffIndices = rtabmap::util3d::passThrough(cloud, otherStuffIndices, "z", maxGroundHeight, std::numeric_limits<float>::max());
|
float max = biggestSurfaceMax[2];
|
||||||
|
if(maxGroundHeight > 0)
|
||||||
|
{
|
||||||
|
max += maxGroundHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
pcl::IndicesPtr otherStuffIndices = util3d::extractIndices(cloud, notObstacles, true);
|
||||||
|
pcl::IndicesPtr underground = rtabmap::util3d::passThrough(cloud, otherStuffIndices, "z", (float)std::numeric_limits<int>::min(), max);
|
||||||
|
if(!underground->empty())
|
||||||
|
{
|
||||||
|
ground = util3d::concatenate(ground, underground);
|
||||||
|
notObstacles = util3d::concatenate(underground, notObstacles);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pcl::IndicesPtr otherStuffIndices = util3d::extractIndices(cloud, notObstacles, true);
|
||||||
|
|
||||||
//Cluster remaining stuff (obstacles)
|
//Cluster remaining stuff (obstacles)
|
||||||
if(otherStuffIndices->size())
|
if(otherStuffIndices->size())
|
||||||
{
|
{
|
||||||
std::vector<pcl::IndicesPtr> clusteredObstaclesSurfaces = util3d::extractClusters(
|
if(minClusterSize>1)
|
||||||
cloud,
|
{
|
||||||
otherStuffIndices,
|
std::vector<pcl::IndicesPtr> clusteredObstaclesSurfaces = util3d::extractClusters(
|
||||||
clusterRadius,
|
cloud,
|
||||||
minClusterSize);
|
otherStuffIndices,
|
||||||
|
clusterRadius,
|
||||||
|
minClusterSize);
|
||||||
|
|
||||||
// merge indices
|
// merge indices
|
||||||
obstacles = util3d::concatenate(clusteredObstaclesSurfaces);
|
obstacles = util3d::concatenate(clusteredObstaclesSurfaces);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
obstacles = otherStuffIndices;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -208,7 +363,8 @@ void segmentObstaclesFromGround(
|
|||||||
float maxGroundHeight,
|
float maxGroundHeight,
|
||||||
pcl::IndicesPtr * flatObstacles,
|
pcl::IndicesPtr * flatObstacles,
|
||||||
const Eigen::Vector4f & viewPoint,
|
const Eigen::Vector4f & viewPoint,
|
||||||
float groundNormalsUp)
|
float groundNormalsUp,
|
||||||
|
bool labelUndergroundObstaclesAsGround)
|
||||||
{
|
{
|
||||||
pcl::IndicesPtr indices(new std::vector<int>);
|
pcl::IndicesPtr indices(new std::vector<int>);
|
||||||
segmentObstaclesFromGround<PointT>(
|
segmentObstaclesFromGround<PointT>(
|
||||||
@@ -224,7 +380,8 @@ void segmentObstaclesFromGround(
|
|||||||
maxGroundHeight,
|
maxGroundHeight,
|
||||||
flatObstacles,
|
flatObstacles,
|
||||||
viewPoint,
|
viewPoint,
|
||||||
groundNormalsUp);
|
groundNormalsUp,
|
||||||
|
labelUndergroundObstaclesAsGround);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename PointT>
|
template<typename PointT>
|
||||||
|
|||||||
@@ -157,7 +157,8 @@ void segmentObstaclesFromGround(
|
|||||||
float maxGroundHeight = 0.0f,
|
float maxGroundHeight = 0.0f,
|
||||||
pcl::IndicesPtr * flatObstacles = 0,
|
pcl::IndicesPtr * flatObstacles = 0,
|
||||||
const Eigen::Vector4f & viewPoint = Eigen::Vector4f(0,0,100,0),
|
const Eigen::Vector4f & viewPoint = Eigen::Vector4f(0,0,100,0),
|
||||||
float groundNormalsUp = 0);
|
float groundNormalsUp = 0,
|
||||||
|
bool labelUndergroundObstaclesAsGround = false);
|
||||||
template<typename PointT>
|
template<typename PointT>
|
||||||
void segmentObstaclesFromGround(
|
void segmentObstaclesFromGround(
|
||||||
const typename pcl::PointCloud<PointT>::Ptr & cloud,
|
const typename pcl::PointCloud<PointT>::Ptr & cloud,
|
||||||
@@ -171,7 +172,8 @@ void segmentObstaclesFromGround(
|
|||||||
float maxGroundHeight = 0.0f,
|
float maxGroundHeight = 0.0f,
|
||||||
pcl::IndicesPtr * flatObstacles = 0,
|
pcl::IndicesPtr * flatObstacles = 0,
|
||||||
const Eigen::Vector4f & viewPoint = Eigen::Vector4f(0,0,100,0),
|
const Eigen::Vector4f & viewPoint = Eigen::Vector4f(0,0,100,0),
|
||||||
float groundNormalsUp = 0);
|
float groundNormalsUp = 0,
|
||||||
|
bool labelUndergroundObstaclesAsGround = false);
|
||||||
|
|
||||||
template<typename PointT>
|
template<typename PointT>
|
||||||
void occupancy2DFromGroundObstacles(
|
void occupancy2DFromGroundObstacles(
|
||||||
|
|||||||
@@ -381,6 +381,17 @@ pcl::PointCloud<pcl::Normal>::Ptr RTABMAP_CORE_EXPORT computeFastOrganizedNormal
|
|||||||
float searchRadius = 0.0f,
|
float searchRadius = 0.0f,
|
||||||
const Eigen::Vector3f & viewPoint = Eigen::Vector3f(0,0,0));
|
const Eigen::Vector3f & viewPoint = Eigen::Vector3f(0,0,0));
|
||||||
|
|
||||||
|
pcl::PointCloud<pcl::Normal>::Ptr RTABMAP_CORE_EXPORT computeFastOrganizedNormals(
|
||||||
|
const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud,
|
||||||
|
float maxDepthChangeFactor = 0.02f,
|
||||||
|
float normalSmoothingSize = 10.0f,
|
||||||
|
const Eigen::Vector3f & viewPoint = Eigen::Vector3f(0,0,0));
|
||||||
|
pcl::PointCloud<pcl::Normal>::Ptr RTABMAP_CORE_EXPORT computeFastOrganizedNormals(
|
||||||
|
const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud,
|
||||||
|
const pcl::IndicesPtr & indices,
|
||||||
|
float maxDepthChangeFactor = 0.02f,
|
||||||
|
float normalSmoothingSize = 10.0f,
|
||||||
|
const Eigen::Vector3f & viewPoint = Eigen::Vector3f(0,0,0));
|
||||||
pcl::PointCloud<pcl::Normal>::Ptr RTABMAP_CORE_EXPORT computeFastOrganizedNormals(
|
pcl::PointCloud<pcl::Normal>::Ptr RTABMAP_CORE_EXPORT computeFastOrganizedNormals(
|
||||||
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
|
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
|
||||||
float maxDepthChangeFactor = 0.02f,
|
float maxDepthChangeFactor = 0.02f,
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ OccupancyGrid::OccupancyGrid(const ParametersMap & parameters) :
|
|||||||
normalsSegmentation_(Parameters::defaultGridNormalsSegmentation()),
|
normalsSegmentation_(Parameters::defaultGridNormalsSegmentation()),
|
||||||
grid3D_(Parameters::defaultGrid3D()),
|
grid3D_(Parameters::defaultGrid3D()),
|
||||||
groundIsObstacle_(Parameters::defaultGridGroundIsObstacle()),
|
groundIsObstacle_(Parameters::defaultGridGroundIsObstacle()),
|
||||||
|
labelUndergroundObstaclesAsGround_(Parameters::defaultGridUndergroundIsGround()),
|
||||||
noiseFilteringRadius_(Parameters::defaultGridNoiseFilteringRadius()),
|
noiseFilteringRadius_(Parameters::defaultGridNoiseFilteringRadius()),
|
||||||
noiseFilteringMinNeighbors_(Parameters::defaultGridNoiseFilteringMinNeighbors()),
|
noiseFilteringMinNeighbors_(Parameters::defaultGridNoiseFilteringMinNeighbors()),
|
||||||
scan2dUnknownSpaceFilled_(Parameters::defaultGridScan2dUnknownSpaceFilled()),
|
scan2dUnknownSpaceFilled_(Parameters::defaultGridScan2dUnknownSpaceFilled()),
|
||||||
@@ -128,6 +129,7 @@ void OccupancyGrid::parseParameters(const ParametersMap & parameters)
|
|||||||
Parameters::parse(parameters, Parameters::kGridNormalsSegmentation(), normalsSegmentation_);
|
Parameters::parse(parameters, Parameters::kGridNormalsSegmentation(), normalsSegmentation_);
|
||||||
Parameters::parse(parameters, Parameters::kGrid3D(), grid3D_);
|
Parameters::parse(parameters, Parameters::kGrid3D(), grid3D_);
|
||||||
Parameters::parse(parameters, Parameters::kGridGroundIsObstacle(), groundIsObstacle_);
|
Parameters::parse(parameters, Parameters::kGridGroundIsObstacle(), groundIsObstacle_);
|
||||||
|
Parameters::parse(parameters, Parameters::kGridUndergroundIsGround(), labelUndergroundObstaclesAsGround_);
|
||||||
Parameters::parse(parameters, Parameters::kGridNoiseFilteringRadius(), noiseFilteringRadius_);
|
Parameters::parse(parameters, Parameters::kGridNoiseFilteringRadius(), noiseFilteringRadius_);
|
||||||
Parameters::parse(parameters, Parameters::kGridNoiseFilteringMinNeighbors(), noiseFilteringMinNeighbors_);
|
Parameters::parse(parameters, Parameters::kGridNoiseFilteringMinNeighbors(), noiseFilteringMinNeighbors_);
|
||||||
Parameters::parse(parameters, Parameters::kGridScan2dUnknownSpaceFilled(), scan2dUnknownSpaceFilled_);
|
Parameters::parse(parameters, Parameters::kGridScan2dUnknownSpaceFilled(), scan2dUnknownSpaceFilled_);
|
||||||
|
|||||||
@@ -372,34 +372,127 @@ pcl::PointCloud<pcl::PointXYZ>::Ptr cloudFromDepth(
|
|||||||
float depthCx = model.cx() * rgbToDepthFactorX;
|
float depthCx = model.cx() * rgbToDepthFactorX;
|
||||||
float depthCy = model.cy() * rgbToDepthFactorY;
|
float depthCy = model.cy() * rgbToDepthFactorY;
|
||||||
|
|
||||||
UDEBUG("depth=%dx%d fx=%f fy=%f cx=%f cy=%f (depth factors=%f %f) decimation=%d",
|
bool isMM = imageDepth.type() == CV_16UC1;
|
||||||
|
|
||||||
|
UDEBUG("depth=%dx%d (isMM=%d) fx=%f fy=%f cx=%f cy=%f (depth factors=%f %f) decimation=%d",
|
||||||
imageDepth.cols, imageDepth.rows,
|
imageDepth.cols, imageDepth.rows,
|
||||||
|
isMM?1:0,
|
||||||
model.fx(), model.fy(), model.cx(), model.cy(),
|
model.fx(), model.fy(), model.cx(), model.cy(),
|
||||||
rgbToDepthFactorX,
|
rgbToDepthFactorX,
|
||||||
rgbToDepthFactorY,
|
rgbToDepthFactorY,
|
||||||
decimation);
|
decimation);
|
||||||
|
|
||||||
|
int decimationMode = 1;
|
||||||
int oi = 0;
|
int oi = 0;
|
||||||
for(int h = 0; h < imageDepth.rows && h/decimation < (int)cloud->height; h+=decimation)
|
if(isMM)
|
||||||
{
|
{
|
||||||
for(int w = 0; w < imageDepth.cols && w/decimation < (int)cloud->width; w+=decimation)
|
for(int h = 0; h < imageDepth.rows && h/decimation < (int)cloud->height; h+=decimation)
|
||||||
{
|
{
|
||||||
pcl::PointXYZ & pt = cloud->at((h/decimation)*cloud->width + (w/decimation));
|
const unsigned short * rowPtr = imageDepth.ptr<unsigned short>(h);
|
||||||
|
for(int w = 0; w < imageDepth.cols && w/decimation < (int)cloud->width; w+=decimation)
|
||||||
pcl::PointXYZ ptXYZ = projectDepthTo3D(imageDepth, w, h, depthCx, depthCy, depthFx, depthFy, false);
|
|
||||||
if(pcl::isFinite(ptXYZ) && ptXYZ.z>=minDepth && (maxDepth<=0.0f || ptXYZ.z <= maxDepth))
|
|
||||||
{
|
{
|
||||||
pt.x = ptXYZ.x;
|
pcl::PointXYZ & pt = cloud->at((h/decimation)*cloud->width + (w/decimation));
|
||||||
pt.y = ptXYZ.y;
|
|
||||||
pt.z = ptXYZ.z;
|
pt.x = pt.y = pt.z = std::numeric_limits<float>::quiet_NaN();
|
||||||
if(validIndices)
|
|
||||||
|
if(decimationMode == 1 && decimation>1)
|
||||||
|
{
|
||||||
|
// project closest point
|
||||||
|
cv::Point2i closestPixel(w,h);
|
||||||
|
unsigned short closestDepthMM = 0;
|
||||||
|
for(int v = h; v < h + decimation; ++v)
|
||||||
|
{
|
||||||
|
const unsigned short * roiRowPtr = imageDepth.ptr<unsigned short>(v);
|
||||||
|
for(int u = w; u < w + decimation; ++u)
|
||||||
|
{
|
||||||
|
const unsigned short & depthMM = roiRowPtr[u];
|
||||||
|
if(depthMM > 0 && (depthMM < closestDepthMM || closestDepthMM == 0))
|
||||||
|
{
|
||||||
|
closestDepthMM = depthMM;
|
||||||
|
closestPixel.x = u;
|
||||||
|
closestPixel.y = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(closestDepthMM > 0)
|
||||||
|
{
|
||||||
|
float depth = ((float)closestDepthMM)/1000.0f;
|
||||||
|
if(depth>=minDepth && (maxDepth<=0.0f || depth <= maxDepth))
|
||||||
|
{
|
||||||
|
// Fill in XYZ
|
||||||
|
pt.z = depth;
|
||||||
|
pt.x = ((float)closestPixel.x - depthCx) * pt.z / depthFx;
|
||||||
|
pt.y = ((float)closestPixel.y - depthCy) * pt.z / depthFy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(rowPtr[w]>0)
|
||||||
|
{
|
||||||
|
float depth = ((float)rowPtr[w])/1000.0f;
|
||||||
|
if(depth>=minDepth && (maxDepth<=0.0f || depth <= maxDepth))
|
||||||
|
{
|
||||||
|
// Fill in XYZ
|
||||||
|
pt.z = depth;
|
||||||
|
pt.x = ((float)w - depthCx) * pt.z / depthFx;
|
||||||
|
pt.y = ((float)h - depthCy) * pt.z / depthFy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(pcl::isFinite(pt) && validIndices)
|
||||||
{
|
{
|
||||||
validIndices->at(oi++) = (h/decimation)*cloud->width + (w/decimation);
|
validIndices->at(oi++) = (h/decimation)*cloud->width + (w/decimation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for(int h = 0; h < imageDepth.rows && h/decimation < (int)cloud->height; h+=decimation)
|
||||||
|
{
|
||||||
|
const float * rowPtr = imageDepth.ptr<float>(h);
|
||||||
|
for(int w = 0; w < imageDepth.cols && w/decimation < (int)cloud->width; w+=decimation)
|
||||||
{
|
{
|
||||||
|
pcl::PointXYZ & pt = cloud->at((h/decimation)*cloud->width + (w/decimation));
|
||||||
|
|
||||||
pt.x = pt.y = pt.z = std::numeric_limits<float>::quiet_NaN();
|
pt.x = pt.y = pt.z = std::numeric_limits<float>::quiet_NaN();
|
||||||
|
|
||||||
|
if(decimationMode == 1 && decimation>1)
|
||||||
|
{
|
||||||
|
// project closest point
|
||||||
|
cv::Point2i closestPixel(w,h);
|
||||||
|
float closestDepth = 0.0f;
|
||||||
|
for(int v = h; v < h + decimation; ++v)
|
||||||
|
{
|
||||||
|
const float * roiRowPtr = imageDepth.ptr<float>(v);
|
||||||
|
for(int u = w; u < w + decimation; ++u)
|
||||||
|
{
|
||||||
|
const float & depth = roiRowPtr[u];
|
||||||
|
if(depth > 0.0f && (depth < closestDepth || closestDepth == 0.0f))
|
||||||
|
{
|
||||||
|
closestDepth = depth;
|
||||||
|
closestPixel.x = u;
|
||||||
|
closestPixel.y = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(closestDepth > 0.0f && closestDepth>=minDepth && (maxDepth<=0.0f || closestDepth <= maxDepth))
|
||||||
|
{
|
||||||
|
// Fill in XYZ
|
||||||
|
pt.z = closestDepth;
|
||||||
|
pt.x = ((float)closestPixel.x - depthCx) * pt.z / depthFx;
|
||||||
|
pt.y = ((float)closestPixel.y - depthCy) * pt.z / depthFy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(rowPtr[w] > 0 && rowPtr[w]>=minDepth && (maxDepth<=0.0f || rowPtr[w] <= maxDepth))
|
||||||
|
{
|
||||||
|
// Fill in XYZ
|
||||||
|
pt.z = rowPtr[w];
|
||||||
|
pt.x = ((float)w - depthCx) * pt.z / depthFx;
|
||||||
|
pt.y = ((float)h - depthCy) * pt.z / depthFy;
|
||||||
|
}
|
||||||
|
if(pcl::isFinite(pt) && validIndices)
|
||||||
|
{
|
||||||
|
validIndices->at(oi++) = (h/decimation)*cloud->width + (w/decimation);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1026,6 +1026,36 @@ cv::Mat erodeMap(const cv::Mat & map)
|
|||||||
return erodedMap;
|
return erodedMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void clusterIndicesFloodfill(std::vector<int> & cluster,
|
||||||
|
float * visitedIndices,
|
||||||
|
int width,
|
||||||
|
int height,
|
||||||
|
float clusterRadius,
|
||||||
|
int currentIndex,
|
||||||
|
float previousHeight)
|
||||||
|
{
|
||||||
|
if(visitedIndices[currentIndex] == 0.0f ||
|
||||||
|
(clusterRadius>0.0f && fabs(visitedIndices[currentIndex]-previousHeight)>clusterRadius))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int y = currentIndex / width;
|
||||||
|
int x = currentIndex - y*width;
|
||||||
|
|
||||||
|
if(x>=0 && x<width && y>=0 && y<height)
|
||||||
|
{
|
||||||
|
cluster.push_back(currentIndex);
|
||||||
|
float currentHeight = visitedIndices[currentIndex];
|
||||||
|
visitedIndices[currentIndex] = 0;
|
||||||
|
|
||||||
|
clusterIndicesFloodfill(cluster, visitedIndices, width, height, clusterRadius, (y+1)*width + x, currentHeight);
|
||||||
|
clusterIndicesFloodfill(cluster, visitedIndices, width, height, clusterRadius, (y-1)*width + x, currentHeight);
|
||||||
|
clusterIndicesFloodfill(cluster, visitedIndices, width, height, clusterRadius, y*width + x+1, currentHeight);
|
||||||
|
clusterIndicesFloodfill(cluster, visitedIndices, width, height, clusterRadius, y*width + x-1, currentHeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3033,6 +3033,65 @@ pcl::PointCloud<pcl::Normal>::Ptr computeFastOrganizedNormals2D(
|
|||||||
return computeFastOrganizedNormals2DImpl<pcl::PointXYZI>(cloud, searchK, searchRadius, viewPoint);
|
return computeFastOrganizedNormals2DImpl<pcl::PointXYZI>(cloud, searchK, searchRadius, viewPoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename PointT>
|
||||||
|
pcl::PointCloud<pcl::Normal>::Ptr computeFastOrganizedNormalsImpl(
|
||||||
|
const typename pcl::PointCloud<PointT>::Ptr & cloud,
|
||||||
|
const pcl::IndicesPtr & indices,
|
||||||
|
float maxDepthChangeFactor,
|
||||||
|
float normalSmoothingSize,
|
||||||
|
const Eigen::Vector3f & viewPoint)
|
||||||
|
{
|
||||||
|
UASSERT(cloud->isOrganized());
|
||||||
|
|
||||||
|
// Normal estimation
|
||||||
|
pcl::PointCloud<pcl::Normal>::Ptr normals (new pcl::PointCloud<pcl::Normal>);
|
||||||
|
pcl::IntegralImageNormalEstimation<PointT, pcl::Normal> ne;
|
||||||
|
#if PCL_VERSION_COMPARE(<, 1, 7, 0)
|
||||||
|
ne.setNormalEstimationMethod (ne.AVERAGE_3D_GRADIENT);
|
||||||
|
ne.setBorderPolicy(ne.BORDER_POLICY_MIRROR);
|
||||||
|
#else
|
||||||
|
ne.setNormalEstimationMethod (ne.SIMPLE_3D_GRADIENT);
|
||||||
|
ne.setBorderPolicy(ne.BORDER_POLICY_IGNORE);
|
||||||
|
#endif
|
||||||
|
ne.setMaxDepthChangeFactor(maxDepthChangeFactor);
|
||||||
|
ne.setNormalSmoothingSize(normalSmoothingSize);
|
||||||
|
ne.setInputCloud(cloud);
|
||||||
|
// Commented: Keep the output normals size the same as the input cloud
|
||||||
|
//if(indices->size())
|
||||||
|
//{
|
||||||
|
// ne.setIndices(indices);
|
||||||
|
//}
|
||||||
|
|
||||||
|
// create kdtree search tree (not used by IntegralImageNormalEstimation) to avoid
|
||||||
|
// "[pcl::OrganizedNeighbor::radiusSearch] Input dataset is not from a projective device!"
|
||||||
|
// on clouds smaller than regular organized clouds from camera (640x480)
|
||||||
|
typename pcl::search::KdTree<PointT>::Ptr tree (new pcl::search::KdTree<PointT>);
|
||||||
|
ne.setSearchMethod(tree);
|
||||||
|
|
||||||
|
ne.setViewPoint(viewPoint[0], viewPoint[1], viewPoint[2]);
|
||||||
|
ne.compute(*normals);
|
||||||
|
|
||||||
|
return normals;
|
||||||
|
}
|
||||||
|
pcl::PointCloud<pcl::Normal>::Ptr computeFastOrganizedNormals(
|
||||||
|
const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud,
|
||||||
|
float maxDepthChangeFactor,
|
||||||
|
float normalSmoothingSize,
|
||||||
|
const Eigen::Vector3f & viewPoint)
|
||||||
|
{
|
||||||
|
pcl::IndicesPtr indices(new std::vector<int>);
|
||||||
|
return computeFastOrganizedNormals(cloud, indices, maxDepthChangeFactor, normalSmoothingSize, viewPoint);
|
||||||
|
}
|
||||||
|
pcl::PointCloud<pcl::Normal>::Ptr computeFastOrganizedNormals(
|
||||||
|
const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud,
|
||||||
|
const pcl::IndicesPtr & indices,
|
||||||
|
float maxDepthChangeFactor,
|
||||||
|
float normalSmoothingSize,
|
||||||
|
const Eigen::Vector3f & viewPoint)
|
||||||
|
{
|
||||||
|
return computeFastOrganizedNormalsImpl<pcl::PointXYZ>(cloud, indices, maxDepthChangeFactor, normalSmoothingSize, viewPoint);
|
||||||
|
}
|
||||||
|
|
||||||
pcl::PointCloud<pcl::Normal>::Ptr computeFastOrganizedNormals(
|
pcl::PointCloud<pcl::Normal>::Ptr computeFastOrganizedNormals(
|
||||||
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
|
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
|
||||||
float maxDepthChangeFactor,
|
float maxDepthChangeFactor,
|
||||||
@@ -3049,36 +3108,7 @@ pcl::PointCloud<pcl::Normal>::Ptr computeFastOrganizedNormals(
|
|||||||
float normalSmoothingSize,
|
float normalSmoothingSize,
|
||||||
const Eigen::Vector3f & viewPoint)
|
const Eigen::Vector3f & viewPoint)
|
||||||
{
|
{
|
||||||
UASSERT(cloud->isOrganized());
|
return computeFastOrganizedNormalsImpl<pcl::PointXYZRGB>(cloud, indices, maxDepthChangeFactor, normalSmoothingSize, viewPoint);
|
||||||
|
|
||||||
pcl::search::KdTree<pcl::PointXYZRGB>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZRGB>);
|
|
||||||
if(indices->size())
|
|
||||||
{
|
|
||||||
tree->setInputCloud(cloud, indices);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tree->setInputCloud (cloud);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Normal estimation
|
|
||||||
pcl::PointCloud<pcl::Normal>::Ptr normals (new pcl::PointCloud<pcl::Normal>);
|
|
||||||
pcl::IntegralImageNormalEstimation<pcl::PointXYZRGB, pcl::Normal> ne;
|
|
||||||
ne.setNormalEstimationMethod (ne.AVERAGE_3D_GRADIENT);
|
|
||||||
ne.setMaxDepthChangeFactor(maxDepthChangeFactor);
|
|
||||||
ne.setNormalSmoothingSize(normalSmoothingSize);
|
|
||||||
ne.setBorderPolicy(ne.BORDER_POLICY_MIRROR);
|
|
||||||
ne.setInputCloud(cloud);
|
|
||||||
// Commented: Keep the output normals size the same as the input cloud
|
|
||||||
//if(indices->size())
|
|
||||||
//{
|
|
||||||
// ne.setIndices(indices);
|
|
||||||
//}
|
|
||||||
ne.setSearchMethod(tree);
|
|
||||||
ne.setViewPoint(viewPoint[0], viewPoint[1], viewPoint[2]);
|
|
||||||
ne.compute(*normals);
|
|
||||||
|
|
||||||
return normals;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float computeNormalsComplexity(
|
float computeNormalsComplexity(
|
||||||
|
|||||||
Reference in New Issue
Block a user