• 5.点云法向量的计算(代码)


    本文看了博主三维点云学习(1)上-PCA主成分分析 法向量估计_主成分分析法表面法向量估计-CSDN博客的文章,内容基本上参考了该博文,在这里写只是为了记笔记,没有要抄袭的意思,如果要更详细的了解,可以去看该博文。

    首先,读取点云数据并且处理点云数据,我下载的一个点云数据文件不是pcd文件,我首先读取了点云数据,并将其处理为array数据,该数据的shape为(641, 3),表示有641个xyz的数据,后面的代码和前面博文的相同(该代码用到了pca主成分分析原理,也很好理解,在前面博文有解释,要单独理解主成分分析原理,可以看我的另一篇博文12.1 主成分分析原理(PCA)_主成分分析零均值化-CSDN博客,该博文详细解释了主成分分析原理),代码如下:

    1. import numpy as np
    2. import open3d as o3d
    3. import open3d as o3d
    4. import os
    5. import numpy as np
    6. import matplotlib.pyplot as plt
    7. from pandas import DataFrame
    8. from pyntcloud import PyntCloud
    9. # 聚类算法
    10. def cluster(points, radius=100, nums=250):
    11. """
    12. points: pointcloud
    13. radius: max cluster range
    14. """
    15. print("................", len(points))
    16. items = []
    17. while len(points) > 1:
    18. item = np.array([points[0]])
    19. base = points[0]
    20. points = np.delete(points, 0, 0)
    21. distance = (points[:, 0] - base[0]) ** 2 + (points[:, 1] - base[1]) ** 2 + (points[:, 2] - base[2]) ** 2# 获得距离
    22. infected_points = np.where(distance <= radius ** 2) # 与base距离小于radius**2的点的坐标
    23. item = np.append(item, points[infected_points], axis=0)
    24. border_points = points[infected_points]
    25. points = np.delete(points, infected_points, 0)
    26. while len(border_points) > 0:
    27. border_base = border_points[0]
    28. border_points = np.delete(border_points, 0, 0)
    29. border_distance = (points[:, 0] - border_base[0]) ** 2 + (points[:, 1] - border_base[1]) ** 2
    30. border_infected_points = np.where(border_distance <= radius ** 2)
    31. # print("/",border_infected_points)
    32. item = np.append(item, points[border_infected_points], axis=0)
    33. if len(border_infected_points) > 0:
    34. for k in border_infected_points:
    35. if points[k] not in border_points:
    36. border_points = np.append(border_points, points[k], axis=0)
    37. points = np.delete(points, border_infected_points, 0)
    38. if len(item) >= nums:
    39. items.append(item)
    40. return items
    41. # matplotlib显示点云函数
    42. def Point_Cloud_Show(points):
    43. fig = plt.figure(dpi=150)
    44. ax = fig.add_subplot(111, projection='3d')
    45. ax.scatter(points[:, 0], points[:, 1], points[:, 2], cmap='spectral', s=2, linewidths=0, alpha=1, marker=".")
    46. plt.title('Point Cloud')
    47. ax.set_xlabel('x')
    48. ax.set_ylabel('y')
    49. ax.set_zlabel('z')
    50. plt.show()
    51. # 二维点云显示函数
    52. def Point_Show(pca_point_cloud):
    53. x = []
    54. y = []
    55. pca_point_cloud = np.asarray(pca_point_cloud)
    56. for i in range(640):
    57. x.append(pca_point_cloud[i][0])
    58. y.append(pca_point_cloud[i][1])
    59. plt.scatter(x, y)
    60. plt.show()
    61. # 功能:计算PCA的函数
    62. # 输入:
    63. # data:点云,NX3的矩阵
    64. # correlation:区分np的cov和corrcoef,不输入时默认为False
    65. # sort: 特征值排序,排序是为了其他功能方便使用,不输入时默认为True
    66. # 输出:
    67. # eigenvalues:特征值
    68. # eigenvectors:特征向量
    69. def PCA(data, correlation=False, sort=True):
    70. # 作业1
    71. # 屏蔽开始
    72. average_data = np.mean(data, axis=0) # 求 NX3 向量的均值
    73. decentration_matrix = data - average_data # 去中心化
    74. H = np.dot(decentration_matrix.T, decentration_matrix) # 求解协方差矩阵 H
    75. eigenvectors, eigenvalues, eigenvectors_T = np.linalg.svd(H) # SVD求解特征值、特征向量
    76. # 屏蔽结束
    77. if sort:
    78. sort = eigenvalues.argsort()[::-1] # 降序排列
    79. eigenvalues = eigenvalues[sort] # 索引
    80. eigenvectors = eigenvectors[:, sort]
    81. return eigenvalues, eigenvectors
    82. if __name__ == '__main__':
    83. # 1.读取数据
    84. datas_path = "datas/pine/111.txt"
    85. ss = []
    86. with open(datas_path, "r") as f: # 打开文件
    87. data = f.readlines() # 读取文件
    88. for item in data:
    89. t = np.asarray(item[:-1].split(" ")[2:])
    90. ss.append([float(t[0]) ,float(t[1]) ,float(t[2])])
    91. datas = np.asarray(ss)
    92. print(datas.shape)
    93. # items = cluster(datas, radius=30, nums=100)
    94. # da = np.asarray(items)
    95. # da = da.reshape((da.shape[1],da.shape[2]))
    96. # print(da)
    97. # pcd = o3d.geometry.PointCloud()
    98. # pcd.points = o3d.utility.Vector3dVector(da)
    99. # o3d.visualization.draw_geometries([pcd])
    100. da = datas
    101. point_cloud_raw = DataFrame(da[:, 0:3]) # 选取每一列 的 第0个元素到第二个元素 [0,3)
    102. point_cloud_raw.columns = ['x', 'y', 'z'] # 给选取到的数据 附上标题
    103. point_cloud_pynt = PyntCloud(point_cloud_raw) # 将points的数据 存到结构体中
    104. point_cloud_o3d = point_cloud_pynt.to_instance("open3d", mesh=False) # 实例化
    105. # o3d.visualization.draw_geometries([point_cloud_o3d]) # 显示原始点云
    106. # 用PCA分析点云主方向
    107. w, v = PCA(point_cloud_raw) # w为特征值 v为主方向
    108. point_cloud_vector1 = v[:, 0] # 点云主方向对应的向量,第一主成分
    109. point_cloud_vector2 = v[:, 1] # 点云主方向对应的向量,第二主成分
    110. point_cloud_vector = v[:, 0:2] # 点云主方向与次方向
    111. print('the main orientation of this pointcloud is: ', point_cloud_vector1)
    112. print('the main orientation of this pointcloud is: ', point_cloud_vector2)
    113. # 在原点云中画图
    114. point = [[0, 0, 0], point_cloud_vector1, point_cloud_vector2] # 画点:原点、第一主成分、第二主成分
    115. lines = [[0, 1], [0, 2]] # 画出三点之间两两连线
    116. colors = [[1, 0, 0], [0, 0, 0]]
    117. # 构造open3d中的LineSet对象,用于主成分显示
    118. line_set = o3d.geometry.LineSet(points=o3d.utility.Vector3dVector(point), lines=o3d.utility.Vector2iVector(lines))
    119. line_set.colors = o3d.utility.Vector3dVector(colors)
    120. o3d.visualization.draw_geometries([point_cloud_o3d, line_set]) # 显示原始点云和PCA后的连线
    121. # 将原数据进行降维度处理
    122. point_cloud_encode = (np.dot(point_cloud_vector.T, point_cloud_raw.T)).T # 主成分的转置 dot 原数据
    123. Point_Show(point_cloud_encode)
    124. # 使用主方向进行升维
    125. point_cloud_decode = (np.dot(point_cloud_vector, point_cloud_encode.T)).T
    126. Point_Cloud_Show(point_cloud_decode)
    127. # 循环计算每个点的法向量
    128. pcd_tree = o3d.geometry.KDTreeFlann(point_cloud_o3d) # 将原始点云数据输入到KD,进行近邻取点
    129. normals = [] # 储存曲面的法向量
    130. # 作业2
    131. # 屏蔽开始
    132. print(point_cloud_raw.shape[0]) # 打印当前点数 20000个点
    133. for i in range(point_cloud_raw.shape[0]):
    134. # search_knn_vector_3d函数 , 输入值[每一点,x] 返回值 [int, open3d.utility.IntVector, open3d.utility.DoubleVector]
    135. [_, idx, _] = pcd_tree.search_knn_vector_3d(point_cloud_o3d.points[i], 10) # 取10个临近点进行曲线拟合
    136. # asarray和array 一样 但是array会copy出一个副本,asarray不会,节省内存
    137. k_nearest_point = np.asarray(point_cloud_o3d.points)[idx, :] # 找出每一点的10个临近点,类似于拟合成曲面,然后进行PCA找到特征向量最小的值,作为法向量
    138. w, v = PCA(k_nearest_point)
    139. normals.append(v[:, 2])
    140. # # 屏蔽结束
    141. normals = np.array(normals, dtype=np.float64)
    142. # print(normals)
    143. # # TODO: 此处把法向量存放在了normals中
    144. point_cloud_o3d.normals = o3d.utility.Vector3dVector(normals)
    145. o3d.visualization.draw_geometries([point_cloud_o3d])

            注意:上面代码比前面博文的代码多加了个聚类算法,在该代码中屏蔽了没用,如果想先用聚类处理点云,可以直接用上面的聚类函数处理点云。在这里可以结合理论和代码详细了解pca主成分分析的原理及应用,该主成分分析也可以通用于其他项目。

  • 相关阅读:
    【数据库编程-SQLite3(三)】Ubuntu下sqlite3的使用
    PyTorch深度学习实战(17)——多任务学习
    随笔记:计算机基础及进制计数法
    WiFi模块引领智能家居革命:连接未来的生活
    每日三题 9.07
    Java项目:ssm电影院购票系统
    直播回放含 PPT 下载|基于 Flink & DeepRec 构建 Online Deep Learning
    hystrix断路器
    ESP8266-Arduino编程实例-VEML6070紫外光传感器驱动
    leetcode面试经典150题——30 长度最小的子数组
  • 原文地址:https://blog.csdn.net/weixin_71719718/article/details/139838871