mission_stock_pile_voxel_true_data.py 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. import open3d as o3d
  2. import numpy as np
  3. import math
  4. import math
  5. from functools import reduce
  6. import sys
  7. import copy
  8. # pcd = o3d.io.read_point_cloud("data/stockpile.ply")
  9. # pcd = o3d.io.read_point_cloud("data/2box-SG-t-MnQ0zoEQIBX.ply")
  10. # pcd = o3d.io.read_point_cloud("data/4box-1-SG-t-AsSRO3iA0XT.ply")
  11. # pcd = o3d.io.read_point_cloud("data/4box-2-SG-t-cp3kSewxMKi.ply")
  12. pcd = o3d.io.read_point_cloud("data/4box-3-SG-t-kuuv0moEP0C.ply")
  13. print(pcd)
  14. assert (pcd.has_normals())
  15. # o3d.visualization.draw_geometries([pcd])
  16. axes = o3d.geometry.TriangleMesh.create_coordinate_frame()
  17. # 找出地面所在平面
  18. plane_model, inliers = pcd.segment_plane(distance_threshold=0.01,
  19. ransac_n=5,
  20. num_iterations=10000)
  21. # 把地面上的点和其他点分开
  22. [a, b, c, d] = plane_model
  23. plane_pcd = pcd.select_by_index(inliers)
  24. plane_pcd.paint_uniform_color([1.0, 0, 0])
  25. stockpile_pcd = pcd.select_by_index(inliers, invert=True)
  26. # stockpile_pcd = pcd
  27. stockpile_pcd.paint_uniform_color([0, 0, 1.0])
  28. # o3d.visualization.draw_geometries([plane_pcd, stockpile_pcd, axes], point_show_normal=True)
  29. o3d.visualization.draw_geometries([plane_pcd, stockpile_pcd])
  30. # o3d.visualization.draw_geometries([plane_pcd, stockpile_pcd, axes])
  31. # 移动到原点
  32. plane_pcd = plane_pcd.translate((0,0,d/c))
  33. stockpile_pcd = stockpile_pcd.translate((0,0,d/c))
  34. # 旋转至与坐标轴对齐
  35. cos_theta = c / math.sqrt(a**2 + b**2 + c**2)
  36. sin_theta = math.sqrt((a**2+b**2)/(a**2 + b**2 + c**2))
  37. u_1 = b / math.sqrt(a**2 + b**2 )
  38. u_2 = -a / math.sqrt(a**2 + b**2)
  39. rotation_matrix = np.array([[cos_theta + u_1**2 * (1-cos_theta), u_1*u_2*(1-cos_theta), u_2*sin_theta],
  40. [u_1*u_2*(1-cos_theta), cos_theta + u_2**2*(1- cos_theta), -u_1*sin_theta],
  41. [-u_2*sin_theta, u_1*sin_theta, cos_theta]])
  42. plane_pcd.rotate(rotation_matrix)
  43. stockpile_pcd.rotate(rotation_matrix)
  44. o3d.visualization.draw_geometries([plane_pcd, stockpile_pcd, axes])
  45. # 用statistical outlier算法去除噪点
  46. cl, ind = stockpile_pcd.remove_statistical_outlier(nb_neighbors=100,
  47. std_ratio=1)
  48. stockpile_pcd = stockpile_pcd.select_by_index(ind)
  49. o3d.visualization.draw_geometries([plane_pcd, stockpile_pcd, axes])
  50. # 依据法向量去除噪点
  51. kd_tree_3d = o3d.geometry.KDTreeFlann(stockpile_pcd)
  52. noise_list_by_normal = []
  53. for idx in range (0, len(stockpile_pcd.points)):
  54. [k, neighbor_idx_list, _] = kd_tree_3d.search_radius_vector_3d(stockpile_pcd.points[idx], 0.1)
  55. if len(neighbor_idx_list) == 0:
  56. continue
  57. normal_sum = np.zeros((3))
  58. count = 0
  59. for neib_idx in neighbor_idx_list:
  60. normal_sum += np.asarray(stockpile_pcd.normals[neib_idx])
  61. count += 1
  62. normal_mean = normal_sum / count
  63. normal_angle = normal_mean[0] * stockpile_pcd.normals[idx][0] + normal_mean[1] * stockpile_pcd.normals[idx][1] + normal_mean[2] * stockpile_pcd.normals[idx][2]
  64. if normal_angle < 0:
  65. print(normal_angle)
  66. noise_list_by_normal.append(idx)
  67. noise_by_normal_pcd = stockpile_pcd.select_by_index(noise_list_by_normal)
  68. noise_by_normal_pcd.paint_uniform_color([0, 1.0, 0])
  69. stockpile_pcd = stockpile_pcd.select_by_index(noise_list_by_normal, invert=True)
  70. o3d.visualization.draw_geometries([plane_pcd, noise_by_normal_pcd, axes])
  71. o3d.visualization.draw_geometries([plane_pcd, stockpile_pcd, axes])
  72. # 降采样
  73. # downpcd = stockpile_pcd.voxel_down_sample(voxel_size=0.1)
  74. downpcd = stockpile_pcd
  75. print('有效点云:', np.asarray(downpcd.points))
  76. # 对stockpile建立二维网格
  77. bbox = downpcd.get_axis_aligned_bounding_box()
  78. print('bbox: ', bbox)
  79. bin_num_1d = 250
  80. bin_size_x = (bbox.max_bound[0] - bbox.min_bound[0]) / bin_num_1d
  81. bin_size_y = (bbox.max_bound[1] - bbox.min_bound[1]) / bin_num_1d
  82. grid2d = np.zeros((bin_num_1d, bin_num_1d, 2))
  83. print('bin_size: ', bin_size_x, bin_size_y)
  84. points = np.asarray(downpcd.points)
  85. bin_idx_x = -1
  86. bin_idx_y = -1
  87. for point in points:
  88. bin_idx_x = math.floor((point[0] - bbox.min_bound[0]) / (bbox.max_bound[0] - bbox.min_bound[0]) * bin_num_1d)
  89. if bin_idx_x <= -1: # 浮点数溢出
  90. bin_idx_x = 0
  91. if bin_idx_x >= bin_num_1d:
  92. bin_idx_x = bin_num_1d - 1
  93. bin_idx_y = math.floor((point[1] - bbox.min_bound[1]) / (bbox.max_bound[1] - bbox.min_bound[1]) * bin_num_1d)
  94. if bin_idx_y <= -1: # 浮点数溢出
  95. bin_idx_y = 0
  96. if bin_idx_y >= bin_num_1d:
  97. bin_idx_y = bin_num_1d - 1
  98. # print('bin before ', bin_idx_x, bin_idx_y, grid2d[bin_idx_x, bin_idx_y, 0], grid2d[bin_idx_x, bin_idx_y, 1])
  99. # print('point', point)
  100. grid2d[bin_idx_x, bin_idx_y, 0] += (point[2]) # 注意!认为地面高度为0!
  101. grid2d[bin_idx_x, bin_idx_y, 1] += 1
  102. # print('bin after ', bin_idx_x, bin_idx_y, grid2d[bin_idx_x, bin_idx_y, 0], grid2d[bin_idx_x, bin_idx_y, 1])
  103. # 对地面建立二维网格,空的格子就是被物体盖住的。
  104. grid_ground = np.zeros((bin_num_1d, bin_num_1d))
  105. for ground_point in np.asarray(plane_pcd.points):
  106. if ground_point[0] >= bbox.min_bound[0] and ground_point[0] <= bbox.max_bound[0] and ground_point[1] >= bbox.min_bound[1] and ground_point[1] <= bbox.max_bound[1]:
  107. bin_idx_x = math.floor((ground_point[0] - bbox.min_bound[0]) / (bbox.max_bound[0] - bbox.min_bound[0]) * bin_num_1d)
  108. if bin_idx_x <= -1: # 浮点数溢出
  109. bin_idx_x = 0
  110. if bin_idx_x >= bin_num_1d:
  111. bin_idx_x = bin_num_1d - 1
  112. bin_idx_y = math.floor((ground_point[1] - bbox.min_bound[1]) / (bbox.max_bound[1] - bbox.min_bound[1]) * bin_num_1d)
  113. if bin_idx_y <= -1: # 浮点数溢出
  114. bin_idx_y = 0
  115. if bin_idx_y >= bin_num_1d:
  116. bin_idx_y = bin_num_1d - 1
  117. grid_ground[bin_idx_x, bin_idx_y] += 1
  118. for i in range(0, len(stockpile_pcd.points)):
  119. point = stockpile_pcd.points[i]
  120. bin_idx_x = math.floor((point[0] - bbox.min_bound[0]) / (bbox.max_bound[0] - bbox.min_bound[0]) * bin_num_1d)
  121. if bin_idx_x <= -1: # 浮点数溢出
  122. bin_idx_x = 0
  123. if bin_idx_x >= bin_num_1d:
  124. bin_idx_x = bin_num_1d - 1
  125. bin_idx_y = math.floor((point[1] - bbox.min_bound[1]) / (bbox.max_bound[1] - bbox.min_bound[1]) * bin_num_1d)
  126. if bin_idx_y <= -1: # 浮点数溢出
  127. bin_idx_y = 0
  128. if bin_idx_y >= bin_num_1d:
  129. bin_idx_y = bin_num_1d - 1
  130. # 对stockpile建立二维kdtree以便查询邻居,对stockpile二维网格中没有点的网格做插值
  131. downpcd_2d = copy.deepcopy(downpcd)
  132. for point in downpcd_2d.points:
  133. point[2] = 0
  134. # print('build kdtree...')
  135. kd_tree_2d = o3d.geometry.KDTreeFlann(downpcd_2d)
  136. # print('build over')
  137. # 二维网格体积累积
  138. sum = 0
  139. interCount = 0
  140. for i in range(0, bin_num_1d):
  141. for j in range(0, bin_num_1d):
  142. # print('~~~~~~~~~~~~~')
  143. if grid_ground[i, j] == 1:
  144. continue
  145. if grid2d[i, j, 1] == 0:
  146. # print('做插值……')
  147. interCount += 1
  148. [k, neighbor_idx_list, _] = kd_tree_2d.search_knn_vector_3d([bin_size_x * (i + 0.5) + bbox.min_bound[0], bin_size_y * (j + 0.5) + bbox.min_bound[1], 0], 50)
  149. # 针对物体有垂直的侧面的情况,拿k近邻中z值最小的
  150. neighbor_pcd = downpcd.select_by_index(neighbor_idx_list)
  151. neighbor_pcd_pos = np.asarray(neighbor_pcd.points)
  152. z_min = 100
  153. for pos in neighbor_pcd_pos:
  154. if pos[2] < z_min:
  155. z_min = pos[2]
  156. grid2d[i, j, 0] = z_min
  157. grid2d[i, j, 1] = 1
  158. if(grid2d[i, j, 1]):
  159. sum += (grid2d[i, j, 0] / grid2d[i, j, 1] * bin_size_x * bin_size_y)
  160. # print('本网格idx', i, j)
  161. # print('本网格sum',grid2d[i, j, 0])
  162. # print('本网格点数',grid2d[i, j, 1])
  163. # print('sum: ', sum)
  164. # print('~~~~~~~~~~~~~')
  165. print('体积:', sum)
  166. # print('插值次数:', interCount)
  167. exit(0)