使用halcon实现3维点云物体与模型的匹配并显示差异
基于python的ply格式点云数据处理(学习笔记)
基于python的点云处理库总结
一、PCL和Open3D
PCL:PCL(Point Cloud Library)大型跨平台开源C++编程库,实现了大量点云相关的通用算法和高效数据结构,涉及到点云获取、滤波、分割、配准、检索、特征提取、识别、追踪、曲面重建、可视化等。支持多种操作系统平台,可在Windows、Linux、Android、Mac OS X、部分嵌入式实时系统上运行。如果说OpenCV是2D信息获取与处理的结晶,那么PCL就在3D信息获取与处理上具有同等地位,PCL是BSD授权方式,可以免费进行商业和学术应用。
Open3D:开源库,支持处理3D数据的软件的快速开发。Open3D前端在C++和Python中有一些公开的数据结构和算法。后端经过高度优化,并设置为并行化。Open3D的核心功能包括三维数据结构、三维数据处理算法、场景重建、曲面对齐、三维可视化、基于物理的渲染(PBR)、基于PyTorch和TensorFlow的三维机器学习支持、对三维数据操作用GPU加速、支持C++和Python
PCL和Open3D都是3D点云数据处理的优秀开源库,尤其是C++库都很给力。但是设计到Python对应的库就不同了,python-pcl长时间不更新,维护少,不太好用,不建议使用。Open3D由Intel发布,效率很快,python版本的库也很友好,python环境下建议使用!
Open3d官方开发文档
二、点云算法
1、点云配准
点云配准,又称为点云拼接或坐标纠正。由于目标物的复杂性,通常需要从不同方位扫描多个测站,才能把目标物扫描完整,每一测站扫描数据都有自己的坐标系统,要获得完整的数据必需把不同测站的扫描数据纠正到统一的坐标系下,这就需要点云拼接。
点云拼接方法主要如下:
① 标靶拼接。标靶拼接是点云拼接最常用的方法,首先在扫描两站的公共区域放置3个或3个以上的标靶,依次对各个测站的数据和标靶进行扫描,最后利用不同站点相同的标靶数据进行点云配准。每一个标靶对应一个ID号,同一标靶在不同测站的ID号必须一致,才能完成拼接。
② 点云拼接。基于点云的拼接方式要求在扫描目标对象时要有一定的区域重叠度,而且目标对象特征点要明显,否则无法完成数据的拼接。此方法需要依靠寻找重叠区域的同名点进行拼接,因此重叠区域特征点的确定直接关系到配准结果的好坏。
③ 控制点拼接。为了提高拼接精度,三维激光扫描系统可以与全站仪或GPS技术联合使用。通过全站仪或者GPS确定公共控制点的大地坐标,然后用三维激光扫描仪对所有公共控制点进行精确扫描。再以控制点为基站直接将扫描的多测站的点云数据与其拼接,即可将扫描的所有点云数据转换成工程实际需要的坐标系。
点云配准可以分为粗配准(Coarse Registration)和精配准(Fine Registration)两步。粗配准指的是在两幅点云之间的变换完全未知的情况下进行较为粗糙的配准,目的主要是为精配准提供较好的变换初值;精配准则是给定一个初始变换,进一步优化得到更精确的变换。
目前应用最广泛的点云精配准算法是迭代最近点算法(Iterative Closest Point, ICP)及各种变种 ICP 算法。
ICP匹配
Point-to-point ICP
最优变换是有解析解(closed-form solution)的,可以使用SVD 分解来计算。该解析解可以作为粗配准的结果。
Point-line ICP
点到点ICP算存在以下缺点:依赖初始值,初始值不好时,迭代次数增加;对于较大的初始误差,可能会出现错误的迭代结果;ICP是一阶收敛,收敛速度慢(为了弥补这一点,通常使用K-D树加快搜索);会有离群点及噪声。为此改善上述缺点,有人提出了PLICP,顾名思义,这种方式使用源点云到目标点云直线的距离度量来估计变换。主要区别在于误差函数的构建上。ICP是找最近邻的一点,以点与点之间的距离作为误差,而PLICP是找到最近邻的两点,两点连线,是以点到线的距离作为误差,实际上,后者的误差度量方式更符合结构化场景中的雷达点云的实际情况。因此具有更小的误差(图2)。然而,它对非常大的初始位移误差的鲁棒性较差,因此需要比较精确的初始值。
Point-plane ICP
使用点到平面(point-plane)误差度量的迭代最近点 (ICP) 算法已被证明比使用点到点(point-point)误差度量的算法收敛得更快。在 ICP 算法的每次迭代中,产生最小点到平面误差的相对位姿变化通常使用标准的非线性最小二乘法来解决。例如 Levenberg-Marquardt 方法。当使用点到平面误差度量时,最小化的对象是每个源点与其对应目标点的切平面之间的平方距离之和。缺点不能够阻止两个平面滑动.
NICP
Normal Iterative Closest Point (NICP)在匹配两组点云时,将点云的局部特征(法向量,曲率)考虑在内,即在迭代求解过程中,误差函数不仅包含点云之间的法向量的投影距离(同point to plane ICP),还包含了法向量方向误差。相比于上述的方法,NICP更加鲁棒。NICP 算法的特点在于,其在匹配两组点云时并非考虑匹配点云之间的欧氏距离,而是将点云曲面的局部特征作为点对匹配以及计算变换的准则。具体来说主要可以分为以下几部分:计算点云中每个点的特征,即其表面的的法向量(normal)和曲面曲率(curvature),以标记每个点;根据点的距离和特征找两组点云中的匹配点对;利用最小二乘法最小化,最小化目标函数,以求解点云变换矩阵。此处目标函数包括点面投影和法向量旋转误差。
ICP 一般算法流程为:
-
点云预处理:滤波、清理数据等
-
匹配:应用上一步求解出的变换,找最近点
-
加权:调整一些对应点对的权重
-
剔除不合理的对应点对
-
计算 loss
-
最小化 loss,求解当前最优变换
-
回到步骤 2. 进行迭代,直到收敛
整体上来看,ICP 把点云配准问题拆分成了两个子问题:
- 找最近点(Find Closet Point)
这一步会比较耗时,常见的加速方法有:
1、设置距离阈值,当点与点距离小于一定阈值就认为找到了对应点,不用遍历完整个点集;
2、使用 ANN(Approximate Nearest Neighbor) 加速查找,常用的有 KD-tree;KD-tree 建树的计算复杂度为 O(N log(N)),查找通常复杂度为 O(log(N))(最坏情况下 O(N))。 - 找最优变换(Find Best Transform)
彩色点云配准
多视角配准
是在全局空间中对齐多个几何形状的过程。比较有代表性的是,输入是一组几何形状 { P i } (可以是点云或者RGBD图像)。输出是一组刚性变换{ T i } ,变换后的点云 { T i P i }可以在全局空间中对齐。刚性变换:图像的平移加旋转,图像形状不变。非刚性变换:就是比这更复杂的变换,如伸缩,仿射,透射等一些比较复杂的变换。
Open3d利用多个pcd文件配准融合
Open3d(八)——ICP配准
2、点云去噪
在利用三维激光扫描仪扫描目标时,会受到扫描设备、周围环境、人为扰动、目标特性等影响,使得点云数据无法避免的存在一些噪点,导致数据无法正确表达扫描对象的空间位置。
噪声点主要分为三类:
1)由于物体表面材质或光照环境导致反射信号较弱等情况下产生的噪点;
2)由于扫描过程中,人、车辆或其他物体从扫描仪器与物体之间经过而产生的噪点;
3)由于测量设备自身原因,如扫描仪精度、相机分辨率等引起的系统误差和随机误差。
数据去噪的方法可以根据不同的情况分为不同的处理方法:
1)基于有序点云数据用平滑滤波去噪法,目前数据平滑滤波主要采取的是高斯滤波、均值滤波以及中值滤波。
①高斯滤波属于线性平滑滤波,是对指定区域内的数据加权平均,可以去除高频信息,其优点为能够在保证去噪质量的前提下保留住点云数据特征信息。
②均值滤波也叫平均滤波,也是一种较为典型的线性滤波,其原理为选择一定范围内的点求取其平均值来代替其原本的数据点,优点为算法简单易行,缺点为去噪的效果较为平均.且不能很好的保留住点云的特征细节。
③中值滤波属于非线性平滑滤波,其原理是对某点数据相邻的三个或以上的数据求中值,求取后的结果取代其原始值,其优点在于对毛刺噪声的去除有很好效果,而且也能很好的保护数据边缘特征信息。
2)基于散乱点云数据去噪常用的方法为拉普拉斯去噪、平均曲率流方法、双边滤波算法。
①拉普拉斯算法虽然能够很好的保证模型的细节特征,但是还会残存有噪声点。
②双边滤波算法虽然能够很好的去除噪声点,但是不能够很好的保留住模型的细节特征。
③平均曲率是依赖于曲率估计,对于模型简单噪声点较少的数据去噪效果较好,而对于复杂且噪声点多的数据,其计算速度慢且去噪效果较差。
3、点云校平
4、点云法向量估计
由空间变换可知,点云中每一点的法向量夹角及曲率值均不随物体的运动而改变,具有刚体运动不变性。众多点云算法的实施都基于精确的法向量估计,例如许多表面重建算法、点云分割算法、点云去噪算法以及特征描述算法等。 点云法向量求解需要其邻域内点支持,而邻域的大小一般由邻域半径值或临近点个数来表示。现实中需要根据点分别率、物体细节精细程度和用途等因素来取值。过大的邻域会抹平三维结构细节使得法向量过于粗糙,而过小的邻域由于包含了太少的点受噪声干扰程度较强。
5、点云三角面化 mesh
import open3d as o3d
import numpy as np
import trimesh
pcd = o3d.io.read_point_cloud("batt/2169 - Cloud - 1.ply")
pcd.estimate_normals()
# estimate radius for rolling ball
distances = pcd.compute_nearest_neighbor_distance()
avg_dist = np.mean(distances)
radius = 1.5 * avg_dist
mesh = o3d.geometry.TriangleMesh.create_from_point_cloud_ball_pivoting(
pcd,
o3d.utility.DoubleVector([radius, radius * 2]))
print(mesh.get_surface_area())
o3d.visualization.draw_geometries([mesh], window_name='Open3D downSample', width=1024, height=618, left=50,
top=50, point_show_normal=True, mesh_show_wireframe=True, mesh_show_back_face=True,)
o3d.io.write_triangle_mesh('22.ply',mesh)
三、2D和3D联合标定
进行2D-3D传感器标定的三种算法
livox_camera_lidar_calibration
一种2D面阵相机与线激光3D传感器联合标定方法及装置