ROS_发布点云_pcd_rviz_pcd_bag_点云文件保存到bag包

发布标注好的点云

发布保存的点云
将可视化后的点云保存为图像

读取点云文件-发布

 std_msgs/Header header:数据头,包含该帧点云的时间戳、坐标系等属性信息
 uint32 			height:data的高度,一帧点云通常height=1,即表示无序点云;
 uint32 			width:data的宽度,即每行对应点的数量;
 sensor_msgs/PointField[] fields:包含每个点的字段属性信息,详见下文。
 bool 			is_bigendian:点云是否按正序排列
 uint32 			point_step:每个点占用的比特数,1字节=8比特,与PointField里所有字节数之和相等。
 uint32 			row_step:每行占用的比特数,=点的数量*Point_step;
 uint8[] 		data:序列化后的点云二进制数据,所有点信息都在一串字符中,无法通过data[i]取值。
 bool 			is_dense:是否存在无效点。

示例代码

#! /usr/bin/env python3
# -*- coding=utf-8 -*-

import rospy
from sensor_msgs.msg import PointField
from sensor_msgs.msg import PointCloud2
import open3d as o3d
import numpy as np
import os
 
def talker():
    pub = rospy.Publisher('points_b', PointCloud2, queue_size=10)
    rospy.init_node('node', anonymous=True)
    rate = rospy.Rate(2) # 2hz
    ##处理PCD点云
    pcd_path = '~/pcd'
	#得到文件夹下的所有文件名称
    files= os.listdir(pcd_path) 
    #files.sort(key = lambda x: int(x[:-4]))
    files.sort()
    for i,pcd_file in enumerate(files):
        print(i,pcd_file)
        pcd = o3d.t.io.read_point_cloud(os.path.join(pcd_path,pcd_file))
        exp_points = pcd.point
        point_xyz = exp_points['positions'].numpy()
        # 构造消息
        msg = PointCloud2()
        msg.header.stamp = rospy.Time().now()
        msg.header.frame_id = "map"
        msg.fields = [
            PointField('x', 0, PointField.FLOAT32, 1),
            PointField('y', 4, PointField.FLOAT32, 1),
            PointField('z', 8, PointField.FLOAT32, 1)]
        msg.is_bigendian = False
        msg.point_step = 12
        msg.row_step = msg.point_step * point_xyz.shape[0]
        msg.is_dense = False
        if len(point_xyz.shape) == 3:
            msg.height = point_xyz.shape[1]
            msg.width = point_xyz.shape[0]
        else:
            msg.height = 1
            msg.width = len(point_xyz)
        msg.data = np.asarray(point_xyz, np.float32).tostring()
        pub.publish(msg)       
        rate.sleep()
        
if __name__ == '__main__':     
    for i in range(20):
        talker()

点云保存为图像

vis = o3d.visualization.Visualizer()
vis.create_window()
vis.add_geometry(pcd)
vis.update_geometry()
vis.poll_events()
vis.update_renderer()
### 将点云保存为图像
vis.capture_screen_image('test.png') 
vis.run() 
vis.destroy_window() 
 
###Have you tried: vis.capture_screen_image('test.png', true)?
###Is the window visible and showing the image prior to this function call, 
###i.e., try to add time.sleep(5) before the capture_screen_image? 

说明

bag函数

 bag.open()函数有两个参数:第一个是打开的文件名,如果该文件不存在则创建新文件,;第二个参数是打开方式,打开方式在BagMode里。
 bag.write()有三个参数:第一个是发布的话题;第二个参数是时间戳,
    一般是选择ros::Time::now(),有的时候也可以用ros::Time(0.0),
    最后一个参数是消息,注意要包std_msgs/String.h头文件。
 bag.close()关闭文件, 记得一定要关闭,否则会造成内存泄露。

sensor_msgs.msg.PointCloud2

sensor_msgs.msg.PointCloud2 函数 read_points  create_cloud
   point_cloud2.create_cloud 函数说明
   
from std_msgs.msg import Header
from sensor_msgs.msg import PointField
from sensor_msgs.msg import PointCloud2	

    pcd = o3d.t.io.read_point_cloud(data_sig)
    pcd_intensity = pcd.point["intensity"].numpy() #强度-转换为数组类型
    pcd_points = pcd.point["positions"].numpy() #坐标 -转换为数组类型
    complex_points = np.zeros(( pcd_points.shape[0],4))
    complex_points[:,:3] = pcd_points
    complex_points[:,3] = pcd_intensity.reshape(1,-1)
    pc2_msg = point_cloud2.create_cloud(header, msg_fields, complex_points)	 

