内容: 关于雷达和相机外参联合标定的踩坑纪录。

Date: 2023/03/19

硬件:

  • 上位机: Jetson ORIN (Ubuntu 20.04, ROS noetic)
  • 雷达: Ouster 32线
  • 相机: Intel D435

一、 标定方案

目前流行的 雷达+相机 标定方案有五种:Autoware, apollo, lidar_camera_calibration, but_velodyne。

Ubuntu20.04安装autoware我看bug比较多,因此我follow的是: https://github.com/ankitdhall/lidar_camera_calibration

1.1 opencv

这一步花了我一天时间,坑比较多,需要安装opencv_contrib才能进行进一步的操作,仅仅安装opencv是不行的!

我安的版本是3.4.10。

参考:

  • https://blog.csdn.net/m0_73694897/article/details/129175515?spm=1001.2014.3001.5506
  • https://blog.csdn.net/weixin_34910922/article/details/125248118?spm=1001.2014.3001.5506

二、 时间强行同步

直接实时或者直接播包的话就会发生: 只有mono8这一个窗口,没有其他窗口弹出!

  • Only Mono8 window visible · Issue #94 · ankitdhall/lidar_camera_calibration
  • https://github.com/ankitdhall/lidar_camera_calibration/issues/65
  • https://github.com/ankitdhall/lidar_camera_calibration/issues/53

因为车是静止的,如果时间戳不完全一致,标定的程序是无法弹出点云窗口的,这个bug困扰了我很久,在issues中也没找到也没有人能给出解决方案,于是我把时间戳都强行设置到1970年,解决。

#!/usr/bin/env python3import rospy
import rosbag
import sysif sys.getdefaultencoding() != 'utf-8':reload(sys)sys.setdefaultencoding('utf-8')
bag_name = 'subset_2023-03-19-15-52-03.bag' #被修改的bag名
out_bag_name = 'change.bag' #修改后的bag名
dst_dir = '/aigo/' #使用路径with rosbag.Bag(dst_dir+out_bag_name, 'w') as outbag:stamp = None#topic:就是发布的topic msg:该topic在当前时间点下的message t:消息记录时间(非header)##read_messages内可以指定的某个topicfor topic, msg, t in rosbag.Bag(dst_dir+bag_name).read_messages():if topic == '/ouster/points':stamp = msg.header.stamp# print("imu")#print(stamp)outbag.write(topic, msg, stamp)#针对没有header的文件,使用上面帧数最高的topic(即:/gps)的时间戳##因为read_messages是逐时间读取,所以该方法可以使用elif topic == '/camera/color/image_raw' and stamp is not None: #print("lidar")#print(msg.header.stamp)outbag.write(topic, msg, stamp)#    continue# #针对格式为Header的topicelif topic == '/camera/depth/image_rect_raw' and stamp is not None:#print("image")#print(msg.header.stamp)outbag.write(topic, msg, stamp)#     outbag.write(topic, msg, msg.stamp)#     continue# #针对一般topic#outbag.write(topic, msg, msg.header.stamp)print("finished")
  • 前:

  • 后:

三、 标定

我用的雷达是32线的,我修改了/home/nvidia/wuke/a2b_ws/src/lidar_camera_calibration/include/lidar_camera_calibration/PreprocessUtils.h:

// line 200
// std::vector <std::vector<myPointXYZRID *>> rings(16);
std::vector <std::vector<myPointXYZRID *>> rings(32);
  • 播包:
roscorecd /aigo/
rosbag play -l --clock change.bag
  • 标定:
cd ~/wuke/a2b_ws
source devel/setup.bashroslaunch lidar_camera_calibration find_transform.launch

四、 标定结果

--------------------------------------------------------------------
After 40 iterations
--------------------------------------------------------------------
Average translation is:
0.00659326-0.241034-0.113246
Average rotation is:0.901867 0.00575031   0.431975
-0.0142371   0.999764  0.0164154-0.431778 -0.0209546   0.901736
Average transformation is: 0.901867 0.00575031   0.431975 0.00659326
-0.0142371   0.999764  0.0164154  -0.241034-0.431778 -0.0209546   0.901736  -0.1132460          0          0          1
Final rotation is:0.0174841   -0.999826 -0.006546440.0208512  0.00691063   -0.9997590.99963   0.0173434   0.0209684
Final ypr is:
0.873007
-1.543580.69106
Average RMSE is: 0.0291125
RMSE on average transformation is: 0.0298826

