diff --git a/include/CloudSamplingTools.h b/include/CloudSamplingTools.h index dd48d4e..6fed78b 100644 --- a/include/CloudSamplingTools.h +++ b/include/CloudSamplingTools.h @@ -143,6 +143,24 @@ namespace CCCoreLib DgmOctree* octree = nullptr, GenericProgressCallback* progressCb = nullptr); + //! Resamples a point cloud (process based on inter point distance) + /** The cloud is resampled so that there is no point nearer than a given distance to other points + It works by picking a reference point, removing all points which are to close to this point, and repeating these two steps until the result is reached + \param cloud the point cloud to resample + \param minDistance the distance under which a point in the resulting cloud cannot have any neighbour + \param modParams parameters of the subsampling behavior modulation with a scalar field (optional) + \param octree associated octree if available + \param markers per-point marker for filtered-in points (required to be size of cloud) + \param progressCb the client application can get some notification of the process progress through this callback mechanism (see GenericProgressCallback) + \return a reference cloud corresponding to the resampling 'selection' + **/ + static size_t resampleCloudSpatially( GenericIndexedCloudPersist* cloud, + PointCoordinateType minDistance, + const SFModulationParams& modParams, + char* markers, + DgmOctree* octree = nullptr, + GenericProgressCallback* progressCb = nullptr); + //! Statistical Outliers Removal (SOR) filter /** This filter removes points based on their mean distance to their distance (by comparing it to the average distance of all points to their neighbors). It is equivalent to PCL StatisticalOutlierRemoval filter (see http://pointclouds.org/documentation/tutorials/statistical_outlier.php) diff --git a/src/CloudSamplingTools.cpp b/src/CloudSamplingTools.cpp index 89d3439..6d7164d 100644 --- a/src/CloudSamplingTools.cpp +++ b/src/CloudSamplingTools.cpp @@ -245,40 +245,65 @@ ReferenceCloud* CloudSamplingTools::resampleCloudSpatially(GenericIndexedCloudPe assert(inputCloud); unsigned cloudSize = inputCloud->size(); - DgmOctree* octree = inputOctree; - if (!octree) + std::vector markers; //DGM: upgraded from vector, as this can be quite huge! + try { - octree = new DgmOctree(inputCloud); - if (octree->build() < static_cast(cloudSize)) - { - delete octree; - return nullptr; - } + markers.resize(cloudSize, 1); //true by default } - assert(octree && octree->associatedCloud() == inputCloud); - - //output cloud - ReferenceCloud* sampledCloud = new ReferenceCloud(inputCloud); - const unsigned c_reserveStep = 65536; - if (!sampledCloud->reserve(std::min(cloudSize, c_reserveStep))) + catch (const std::bad_alloc&) { - if (!inputOctree) - delete octree; return nullptr; } - std::vector markers; //DGM: upgraded from vector, as this can be quite huge! - try + size_t filtered = resampleCloudSpatially(inputCloud, minDistance, modParams, &markers[0], inputOctree, progressCb); + if (filtered) { - markers.resize(cloudSize, 1); //true by default + //output cloud + ReferenceCloud* sampledCloud = new ReferenceCloud(inputCloud); + if (!sampledCloud->reserve(filtered)) + { + delete sampledCloud; + return nullptr; + } + + for (unsigned i = 0; i < cloudSize; i++) + { + if (markers[i]) + { + if (!sampledCloud->addPointIndex(i)) + { + delete sampledCloud; + return nullptr; + } + } + } + return sampledCloud; } - catch (const std::bad_alloc&) + return nullptr; +} + +/* Return 0 for error */ +size_t CloudSamplingTools::resampleCloudSpatially(GenericIndexedCloudPersist* inputCloud, + PointCoordinateType minDistance, + const SFModulationParams& modParams, + char* markers, + DgmOctree* inputOctree/*=0*/, + GenericProgressCallback* progressCb/*=0*/) +{ + assert(inputCloud); + unsigned cloudSize = inputCloud->size(); + + DgmOctree* octree = inputOctree; + if (!octree) { - if (!inputOctree) + octree = new DgmOctree(inputCloud); + if (octree->build() < static_cast(cloudSize)) + { delete octree; - delete sampledCloud; - return nullptr; + return 0; + } } + assert(octree && octree->associatedCloud() == inputCloud); //best octree level (there may be several of them if we use parameter modulation) std::vector bestOctreeLevel; @@ -336,8 +361,7 @@ ReferenceCloud* CloudSamplingTools::resampleCloudSpatially(GenericIndexedCloudPe { delete octree; } - delete sampledCloud; - return nullptr; + return 0; } //progress notification @@ -361,6 +385,7 @@ ReferenceCloud* CloudSamplingTools::resampleCloudSpatially(GenericIndexedCloudPe //default octree level assert(!bestOctreeLevel.empty()); unsigned char octreeLevel = bestOctreeLevel.front(); + size_t filtered = 0; //default distance between points PointCoordinateType minDistBetweenPoints = minDistance; for (unsigned i = 0; i < cloudSize; i++) @@ -403,18 +428,7 @@ ReferenceCloud* CloudSamplingTools::resampleCloudSpatially(GenericIndexedCloudPe //At this stage, the ith point is the only one marked in a radius of . //Therefore it will necessarily be in the final cloud! - if (sampledCloud->size() == sampledCloud->capacity() && !sampledCloud->reserve(sampledCloud->capacity() + c_reserveStep)) - { - //not enough memory - error = true; - break; - } - if (!sampledCloud->addPointIndex(i)) - { - //not enough memory - error = true; - break; - } + ++filtered; } //progress indicator @@ -426,18 +440,6 @@ ReferenceCloud* CloudSamplingTools::resampleCloudSpatially(GenericIndexedCloudPe } } - //remove unnecessarily allocated memory - if (!error) - { - if (sampledCloud->capacity() > sampledCloud->size()) - sampledCloud->resize(sampledCloud->size()); - } - else - { - delete sampledCloud; - sampledCloud = nullptr; - } - if (progressCb) { progressCb->stop(); @@ -450,7 +452,7 @@ ReferenceCloud* CloudSamplingTools::resampleCloudSpatially(GenericIndexedCloudPe octree = nullptr; } - return sampledCloud; + return error ? 0 : filtered; } ReferenceCloud* CloudSamplingTools::sorFilter( GenericIndexedCloudPersist* inputCloud,