点云的基本几何计算

1.计算法向量

原文件

function normal = estimateNormal(data, tree, query, radius, min_neighbors)
% ESTIMATENORMAL Given a point cloud and query point, estimate the surface 
% normal by performing an eigendecomposition of the covariance matrix created 
% from the nearest neighbors of the query point for a fixed radius.
%
%  Example: 
%       data = randn(256,3);
%       tree = KDTreeSearcher(data);
%       query = [data(1,1) data(1,2) data(1,3)];
%       radius = 1.0;
%       min_neighbors = 8;
%       normal = estimateNormal(data, tree, query, radius, min_neighbors)
%
%  Copyright (c) 2014, William J. Beksi <beksi@cs.umn.edu>
% 

% Find neighbors within the fixed radius 
idx = rangesearch(tree, query, radius);                                                   
idxs = idx{1};
neighbors = [data(idxs(:),1) data(idxs(:),2) data(idxs(:),3)];

if size(neighbors) < min_neighbors
    normal = {1};
    return;
end

% Compute the covariance matrix C
C = cov(neighbors);

% Compute the eigenvector of C
[v, lambda] = eig(C);

% Find the eigenvector corresponding to the minimum eigenvalue in C
[~, i] = min(diag(lambda));

% Normalize
normal = v(:,i) ./ norm(v(:,i));

end 

  

2.计算曲率

  曲线的曲率(curvature)就是针对曲线上某个点的切线方向角对弧长的转动率,通过微分来定义,表明曲线偏离直线的程度。数学上表明曲线在某一点的弯曲程度的数值。曲率越大,表示曲线的弯曲程度越大。曲率的倒数就是曲率半径

  平均曲率高斯曲率主曲率计算

  贺美芳, et al. (2005.8). "散乱点云数据的曲率估算及应用."

  1 ScalarType Neighbourhood::computeCurvature(unsigned neighbourIndex, CC_CURVATURE_TYPE cType)
  2 {
  3     switch (cType)
  4     {
  5     case GAUSSIAN_CURV:
  6     case MEAN_CURV:
  7         {
  8             //we get 2D1/2 quadric parameters
  9             const PointCoordinateType* H = getQuadric();
 10             if (!H)
 11                 return NAN_VALUE;
 12 
 13             //compute centroid
 14             const CCVector3* G = getGravityCenter();
 15 
 16             //we compute curvature at the input neighbour position + we recenter it by the way
 17             CCVector3 Q = *m_associatedCloud->getPoint(neighbourIndex) - *G;
 18 
 19             const unsigned char X = m_quadricEquationDirections.x;
 20             const unsigned char Y = m_quadricEquationDirections.y;
 21 
 22             //z = a+b.x+c.y+d.x^2+e.x.y+f.y^2
 23             //const PointCoordinateType& a = H[0];
 24             const PointCoordinateType& b = H[1];
 25             const PointCoordinateType& c = H[2];
 26             const PointCoordinateType& d = H[3];
 27             const PointCoordinateType& e = H[4];
 28             const PointCoordinateType& f = H[5];
 29 
 30             //See "CURVATURE OF CURVES AND SURFACES – A PARABOLIC APPROACH" by ZVI HAR’EL
 31             const PointCoordinateType  fx    = b + (d*2) * Q.u[X] + (e  ) * Q.u[Y];    // b+2d*X+eY
 32             const PointCoordinateType  fy    = c + (e  ) * Q.u[X] + (f*2) * Q.u[Y];    // c+2f*Y+eX
 33             const PointCoordinateType  fxx    = d*2;                                    // 2d
 34             const PointCoordinateType  fyy    = f*2;                                    // 2f
 35             const PointCoordinateType& fxy    = e;                                    // e
 36 
 37             const PointCoordinateType fx2 = fx*fx;
 38             const PointCoordinateType fy2 = fy*fy;
 39             const PointCoordinateType q = (1 + fx2 + fy2);
 40 
 41             switch (cType)
 42             {
 43             case GAUSSIAN_CURV:
 44                 {
 45                     //to sign the curvature, we need a normal!
 46                     PointCoordinateType K = fabs( fxx*fyy - fxy*fxy ) / (q*q);
 47                     return static_cast<ScalarType>(K);
 48                 }
 49 
 50             case MEAN_CURV:
 51                 {
 52                     //to sign the curvature, we need a normal!
 53                     PointCoordinateType H = fabs( ((1+fx2)*fyy - 2*fx*fy*fxy + (1+fy2)*fxx) ) / (2*sqrt(q)*q);
 54                     return static_cast<ScalarType>(H);
 55                 }
 56 
 57             default:
 58                 assert(false);
 59             }
 60         }
 61         break;
 62 
 63     case NORMAL_CHANGE_RATE:
 64         {
 65             assert(m_associatedCloud);
 66             unsigned pointCount = (m_associatedCloud ? m_associatedCloud->size() : 0);
 67 
 68             //we need at least 4 points
 69             if (pointCount < 4)
 70             {
 71                 //not enough points!
 72                 return pointCount == 3 ? 0 : NAN_VALUE;
 73             }
 74 
 75             //we determine plane normal by computing the smallest eigen value of M = 1/n * S[(p-µ)*(p-µ)']
 76             CCLib::SquareMatrixd eigVectors;
 77             std::vector<double> eigValues;
 78             if (!Jacobi<double>::ComputeEigenValuesAndVectors(computeCovarianceMatrix(), eigVectors, eigValues))
 79             {
 80                 //failure
 81                 return NAN_VALUE;
 82             }
 83 
 84             //compute curvature as the rate of change of the surface
 85             double e0 = eigValues[0];
 86             double e1 = eigValues[1];
 87             double e2 = eigValues[2];
 88             double sum = fabs(e0+e1+e2);
 89             if (sum < ZERO_TOLERANCE)
 90             {
 91                 return NAN_VALUE;
 92             }
 93 
 94             double eMin = std::min(std::min(e0,e1),e2);
 95             return static_cast<ScalarType>(fabs(eMin) / sum);
 96         }
 97         break;
 98 
 99     default:
100         assert(false);
101     }
102 
103     return NAN_VALUE;
104 }
Neighbourhood::computeCurvature

 

