pcd_to_video.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. """
  2. 功能:将ROS bag文件中的点云数据转换为PCD文件,并将PCD文件转换为图像,最后生成视频。
  3. 输入:rosbag文件路径,输出路径
  4. 输出:生成的视频文件
  5. 注意:需要安装pyntcloud、matplotlib、opencv库
  6. """
  7. import sys
  8. import matplotlib.pyplot as plt
  9. import cv2
  10. import os
  11. import subprocess
  12. import matplotlib.pyplot as plt
  13. from pyntcloud import PyntCloud
  14. import rosbag
  15. import shutil
  16. def process_pcd_to_top_view_image(pcd_path, output_path):
  17. # 使用 PyntCloud 读取点云数据
  18. cloud = PyntCloud.from_file(pcd_path)
  19. points = cloud.points
  20. plt.figure(figsize=(10, 10))
  21. ax = plt.axes(projection='3d')
  22. ax.scatter(points['x'], points['y'], points['z'], s=1, color='blue')
  23. ax.view_init(elev=90, azim=90)
  24. ax.set_xlabel('X')
  25. ax.set_ylabel('Y')
  26. ax.set_zlabel('Z')
  27. ax.set_xticks([])
  28. ax.set_yticks([])
  29. ax.set_zticks([])
  30. plt.axis('off') # 隐藏坐标轴
  31. plt.savefig(output_path, bbox_inches='tight', pad_inches=0)
  32. plt.close()
  33. def create_video_from_images(image_folder, output_video_path, frame_rate):
  34. images = [img for img in sorted(os.listdir(image_folder)) if img.endswith(".jpg")]
  35. if not images:
  36. print("没有找到任何JPG图像,请检查图像文件夹!")
  37. return
  38. frame = cv2.imread(os.path.join(image_folder, images[0]))
  39. height, width, layers = frame.shape
  40. video = cv2.VideoWriter(output_video_path, cv2.VideoWriter_fourcc(*'mp4v'), float(frame_rate), (width, height))
  41. for image in images:
  42. frame = cv2.imread(os.path.join(image_folder, image))
  43. if frame is not None:
  44. video.write(frame)
  45. video.release()
  46. print(f"视频已成功保存在:{output_video_path}")
  47. def convert_bag_to_pcd(input_dir, output_dir):
  48. """ 将ROS bag文件中的点云数据转换为PCD文件 """
  49. command = f'rosrun pcl_ros bag_to_pcd {input_dir} /scan_map_icp_amcl_node/scan_point_transformed {output_dir}'
  50. process = subprocess.run(command, shell=True, text=True, capture_output=True)
  51. if process.returncode != 0:
  52. print("转换失败:", process.stderr)
  53. else:
  54. print("PCD文件已成功生成")
  55. if __name__ == '__main__':
  56. rosbag_path = sys.argv[1]
  57. output_base_path = sys.argv[2]
  58. #input_dir = '/media/server/00D7-0524/点云解析/2024-04-16-10-20-45_obstacledetection_30.bag'
  59. #output_dir = '/media/server/00D7-0524/点云解析/2024-04-16-10-20-45_obstacledetection_30'
  60. bag_base_name = rosbag_path.split('/')[-1].split('.')[0]
  61. lidar_output_base = os.path.join(output_base_path, bag_base_name + '_pcd_lidar')
  62. pcd_folder_path = os.path.join(lidar_output_base, 'pcd')
  63. images_folder_path = os.path.join(lidar_output_base, 'images')
  64. if not os.path.exists(pcd_folder_path):
  65. os.makedirs(pcd_folder_path)
  66. if not os.path.exists(images_folder_path):
  67. os.makedirs(images_folder_path)
  68. with rosbag.Bag(rosbag_path ,'r') as bag:
  69. num_count=0
  70. for topic,msg,t in bag.read_messages():
  71. if topic == "/scan_map_icp_amcl_node/scan_point_transformed":
  72. num_count+=1
  73. start_time = bag.get_start_time()
  74. end_time = bag.get_end_time()
  75. # 计算rosbag的持续时间
  76. duration = end_time - start_time
  77. bagtime = duration
  78. hz=str(float(float(num_count)/bagtime))
  79. print(hz)
  80. # 转换ROS bag到PCD
  81. convert_bag_to_pcd(rosbag_path, pcd_folder_path)
  82. pcd_files = [f for f in os.listdir(pcd_folder_path) if f.endswith('.pcd')]
  83. for file_name in pcd_files:
  84. pcd_file_path = os.path.join(pcd_folder_path, file_name)
  85. image_file_path = os.path.join(images_folder_path, f"{file_name[:-4]}.jpg")
  86. process_pcd_to_top_view_image(pcd_file_path, image_file_path)
  87. # 从图像生成视频
  88. video_path = os.path.join(lidar_output_base, 'output_video.mp4')
  89. create_video_from_images(images_folder_path, video_path, hz)
  90. # 清理临时文件
  91. shutil.rmtree(pcd_folder_path)
  92. shutil.rmtree(images_folder_path)