for topic, msg, t in tqdm(bag.read_messages(topics=topic)): 
    cloud  = np.asarray(list(point_cloud2.read_points(msg, field_names=['x', 'y', 'z', "intensity"])))          
    pcd_obj = o3d.t.geometry.PointCloud()
    pcd_obj.point['positions'] = o3d.core.Tensor(cloud[:, :3],dtype=o3d.core.Dtype.Float32)
    pcd_obj.point['intensity'] = o3d.core.Tensor(cloud[:, 3].reshape(-1,1),dtype=o3d.core.Dtype.Float32)

排序

sorted() 函数对序列进行排序, 并不会在原序列的基础进行修改,而是会重新生成一个排好序的列表
  exp_list = sorted(iterable, key=None, reverse=False)
  #自定义按照字符串长度排序 sorted(chars,key=lambda x:len(x)) 
  
  ex_list.sort(key=lambda x: float(x.split("_")[-1][0:-5]))

示例代码

#!/usr/bin/python3
# -*- coding: utf-8 -*- 

import  os
import roslib
import rospy
roslib.load_manifest('sensor_msgs')
import numpy as np
import open3d as o3d
from ros import rosbag
from std_msgs.msg import Header
from sensor_msgs.msg import PointField
from sensor_msgs.msg import PointCloud2
from sensor_msgs.point_cloud2 import create_cloud   

'''get pcd from dir'''
def get_pcd(pcd_dir):
    '''Generates a list of files from the directory'''
    print( "Searching directory %s" % pcd_dir )
    pcd_files = []
    pcd_timestamps =[]
    if os.path.exists(pcd_dir):
        for path, names, files in os.walk(pcd_dir ):
            for f in sorted(files):
                if os.path.splitext(f)[1] in ['.pcd']:
                        file_nm =os.path.join( path, f )
                        pcd_files.append( file_nm )
                        time_img =os.path.splitext(f)[0]
                        pcd_timestamps.append(time_img)
    return pcd_files,pcd_timestamps 


def creat_pcd_rosbag(pcd_dir,out_bag_nm):
    pts_dtype = PointField.FLOAT32
    msg_fields = [PointField(name='x', offset=0, datatype=pts_dtype, count=1),
                  PointField(name='y', offset=4, datatype=pts_dtype, count=1),
                  PointField(name='z', offset=8, datatype=pts_dtype, count=1),
                  PointField(name='intensity', offset=12, datatype=pts_dtype, count=1) ]
    bag = rosbag.Bag(out_bag_nm, 'w')   
    pcd_data = get_pcd(pcd_dir)      
    all_pcd_file = pcd_data[0]
    all_time_file = pcd_data[1]
    for i,data_sig in enumerate(all_pcd_file) :
        print("Adding {} {}  ".format(i,data_sig ))
        pcd = o3d.t.io.read_point_cloud(data_sig)
        pcd_intensity = pcd.point["intensity"].numpy() #强度-转换为数组类型
        pcd_points = pcd.point["positions"].numpy() #坐标 -转换为数组类型
        complex_points = np.zeros(( pcd_points.shape[0],4))
        complex_points[:,:3] = pcd_points
        complex_points[:,3] = pcd_intensity.reshape(1,-1)
        
        stamp_time = rospy.rostime.Time.from_sec(float(all_time_file[i]))
        header = Header() 
        header.stamp = stamp_time
        header.frame_id = "map"
        pc2_msg = create_cloud(header, msg_fields, complex_points)
        
        topic_nm ="/test/cloud_points"
        bag.write(topic_nm, pc2_msg, stamp_time)
    bag.close()

 

if __name__ == '__main__':
    dir_exp = r"/test/pts/"
    bag_nm_exp = r"/test/pts.bag"
    creat_pcd_rosbag(dir_exp,bag_nm_exp)

参考

 【ros】numpy 格式点云转 sensor_msgs/PointCloud2 格式发布 https://blog.csdn.net/qq_35632833/article/details/108050233
 动手学ROS(13):点云(PointCloud2)的发送与接收--python和c++示例 https://zhuanlan.zhihu.com/p/421691350
 ROS(机器人操作系统) http://www.autolabor.com.cn/book/ROSTutorials/
  【Open3D】点云可视化 https://zhuanlan.zhihu.com/p/483414760
  https://github.com/isl-org/Open3D/issues/1110
    Ros_JPG_rosbag提取点云数据_pcd和图像数据_jpg https://www.cnblogs.com/ytwang/p/16087709.html
posted @ 2022-11-24 19:27  辰令  阅读(579)  评论(0编辑  收藏  举报