4.1 将雷达点云投影到相机坐标系

上面的位姿变换是从雷达坐标系到相机坐标系的变换。

我打算把雷达点云变换到相机坐标系下然后和深度图对比,看重叠效果咋样:

  • 将D435的深度图变成点云:

    #include <ros/ros.h>
    #include <cv_bridge/cv_bridge.h>
    #include <sensor_msgs/Image.h>
    #include <sensor_msgs/CameraInfo.h>
    #include <sensor_msgs/PointCloud2.h>
    #include <pcl_conversions/pcl_conversions.h>
    #include <pcl/point_types.h>
    #include <pcl/PCLPointCloud2.h>
    #include <pcl/conversions.h>
    #include <iostream>
    using namespace std;ros::Publisher pub_point_cloud2;bool is_K_empty = 1;
    double K[9];
    //     [fx  0 cx]
    // K = [ 0 fy cy]
    //     [ 0  0  1]void img_callback(const sensor_msgs::ImageConstPtr &img_msg)
    {// Step1: 读取深度图//ROS_INFO("image format: %s %dx%d", img_msg->encoding.c_str(), img_msg->height, img_msg->width);int height = img_msg->height;int width = img_msg->width;// 通过指针强制转换,读取为16UC1数据,单位是mmunsigned short *depth_data = (unsigned short*)&img_msg->data[0];// Step2: 深度图转点云sensor_msgs::PointCloud2 point_cloud2;pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);for(int uy=0; uy<height; uy++){for(int ux=0; ux<width; ux++){float x, y, z;z = *(depth_data + uy*width + ux) / 1000.0;if(z!=0){x = z * (ux - K[2]) / K[0];y = z * (uy - K[5]) / K[4];pcl::PointXYZ p(x, y, z);cloud->push_back(p);}}}// Step3: 发布点云pcl::toROSMsg(*cloud, point_cloud2);point_cloud2.header.frame_id = "world";pub_point_cloud2.publish(point_cloud2);
    }void camera_info_callback(const sensor_msgs::CameraInfoConstPtr &camera_info_msg)
    {// 读取相机参数if(is_K_empty){for(int i=0; i<9; i++){K[i] = camera_info_msg->K[i];}is_K_empty = 0;}
    }int main(int argc, char **argv)
    {ros::init(argc, argv, "ros_tutorial_node");ros::NodeHandle n;// 订阅D435i的深度图,在其回调函数中把深度图转化为点云,并发布出来ros::Subscriber sub_img = n.subscribe("/camera/depth/image_rect_raw", 100, img_callback);// 订阅D435i的深度相机参数ros::Subscriber sub_cmara_info = n.subscribe("/camera/depth/camera_info", 1, camera_info_callback);pub_point_cloud2 = n.advertise<sensor_msgs::PointCloud2>("/d435i_point_cloud", 1000);ROS_INFO("Runing ...");ros::spin();return 0;
    }
    
  • 发布tf变换消息:

    rosrun tf2_ros static_transform_publisher 0 0 0 1.57 -1.57 0 world os_sensor
    
  • result:

    • raw

    • after (红色是雷达点云,白色是深度相机的投影)

Reference

[1] https://github.com/ankitdhall/lidar_camera_calibration/wiki/Welcome-to-%60lidar_camera_calibration%60-Wiki!

[2] 3D雷达与相机的标定方法详细教程_lidar_camera_calibration_敢敢のwings的博客-CSDN博客

[3] https://blog.csdn.net/m0_73694897/article/details/129175515?spm=1001.2014.3001.5506

[4] https://blog.csdn.net/weixin_34910922/article/details/125248118?spm=1001.2014.3001.5506

[5] https://blog.csdn.net/weixin_42840360/article/details/119844648?spm=1001.2014.3001.5506

[6] https://blog.csdn.net/Jeff_zjf/article/details/124255916?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522167922032616800213053412%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=167922032616800213053412&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_ecpm_v1~pc_rank_34-1-124255916-null-null.142

