对于一个研究项目,我尝试进行点云比较。 简而言之,我有一个 CAD 文件 (.stl) 和几个由激光扫描仪创建的点云。 现在我想计算CAD文件和每个点云之间的差异。
首先我从 Cloud Compare 开始,这对我获得基本的了解很有帮助。 (减少点、删除重复项、创建网格并比较距离)
在 python 中,我能够导入文件并进行一些基本计算。但是,我无法计算距离。
这是我的代码:
import numpy as np
import open3d as o3d
#read point cloud
dataname_pcd= "pcd.xyz"
point_cloud = np.loadtxt(input_path+dataname_pcd,skiprows=1)
#read mesh
dataname_mesh = "cad.stl"
mesh = o3d.io.read_triangle_mesh(input_path+dataname_mesh)
print (mesh)
#calulate the distance
mD = o3d.geometry.PointCloud.compute_point_cloud_distance([point_cloud],[mesh])
#计算距离给了我这个错误: “类型错误:compute_point_cloud_distance():函数参数不兼容。支持以下参数类型: 1.(自身:open3d.cpu.pybind.geometry.PointCloud,目标:open3d.cpu.pybind.geometry.PointCloud)-> open3d.cpu.pybind.utility.DoubleVector”
问题: 需要对网格和点云进行哪些预变换来计算它们的距离? 有推荐的方式来显示差异吗?
到目前为止我只使用了下面的可视化线
o3d.visualization.draw_geometries([pcd],
zoom=0.3412,
front=[0.4257, -0.2125, -0.8795],
lookat=[2.6172, 2.0475, 1.532],
up=[-0.0694, -0.9768, 0.2024])
“计算点云距离()”功能需要 2 个点云,但其中一个几何图形是网格,它由多边形和顶点组成。只需将其转换为点云即可:
pcd = o3d.geometry.PointCloud() # create a empty geometry
pcd.points = mesh.vertices # take the vertices of your mesh
我将说明如何可视化 2 个云之间的距离,这两个云都是由移动机器人(Velodyne LIDAR)捕获的,平均间隔为 1 米。考虑注册前后的 2 个云,它们之间的距离应该会减小,对吗?这是一些代码:
import copy
import pandas as pd
import numpy as np
import open3d as o3d
from matplotlib import pyplot as plt
# Import 2 clouds, paint and show both
pc_1 = o3d.io.read_point_cloud("scan_0.pcd") # 18,421 points
pc_2 = o3d.io.read_point_cloud("scan_1.pcd") # 19,051 points
pc_1.paint_uniform_color([0,0,1])
pc_2.paint_uniform_color([0.5,0.5,0])
o3d.visualization.draw_geometries([pc_1,pc_2])
# Calculate distances of pc_1 to pc_2.
dist_pc1_pc2 = pc_1.compute_point_cloud_distance(pc_2)
# dist_pc1_pc2 is an Open3d object, we need to convert it to a numpy array to
# acess the data
dist_pc1_pc2 = np.asarray(dist_pc1_pc2)
# We have 18,421 distances in dist_pc1_pc2, because cloud pc_1 has 18,421 pts.
# Let's make a boxplot, histogram and serie to visualize it.
# We'll use matplotlib + pandas.
df = pd.DataFrame({"distances": dist_pc1_pc2}) # transform to a dataframe
# Some graphs
ax1 = df.boxplot(return_type="axes") # BOXPLOT
ax2 = df.plot(kind="hist", alpha=0.5, bins = 1000) # HISTOGRAM
ax3 = df.plot(kind="line") # SERIE
plt.show()
# Load a previos transformation to register pc_2 on pc_1
# I finded it with the Fast Global Registration algorithm, in Open3D
T = np.array([[ 0.997, -0.062 , 0.038, 1.161],
[ 0.062, 0.9980, 0.002, 0.031],
[-0.038, 0.001, 0.999, 0.077],
[ 0.0, 0.0 , 0.0 , 1.0 ]])
# Make a copy of pc_2 to preserv the original cloud
pc_2_copy = copy.deepcopy(pc_2)
# Aply the transformation T on pc_2_copy
pc_2_copy.transform(T)
o3d.visualization.draw_geometries([pc_1,pc_2_copy]) # show again
# Calculate distances
dist_pc1_pc2_transformed = pc_1.compute_point_cloud_distance(pc_2_copy)
dist_pc1_pc2_transformed = np.asarray(dist_pc1_pc2_transformed)
# Do as before to show diferences
df_2 = pd.DataFrame({"distances": dist_pc1_pc2_transformed})
# Some graphs (after registration)
ax1 = df_2.boxplot(return_type="axes") # BOXPLOT
ax2 = df_2.plot(kind="hist", alpha=0.5, bins = 1000) # HISTOGRAM
ax3 = df_2.plot(kind="line") # SERIE
plt.show()
compute_point_cloud_distance
是点到点的距离。如果这就是人们想要的,那么Rubens Benevides的答案就涵盖了它,以及可视化部分。
但是对于那些对点到平面距离感兴趣的人(这个问题的标题暗示了这一点:“网格和点云之间的距离”:
Open3d 通过其基于“张量”的 api (
open3d.t
) 和 sdf 计算 方法(通过光线投射实现)提供点到网格距离。 distance_queries 教程对此进行了介绍。
def mesh_to_cloud_signed_distances(o3d_mesh: open3d.t.geometry.TriangleMesh, cloud: open3d.t.geometry.PointCloud) -> np.ndarray:
scene = open3d.t.geometry.RaycastingScene()
_ = scene.add_triangles(o3d_mesh)
sdf = scene.compute_signed_distance(cloud.point.positions)
return sdf.numpy()
备注:
o3d.geometry.TriangleMesh
转换为 o3d.t.geometry.TriangleMesh
:mesh = o3d.t.geometry.TriangleMesh.from_legacy(mesh)