这段时间在计算法线时发现,当kdtree设置有序和无序时,协方差矩阵计算结果不一致,
点云图如上:
计算法线结果
法线计算结果(默认情况,不排序)
不排序计算协方差(第一个点)
3.05176e-05 0 4.76837e-06
0 1.66893e-05 -3.57628e-07
4.76837e-06 -3.57628e-07 5.126e-06
法线
-0.178541
0.0282765
0.983526
排序后协方差(第一个点)
2.28882e-05 1.90735e-06 6.67572e-06
1.90735e-06 1.7643e-05 -3.57628e-07
6.67572e-06 -3.57628e-07 4.70877e-06
法线
-0.315286
0.0619243
0.946974
看源码得知,以下代码导致计算结果不一致
for (std::vector<int>::const_iterator iIt = indices.begin (); iIt != indices.end (); ++iIt)
{
std::cout << cloud[*iIt] << std::endl;
//const PointT& point = cloud[*iIt];
accu [0] += cloud[*iIt].x * cloud[*iIt].x;
accu [1] += cloud[*iIt].x * cloud[*iIt].y;
accu [2] += cloud[*iIt].x * cloud[*iIt].z;
accu [3] += cloud[*iIt].y * cloud[*iIt].y;
accu [4] += cloud[*iIt].y * cloud[*iIt].z;
accu [5] += cloud[*iIt].z * cloud[*iIt].z;
accu [6] += cloud[*iIt].x;
accu [7] += cloud[*iIt].y;
accu [8] += cloud[*iIt].z;
}
有序accu [0]=5459.22266
无序accu [0]=5459.22412
小数点第三位出现不一致,这对点云估计有很大的影响,因为协方差基本都是在小数点后五位的量级。
对以上结果进行分析,无论是否排序,indices都是内容都是一致的,只是顺序不同,考虑计算过程可能出现问题
改变代码如下:
float temp = 0;
for (size_t i = 0; i < indices.size(); i++)
{
temp += cloud->points[indices[i]].x * cloud->points[indices[i]].x;
std::cout << setprecision(10) << cloud->points[indices[i]].x<<'\t'<< temp << "\t"<<indices[i]<<std::endl;
}
计算出的结果没有变化,依然有差异,由此猜想可能是float精度不够导致的,将float换成double,发现结果一致,为5459.223686.
以上结果表明在进行计算时,最好选择double,防止因为精度问题导致的结果差异。
float保留9位有效数字,其中前六位是准确的,后三位可能出现偏差。针对大尺度数据没有问题,小尺度微小的差异都将对点云法线估计造成比较大的影响。
pcl法线估计不好修改,主要是点云的存储为float,Eigen不能混合不同类型,比较麻烦,可以选择直接继承NormalEstimation。