C++使用最小二乘法计算点云法向量原理以及全部代码
最小二乘计算点云法向量原理对于任意一点 p(x,y,z)p(x, y, z)p(x,y,z)查找其一定领域内的点{pi}\{{p_i}\}{pi};求得一个平面 ∏:a0x+a1y+a2z+1=0\prod: a_0x + a_1y+a_2z + 1 = 0∏:a0x+a1y+a2z+1=0使得其到平面距离的平方和最小,即:min∑i=1ndist(pi,∏)min \sum_{i=1}^
最小二乘计算点云法向量原理
对于任意一点 p(x,y,z)p(x, y, z)p(x,y,z)查找其一定领域内的点{pi}\{{p_i}\}{pi};
求得一个平面 ∏:a0x+a1y+a2z+1=0\prod: a_0x + a_1y+a_2z + 1 = 0∏:a0x+a1y+a2z+1=0使得其到平面距离的平方和最小,即:
min∑i=1ndist(pi,∏)min \sum_{i=1}^{n}dist(p_i, \prod)min∑i=1ndist(pi,∏) = min∑i=1n(a0xi+a1yi+a2zi+1)2min \sum_{i=1}^{n}(a_0x_i + a_1y_i+a_2z_i + 1 )^2min∑i=1n(a0xi+a1yi+a2zi+1)2
记S=min∑i=1n(a0x+a1y+a2z+1)2S = min \sum_{i=1}^{n}(a_0x + a_1y+a_2z + 1 )^2S=min∑i=1n(a0x+a1y+a2z+1)2
要使得S最小,则∂S∂a0=0,∂S∂b0=0,∂S∂c0=0\frac{\partial S}{\partial a_0} = 0, \frac{\partial S}{\partial b_0} = 0, \frac{\partial S}{\partial c_0} = 0∂a0∂S=0,∂b0∂S=0,∂c0∂S=0
即:
∂S∂a0=∑i=1n2(a0x+a1y+a2z+1)xi=0\frac{\partial S}{\partial a_0} = \sum_{i=1}^n2(a_0x + a_1y+a_2z + 1 )x_i = 0∂a0∂S=∑i=1n2(a0x+a1y+a2z+1)xi=0
∂S∂b0=∑i=1n2(a0x+a1y+a2z+1)yi=0\frac{\partial S}{\partial b_0} = \sum_{i=1}^n2(a_0x + a_1y+a_2z + 1 )y_i = 0∂b0∂S=∑i=1n2(a0x+a1y+a2z+1)yi=0
∂S∂c0=∑i=1n2(a0x+a1y+a2z+1)zi=0\frac{\partial S}{\partial c_0} = \sum_{i=1}^n2(a_0x + a_1y+a_2z + 1 )z_i = 0∂c0∂S=∑i=1n2(a0x+a1y+a2z+1)zi=0
上式经过变形可得(请读者自行下去推导)
[∑xi2∑xiyy∑xizi∑xiyi∑yi2∑yizi∑xizi∑yizi∑zi2]⋅[a0b0c0]+[∑xi∑yi∑zi]=0\begin{bmatrix} \sum x_i^2 &\sum x_iy_y &\sum x_iz_i \\ \sum x_iy_i &\sum y_i^2 &\sum y_iz_i \\ \sum x_iz_i&\sum y_iz_i &\sum z_i^2 \\ \end{bmatrix} \cdot \begin{bmatrix} a_0\\ b_0 \\ c_0 \\ \end{bmatrix} + \begin{bmatrix} \sum x_i\\ \sum y_i \\ \sum z_i \\ \end{bmatrix} = 0⎣⎡∑xi2∑xiyi∑xizi∑xiyy∑yi2∑yizi∑xizi∑yizi∑zi2⎦⎤⋅⎣⎡a0b0c0⎦⎤+⎣⎡∑xi∑yi∑zi⎦⎤=0
令A=[x1y1z1x2y2z2⋮⋮⋮xnynzn];−b=[11⋮1] A = \begin{bmatrix} x_1 &y_1&z_1 \\ x_2 &y_2&z_2\\ \vdots &\vdots &\vdots \\ x_n &y_n&z_n\\ \end{bmatrix}; -b = \begin{bmatrix} 1 \\ 1\\ \vdots \\ 1\\ \end{bmatrix}A=⎣⎢⎢⎢⎡x1x2⋮xny1y2⋮ynz1z2⋮zn⎦⎥⎥⎥⎤;−b=⎣⎢⎢⎢⎡11⋮1⎦⎥⎥⎥⎤
则有:ATA[a0b0c0]−ATb=0 A^{T}A \begin{bmatrix} a_0\\ b_0 \\ c_0\\ \end{bmatrix} - A^Tb = 0ATA⎣⎡a0b0c0⎦⎤−ATb=0
由于ATAA^TAATA可逆
所以[a0b0c0]=(ATA)−1ATb \begin{bmatrix} a_0\\ b_0 \\ c_0\\ \end{bmatrix} = (A^TA)^{-1}A^Tb⎣⎡a0b0c0⎦⎤=(ATA)−1ATb
由高等数学等知识可知:[a0b0c0]即为法向量\begin{bmatrix} a_0\\ b_0 \\ c_0\\ \end{bmatrix} 即为法向量⎣⎡a0b0c0⎦⎤即为法向量
代码
void lsNormal(const PointCloud<PointXYZ>::Ptr& cloud, const int& k_neighbors, PointCloud<Normal>::Ptr& normals)
{
//1. build kdtree index
KdTreeFLANN<PointXYZ>::Ptr kdtree(new KdTreeFLANN<PointXYZ>);
kdtree->setInputCloud(cloud);//set input cloud
if (normals == NULL)
normals = PointCloud<Normal>::Ptr(new PointCloud<Normal>);
if (!normals->empty())
normals->resize(0);
for (const auto& point: * cloud)
{
// 3.1 set k nearest neighbors
PointXYZ searchPoint = point;
vector<int> KNNIndices(k_neighbors);//an int vector to store the k nearest neighbor of points
vector<float> KNNSquareDistance(k_neighbors);//a float vector to store the distance of k nearest neighbor
//3.2 least square for each point and calculate the normal vectors
if (kdtree->nearestKSearch(searchPoint, k_neighbors, KNNIndices, KNNSquareDistance) > 0)
{
//if the search result > 0, search succeed
//build a new point cloud, store the k nearest neighbor of current point
PointCloud<PointXYZ>::Ptr neighborsPoints(new PointCloud<PointXYZ>);
pcl::copyPointCloud(*cloud, KNNIndices, *neighborsPoints);
size_t i = 0;
MatrixXd A = MatrixXd::Random(k_neighbors, 3);
MatrixXd b = MatrixXd::Random(k_neighbors, 1);
MatrixXd X = MatrixXd::Random(3, 1);
//A, b, X is correspond to A*X = b
for (int idx = 0; idx < k_neighbors; idx++)
{
A(i, 0) = cloud->points[KNNIndices[idx]].x;
A(i, 1) = cloud->points[KNNIndices[idx]].x;
A(i, 2) = cloud->points[KNNIndices[idx]].x;
b(i, 0) = -1;
i = i + 1;
}
X = (A.transpose() * A).inverse() * A.transpose() * b;
//Normalize
double norm_xyz = sqrt(X(0) * X(0) + X(1) * X(1) + X(2) * X(2));
double nx = X(0) / norm_xyz;
double ny = X(1) / norm_xyz;
double nz = X(2) / norm_xyz;
normals->push_back(Normal(nx, ny, nz));
}
else
normals->push_back(Normal());
}
}

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐
所有评论(0)