dycl_0506.py 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. #!/usr/bin/env python3
  2. import rospy
  3. import numpy as np
  4. import open3d as o3d
  5. from scipy.spatial.transform import Rotation as R
  6. import os
  7. from sensor_msgs.msg import PointCloud2
  8. from sensor_msgs.msg import PointField
  9. folder_path = rospy.get_param("folder_path")
  10. file_path = os.path.join(folder_path, 'pointcloud.txt')
  11. file_path_points = os.path.join(folder_path, 'points.txt')
  12. file_path_down = os.path.join(folder_path, 'pointcloud_down.pcd')
  13. file_path_octomap = os.path.join(folder_path, 'pointcloud_octomap.pcd')
  14. #chen############################################################################################
  15. def cull_pointcloud(data,culling_radius):
  16. data_retained,data_culled = [],[]
  17. for i in range(data.shape[0]): # 遍历每一个点 P
  18. for j in range(len(vectors)): # 遍历每一个向量 u
  19. A = start_points[j] - culling_radius * (vectors[j] / np.linalg.norm(vectors[j]))
  20. B = end_points[j] + culling_radius * (vectors[j] / np.linalg.norm(vectors[j]))
  21. aaa = (np.linalg.norm(data[i] - A) + np.linalg.norm(data[i] - B)) <= (2 * culling_radius + np.linalg.norm(B - A))
  22. distance = np.linalg.norm(np.cross(vectors[j], data[i]-start_points[j])) / np.linalg.norm(vectors[j])
  23. # 如果有任何一个距离小于等于10,则标记为不满足条件
  24. if distance <= culling_radius and aaa:
  25. # if aaa:
  26. data_culled.append(data[i])
  27. break
  28. # 如果该点对所有向量的距离都大于10,则保留该点
  29. elif j == len(vectors)-1:
  30. data_retained.append(data[i])
  31. data_retained = np.array(data_retained)
  32. data_culled = np.array(data_culled)
  33. return data_retained,data_culled
  34. def visual_data(data):
  35. # 可视化
  36. pt_cloud_circular = o3d.geometry.PointCloud()
  37. pt_cloud_circular.points = o3d.utility.Vector3dVector(data)
  38. o3d.visualization.draw_geometries([pt_cloud_circular])
  39. ################################点云降采样################################
  40. # 从文件中读取焊缝起点和终点,并计算两点构成的向量
  41. def read_and_calculate_vectors(file_path):
  42. with open(file_path, 'r') as file:
  43. # 逐行读取文件内容
  44. lines = file.readlines()
  45. start_points,end_points,vectors = [],[],[]
  46. for line in lines:
  47. # 去除行尾的换行符并按'/'分割每一行
  48. points_str = line.strip().split('/')
  49. # 确保每一行都正确地分为两部分
  50. if len(points_str) == 2:
  51. point1_str = points_str[0].split(',')
  52. point2_str = points_str[1].split(',')
  53. # 转换字符串为浮点数列表,构造三维点
  54. point1 = [float(coord) for coord in point1_str]
  55. point2 = [float(coord) for coord in point2_str]
  56. start_points.append(point1)
  57. end_points.append(point2)
  58. # 计算向量:向量 = 点2 - 点1
  59. vector = [p2 - p1 for p1, p2 in zip(point1, point2)]
  60. vectors.append(vector)
  61. return start_points,end_points,vectors
  62. # 读取文件
  63. def load_point_cloud_from_binary_txt(file_path):
  64. with open(file_path, 'rb') as f:
  65. binary_data = f.read()
  66. # 将二进制数据转换为 NumPy 数组
  67. point_cloud = np.frombuffer(binary_data, dtype=np.float64).reshape(-1, 3)
  68. # 将数组转换为可写状态
  69. point_cloud = np.copy(point_cloud)
  70. return point_cloud
  71. def open_file(file_path):
  72. if '.txt' in file_path:
  73. pcd = o3d.io.read_point_cloud(file_path, format='xyz')
  74. else:
  75. pcd = o3d.io.read_point_cloud(file_path)
  76. return pcd
  77. def save_file(content, file_path, write_ascii=True):
  78. if '.txt' in file_path:
  79. np.savetxt(file_path, np.asarray(content.points), fmt='%f %f %f')
  80. else:
  81. o3d.io.write_point_cloud(file_path, content, write_ascii=write_ascii)
  82. def voxel_down_sample(pcd, voxel_size):
  83. """
  84. 体素方法点云降采样
  85. :param pcd: 点云数据
  86. :param voxel_size: 体素降采样的网格长度
  87. :return: 降采样点云数据
  88. """
  89. return pcd.voxel_down_sample(voxel_size=voxel_size)
  90. def add_rgb_to_pcd(pcd):
  91. # 为点云中的每个点指定RGB颜色,这里我们使用红色作为示例
  92. # RGB值范围为[0, 1],红色可以表示为(1, 0, 0)
  93. pcd = np.asarray(pcd.points).shape[0]
  94. colors = np.repeat([[1, 0, 0]], pcd, axis=0) # 创建一个全是红色的颜色数组
  95. # 将颜色信息添加到点云对象中
  96. pcd.colors = o3d.utility.Vector3dVector(colors)
  97. return pcd
  98. # 降采样
  99. # pcd = open_file(file_path)
  100. pcd = o3d.geometry.PointCloud()
  101. pcd.points = o3d.utility.Vector3dVector(load_point_cloud_from_binary_txt(file_path))
  102. pcd = pcd.voxel_down_sample(voxel_size = 4)
  103. save_file(pcd,file_path_down)
  104. ################################去掉焊缝周围的点云#################################
  105. # 计算焊缝向量
  106. start_points,end_points,vectors = np.array(read_and_calculate_vectors(file_path_points))
  107. # 使用pcread直接读取点云数据
  108. ptCloud = o3d.io.read_point_cloud(file_path_down)
  109. data = np.asarray(ptCloud.points)
  110. culling_radius1 = 20
  111. culling_radius2 = float(rospy.get_param('culling_radius'))
  112. # culling_radius2 = 6
  113. data_retained2,data_culled2 =cull_pointcloud(data,culling_radius2)
  114. # rospy.loginfo('Point cloud culling is complete')
  115. #分批剔除
  116. # data_retained1,data_culled1 =cull_pointcloud(data,culling_radius1)
  117. # # visual_data(data_culled1)
  118. # data_retained2,data_culled2 =cull_pointcloud(data_culled1,culling_radius2)
  119. # visual_data(data_retained2)
  120. # visual_data(data_culled2)
  121. ################################变换单位并保存################################
  122. # 将点云数据的小数点向前移动三位(即乘以1000)
  123. # data_scaled1 = np.array(data_retained1) / 1000
  124. data_scaled2 = np.array(data_retained2) / 1000
  125. # 创建一个新的pointCloud对象来存储缩放后的数据
  126. ptCloud_scaled1 = o3d.geometry.PointCloud()
  127. # ptCloud_scaled1.points = o3d.utility.Vector3dVector(data_scaled1)
  128. ptCloud_scaled2 = o3d.geometry.PointCloud()
  129. ptCloud_scaled2.points = o3d.utility.Vector3dVector(data_scaled2)
  130. # 将缩放后的点云数据写入新的 PCD 文件
  131. # o3d.io.write_point_cloud(file_path_octomap, ptCloud_scaled1, write_ascii=True)
  132. # 读取保存的点云数据
  133. # pcd = o3d.io.read_point_cloud(file_path_octomap)
  134. #####################################################################################################################################################################
  135. def build_pointcloud2_msg(points):
  136. msg = PointCloud2()
  137. msg.header.stamp = rospy.Time(0)
  138. msg.header.frame_id = "base_link"
  139. if len(points.shape) == 3:
  140. msg.height = points.shape[1]
  141. msg.width = points.shape[0]
  142. else:
  143. msg.height = 1
  144. msg.width = len(points)
  145. msg.fields = [
  146. PointField('x', 0, PointField.FLOAT32, 1),
  147. PointField('y', 4, PointField.FLOAT32, 1),
  148. PointField('z', 8, PointField.FLOAT32, 1)]
  149. msg.is_bigendian = False
  150. msg.point_step = 12
  151. msg.row_step = msg.point_step * points.shape[0]
  152. msg.is_dense = False
  153. msg.data = np.asarray(points, np.float32).tobytes()
  154. return msg
  155. def talker():
  156. pointcloud_topic = rospy.get_param('pointcloud_topic')
  157. pub1 = rospy.Publisher("/pointcloud/output", PointCloud2, queue_size=10)
  158. # pub2 = rospy.Publisher("/pointcloud/output2", PointCloud2, queue_size=10)
  159. rospy.init_node('publish_pointcloud', anonymous=True)
  160. rate = rospy.Rate(10)
  161. points1 = np.asarray(ptCloud_scaled1.points)
  162. points2 = np.asarray(ptCloud_scaled2.points)
  163. # msg1 = build_pointcloud2_msg(points1)
  164. msg2 = build_pointcloud2_msg(points2)
  165. while not rospy.is_shutdown():
  166. #机械臂完毕,退出点云发布
  167. sign_pointcloud = str(rospy.get_param("sign_pointcloud"))
  168. if sign_pointcloud == "1":
  169. rospy.set_param("sign_pointcloud",0)
  170. break
  171. pub1.publish(msg2)
  172. # pub2.publish(msg2)
  173. # print("pointcloud has published,sign_pointcloud ={}".format(sign_pointcloud))
  174. rate.sleep()
  175. if __name__ == '__main__':
  176. talker()