mission_stock_pile_voxel.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  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. print(pcd)
  10. axes = o3d.geometry.TriangleMesh.create_coordinate_frame()
  11. # 找出地面所在平面
  12. plane_model, inliers = pcd.segment_plane(distance_threshold=0.01,
  13. ransac_n=3,
  14. num_iterations=10000)
  15. # 把地面上的点和其他点分开
  16. [a, b, c, d] = plane_model
  17. plane_pcd = pcd.select_by_index(inliers)
  18. plane_pcd.paint_uniform_color([1.0, 0, 0])
  19. stockpile_pcd = pcd.select_by_index(inliers, invert=True)
  20. # stockpile_pcd = pcd
  21. stockpile_pcd.paint_uniform_color([0, 0, 1.0])
  22. # o3d.visualization.draw_geometries([plane_pcd, stockpile_pcd, axes])
  23. # 移动到原点
  24. plane_pcd = plane_pcd.translate((0,0,d/c))
  25. stockpile_pcd = stockpile_pcd.translate((0,0,d/c))
  26. # 旋转至与坐标轴对齐
  27. cos_theta = c / math.sqrt(a**2 + b**2 + c**2)
  28. sin_theta = math.sqrt((a**2+b**2)/(a**2 + b**2 + c**2))
  29. u_1 = b / math.sqrt(a**2 + b**2 )
  30. u_2 = -a / math.sqrt(a**2 + b**2)
  31. rotation_matrix = np.array([[cos_theta + u_1**2 * (1-cos_theta), u_1*u_2*(1-cos_theta), u_2*sin_theta],
  32. [u_1*u_2*(1-cos_theta), cos_theta + u_2**2*(1- cos_theta), -u_1*sin_theta],
  33. [-u_2*sin_theta, u_1*sin_theta, cos_theta]])
  34. plane_pcd.rotate(rotation_matrix)
  35. stockpile_pcd.rotate(rotation_matrix)
  36. o3d.visualization.draw_geometries([plane_pcd, stockpile_pcd, axes])
  37. # 去除噪点
  38. cl, ind = stockpile_pcd.remove_statistical_outlier(nb_neighbors=100,
  39. std_ratio=10.0)
  40. stockpile_pcd = stockpile_pcd.select_by_index(ind)
  41. print('有效点:', stockpile_pcd)
  42. o3d.visualization.draw_geometries([stockpile_pcd])
  43. # 降采样
  44. # downpcd = stockpile_pcd.voxel_down_sample(voxel_size=0.1)
  45. downpcd = stockpile_pcd
  46. print('有效点云:', np.asarray(downpcd.points))
  47. mean = 0
  48. meanCount = 0
  49. for point in np.asarray(downpcd.points):
  50. mean += point[2]
  51. meanCount += 1
  52. mean = mean / meanCount
  53. print('z均值:', mean)
  54. # 建立二维网格
  55. bbox = downpcd.get_axis_aligned_bounding_box()
  56. print('bbox: ', bbox)
  57. bin_num_1d = 100
  58. bin_size_x = (bbox.max_bound[0] - bbox.min_bound[0]) / bin_num_1d
  59. bin_size_y = (bbox.max_bound[1] - bbox.min_bound[1]) / bin_num_1d
  60. grid2d = np.zeros((bin_num_1d, bin_num_1d, 2))
  61. print('bin_size: ', bin_size_x, bin_size_y)
  62. points = np.asarray(downpcd.points)
  63. bin_idx_x = -1
  64. bin_idx_y = -1
  65. for point in points:
  66. bin_idx_x = math.floor((point[0] - bbox.min_bound[0]) / (bbox.max_bound[0] - bbox.min_bound[0]) * bin_num_1d)
  67. if bin_idx_x <= -1: # 浮点数溢出
  68. bin_idx_x = 0
  69. if bin_idx_x >= bin_num_1d:
  70. bin_idx_x = bin_num_1d - 1
  71. bin_idx_y = math.floor((point[1] - bbox.min_bound[1]) / (bbox.max_bound[1] - bbox.min_bound[1]) * bin_num_1d)
  72. if bin_idx_y <= -1: # 浮点数溢出
  73. bin_idx_y = 0
  74. if bin_idx_y >= bin_num_1d:
  75. bin_idx_y = bin_num_1d - 1
  76. # 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])
  77. # print('point', point)
  78. grid2d[bin_idx_x, bin_idx_y, 0] += (point[2]) # 注意!认为地面高度为0!
  79. grid2d[bin_idx_x, bin_idx_y, 1] += 1
  80. # 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])
  81. # 建立二维kdtree以便查询邻居,对二维网格中没有点的网格做插值
  82. downpcd_2d = copy.deepcopy(downpcd)
  83. for point in downpcd_2d.points:
  84. point[2] = 0
  85. # print('build kdtree...')
  86. kd_tree_2d = o3d.geometry.KDTreeFlann(downpcd_2d)
  87. # print('build over')
  88. # 二维网格插值
  89. sum = 0
  90. interCount = 0
  91. interSum = 0
  92. for i in range(0, bin_num_1d):
  93. for j in range(0, bin_num_1d):
  94. # print('~~~~~~~~~~~~~')
  95. if grid2d[i, j, 1] == 0:
  96. # print('做插值……')
  97. interCount += 1
  98. [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], 1)
  99. # print(neighbor_idx_list)
  100. pointNeighbor = np.asarray(downpcd.points)[neighbor_idx_list[0]]
  101. # if pointNeighbor[2] > 0.08:
  102. # print('最近点:', pointNeighbor)
  103. grid2d[i, j, 0] = pointNeighbor[2]
  104. grid2d[i, j, 1] = 1
  105. interSum += pointNeighbor[2]
  106. if(grid2d[i, j, 1]):
  107. sum += (grid2d[i, j, 0] / grid2d[i, j, 1] * bin_size_x * bin_size_y)
  108. # print('本网格idx', i, j)
  109. # print('本网格sum',grid2d[i, j, 0])
  110. # print('本网格点数',grid2d[i, j, 1])
  111. # print('sum: ', sum)
  112. # print('~~~~~~~~~~~~~')
  113. print('插值均值:', interSum / interCount)
  114. print('体积:', sum)
  115. print('插值次数:', interCount)
  116. exit(0)