相机和雷达外参联合标定相关推荐

  1. 二十一.激光、视觉和惯导LVIO-SLAM框架学习之相机与雷达外参标定(1)

    专栏系列文章如下: 一:Tixiao Shan最新力作LVI-SAM(Lio-SAM+Vins-Mono),基于视觉-激光-惯导里程计的SLAM框架,环境搭建和跑通过程_goldqiu的博客-CSDN ...

  2. 针对高分辨率雷达和相机的无标定板的像素级外参自标定方法

    介绍:固态激光雷达和相机的外参标定系统 摘要 这是今年的一篇针对高分辨率的固态激光雷达(非重复性扫描型)或者多线的激光雷达和相机在无标定板的环境中自动化外参标定的一篇文章.本文的方法不需要基于巧克力板 ...

  3. imu相机标定_解放双手——相机与IMU外参的在线标定

    本文作者 沈玥伶,公众号:计算机视觉life,编辑部成员 一.相机与IMU的融合 在SLAM的众多传感器解决方案中,相机与IMU的融合被认为具有很大的潜力实现低成本且高精度的定位与建图.这是因为这两个 ...

  4. Ubuntu16.04 在ROS中配置RealSence D435 并标定深度相机与rplidar外参

    Ubuntu16.04系统,在ROS中配置RealSence D435 ,并标定其与rplidar的外参 主要目的是为rplidar标定深度相机外参,为机器人导航的过程提供障碍物识别的功能,因此需要知 ...

  5. mynt product model: D1000-IR-120标定相机和IMU外参之二

    1. 在之一中使用kalibr标定mynt相机和内置imu的外参数,使用的是720p,30fps的双目图像和200hz的imu数据,标定结果误差比较大,这一次我们改用480p,60hz的双目图像和20 ...

  6. 小觅相机 相机以及IMU外参标定

    最近在使用IMU和双目相机进行相关VIO算法的测试,首先要对IMU和相机的外参进行标定,本文主要是对标定过程做一个全面的记录,方便总结和讨论.测试中采用的是小觅双目模组标准版S1030-IR-120/ ...

  7. ros --- 双目相机内参与外参标定

    ros --- 双目相机内参与外参标定 小觅相机直接获取参数 手动重新标定 1. 双目相机内外参标定 生成标定板 录制 stereo_calibra.bag 标定 标定结果 标定验证 2. 双目 + ...

  8. IROS2020开源软硬件!多激光雷达的协同定位建图及在线外参自标定

    点击上方"3D视觉工坊",选择"星标" 干货第一时间送达 本文由作者林家荣授权转载,二次转载请联系作者 https://zhuanlan.zhihu.com/p ...

  9. VINS 外参在线标定

    在VINS中相机的外参RicR_{ic}Ric​是可以在线动态标定的,实现函数为: /*** @brief 外参在线标定* * @param corres 两帧图像之间的共视特征点* @param d ...

最新文章

  1. 托马斯·弗里德曼:美政府应研究任正非的提议
  2. 三次简化一张图:一招理解LSTM/GRU门控机制
  3. linux远程访问及控制
  4. payara 创建 集群_Apache Payara:让我们加密
  5. Spring框架中的内容协商
  6. 【超级鼠标键盘锁】项目工程下载地址
  7. 2018高职计算机474分排名,2018年高职分类考试招生录取分数线出炉
  8. 2017.9.6 Robot 失败总结
  9. C++学习笔记(11) 重载流插入运算符和流提取运算符,以及自动类型转换
  10. python文件同时读写_python 同时读取多个文件的例子
  11. 保护私有信息的叉积协议及其应用 in c
  12. 找不到工作?女生转行学IT到底靠不靠谱!
  13. 独家解读 | 2018 恶意机器流量报告
  14. idea常用的搜索方式
  15. oracle的权限授予,oracle权限命令
  16. IT:如何把骨干留住
  17. 性能和稳定性测试报告模板
  18. 结巴分词有前空格_jieba英文空格分词问题
  19. word插入和删除水印
  20. 顺序栈的实现和两栈共享空间

热门文章

  1. 使用 mesh 实现多边形裁剪图片!Cocos Creator!
  2. STM32复习笔记(五) —— GPIO锁定机制
  3. GHGL项目-其他问题锦集
  4. re正则表达式必备基础知识
  5. 双一次算法作业hhhhhhhhh
  6. 80后最牛的辞职信+出师表
  7. stimulsoft mysql_Stimulsoft Server
  8. c语言三种循环结构特点,c语言循环结构(c语言循环结构特点)
  9. 网站维护怎么做?网站维护内容有哪些
  10. Mask RCNN 实战(二)--像黑镜一样屏蔽图片和视频中的人和物体