3.计算点云密度

    CloudCompare中的实现方法 http://www.cnblogs.com/yhlx125/p/5874936.html

4.计算点云表面粗糙度

    表面粗糙度

 1 //"PER-CELL" METHOD: ROUGHNESS ESTIMATION (LEAST SQUARES PLANE FIT)
 2 //ADDITIONNAL PARAMETERS (1):
 3 // [0] -> (PointCoordinateType*) kernelRadius : neighbourhood radius
 4 bool GeometricalAnalysisTools::computePointsRoughnessInACellAtLevel(const DgmOctree::octreeCell& cell, 
 5                                                                     void** additionalParameters,
 6                                                                     NormalizedProgress* nProgress/*=0*/)
 7 {
 8     //parameter(s)
 9     PointCoordinateType radius = *static_cast<PointCoordinateType*>(additionalParameters[0]);
10 
11     //structure for nearest neighbors search
12     DgmOctree::NearestNeighboursSphericalSearchStruct nNSS;
13     nNSS.level = cell.level;
14     nNSS.prepare(radius,cell.parentOctree->getCellSize(nNSS.level));
15     cell.parentOctree->getCellPos(cell.truncatedCode,cell.level,nNSS.cellPos,true);
16     cell.parentOctree->computeCellCenter(nNSS.cellPos,cell.level,nNSS.cellCenter);
17 
18     unsigned n = cell.points->size(); //number of points in the current cell
19     
20     //for each point in the cell
21     for (unsigned i=0; i<n; ++i)
22     {
23         ScalarType d = NAN_VALUE;
24         cell.points->getPoint(i,nNSS.queryPoint);
25 
26         //look for neighbors inside a sphere
27         //warning: there may be more points at the end of nNSS.pointsInNeighbourhood than the actual nearest neighbors (= neighborCount)!
28         unsigned neighborCount = cell.parentOctree->findNeighborsInASphereStartingFromCell(nNSS,radius,false);
29         if (neighborCount > 3)
30         {
31             //find the query point in the nearest neighbors set and place it at the end
32             const unsigned globalIndex = cell.points->getPointGlobalIndex(i);
33             unsigned localIndex = 0;
34             while (localIndex < neighborCount && nNSS.pointsInNeighbourhood[localIndex].pointIndex != globalIndex)
35                 ++localIndex;
36             //the query point should be in the nearest neighbors set!
37             assert(localIndex < neighborCount);
38             if (localIndex+1 < neighborCount) //no need to swap with another point if it's already at the end!
39             {
40                 std::swap(nNSS.pointsInNeighbourhood[localIndex],nNSS.pointsInNeighbourhood[neighborCount-1]);
41             }
42 
43             DgmOctreeReferenceCloud neighboursCloud(&nNSS.pointsInNeighbourhood,neighborCount-1); //we don't take the query point into account!
44             Neighbourhood Z(&neighboursCloud);
45 
46             const PointCoordinateType* lsPlane = Z.getLSPlane();
47             if (lsPlane)
48                 d = fabs(DistanceComputationTools::computePoint2PlaneDistance(&nNSS.queryPoint,lsPlane));
49 
50             //swap the points back to their original position (DGM: not necessary)
51             //if (localIndex+1 < neighborCount)
52             //{
53             //    std::swap(nNSS.pointsInNeighbourhood[localIndex],nNSS.pointsInNeighbourhood[neighborCount-1]);
54             //}
55         }
56 
57         cell.points->setPointScalarValue(i,d);
58 
59         if (nProgress && !nProgress->oneStep())
60         {
61             return false;
62         }
63     }
64 
65     return true;
66 }
computePointsRoughnessInACellAtLevel

  地面粗糙度是指在一个特定的区域内,地球表面积与其投影面积之比。它也是反映地表形态的一个宏观指标。

