DgmOctree类的executeFunctionForAllCellsAtLevel和executeFunctionForAllCellsStartingAtLevel方法通过回调函数octreeCellFunc,执行八叉树中每个单元的相关计算。
unsigned DgmOctree::executeFunctionForAllCellsAtLevel( unsigned char level, octreeCellFunc func, void** additionalParameters, bool multiThread/*=false*/, GenericProgressCallback* progressCb/*=0*/, const char* functionTitle/*=0*/, int maxThreadCount/*=0*/)
unsigned DgmOctree::executeFunctionForAllCellsStartingAtLevel(unsigned char startingLevel, octreeCellFunc func, void** additionalParameters, unsigned minNumberOfPointsPerCell, unsigned maxNumberOfPointsPerCell, bool multiThread/* = true*/, GenericProgressCallback* progressCb/*=0*/, const char* functionTitle/*=0*/, int maxThreadCount/*=0*/)
通过DgmOctree遍历获取每一个Cell单元似乎还是一件很复杂的事情啊!
//! The coded octree structure cellsContainer m_thePointsAndTheirCellCodes;
通过编码集合实现?m_thePointsAndTheirCellCodes根据CellCodes对所有的点进行了排序。注意,所以知道每个Cell中的起始点的Index就可以确定Cell中的其他点。
const cellsContainer& pointsAndTheirCellCodes() const { return m_thePointsAndTheirCellCodes; }
注意octreeCellFunc 回调函数的参数,第一个是const引用传递参数,值不可以修改。
typedef bool (*octreeCellFunc)(const octreeCell& cell, void**, NormalizedProgress*);
因此尝试了使用下面的代码,应该是可行的:
if (!m_app) return; const ccHObject::Container& selectedEntities = m_app->getSelectedEntities(); size_t selNum = selectedEntities.size(); if (selNum!=1) { m_app->dispToConsole("Select only one cloud!",ccMainAppInterface::ERR_CONSOLE_MESSAGE); return; } ccHObject* ent = selectedEntities[0]; assert(ent); if (!ent || !ent->isA(CC_TYPES::POINT_CLOUD)) { m_app->dispToConsole("Select a real point cloud!",ccMainAppInterface::ERR_CONSOLE_MESSAGE); return; } ccPointCloud* theCloud = static_cast<ccPointCloud*>(ent); if (!theCloud) return; //输入参数,半径大小 float kernelRadius=1; unsigned count = theCloud->size(); bool hasNorms = theCloud->hasNormals(); CCVector3 bbMin, bbMax; theCloud->getBoundingBox(bbMin,bbMax); const CCVector3d& globalShift = theCloud->getGlobalShift(); double globalScale = theCloud->getGlobalScale(); //进度条 ccProgressDialog pDlg(true,m_app->getMainWindow()); unsigned numberOfPoints = theCloud->size(); if (numberOfPoints < 5) return ; //构建八叉树 CCLib::DgmOctree* theOctree = NULL; if (!theOctree) { theOctree = new CCLib::DgmOctree(theCloud); if (theOctree->build(&pDlg) < 1) { delete theOctree; return ; } } int result = 0; QString sfName="Eigen_Value"; int sfIdx = -1; ccPointCloud* pc = 0; //注意先添加ScalarField,并设置为当前的 if (theCloud->isA(CC_TYPES::POINT_CLOUD)) { pc = static_cast<ccPointCloud*>(theCloud); sfIdx = pc->getScalarFieldIndexByName(qPrintable(sfName)); if (sfIdx < 0) sfIdx = pc->addScalarField(qPrintable(sfName)); if (sfIdx >= 0) pc->setCurrentInScalarField(sfIdx); else { ccConsole::Error(QString("Failed to create scalar field on cloud '%1' (not enough memory?)").arg(pc->getName())); } } //开启ScalarField模式 theCloud->enableScalarField(); //给定的半径,寻找最佳的Level unsigned char level = theOctree->findBestLevelForAGivenNeighbourhoodSizeExtraction(kernelRadius); //parameters void* additionalParameters[1] = {static_cast<void*>(&kernelRadius) }; if (theOctree->executeFunctionForAllCellsAtLevel(level, &computeCellEigenValueAtLevel, additionalParameters, true, &pDlg, "Eigen value Computation") == 0) { //something went wrong result = -4; } //number of cells for this level unsigned cellCount = theOctree->getCellNumber(level); unsigned maxCellPopulation =theOctree->getmaxCellPopulation(level); //cell descriptor (initialize it with first cell/point) CCLib::DgmOctree::octreeCell cell(theOctree); if (!cell.points->reserve(maxCellPopulation)) //not enough memory return; cell.level = level; cell.index = 0; CCLib::DgmOctree::cellIndexesContainer vec; try { vec.resize(cellCount); } catch (const std::bad_alloc&) { //not enough memory return; } //binary shift for cell code truncation unsigned char bitDec = GET_NDT_BIT_SHIFT(level); CCLib::DgmOctree::cellsContainer::const_iterator p =theOctree->pointsAndTheirCellCodes().begin(); CCLib::DgmOctree::OctreeCellCodeType predCode = (p->theCode >> bitDec)+1; //pred value must be different than the first element's for (unsigned i=0,j=0; i<theOctree->getNumberOfProjectedPoints(); ++i,++p) { CCLib::DgmOctree::OctreeCellCodeType currentCode = (p->theCode >> bitDec); if (predCode != currentCode) { vec[j++] = i;//存储索引 int n=cell.points->size(); if(n>=5) { CCVector3d Psum(0,0,0); for (unsigned i=0; i<n; ++i) { CCVector3 P; cell.points->getPoint(i,P); Psum.x += P.x; Psum.y += P.y; Psum.z += P.z; } ScalarType curv = NAN_VALUE; CCVector3 G(static_cast<PointCoordinateType>(Psum.x / n), static_cast<PointCoordinateType>(Psum.y / n), static_cast<PointCoordinateType>(Psum.z / n) ); double mXX = 0.0; double mYY = 0.0; double mZZ = 0.0; double mXY = 0.0; double mXZ = 0.0; double mYZ = 0.0; //for each point in the cell for (unsigned i=0; i<n; ++i) { CCVector3 CellP; cell.points->getPoint(i,CellP); CCVector3 P = CellP - G; mXX += static_cast<double>(P.x)*P.x; mYY += static_cast<double>(P.y)*P.y; mZZ += static_cast<double>(P.z)*P.z; mXY += static_cast<double>(P.x)*P.y; mXZ += static_cast<double>(P.x)*P.z; mYZ += static_cast<double>(P.y)*P.z; } //symmetry CCLib::SquareMatrixd covMat(3); covMat.m_values[0][0] = mXX/n; covMat.m_values[1][1] = mYY/n; covMat.m_values[2][2] = mZZ/n; covMat.m_values[1][0] = covMat.m_values[0][1] = mXY/n; covMat.m_values[2][0] = covMat.m_values[0][2] = mXZ/n; covMat.m_values[2][1] = covMat.m_values[1][2] = mYZ/n; CCLib::SquareMatrixd eigVectors; std::vector<double> eigValues; if (!Jacobi<double>::ComputeEigenValuesAndVectors(covMat, eigVectors, eigValues)) { //failure curv= NAN_VALUE; } //compute eigen value double e0 = eigValues[0]; double e1 = eigValues[1]; double e2 = eigValues[2]; double sum = fabs(e0+e1+e2); if (sum < ZERO_TOLERANCE) { curv= NAN_VALUE; } double eMin = std::min(std::min(e0,e1),e2); curv= static_cast<ScalarType>(fabs(eMin) / sum); for (unsigned i=0; i<n; ++i) { //current point index unsigned index = cell.points->getPointGlobalIndex(i); //current point index in neighbourhood (to compute curvature at the right position!) unsigned indexInNeighbourhood = 0; cell.points->setPointScalarValue(i,curv); } } //and we start a new cell开始新的Cell cell.index += cell.points->size(); cell.points->clear(false); cell.truncatedCode = currentCode; /*cell.mean_=G; cell.cov_=covMat; CCVector3 eigvalues1(e0,e1,e2); cell.evals_=eigvalues1;*/ } cell.points->addPointIndex(p->theIndex); //can't fail (see above) predCode = currentCode; } if (result == 0) { if (pc && sfIdx >= 0) { //设置当前显示的ScalarField pc->setCurrentDisplayedScalarField(sfIdx); pc->showSF(sfIdx >= 0); pc->getCurrentInScalarField()->computeMinAndMax(); } theCloud->prepareDisplayForRefresh(); } else { ccConsole::Warning(QString("Failed to apply processing to cloud '%1'").arg(theCloud->getName())); if (pc && sfIdx >= 0) { pc->deleteScalarField(sfIdx); sfIdx = -1; } }
参考DgmOctree::getCellIndexes DgmOctree::getPointsInCellByCellIndex
1 //重要,获取每一八叉树层的Cell索引的集合 2 bool DgmOctreeNDT::getCellIndexes(unsigned char level, cellIndexesContainer& vec) const 3 { 4 try 5 { 6 vec.resize(m_cellCount[level]); 7 } 8 catch (const std::bad_alloc&) 9 { 10 //not enough memory 11 return false; 12 } 13 14 //binary shift for cell code truncation 15 unsigned char bitDec = GET_NDT_BIT_SHIFT(level); 16 17 cellsContainer::const_iterator p = m_thePointsAndTheirCellCodes.begin(); 18 19 OctreeCellCodeType predCode = (p->theCode >> bitDec)+1; //pred value must be different than the first element's 20 21 for (unsigned i=0,j=0; i<m_numberOfProjectedPoints; ++i,++p) 22 { 23 OctreeCellCodeType currentCode = (p->theCode >> bitDec); 24 25 if (predCode != currentCode) 26 vec[j++] = i; 27 28 predCode = currentCode; 29 } 30 31 return true; 32 }
1 bool DgmOctreeNDT::getPointsInCellByCellIndex( ReferenceCloud* cloud, 2 unsigned cellIndex, 3 unsigned char level, 4 bool clearOutputCloud/* = true*/) const 5 { 6 assert(cloud && cloud->getAssociatedCloud() == m_theAssociatedCloud); 7 8 //binary shift for cell code truncation 9 unsigned char bitDec = GET_NDT_BIT_SHIFT(level); 10 11 //we look for the first index in 'm_thePointsAndTheirCellCodes' corresponding to this cell 12 cellsContainer::const_iterator p = m_thePointsAndTheirCellCodes.begin()+cellIndex; 13 OctreeCellCodeType searchCode = (p->theCode >> bitDec); 14 15 if (clearOutputCloud) 16 cloud->clear(false); 17 18 //while the (partial) cell code matches this cell 19 while ((p != m_thePointsAndTheirCellCodes.end()) && ((p->theCode >> bitDec) == searchCode)) 20 { 21 if (!cloud->addPointIndex(p->theIndex)) 22 return false; 23 ++p; 24 } 25 26 return true; 27 }
涉及的类包括:近邻点类、近邻点查询结构体
另外:
1 bool qNDTRansacSD::computeCellEigenValueAtLevel(const CCNDTLib::DgmOctreeNDT::octreeCellNDT& cell, 2 void** additionalParameters,NormalizedProgress* nProgress/*=0*/) 3 { 4 //parameters 5 PointCoordinateType radius = *static_cast<PointCoordinateType*>(additionalParameters[0]); 6 7 structure for nearest neighbors search 8 int n=cell.points->size(); 9 CCVector3d Psum(0,0,0); 10 for (unsigned i=0; i<n; ++i) 11 { 12 CCVector3 P; 13 cell.points->getPoint(i,P); 14 Psum.x += P.x; 15 Psum.y += P.y; 16 Psum.z += P.z; 17 } 18 ScalarType curv = NAN_VALUE; 19 CCVector3 G(static_cast<PointCoordinateType>(Psum.x / n), 20 static_cast<PointCoordinateType>(Psum.y / n), 21 static_cast<PointCoordinateType>(Psum.z / n) ); 22 23 double mXX = 0.0; 24 double mYY = 0.0; 25 double mZZ = 0.0; 26 double mXY = 0.0; 27 double mXZ = 0.0; 28 double mYZ = 0.0; 29 //for each point in the cell 30 for (unsigned i=0; i<n; ++i) 31 { 32 CCVector3 CellP; 33 cell.points->getPoint(i,CellP); 34 CCVector3 P = CellP - G; 35 36 mXX += static_cast<double>(P.x)*P.x; 37 mYY += static_cast<double>(P.y)*P.y; 38 mZZ += static_cast<double>(P.z)*P.z; 39 mXY += static_cast<double>(P.x)*P.y; 40 mXZ += static_cast<double>(P.x)*P.z; 41 mYZ += static_cast<double>(P.y)*P.z; 42 } 43 //symmetry 44 CCLib::SquareMatrixd covMat(3); 45 covMat.m_values[0][0] = mXX/n; 46 covMat.m_values[1][1] = mYY/n; 47 covMat.m_values[2][2] = mZZ/n; 48 covMat.m_values[1][0] = covMat.m_values[0][1] = mXY/n; 49 covMat.m_values[2][0] = covMat.m_values[0][2] = mXZ/n; 50 covMat.m_values[2][1] = covMat.m_values[1][2] = mYZ/n; 51 52 CCLib::SquareMatrixd eigVectors; 53 std::vector<double> eigValues; 54 55 if (!Jacobi<double>::ComputeEigenValuesAndVectors(covMat, eigVectors, eigValues)) 56 { 57 //failure 58 curv= NAN_VALUE; 59 } 60 61 //compute curvature as the rate of change of the surface 62 double e0 = eigValues[0]; 63 double e1 = eigValues[1]; 64 double e2 = eigValues[2]; 65 double sum = fabs(e0+e1+e2); 66 if (sum < ZERO_TOLERANCE) 67 { 68 curv= NAN_VALUE; 69 } 70 71 double eMin = std::min(std::min(e0,e1),e2); 72 curv= static_cast<ScalarType>(fabs(eMin) / sum); 73 74 75 for (unsigned i=0; i<n; ++i) 76 { 77 //current point index 78 unsigned index = cell.points->getPointGlobalIndex(i); 79 //current point index in neighbourhood (to compute curvature at the right position!) 80 unsigned indexInNeighbourhood = 0; 81 82 cell.points->setPointScalarValue(i,curv); 83 if (nProgress && !nProgress->oneStep()) 84 { 85 return false; 86 } 87 } 88 89 return true; 90 }