点云学习【1.2】法向量计算

1.1中学习了PCA算法,其中最大主成分为投影到某方向后方差最大的方向(信息量最大的方向);而法向量为投影到某方向后,信息量最小的方向,因此需要PCA变换,将点云投影到特征值最小的方向。由于需要PCA算法,因此先把昨天的PCA算法拷贝过来。`

import open3d as o3d
import numpy as np
from pyntcloud import PyntCloud
from pandas import DataFrame

def PCA(data,correlation=False,sort=True):
    data_mean = np.mean(data,axis=0)
    data_normalize = data - data_mean
    H = np.dot(data_normalize.T,data_normalize)
    eigenvectors,eigenvalues,eigenvectors_t=np.linalg.svd(H)
    if sort:
        sort = eigenvalues.argsort()[::-1]
        eigenvalues = eigenvalues[sort]
        eigenvectors = eigenvectors[:,sort]
    return eigenvectors , eigenvalues

def main():
    #创建数组表格数据 读取txt文档
    raw_point_cloud_matrix = np.genfromtxt(r"F:\\point cloud\\三维点云课程\\3d数据集\\modelnet40_normal_resampled\\airplane\\airplane_0002.txt", delimiter=",")
    #可以理解为建立表格,类似excel,且只需要前三列数据(x,y,z)
    raw_point_cloud=DataFrame(raw_point_cloud_matrix[:,0:3])
    raw_point_cloud.columns = ['x','y','z']
    #将数据转化为open3d可以识别的格式
    point_cloud_pynt = PyntCloud(raw_point_cloud)
    
    #从点云中获取点
    points = point_cloud_pynt.points
    print("total points number is :"points.shape[0])

    #使用PCA分析点云主方向
    w,v = PCA(points)
    #提取前两个主分量
    point_cloud_vector = v[:,2]
    print("the main orientation of this pointcloud is :",point_cloud_vector)

    point = [[0,0,0],v[:,0],v[:,1]]
    lines = [[0,1],[0,2]]
    colors = [[1,0,0],[0,1,0]]

    line_set = o3d.geometry.LineSet(points = o3d.utility.Vector3dVector(point),lines = o3d.utility.Vector2iVector(lines))
    line_set.colors = o3d.utility.Vector3dVector(colors)
    o3d.visualization.draw_geometries([point_cloud_o3d,line_set])

下面开始计算法向量

#首先建立一个KD树
    pcd_tree = o3d.geometry.KDTreeFlann(point_cloud_o3d)
    normals = [] #存储法向量
    #由于一个点的法向量有无穷多个,因此计算一定数量最邻近点,求其法向量
    for i in range(points.shape[0]):
        [_,idx,_] = pcd_tree.search_knn_vector_3d(point_cloud_o3d.points[i],10)
        k_nearest_point = np.asarray(point_cloud_o3d.points)[idx,:]
        v,u = PCA(k_nearest_point)
        #提取最后一个成分
        normals.append(u[:,2])
    normals = np.array(normals, dtype=np.float64)
    point_cloud_o3d.normals = o3d.utility.Vector3dVector(normals)
    o3d.visualization.draw_geometries([point_cloud_o3d])

变换后点云:
点云学习【1.2】法向量计算_第1张图片按下n键显示法向量
点云学习【1.2】法向量计算_第2张图片

你可能感兴趣的:(点云学习,算法,python)