5.计算点云重心

   

 1 //计算重心
 2 CCVector3 GeometricalAnalysisTools::computeGravityCenter(GenericCloud* theCloud)
 3 {
 4     assert(theCloud);
 5     
 6     unsigned count = theCloud->size();
 7     if (count == 0)
 8         return CCVector3();
 9 
10     CCVector3d sum(0,0,0);
11 
12     theCloud->placeIteratorAtBegining();
13     const CCVector3 *P = 0;
14     while ((P = theCloud->getNextPoint()))
15     {
16         sum += CCVector3d::fromArray(P->u);
17     }
18 
19     sum /= static_cast<double>(count);
20     return CCVector3::fromArray(sum.u);
21 }
computeGravityCenter

 

6.计算点云权重重心

   

 1 //计算权重中心
 2 CCVector3 GeometricalAnalysisTools::computeWeightedGravityCenter(GenericCloud* theCloud, ScalarField* weights)
 3 {
 4     assert(theCloud && weights);
 5 
 6     unsigned count = theCloud->size();
 7     if (count == 0 || !weights || weights->currentSize() < count)
 8         return CCVector3();
 9 
10     CCVector3d sum(0, 0, 0);
11 
12     theCloud->placeIteratorAtBegining();
13     double wSum = 0;
14     for (unsigned i = 0; i < count; ++i)
15     {
16         const CCVector3* P = theCloud->getNextPoint();
17         ScalarType w = weights->getValue(i);
18         if (!ScalarField::ValidValue(w))
19             continue;
20         sum += CCVector3d::fromArray(P->u) * fabs(w);
21         wSum += w;
22     }
23 
24     if (wSum != 0)
25         sum /= wSum;
26 
27     return CCVector3::fromArray(sum.u);
28 }
computeWeightedGravityCenter

 

7.计算点云协方差

   

 1 //计算协方差矩阵
 2 CCLib::SquareMatrixd GeometricalAnalysisTools::computeCovarianceMatrix(GenericCloud* theCloud, const PointCoordinateType* _gravityCenter)
 3 {
 4     assert(theCloud);
 5     unsigned n = (theCloud ? theCloud->size() : 0);
 6     if (n==0)
 7         return CCLib::SquareMatrixd();
 8 
 9     CCLib::SquareMatrixd covMat(3);
10     covMat.clear();
11 
12     //gravity center
13     CCVector3 G = (_gravityCenter ?  CCVector3(_gravityCenter) : computeGravityCenter(theCloud));
14 
15     //cross sums (we use doubles to avoid overflow)
16     double mXX = 0;
17     double mYY = 0;
18     double mZZ = 0;
19     double mXY = 0;
20     double mXZ = 0;
21     double mYZ = 0;
22 
23     theCloud->placeIteratorAtBegining();
24     for (unsigned i=0;i<n;++i)
25     {
26         const CCVector3* Q = theCloud->getNextPoint();
27 
28         CCVector3 P = *Q-G;
29         mXX += static_cast<double>(P.x*P.x);
30         mYY += static_cast<double>(P.y*P.y);
31         mZZ += static_cast<double>(P.z*P.z);
32         mXY += static_cast<double>(P.x*P.y);
33         mXZ += static_cast<double>(P.x*P.z);
34         mYZ += static_cast<double>(P.y*P.z);
35     }
36 
37     covMat.m_values[0][0] = mXX/static_cast<double>(n);
38     covMat.m_values[0][0] = mYY/static_cast<double>(n);
39     covMat.m_values[0][0] = mZZ/static_cast<double>(n);
40     covMat.m_values[1][0] = covMat.m_values[0][1] = mXY/static_cast<double>(n);
41     covMat.m_values[2][0] = covMat.m_values[0][2] = mXZ/static_cast<double>(n);
42     covMat.m_values[2][1] = covMat.m_values[1][2] = mYZ/static_cast<double>(n);
43 
44     return covMat;
45 }
computeCovarianceMatrix

 

