Open3d 自定义点云法向量,朝内或朝外

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提供了大量能使我们快速便捷地处理面片数据的函数和方法,详情查看专栏其他文章。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值