int GeometricalAnalysisTools::computeLocalDensityApprox(GenericIndexedCloudPersist* theCloud, Density densityType, GenericProgressCallback* progressCb/*=0*/, DgmOctree* inputOctree/*=0*/) { if (!theCloud) return -1; unsigned numberOfPoints = theCloud->size(); if (numberOfPoints < 3) return -2; 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->findBestLevelForAGivenPopulationPerCell(3); //parameters void* additionalParameters[] = { static_cast<void*>(&densityType) }; int result = 0; if (theOctree->executeFunctionForAllCellsAtLevel( level, &computeApproxPointsDensityInACellAtLevel, additionalParameters, true, progressCb, "Approximate Local Density Computation") == 0) { //something went wrong result = -4; } if (!inputOctree) delete theOctree; return result; }
bool AutoSegmentationTools::frontPropagationBasedSegmentation(GenericIndexedCloudPersist* theCloud, ScalarType minSeedDist, uchar octreeLevel, ReferenceCloudContainer& theSegmentedLists, GenericProgressCallback* progressCb, DgmOctree* inputOctree, bool applyGaussianFilter, float alpha) { unsigned numberOfPoints = (theCloud ? theCloud->size() : 0); if (numberOfPoints == 0) return false; //compute octree if none was provided DgmOctree* theOctree = inputOctree; if (!theOctree) { theOctree = new DgmOctree(theCloud); if (theOctree->build(progressCb)<1) { delete theOctree; return false; } } //on calcule le gradient (va ecraser le champ des distances) if (ScalarFieldTools::computeScalarFieldGradient(theCloud,true,true,progressCb,theOctree) < 0) { if (!inputOctree) delete theOctree; return false; } //et on lisse le resultat if (applyGaussianFilter) { uchar level = theOctree->findBestLevelForAGivenPopulationPerCell(NUMBER_OF_POINTS_FOR_GRADIENT_COMPUTATION); PointCoordinateType cellSize = theOctree->getCellSize(level); ScalarFieldTools::applyScalarFieldGaussianFilter(static_cast<float>(cellSize/3),theCloud,-1,progressCb,theOctree); } unsigned seedPoints = 0; unsigned numberOfSegmentedLists = 0; //on va faire la propagation avec le FastMarching(); FastMarchingForPropagation* fm = new FastMarchingForPropagation(); fm->setJumpCoef(50.0); fm->setDetectionThreshold(alpha); int result = fm->init(theCloud,theOctree,octreeLevel); int octreeLength = OCTREE_LENGTH(octreeLevel)-1; if (result<0) { if (!inputOctree) delete theOctree; delete fm; return false; } if (progressCb) { progressCb->reset(); progressCb->setMethodTitle("FM Propagation"); char buffer[256]; sprintf(buffer,"Octree level: %i\nNumber of points: %u",octreeLevel,numberOfPoints); progressCb->setInfo(buffer); progressCb->start(); } ScalarField* theDists = new ScalarField("distances"); { ScalarType d = theCloud->getPointScalarValue(0); if (!theDists->resize(numberOfPoints,true,d)) { if (!inputOctree) delete theOctree; return false; } } unsigned maxDistIndex = 0, begin = 0; CCVector3 startPoint; while (true) { ScalarType maxDist = NAN_VALUE; //on cherche la premiere distance superieure ou egale a "minSeedDist" while (begin<numberOfPoints) { const CCVector3 *thePoint = theCloud->getPoint(begin); const ScalarType& theDistance = theDists->getValue(begin); ++begin; //FIXME DGM: what happens if SF is negative?! if (theCloud->getPointScalarValue(begin) >= 0 && theDistance >= minSeedDist) { maxDist = theDistance; startPoint = *thePoint; maxDistIndex = begin; break; } } //il n'y a plus de point avec des distances suffisamment grandes ! if (maxDist<minSeedDist) break; //on finit la recherche du max for (unsigned i=begin; i<numberOfPoints; ++i) { const CCVector3 *thePoint = theCloud->getPoint(i); const ScalarType& theDistance = theDists->getValue(i); if ((theCloud->getPointScalarValue(i)>=0.0)&&(theDistance > maxDist)) { maxDist = theDistance; startPoint = *thePoint; maxDistIndex = i; } } int pos[3]; theOctree->getTheCellPosWhichIncludesThePoint(&startPoint,pos,octreeLevel); //clipping (important!) pos[0] = std::min(octreeLength,pos[0]); pos[1] = std::min(octreeLength,pos[1]); pos[2] = std::min(octreeLength,pos[2]); fm->setSeedCell(pos); ++seedPoints; int result = fm->propagate(); //if the propagation was successful if (result >= 0) { //we extract the corresponding points ReferenceCloud* newCloud = new ReferenceCloud(theCloud); if (fm->extractPropagatedPoints(newCloud) && newCloud->size() != 0) { theSegmentedLists.push_back(newCloud); ++numberOfSegmentedLists; } else { //not enough memory?! delete newCloud; newCloud = 0; } if (progressCb) progressCb->update(float(numberOfSegmentedLists % 100)); fm->cleanLastPropagation(); //break; } if (maxDistIndex == begin) ++begin; } if (progressCb) progressCb->stop(); for (unsigned i=0; i<numberOfPoints; ++i) theCloud->setPointScalarValue(i,theDists->getValue(i)); delete fm; fm = 0; theDists->release(); theDists = 0; if (!inputOctree) delete theOctree; return true; }
double StatisticalTestingTools::testCloudWithStatisticalModel(const GenericDistribution* distrib, GenericIndexedCloudPersist* theCloud, unsigned numberOfNeighbours, double pTrust, GenericProgressCallback* progressCb/*=0*/, DgmOctree* inputOctree/*=0*/) { assert(theCloud); if (!distrib->isValid()) return -1.0; DgmOctree* theOctree = inputOctree; if (!theOctree) { theOctree = new DgmOctree(theCloud); if (theOctree->build(progressCb) < 1) { delete theOctree; return -2.0; } } //on active le champ scalaire (IN) pour recevoir les distances du Chi2 theCloud->enableScalarField(); unsigned char level = theOctree->findBestLevelForAGivenPopulationPerCell(numberOfNeighbours); unsigned numberOfChi2Classes = (unsigned)ceil(sqrt((double)numberOfNeighbours)); //Chi2 hisogram values unsigned* histoValues = new unsigned[numberOfChi2Classes]; if (!histoValues) { if (!inputOctree) delete theOctree; return -3.0; } ScalarType* histoMin = 0, customHistoMin = 0; ScalarType* histoMax = 0, customHistoMax = 0; if (strcmp(distrib->getName(),"Gauss")==0) { const NormalDistribution* nDist = static_cast<const NormalDistribution*>(distrib); ScalarType mu=0, sigma2=0; nDist->getParameters(mu, sigma2); customHistoMin = mu - (ScalarType)3.0 * sqrt(sigma2); histoMin = &customHistoMin; customHistoMax = mu + (ScalarType)3.0 * sqrt(sigma2); histoMax = &customHistoMax; } else if (strcmp(distrib->getName(),"Weibull")==0) { customHistoMin = 0; histoMin = &customHistoMin; } //additionnal parameters for local process void* additionalParameters[] = { reinterpret_cast<void*>(const_cast<GenericDistribution*>(distrib)), reinterpret_cast<void*>(&numberOfNeighbours), reinterpret_cast<void*>(&numberOfChi2Classes), reinterpret_cast<void*>(histoValues), reinterpret_cast<void*>(histoMin), reinterpret_cast<void*>(histoMax) }; double maxChi2 = -1.0; //let's compute Chi2 distances if (theOctree->executeFunctionForAllCellsStartingAtLevel( level, &computeLocalChi2DistAtLevel, additionalParameters, numberOfNeighbours/2, numberOfNeighbours*3, true, progressCb, "Statistical Test") != 0) //sucess { if (!progressCb || !progressCb->isCancelRequested()) { //theoretical Chi2 fractile maxChi2 = computeChi2Fractile(pTrust, numberOfChi2Classes-1); maxChi2 = sqrt(maxChi2); //on travaille avec les racines carrees des distances du Chi2 } } delete[] histoValues; histoValues=0; if (!inputOctree) delete theOctree; return maxChi2; }
bool AutoSegmentationTools::frontPropagationBasedSegmentation(GenericIndexedCloudPersist* theCloud, bool signedSF, DistanceType minSeedDist, uchar octreeLevel, ReferenceCloudContainer& theSegmentedLists, GenericProgressCallback* progressCb, DgmOctree* _theOctree, bool applyGaussianFilter, float alpha) { if (!theCloud) return false; unsigned numberOfPoints = theCloud->size(); if (numberOfPoints<1) return false; //on calcule l'octree DgmOctree* theOctree = _theOctree; if (!theOctree) { theOctree = new DgmOctree(theCloud); if (theOctree->build(progressCb)<1) { delete theOctree; return false; } } ScalarField* theDists = new ScalarField("distances",true); if (!theDists->reserve(numberOfPoints)) { if (!_theOctree) delete theOctree; return false; } theCloud->placeIteratorAtBegining(); unsigned k=0; DistanceType d = theCloud->getPointScalarValue(k); for (;k<numberOfPoints;++k) theDists->addElement(d); //on calcule le gradient (va écraser le champ des distances) if (ScalarFieldTools::computeScalarFieldGradient(theCloud,signedSF,true,true,progressCb,theOctree)<0) { if (!_theOctree) delete theOctree; return false; } //et on lisse le résultat if (applyGaussianFilter) { uchar level = theOctree->findBestLevelForAGivenPopulationPerCell(NUMBER_OF_POINTS_FOR_GRADIENT_COMPUTATION); float cellSize = theOctree->getCellSize(level); ScalarFieldTools::applyScalarFieldGaussianFilter(cellSize*0.33f,theCloud,signedSF,-1,progressCb,theOctree); } DistanceType maxDist; unsigned seedPoints = 0; unsigned numberOfSegmentedLists = 0; //on va faire la propagation avec le FastMarching(); FastMarchingForPropagation* fm = new FastMarchingForPropagation(); fm->setJumpCoef(50.0); fm->setDetectionThreshold(alpha); int result = fm->init(theCloud,theOctree,octreeLevel); int octreeLength = OCTREE_LENGTH(octreeLevel)-1; if (result<0) { if (!_theOctree) delete theOctree; delete fm; return false; } if (progressCb) { progressCb->reset(); progressCb->setMethodTitle("FM Propagation"); char buffer[256]; sprintf(buffer,"Octree level: %i\nNumber of points: %i",octreeLevel,numberOfPoints); progressCb->setInfo(buffer); progressCb->start(); } unsigned maxDistIndex=0,begin = 0; CCVector3 startPoint; while (true) { maxDist = HIDDEN_VALUE; //on cherche la première distance supérieure ou égale à "minSeedDist" while (begin<numberOfPoints) { const CCVector3 *thePoint = theCloud->getPoint(begin); const DistanceType& theDistance = theDists->getValue(begin); ++begin; if ((theCloud->getPointScalarValue(begin)>=0.0)&&(theDistance >= minSeedDist)) { maxDist = theDistance; startPoint = *thePoint; maxDistIndex = begin; break; } } //il n'y a plus de point avec des distances suffisamment grandes ! if (maxDist<minSeedDist) break; //on finit la recherche du max for (unsigned i=begin;i<numberOfPoints;++i) { const CCVector3 *thePoint = theCloud->getPoint(i); const DistanceType& theDistance = theDists->getValue(i); if ((theCloud->getPointScalarValue(i)>=0.0)&&(theDistance > maxDist)) { maxDist = theDistance; startPoint = *thePoint; maxDistIndex = i; } } //on lance la propagation à partir du point de distance maximale //propagateFromPoint(aList,_GradientNorms,maxDistIndex,octreeLevel,_gui); int pos[3]; theOctree->getTheCellPosWhichIncludesThePoint(&startPoint,pos,octreeLevel); //clipping (important !) pos[0] = std::min(octreeLength,pos[0]); pos[1] = std::min(octreeLength,pos[1]); pos[2] = std::min(octreeLength,pos[2]); fm->setSeedCell(pos); ++seedPoints; int result = fm->propagate(); //si la propagation s'est bien passée if (result>=0) { //on la termine (i.e. on extrait les points correspondant) ReferenceCloud* newCloud = fm->extractPropagatedPoints(); //si la liste convient //on la rajoute au groupe des listes segmentées theSegmentedLists.push_back(newCloud); ++numberOfSegmentedLists; if (progressCb) progressCb->update(float(numberOfSegmentedLists % 100)); fm->endPropagation(); //break; } if (maxDistIndex == begin) ++begin; } if (progressCb) progressCb->stop(); for (unsigned i=0;i<numberOfPoints;++i) theCloud->setPointScalarValue(i,theDists->getValue(i)); delete fm; theDists->release(); theDists=0; if (!_theOctree) delete theOctree; return true; }
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::sorFilter( GenericIndexedCloudPersist* inputCloud, int knn/*=6*/, double nSigma/*=1.0*/, DgmOctree* inputOctree/*=0*/, GenericProgressCallback* progressCb/*=0*/) { if (!inputCloud || knn <= 0 || inputCloud->size() <= static_cast<unsigned>(knn)) { //invalid input assert(false); return 0; } DgmOctree* octree = inputOctree; if (!octree) { //compute the octree if necessary octree = new DgmOctree(inputCloud); if (octree->build(progressCb) < 1) { delete octree; return 0; } } //output ReferenceCloud* filteredCloud = 0; for (unsigned step=0; step<1; ++step) //fake loop for easy break { unsigned pointCount = inputCloud->size(); std::vector<PointCoordinateType> meanDistances; try { meanDistances.resize(pointCount,0); } catch (const std::bad_alloc&) { //not enough memory break; } double avgDist = 0, stdDev = 0; //1st step: compute the average distance to the neighbors { //additional parameters void* additionalParameters[] = {reinterpret_cast<void*>(&knn), reinterpret_cast<void*>(&meanDistances) }; unsigned char octreeLevel = octree->findBestLevelForAGivenPopulationPerCell(knn); if (octree->executeFunctionForAllCellsAtLevel( octreeLevel, &applySORFilterAtLevel, additionalParameters, true, progressCb, "SOR filter") == 0) { //something went wrong break; } //deduce the average distance and std. dev. double sumDist = 0; double sumSquareDist = 0; for (unsigned i=0; i<pointCount; ++i) { sumDist += meanDistances[i]; sumSquareDist += meanDistances[i]*meanDistances[i]; } avgDist = sumDist / pointCount; stdDev = sqrt(fabs(sumSquareDist / pointCount - avgDist*avgDist)); } //2nd step: remove the farthest points { //deduce the max distance double maxDist = avgDist + nSigma * stdDev; filteredCloud = new ReferenceCloud(inputCloud); if (!filteredCloud->reserve(pointCount)) { //not enough memory delete filteredCloud; filteredCloud = 0; break; } for (unsigned i=0; i<pointCount; ++i) { if (meanDistances[i] <= maxDist) { filteredCloud->addPointIndex(i); } } filteredCloud->resize(filteredCloud->size()); } } if (!inputOctree) { delete octree; octree = 0; } return filteredCloud; }
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; }