Open3d 自定义点云法向量,朝内或朝外
重写法向量估计函数:根据质心与点的方向估计法向量
前言
前提是我知道这个点云一定会朝着质心向外,或者向内,比如室内扫描基本都是向内,而室外扫描基本向外;Open3d自带的mesh生成的api——estimate_normals是随机判断的,还需要法向量对齐,很麻烦
o3d自带函数计算结果:内外不一
一、思路
点云的质心——与点法向量判定夹角——改变符号,赋值法向量
而法向量的生成,从原理上有很多方式,这里采用最小二乘拟合平面,使用segment plane这个API,拟合临近点的平面的法向量,作为这个点的法向量
#拟合最近的N个点的平面
plane_model, inliers = keypoint.segment_plane(distance_threshold=distance_threshold,
ransac_n=knn_num,
num_iterations=10 * knn_num * knn_num)
二、使用步骤
1.引入库
代码如下(示例):
import numpy as np
import open3d as o3d
2.核心代码
代码如下(示例):
# 判断法向量是否朝向质心外部
outward_direction = np.dot(normal, center) > 0
return outward_direction
# 法向量赋值
pcd_1.normals = o3d.utility.Vector3dVector(np.array(normals))
3.完整代码
代码如下(示例):
import numpy as np
import open3d as o3d
def estimate_normals_by_center(pcd,knn_num=10,distance_threshold=5,outdoor = True):
def is_normal_outward(normal, center):
# 判断法向量是否朝向质心外部
outward_direction = np.dot(normal, center) > 0
return outward_direction
# 创建两个pcd的深拷贝,防止修改pcd
pcd_origin = o3d.geometry.PointCloud()
pcd_origin.points = pcd.points
pcd_1 = o3d.geometry.PointCloud()
pcd_1.points = pcd.points
point = np.asarray(pcd_1.points)
# 点云的质心,确保法向量朝向质心外部
center = np.mean(point, axis=0)
point_size = point.shape[0]
# 计算邻域内法向量夹角的均值
normal_angle = np.zeros(point_size) # 用来存储邻域法向量夹角均值的容器
tree = o3d.geometry.KDTreeFlann(pcd_1) # 建立KD树索引
normals = []
for i in range(point_size):
[_, idx, _] = tree.search_knn_vector_3d(point[i], knn_num + 1)
keypoint = pcd_1.select_by_index(idx)
# 拟合最近的N个点的平面
plane_model, inliers = keypoint.segment_plane(distance_threshold=distance_threshold,
ransac_n=knn_num,
num_iterations=10 * knn_num * knn_num)
[a, b, c, d] = plane_model
# 判断法向量方向是否朝向质心外部,如果不是则翻转方向
normal = np.array([a, b, c])
if outdoor:
if not is_normal_outward(normal, center):
normals.append([-a, -b, -c])
else:
normals.append([a, b, c])
else:
if not is_normal_outward(normal, center):
normals.append([a, b, c])
else:
normals.append([-a, -b, -c])
pcd_1.normals = o3d.utility.Vector3dVector(np.array(normals))
return pcd_1,pcd_origin
if __name__ == '__main__':
pcd = o3d.io.read_point_cloud("../../Data/PCD/pcd_radius.pcd")
pcd_1,pcd_origin = estimate_normals_by_center(pcd,knn_num=10,distance_threshold=5,outdoor=True)
o3d.visualization.draw_geometries([pcd_1], window_name="法向量", width=800, height=800
, point_show_normal=True)
pcd_origin.estimate_normals(search_param=o3d.geometry.KDTreeSearchParamKNN(knn=10))
o3d.visualization.draw_geometries([pcd_origin], window_name="法向量", width=800, height=800
, point_show_normal=True)
该处read_point_cloud请使用自己的点云
测试效果
令法向量全部朝内
法向量全部朝外
outdoor=True
总结
例如:以上就是今天要讲的内容,本文仅仅简单介绍了自定义法向量的使用,适用于已知点云正负向的情况。
而open3d提供了大量能使我们快速便捷地处理面片数据的函数和方法,详情查看专栏其他文章。