赞
踩
首先,需要开雷达驱动和相机驱动,然后检查雷达话题和相机话题,我的是rslidar_points和usb_cam/image_raw,然后使用录制指令,需要将雷达和相机话题更换为你自己的。
rosbag record /rslidar_points /usb_cam/image_raw
需要注意激光雷达和相机的采样频率不一样,导致点云和图像不能帧间匹配,网上有很多方法,1、使用GPS对时间进行硬同步。2、可以使用抽帧的方法进行时间软同步。
解决时间同步的问题很简单,我用了一个很笨的办法,我使用rosbag实现“拍照”的效果。即对每一次标定板的姿态录一个bag包,取点云和图像的第一帧,从而达到点云和图像匹配的效果。
对标定板每个姿态录了包之后用下面的代码将rosbag转换为img和pcd的格式,从而实现了一对点云-图像对,重复上述操作,。就能得到n对点云-图像对。
代码使用教程:创建文件夹,在文件夹下创建extract_bag.py文件和data文件夹,将下面的代码填充进extract_bag.py;在data文件夹下面创建images和pointclouds文件夹,用来保存提取的点云图像。需要修改的地方有话题,bag路径,提取bag里的点云和图像的保存路径。
- #! /usr/bin/python
- # coding=utf-8
-
- import os
- import rosbag
- import cv2
- from cv_bridge import CvBridge
- from tqdm import tqdm
-
- class ExtractBagData(object):
-
- def __init__(self, bagfile_path, camera_topic, pointcloud_topic, root):
- self.bagfile_path = bagfile_path
- self.camera_topic = camera_topic
- self.pointcloud_topic = pointcloud_topic
- self.root = root
- self.image_dir = os.path.join(root, "images")
- self.pointcloud_dir = os.path.join(root, "pointcloud")
-
- #创建提取图片和点云的目录 ./root/images root/pointcloud
- if not os.path.exists(self.image_dir):
- os.makedirs(self.image_dir)
- if not os.path.exists(self.pointcloud_dir):
- os.makedirs(self.pointcloud_dir)
-
- def extract_camera_topic(self):
- bag = rosbag.Bag(self.bagfile_path, "r")
- bridge = CvBridge()
- bag_data_imgs = bag.read_messages(self.camera_topic)
-
- index = 0
-
- pbar = tqdm(bag_data_imgs)
- for topic, msg, t in pbar: # type: ignore
- pbar.set_description("Processing extract image id: %s" % (index+1))
- cv_image = bridge.imgmsg_to_cv2(msg, "bgr8")
- # 如果你需要使用时间戳对提取的图片命名,可以使用msg.header.stamp.to_sec()获取时间戳
- timestr = "%.6f" % msg.header.stamp.to_sec()
- cv2.imwrite(os.path.join(self.image_dir, str(timestr) + ".jpg"), cv_image) # type: ignore
- index += 1
-
- def extract_pointcloud_topic(self):
- '''
- # 提取点云数据为pcd后缀文件,默认提取以为时间戳命名
- # 提取命令:rosrun pcl_ros bag_to_pcd result.bag /velodyne_points ./pointcloud
- # 提取点云以时间戳命令:1616554905.476288682.pcd
- :return:
- '''
- cmd = "rosrun pcl_ros bag_to_pcd %s /rslidar_points %s" % (self.bagfile_path, self.pointcloud_dir)
- os.system(cmd)
-
- # 再读取提取的pcd点云数据,把文件名修改为按照顺序索引名
- #pcd_files_list = os.listdir(self.pointcloud_dir)
- # 因为提取的pcd是以时间戳命令的,但是存放到列表中并不是按照时间戳从小到大排列,这里对时间戳进行重新排序
- #pcd_files_list_sorted = sorted(pcd_files_list)
- # print(zip(pcd_files_list, pcd_files_list_sorted))
-
- #index = 0
- #pbar = tqdm(pcd_files_list_sorted)
- #for pcd_file in pbar:
- # pbar.set_description("Processing extract poindcloud id: %s" % (index + 1))
- # os.rename(os.path.join(self.pointcloud_dir, pcd_file),
- # os.path.join(self.pointcloud_dir, str(index) + ".pcd"))
- # print("pcd_file name: ", pcd_file)
- # index += 5
-
- if __name__ == '__main__':
- #需要处理的bag包的路径
- bagfile_path = '/media/happy406/046dcd53-ee66-4d3b-b556-5f9559acab84/0508/55.bag'
- camera_topic = "/usb_cam/image_raw"
- pointcloud_topic = "/rslidar_points"
- #将bag转换为pcd和jpg格式的保存路径
- extract_bag = ExtractBagData(bagfile_path, camera_topic, pointcloud_topic, "/media/happy406/046dcd53-ee66-4d3b-b556-5f9559acab84/0508")
- extract_bag.extract_camera_topic()
- extract_bag.extract_pointcloud_topic()
-
标定工具重点项讲解:
Open Session:打开保存过的会话
Import:导入点云-图像对
Compute Intrinsic:导入数据后自动计算相机内参
Use Fixed Intrisic:使用修正后的相机内参,这项可以通过matlab的相机标定工具来标定,然后将内参导出至matlab工作区,再导入到联合标定工具中。一般来说,可以直接使用联合标定工具计算的内参。
Edit ROI:感兴趣区域的选择,这一步可以不做更改
Select Checkboard:选择棋盘格,导入数据后会有很多不符合要求的图像点云对,此时需要手动选择棋盘格,相当于告诉标定工具,棋盘格在哪。(这一步尤为关键!!)
Cluster Threshold:聚类阈值
Dimension Tolerance:尺寸误差容忍度,设置为0.2。容忍度越高,被接受的数据越多,但是过大的容忍度也会导致后续标定误差过大
Detect:检测数据是否能被检测到棋盘格。
Calibrate:开始标定。
(1)导入数据,Square size是标定板的每格的长宽大小。
(2)导入后没有任何可接受的数据,这时需要调整聚类阈值和误差容忍度。
(3)选择棋盘格,一张一张的选择标定板,弄完后,apply,再detect一下,检查有多少数据被接受。标完后最好save session,不然等下筛选标定数据后又要重新选择棋盘格,会很麻烦。
我因为标定板比较小,激光雷达扫描效果不好,所以录了比较多的数据。如果标定板大的话可以少录一点。
4、标定
一开始误差特别大
点击柱状线,或者拖动离群值可以选择抛弃的数据。最好一个个的删除误差比较大的数据,因为删除一个数据都可能导致整个误差有很大的波动。优先删除重投影大的数据同时旋转误差大的数据,没有这类数据就删除重投影误差大的数据。
如果数据删的都快没了。或者变得太大,那需要重新调整,打开刚才保存的session,继续标定,然后重复刚才的动作,一遍一遍地调整,直到误差在10左右。(这一步最关键,一定要有耐心!!)
如果误差比较小了,就检查棋盘格是否完好的投在了图像上,如果基本贴合图像且误差较小,就可以直接导出标定数据了。
导入到工作区,这样就得到了我的标定数据,matlab给的是转置矩阵,使用时需转置后使用。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。