bool ScalarFieldTools::applyScalarFieldGaussianFilter(PointCoordinateType sigma, GenericIndexedCloudPersist* theCloud, PointCoordinateType sigmaSF, GenericProgressCallback* progressCb, DgmOctree* theCloudOctree) { if (!theCloud) return false; unsigned n = theCloud->size(); if (n==0) return false; DgmOctree* theOctree = 0; if (theCloudOctree) theOctree = theCloudOctree; else { theOctree = new DgmOctree(theCloud); if (theOctree->build(progressCb)<1) { delete theOctree; return false; } } //best octree level unsigned char level = theOctree->findBestLevelForAGivenNeighbourhoodSizeExtraction(3.0f*sigma); //output scalar field should be different than input one theCloud->enableScalarField(); if (progressCb) { progressCb->reset(); progressCb->setMethodTitle("Gaussian filter"); char infos[256]; sprintf(infos,"Level: %i\n",level); progressCb->setInfo(infos); } void* additionalParameters[2] = { reinterpret_cast<void*>(&sigma), reinterpret_cast<void*>(&sigmaSF) }; bool success = true; if (theOctree->executeFunctionForAllCellsAtLevel( level, computeCellGaussianFilter, additionalParameters, true, progressCb, "Gaussian Filter computation") == 0) { //something went wrong success = false; } return success; }
int GeometricalAnalysisTools::computeCurvature( GenericIndexedCloudPersist* theCloud, Neighbourhood::CC_CURVATURE_TYPE cType, PointCoordinateType kernelRadius, GenericProgressCallback* progressCb/*=0*/, DgmOctree* inputOctree/*=0*/) { if (!theCloud) return -1; unsigned numberOfPoints = theCloud->size(); if (numberOfPoints < 5) return -2; DgmOctree* theOctree = inputOctree; if (!theOctree) { theOctree = new DgmOctree(theCloud); if (theOctree->build(progressCb) < 1) { delete theOctree; return -3; } } theCloud->enableScalarField(); unsigned char level = theOctree->findBestLevelForAGivenNeighbourhoodSizeExtraction(kernelRadius); //parameters void* additionalParameters[2] = { static_cast<void*>(&cType), static_cast<void*>(&kernelRadius) }; int result = 0; if (theOctree->executeFunctionForAllCellsAtLevel(level, &computeCellCurvatureAtLevel, additionalParameters, true, progressCb, "Curvature Computation") == 0) { //something went wrong result = -4; } if (!inputOctree) delete theOctree; return result; }
int GeometricalAnalysisTools::flagDuplicatePoints( GenericIndexedCloudPersist* theCloud, double minDistanceBetweenPoints/*=1.0e-12*/, GenericProgressCallback* progressCb/*=0*/, DgmOctree* inputOctree/*=0*/) { if (!theCloud) return -1; unsigned numberOfPoints = theCloud->size(); if (numberOfPoints <= 1) return -2; DgmOctree* theOctree = inputOctree; if (!theOctree) { theOctree = new DgmOctree(theCloud); if (theOctree->build(progressCb) < 1) { delete theOctree; return -3; } } theCloud->enableScalarField(); //set all flags to 0 by default theCloud->forEach(CCLib::ScalarFieldTools::SetScalarValueToZero); unsigned char level = theOctree->findBestLevelForAGivenNeighbourhoodSizeExtraction(static_cast<PointCoordinateType>(minDistanceBetweenPoints)); //parameters void* additionalParameters[1] = { static_cast<void*>(&minDistanceBetweenPoints) }; int result = 0; if (theOctree->executeFunctionForAllCellsAtLevel( level, &flagDuplicatePointsInACellAtLevel, additionalParameters, false, //doesn't work in parallel! progressCb, "Flag duplicate points") == 0) { //something went wrong result = -4; } if (!inputOctree) delete theOctree; return result; }
ReferenceCloud* CloudSamplingTools::noiseFilter(GenericIndexedCloudPersist* inputCloud, PointCoordinateType kernelRadius, double nSigma, bool removeIsolatedPoints/*=false*/, bool useKnn/*=false*/, int knn/*=6*/, bool useAbsoluteError/*=true*/, double absoluteError/*=0.0*/, DgmOctree* inputOctree/*=0*/, GenericProgressCallback* progressCb/*=0*/) { if (!inputCloud || inputCloud->size() < 2 || (useKnn && knn <= 0) || (!useKnn && kernelRadius <= 0)) { //invalid input assert(false); return 0; } DgmOctree* octree = inputOctree; if (!octree) { octree = new DgmOctree(inputCloud); if (octree->build(progressCb) < 1) { delete octree; return 0; } } ReferenceCloud* filteredCloud = new ReferenceCloud(inputCloud); unsigned pointCount = inputCloud->size(); if (!filteredCloud->reserve(pointCount)) { //not enough memory if (!inputOctree) delete octree; delete filteredCloud; return 0; } //additional parameters void* additionalParameters[] = {reinterpret_cast<void*>(filteredCloud), reinterpret_cast<void*>(&kernelRadius), reinterpret_cast<void*>(&nSigma), reinterpret_cast<void*>(&removeIsolatedPoints), reinterpret_cast<void*>(&useKnn), reinterpret_cast<void*>(&knn), reinterpret_cast<void*>(&useAbsoluteError), reinterpret_cast<void*>(&absoluteError) }; unsigned char octreeLevel = 0; if (useKnn) octreeLevel = octree->findBestLevelForAGivenNeighbourhoodSizeExtraction(kernelRadius); else octreeLevel = octree->findBestLevelForAGivenPopulationPerCell(knn); if (octree->executeFunctionForAllCellsAtLevel( octreeLevel, &applyNoiseFilterAtLevel, additionalParameters, true, progressCb, "Noise filter" ) == 0) { //something went wrong delete filteredCloud; filteredCloud = 0; } if (!inputOctree) { delete octree; octree = 0; } if (filteredCloud) { filteredCloud->resize(filteredCloud->size()); } return filteredCloud; }
ReferenceCloud* CloudSamplingTools::resampleCloudSpatially(GenericIndexedCloudPersist* inputCloud, PointCoordinateType minDistance, const SFModulationParams& modParams, DgmOctree* inputOctree/*=0*/, GenericProgressCallback* progressCb/*=0*/) { assert(inputCloud); unsigned cloudSize = inputCloud->size(); DgmOctree* octree = inputOctree; if (!octree) { octree = new DgmOctree(inputCloud); if (octree->build() < static_cast<int>(cloudSize)) { delete octree; return 0; } } 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))) { if (!inputOctree) delete octree; return 0; } GenericChunkedArray<1,char>* markers = new GenericChunkedArray<1,char>(); //DGM: upgraded from vector, as this can be quite huge! if (!markers->resize(cloudSize,true,1)) //true by default { markers->release(); if (!inputOctree) delete octree; delete sampledCloud; return 0; } //best octree level (there may be several of them if we use parameter modulation) std::vector<unsigned char> bestOctreeLevel; bool modParamsEnabled = modParams.enabled; ScalarType sfMin = 0, sfMax = 0; try { if (modParams.enabled) { //compute min and max sf values ScalarFieldTools::computeScalarFieldExtremas(inputCloud,sfMin,sfMax); if (!ScalarField::ValidValue(sfMin)) { //all SF values are NAN?! modParamsEnabled = false; } else { //compute min and max 'best' levels PointCoordinateType dist0 = static_cast<PointCoordinateType>(sfMin * modParams.a + modParams.b); PointCoordinateType dist1 = static_cast<PointCoordinateType>(sfMax * modParams.a + modParams.b); unsigned char level0 = octree->findBestLevelForAGivenNeighbourhoodSizeExtraction(dist0); unsigned char level1 = octree->findBestLevelForAGivenNeighbourhoodSizeExtraction(dist1); bestOctreeLevel.push_back(level0); if (level1 != level0) { //add intermediate levels if necessary size_t levelCount = (level1 < level0 ? level0-level1 : level1-level0) + 1; assert(levelCount != 0); for (size_t i=1; i<levelCount-1; ++i) //we already know level0 and level1! { ScalarType sfVal = sfMin + i*((sfMax-sfMin)/levelCount); PointCoordinateType dist = static_cast<PointCoordinateType>(sfVal * modParams.a + modParams.b); unsigned char level = octree->findBestLevelForAGivenNeighbourhoodSizeExtraction(dist); bestOctreeLevel.push_back(level); } } bestOctreeLevel.push_back(level1); } } else { unsigned char defaultLevel = octree->findBestLevelForAGivenNeighbourhoodSizeExtraction(minDistance); bestOctreeLevel.push_back(defaultLevel); } } catch (const std::bad_alloc&) { //not enough memory markers->release(); if (!inputOctree) { delete octree; } delete sampledCloud; return 0; } //progress notification NormalizedProgress normProgress(progressCb, cloudSize); if (progressCb) { if (progressCb->textCanBeEdited()) { progressCb->setMethodTitle("Spatial resampling"); char buffer[256]; sprintf(buffer, "Points: %u\nMin dist.: %f", cloudSize, minDistance); progressCb->setInfo(buffer); } progressCb->update(0); progressCb->start(); } //for each point in the cloud that is still 'marked', we look //for its neighbors and remove their own marks markers->placeIteratorAtBegining(); bool error = false; //default octree level assert(!bestOctreeLevel.empty()); unsigned char octreeLevel = bestOctreeLevel.front(); //default distance between points PointCoordinateType minDistBetweenPoints = minDistance; for (unsigned i=0; i<cloudSize; i++, markers->forwardIterator()) { //no mark? we skip this point if (markers->getCurrentValue() != 0) { //init neighbor search structure const CCVector3* P = inputCloud->getPoint(i); //parameters modulation if (modParamsEnabled) { ScalarType sfVal = inputCloud->getPointScalarValue(i); if (ScalarField::ValidValue(sfVal)) { //modulate minDistance minDistBetweenPoints = static_cast<PointCoordinateType>(sfVal * modParams.a + modParams.b); //get (approximate) best level size_t levelIndex = static_cast<size_t>(bestOctreeLevel.size() * (sfVal / (sfMax-sfMin))); if (levelIndex == bestOctreeLevel.size()) --levelIndex; octreeLevel = bestOctreeLevel[levelIndex]; } else { minDistBetweenPoints = minDistance; octreeLevel = bestOctreeLevel.front(); } } //look for neighbors and 'de-mark' them { DgmOctree::NeighboursSet neighbours; octree->getPointsInSphericalNeighbourhood(*P,minDistBetweenPoints,neighbours,octreeLevel); for (DgmOctree::NeighboursSet::iterator it = neighbours.begin(); it != neighbours.end(); ++it) if (it->pointIndex != i) markers->setValue(it->pointIndex,0); } //At this stage, the ith point is the only one marked in a radius of <minDistance>. //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; } } //progress indicator if (progressCb && !normProgress.oneStep()) { //cancel process error = true; break; } } //remove unnecessarily allocated memory if (!error) { if (sampledCloud->capacity() > sampledCloud->size()) sampledCloud->resize(sampledCloud->size()); } else { delete sampledCloud; sampledCloud = 0; } if (progressCb) { progressCb->stop(); } if (!inputOctree) { //locally computed octree delete octree; octree = 0; } markers->release(); markers = 0; return sampledCloud; }
int GeometricalAnalysisTools::computeLocalDensity( GenericIndexedCloudPersist* theCloud, Density densityType, PointCoordinateType kernelRadius, GenericProgressCallback* progressCb/*=0*/, DgmOctree* inputOctree/*=0*/) { if (!theCloud) return -1; unsigned numberOfPoints = theCloud->size(); if (numberOfPoints < 3) return -2; //compute the right dimensional coef based on the expected output double dimensionalCoef = 1.0; switch (densityType) { case DENSITY_KNN: dimensionalCoef = 1.0; break; case DENSITY_2D: dimensionalCoef = M_PI * (static_cast<double>(kernelRadius) * kernelRadius); break; case DENSITY_3D: dimensionalCoef = s_UnitSphereVolume * ((static_cast<double>(kernelRadius) * kernelRadius) * kernelRadius); break; default: assert(false); return -5; } DgmOctree* theOctree = inputOctree; if (!theOctree) { theOctree = new DgmOctree(theCloud); if (theOctree->build(progressCb) < 1) { delete theOctree; return -3; } } theCloud->enableScalarField(); //determine best octree level to perform the computation unsigned char level = theOctree->findBestLevelForAGivenNeighbourhoodSizeExtraction(kernelRadius); //parameters void* additionalParameters[] = { static_cast<void*>(&kernelRadius), static_cast<void*>(&dimensionalCoef) }; int result = 0; if (theOctree->executeFunctionForAllCellsAtLevel( level, &computePointsDensityInACellAtLevel, additionalParameters, true, progressCb, "Local Density Computation") == 0) { //something went wrong result = -4; } if (!inputOctree) delete theOctree; return result; }
int ScalarFieldTools::computeScalarFieldGradient( GenericIndexedCloudPersist* theCloud, PointCoordinateType radius, bool euclideanDistances, bool sameInAndOutScalarField/*=false*/, GenericProgressCallback* progressCb/*=0*/, DgmOctree* theCloudOctree/*=0*/) { if (!theCloud) return -1; DgmOctree* theOctree = theCloudOctree; if (!theOctree) { theOctree = new DgmOctree(theCloud); if (theOctree->build(progressCb)<1) { delete theOctree; return -2; } } unsigned char octreeLevel = 0; if (radius <= 0) { octreeLevel = theOctree->findBestLevelForAGivenPopulationPerCell(AVERAGE_NUMBER_OF_POINTS_FOR_GRADIENT_COMPUTATION); radius = theOctree->getCellSize(octreeLevel); } else { octreeLevel = theOctree->findBestLevelForAGivenNeighbourhoodSizeExtraction(radius); } ScalarField* theGradientNorms = new ScalarField("gradient norms"); ScalarField* _theGradientNorms = 0; //mode champ scalaire "IN" et "OUT" identique if (sameInAndOutScalarField) { if (!theGradientNorms->reserve(theCloud->size())) //not enough memory { if (!theCloudOctree) delete theOctree; theGradientNorms->release(); return -3; } _theGradientNorms = theGradientNorms; } else //mode champs scalaires "IN" et "OUT" dfferents (par defaut) { //on initialise les distances (IN - en ecriture) pour recevoir les normes du gradient if (!theCloud->enableScalarField()) { if (!theCloudOctree) delete theOctree; theGradientNorms->release(); return -4; } } //structure contenant les parametres additionnels void* additionalParameters[3] = { static_cast<void*>(&euclideanDistances), static_cast<void*>(&radius), static_cast<void*>(_theGradientNorms) }; int result = 0; if (theOctree->executeFunctionForAllCellsAtLevel( octreeLevel, computeMeanGradientOnPatch, additionalParameters, true, progressCb, "Gradient Computation") == 0) { //something went wrong result = -5; } if (!theCloudOctree) delete theOctree; theGradientNorms->release(); theGradientNorms=0; return result; }