三维点云学习(1)上
环境安装
1.系统环境 win10 或者 ubuntu
2. Anaconda3+python3.6
使用Anaconda创建的conda虚拟环境进行python的编写
环境安装主要参考如下网址
安装Anaconda3
Anconda3 安装 open3d
3. 使用conda install 或者 pip install 下载需要的py模块
open3d numpy matplotlib pandas plyfile pyntcloud
1 2 3 4 5 | #off_to_ply.py import os import numpy as np from plyfile import PlyData from plyfile import PlyElement |
1 2 3 4 5 | #pca_normal.py import open3d as o3d import os import numpy as np import matplotlib.pyplot as plt |
1 2 3 4 5 | #voxel_filter.py import open3d as o3d import os import numpy as np from pyntcloud import PyntCloud |
4.数据集下载
为40种物体的三维点云数据集
链接:https://pan.baidu.com/s/1LX9xeiXJ0t-Fne8BCGSjlQ
提取码:es14
5.单独读取数据集,并在open3d中显示原点云图
注意:要把对应的数据集文件 如:"sofa_0001.txt"放在对应的代码路径下
1 2 3 4 5 6 7 8 9 | import open3d as o3d #导入open3d import numpy as np import matplotlib as plt raw_point_cloud_matrix = np.genfromtxt(r"sofa_0001.txt", delimiter=",").reshape((-1,3)) # print(raw_point_cloud_matrix) pcd = o3d.geometry.PointCloud() pcd.points = o3d.utility.Vector3dVector(raw_point_cloud_matrix) print(pcd) o3d.visualization.draw_geometries([pcd]) |
原始点云数据在open3d下运行结果如下所示:
6.便捷的显示模块
摘自enginelong的博客代码片
1 2 3 4 5 6 7 8 9 10 | # matplotlib显示点云函数 def Point_Cloud_Show(points): fig = plt.figure(dpi=150) ax = fig.add_subplot(111, projection='3d') ax.scatter(points[:, 0], points[:, 1], points[:, 2], cmap='spectral', s=2, linewidths=0, alpha=1, marker=".") plt.title('Point Cloud') ax.set_xlabel('x') ax.set_ylabel('y') ax.set_zlabel('z') plt.show() |
1 2 3 4 5 6 7 8 9 10 | # 二维点云显示函数 def Point_Show(pca_point_cloud): x = [] y = [] pca_point_cloud = np.asarray(pca_point_cloud) for i in range(10000): x.append(pca_point_cloud[i][0]) y.append(pca_point_cloud[i][1]) plt.scatter(x, y) plt.show() |
7.PCA 主成分分析法
参考公式网址如下所示
三维点云处理学习笔记
代码参考网址如下所示
点云学习(1)参考网址1
点云学习(1)参考网址2
PCA函数编写
主要流程![在这里插入图片描述](//i2.wp.com/img-blog.csdnimg.cn/20200704102143143.png#pic_center)
1.取均值,去中心化![在这里插入图片描述](//i2.wp.com/img-blog.csdnimg.cn/20200704081245703.png)
1 2 | average_data = np.mean(data,axis=0) #求 NX3 向量的均值 decentration_matrix = data - average_data #去中心化 |
2.求取协方差矩阵H,并用SVD奇异值分解,求解出相应的特征值、特征向量
1 2 | H = np.dot(decentration_matrix.T,decentration_matrix) #求解协方差矩阵 H eigenvectors,eigenvalues,eigenvectors_T = np.linalg.svd(H) # SVD求解特征值、特征向量 |
3.对2步求解出的特征值特征向量进行降序排序,并存放到列表中
1 2 3 4 | if sort: sort = eigenvalues.argsort()[::-1] #降序排列 eigenvalues = eigenvalues[sort] #索引 eigenvectors = eigenvectors[:, sort] |
PCA处理整体代码块:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # 功能:计算PCA的函数 # 输入: # data:点云,NX3的矩阵 # correlation:区分np的cov和corrcoef,不输入时默认为False # sort: 特征值排序,排序是为了其他功能方便使用,不输入时默认为True # 输出: # eigenvalues:特征值 # eigenvectors:特征向量 def PCA(data, correlation=False, sort=True): # 作业1 # 屏蔽开始 average_data = np.mean(data,axis=0) #求 NX3 向量的均值 decentration_matrix = data - average_data #去中心化 H = np.dot(decentration_matrix.T,decentration_matrix) #求解协方差矩阵 H eigenvectors,eigenvalues,eigenvectors_T = np.linalg.svd(H) # SVD求解特征值、特征向量 # 屏蔽结束 if sort: sort = eigenvalues.argsort()[::-1] #降序排列 eigenvalues = eigenvalues[sort] #索引 eigenvectors = eigenvectors[:, sort] return eigenvalues, eigenvectors |
4.调用结果
通过调用PCA算法,并显示两个主成分方向,如下图所示黑色线为第一主成分,红色线为第二主成分
5.PCA的应用
降维(Encoder)
1 2 3 | #将原数据进行降维度处理 point_cloud_encode = (np.dot(point_cloud_vector.T,point_cloud_raw.T)).T #主成分的转置 dot 原数据 Point_Show(point_cloud_encode) |
效果如下所示:
降维后效果图
升维(Decoder)
1 2 3 | #使用主方向进行升维 point_cloud_decode = (np.dot(point_cloud_vector,point_cloud_encode.T)).T Point_Cloud_Show(point_cloud_decode) |
效果如下所示:
使用两个主方向再次升维后的结果
8.法向量估计
法向量估计
思想:选取点云中每一点,对其进行临近点的搜索,将包含该点的临近点拟合成曲面,对曲面中的点进行PCA主成分分析,查找特征值最小的对应的特征向量,该特征向量即为该拟合曲面的法向量(摘自:秦乐乐CSDN博客)
1.编码流程
2.代码展示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | # 循环计算每个点的法向量 pcd_tree = o3d.geometry.KDTreeFlann(point_cloud_o3d) #将原始点云数据输入到KD,进行近邻取点 normals = [] #储存曲面的法向量 # 作业2 # 屏蔽开始 print(points.shape[0]) #打印当前点数 20000个点 for i in range(points.shape[0]): # search_knn_vector_3d函数 , 输入值[每一点,x] 返回值 [int, open3d.utility.IntVector, open3d.utility.DoubleVector] [_,idx,_] = pcd_tree.search_knn_vector_3d(point_cloud_o3d.points[i],10) #取10个临近点进行曲线拟合 # asarray和array 一样 但是array会copy出一个副本,asarray不会,节省内存 k_nearest_point = np.asarray(point_cloud_o3d.points)[idx, :] # 找出每一点的10个临近点,类似于拟合成曲面,然后进行PCA找到特征向量最小的值,作为法向量 w, v = PCA(k_nearest_point) normals.append(v[:, 2]) # 屏蔽结束 normals = np.array(normals, dtype=np.float64) # TODO: 此处把法向量存放在了normals中 point_cloud_o3d.normals = o3d.utility.Vector3dVector(normals) o3d.visualization.draw_geometries([point_cloud_o3d]) |
3.效果展示
如下图1所示为图2的法向量加粗展示,
法线向量显示:在显示窗口按n 可按 + - 更改点的大小(o3d)
完整代码(包含PCA算法、PCA应用(升降维)、法向量估计展示)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | # 实现PCA分析和法向量计算,并加载数据集中的文件进行验证 import open3d as o3d import os import numpy as np import matplotlib.pyplot as plt from pandas import DataFrame from pyntcloud import PyntCloud # matplotlib显示点云函数 def Point_Cloud_Show(points): fig = plt.figure(dpi=150) ax = fig.add_subplot(111, projection='3d') ax.scatter(points[:, 0], points[:, 1], points[:, 2], cmap='spectral', s=2, linewidths=0, alpha=1, marker=".") plt.title('Point Cloud') ax.set_xlabel('x') ax.set_ylabel('y') ax.set_zlabel('z') plt.show() # 二维点云显示函数 def Point_Show(pca_point_cloud): x = [] y = [] pca_point_cloud = np.asarray(pca_point_cloud) for i in range(10000): x.append(pca_point_cloud[i][0]) y.append(pca_point_cloud[i][1]) plt.scatter(x, y) plt.show() # 功能:计算PCA的函数 # 输入: # data:点云,NX3的矩阵 # correlation:区分np的cov和corrcoef,不输入时默认为False # sort: 特征值排序,排序是为了其他功能方便使用,不输入时默认为True # 输出: # eigenvalues:特征值 # eigenvectors:特征向量 def PCA(data, correlation=False, sort=True): # 作业1 # 屏蔽开始 average_data = np.mean(data,axis=0) #求 NX3 向量的均值 decentration_matrix = data - average_data #去中心化 H = np.dot(decentration_matrix.T,decentration_matrix) #求解协方差矩阵 H eigenvectors,eigenvalues,eigenvectors_T = np.linalg.svd(H) # SVD求解特征值、特征向量 # 屏蔽结束 if sort: sort = eigenvalues.argsort()[::-1] #降序排列 eigenvalues = eigenvalues[sort] #索引 eigenvectors = eigenvectors[:, sort] return eigenvalues, eigenvectors def main(): # 指定点云路径 # cat_index = 10 # 物体编号,范围是0-39,即对应数据集中40个物体 # root_dir = '/Users/renqian/cloud_lesson/ModelNet40/ply_data_points' # 数据集路径 # cat = os.listdir(root_dir) # filename = os.path.join(root_dir, cat[cat_index],'train', cat[cat_index]+'_0001.ply') # 默认使用第一个点云 # 加载原始点云,txt处理 point_cloud_raw = np.genfromtxt(r"sofa_0001.txt", delimiter=",").reshape((-1,3)) #为 xyz的 N*3矩阵 points = DataFrame(point_cloud_raw[:, 0:3]) # 选取每一列 的 第0个元素到第二个元素 [0,3) points.columns = ['x', 'y', 'z'] # 给选取到的数据 附上标题 point_cloud_o3d = o3d.geometry.PointCloud() #实例化 point_cloud_o3d.points = o3d.utility.Vector3dVector(point_cloud_raw) #转化为点云数据 #o3d.visualization.draw_geometries([point_cloud_o3d]) # 显示原始点云 # 从点云中获取点,只对点进行处理 print(point_cloud_o3d) #打印点数 # 用PCA分析点云主方向 w, v = PCA(points) # w为特征值 v为主方向 point_cloud_vector1 = v[:, 0] #点云主方向对应的向量,第一主成分 point_cloud_vector2 = v[:, 1] # 点云主方向对应的向量,第二主成分 point_cloud_vector = v[:,0:2] # 点云主方向与次方向 print('the main orientation of this pointcloud is: ', point_cloud_vector1) print('the main orientation of this pointcloud is: ', point_cloud_vector2) #在原点云中画图 point = [[0,0,0],point_cloud_vector1,point_cloud_vector2] #画点:原点、第一主成分、第二主成分 lines = [[0,1],[0,2]] #画出三点之间两两连线 colors = [[1,0,0],[0,0,0]] #构造open3d中的LineSet对象,用于主成分显示 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]) # 显示原始点云和PCA后的连线 #将原数据进行降维度处理 point_cloud_encode = (np.dot(point_cloud_vector.T,point_cloud_raw.T)).T #主成分的转置 dot 原数据 #Point_Show(point_cloud_encode) #使用主方向进行升维 point_cloud_decode = (np.dot(point_cloud_vector,point_cloud_encode.T)).T #Point_Cloud_Show(point_cloud_decode) # 循环计算每个点的法向量 pcd_tree = o3d.geometry.KDTreeFlann(point_cloud_o3d) #将原始点云数据输入到KD,进行近邻取点 normals = [] #储存曲面的法向量 # 作业2 # 屏蔽开始 print(points.shape[0]) #打印当前点数 20000个点 for i in range(points.shape[0]): # search_knn_vector_3d函数 , 输入值[每一点,x] 返回值 [int, open3d.utility.IntVector, open3d.utility.DoubleVector] [_,idx,_] = pcd_tree.search_knn_vector_3d(point_cloud_o3d.points[i],10) #取10个临近点进行曲线拟合 # asarray和array 一样 但是array会copy出一个副本,asarray不会,节省内存 k_nearest_point = np.asarray(point_cloud_o3d.points)[idx, :] # 找出每一点的10个临近点,类似于拟合成曲面,然后进行PCA找到特征向量最小的值,作为法向量 w, v = PCA(k_nearest_point) normals.append(v[:, 2]) # 屏蔽结束 normals = np.array(normals, dtype=np.float64) # TODO: 此处把法向量存放在了normals中 point_cloud_o3d.normals = o3d.utility.Vector3dVector(normals) o3d.visualization.draw_geometries([point_cloud_o3d]) if __name__ == '__main__': main() |