前言
我们知道,PCL和OpenGL等三维可视化软件一样,为了兼顾性能需求,只支持加载Float类型的点云数据,但是当我们对精度要求太高时,Float类型支持不了我们的精度要求,我们的数据必须用Double类型存储才可以,要怎么解决呢?
解决方法 一
网上一个比较流行的解决方法是使用一个自定义的PCL数据类型 ,例如这样
// 自定义点云类型
namespace pcl
{
#define PCL_ADD_UNION_POINT4D_DOUBLE \
union EIGEN_ALIGN16 { \
double data[4]; \
struct { \
double x; \
double y; \
double z; \
}; \
};
struct _PointXYZDouble
{
PCL_ADD_UNION_POINT4D_DOUBLE; // This adds the members x,y,z which can also be accessed using the point (which is float[4])
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
};
struct EIGEN_ALIGN16 PointXYZDouble : public _PointXYZDouble
{
inline PointXYZDouble(const _PointXYZDouble& p)
{
x = p.x; y = p.y; z = p.z; data[3] = 1.0;
}
inline PointXYZDouble()
{
x = y = z = 0.0;
data[3] = 1.0;
}
inline PointXYZDouble(double _x, double _y, double _z)
{
x = _x; y = _y; z = _z;
data[3] = 1.0;
}
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
};
}
POINT_CLOUD_REGISTER_POINT_STRUCT(pcl::_PointXYZDouble,
(double, x, x)
(double, y, y)
(double, z, z)
)
POINT_CLOUD_REGISTER_POINT_WRAPPER(pcl::PointXYZDouble, pcl::_PointXYZDouble)
然后在加载点云时使用pcl::XYZDouble这个自定义类型即可。
但是这个有个弊端,因为我还要使用PCL的其他函数接口,例如鼠标点击事件的回调函数,这些函数不支持我自定义的数据格式,如果要完美适配我的自定义数据类型,需要大范围的修改源码才行,工作量巨大。
解决方法二
这里我参考了一个大名鼎鼎的点云显示软件:CloudCompare
当使用CloudCompare加载精度较大的点云时,会提示
这里我引入官方的解释:
大致意思就是:
因为CloudCompare和OpenGL都使用32位浮点值。与64位值相比,这允许增加速度和50%的存储器增益。然而,32位表示具有有限的分辨率,也就是精度。可以说,数字越大,可以存储的小数就越少。然而,如果在地理参考坐标系中表示的点坐标非常大,在这种情况下,数据表示精度上升到1或10厘米,32位浮点值支持不了这么高的精度,这就是为什么在CloudCompare中加载文件时“移动"点非常重要的原因。否则,原始精度将丢失。
它的移动规则也很简单, 默认情况下,CloudCompare尝试自动猜测最佳偏移向量(通常在加载文件时,CloudCompare将使用第一个点坐标作为偏移量)。后面的点都使用相同的偏移量。用TX、TY、 TZ 分别表示x、y、z坐标的偏移量,S表示倍数,LX、LY、LZ表示计算后的坐标,用公式表示就是:
L
X
=
(
X
+
T
X
)
∗
S
L_X=(X+T_X)*S
LX=(X+TX)∗S
L
Y
=
(
Y
+
T
Y
)
∗
S
L_Y=(Y+T_Y)*S
LY=(Y+TY)∗S
L
Z
=
(
Z
+
T
Z
)
∗
S
L_Z=(Z+T_Z)*S
LZ=(Z+TZ)∗S
在CloudCompare中这个偏移量默认是以第一个坐标计算得到的,倍数默认为1倍。
偏移量计算的时候没有特定公式,我举几个例子大家应该就知道是怎么回事了。
- 原始坐标是 1850351.79723,那么偏移量就是 -1850300,偏移后的坐标是51.79723
- 原始坐标是 -1850351.79723,那么偏移量就是 1850300,偏移后的坐标是51.79723
- 原始坐标是 446.100006,那么偏移量就是-400,偏移后的坐标是46.100006,当然由于这个坐标比较小,偏移量也可以设置为0.00,这样偏移后的坐标和原来一致。
为什么以第一个坐标计算偏移量呢?因为大部分情况下,我们的点云坐标都是非常非常密集的,坐标的最大值和最小值差距很小,使用第一个坐标计算得到的偏移量往往是适用于所有坐标的。当然你也可以取平均值来计算偏移量。计算的时候要根据具体的数据来确定偏移量的数量级,说了这些,大家应该都知道偏移量怎么计算了吧?
那么剩下的就简单了,我就可以在PCL读取我的数据的时候,先将原始的x、y、z坐标分别存放到三个double类型的变量中,然后根据我的数据情况,来分别确定x、y、z的偏移量的正负符号和数量级,最终分别得到我x、y、z的偏移量,然后让我全部的原始坐标加上这个偏移量即可。
原始坐标记得也要存放起来,这样就可以实现这样的效果:PCL可视化的点云坐标是我偏移后的坐标,鼠标点击显示的坐标是我的原始坐标,是不是很6😁