8.计算点云互协方差

  

 1 //计算2个点云的互协方差
 2 CCLib::SquareMatrixd GeometricalAnalysisTools::computeCrossCovarianceMatrix(GenericCloud* P,
 3                                                                             GenericCloud* Q,
 4                                                                             const CCVector3& Gp,
 5                                                                             const CCVector3& Gq)
 6 {
 7     assert(P && Q);
 8     assert(Q->size() == P->size());
 9 
10     //shortcuts to output matrix lines
11     CCLib::SquareMatrixd covMat(3);
12     double* l1 = covMat.row(0);
13     double* l2 = covMat.row(1);
14     double* l3 = covMat.row(2);
15 
16     P->placeIteratorAtBegining();
17     Q->placeIteratorAtBegining();
18 
19     //sums
20     unsigned count = P->size();
21     for (unsigned i=0; i<count; i++)
22     {
23         CCVector3 Pt = *P->getNextPoint() - Gp;
24         CCVector3 Qt = *Q->getNextPoint() - Gq;
25 
26         l1[0] += Pt.x*Qt.x;
27         l1[1] += Pt.x*Qt.y;
28         l1[2] += Pt.x*Qt.z;
29         l2[0] += Pt.y*Qt.x;
30         l2[1] += Pt.y*Qt.y;
31         l2[2] += Pt.y*Qt.z;
32         l3[0] += Pt.z*Qt.x;
33         l3[1] += Pt.z*Qt.y;
34         l3[2] += Pt.z*Qt.z;
35     }
36 
37     covMat.scale(1.0/static_cast<double>(count));
38 
39     return covMat;
40 }
computeCrossCovarianceMatrix

 

 1 //计算权重互协方差
 2 CCLib::SquareMatrixd GeometricalAnalysisTools::computeWeightedCrossCovarianceMatrix(GenericCloud* P, //data
 3                                                                                     GenericCloud* Q, //model
 4                                                                                     const CCVector3& Gp,
 5                                                                                     const CCVector3& Gq,
 6                                                                                     ScalarField* coupleWeights/*=0*/)
 7 {
 8     assert(P && Q);
 9     assert(Q->size() == P->size());
10     assert(coupleWeights);
11     assert(coupleWeights->currentSize() == P->size());
12 
13     //shortcuts to output matrix lines
14     CCLib::SquareMatrixd covMat(3);
15     double* r1 = covMat.row(0);
16     double* r2 = covMat.row(1);
17     double* r3 = covMat.row(2);
18 
19     P->placeIteratorAtBegining();
20     Q->placeIteratorAtBegining();
21 
22     //sums
23     unsigned count = P->size();
24     double wSum = 0.0; //we will normalize by the sum
25     for (unsigned i = 0; i<count; i++)
26     {
27         CCVector3d Pt = CCVector3d::fromArray((*P->getNextPoint() - Gp).u);
28         CCVector3 Qt = *Q->getNextPoint() - Gq;
29 
30         //Weighting scheme for cross-covariance is inspired from
31         //https://en.wikipedia.org/wiki/Weighted_arithmetic_mean#Weighted_sample_covariance
32         double wi = 1.0;
33         if (coupleWeights)
34         {
35             ScalarType w = coupleWeights->getValue(i);
36             if (!ScalarField::ValidValue(w))
37                 continue;
38             wi = fabs(w);
39         }
40 
41         //DGM: we virtually make the P (data) point nearer if it has a lower weight
42         Pt *= wi;
43         wSum += wi;
44 
45         //1st row
46         r1[0] += Pt.x * Qt.x;
47         r1[1] += Pt.x * Qt.y;
48         r1[2] += Pt.x * Qt.z;
49         //2nd row
50         r2[0] += Pt.y * Qt.x;
51         r2[1] += Pt.y * Qt.y;
52         r2[2] += Pt.y * Qt.z;
53         //3rd row
54         r3[0] += Pt.z * Qt.x;
55         r3[1] += Pt.z * Qt.y;
56         r3[2] += Pt.z * Qt.z;
57     }
58 
59     if (wSum != 0.0)
60         covMat.scale(1.0/wSum);
61 
62     return covMat;
63 }
computeWeightedCrossCovarianceMatrix

 

posted @ 2016-08-13 10:47  太一吾鱼水  阅读(13576)  评论(2编辑  收藏  举报