当前位置: 首页 > news >正文

如何将LiDAR坐标系下的3D点投影到相机2D图像上

将激光雷达点云投影到相机图像上做数据层的前融合,或者把激光雷达坐标系下标注的物体点云的3d bbox投影到相机图像上画出来,都需要做点云3D点坐标到图像像素坐标的转换计算,也就是LiDAR 3D坐标转像素坐标。

看了网上一些文章都存在有错误或者把公式推导说的含混不清有误导人的地方(如果你完全按那些列出来的公式去计算,发现投影结果在图像上怎么都不对!),在此结合我经过验证是正确的代码详细解释一下,也供备忘,插图是对网上的原图做了正确修改的。

对于普通无畸变平面相机,坐标转换涉及到的主要是两个参数矩阵:用于激光雷达坐标系到相机坐标系转换的外参矩阵和用于相机坐标系到像素坐标系转换的相机本身的内参矩阵。

针孔相机模型下,相机坐标系下的三维空间中点P(X,Y,Z),对应在相机成像平面的图像坐标系(注意不是像素坐标系!)中的坐标点是p(x,y),焦距f是焦点到成像平面之间的距离,Z是P点到焦点的距离。

 根据相似三角形原理,有:

 由此可得,根据相机坐标系下的坐标(X,Y,Z)计算相机图像坐标系下的坐标(x,y)的计算公式:

注意,此处的x、y、f都是实际空间尺寸,单位一般是mm,如果将等式两边都除以图像每像素对应的实际尺寸,等式仍然成立,此时的x、y、和f就都是像素了,所以我们平时看到的数据集里camera的焦距值都是像素值,正是我们计算像素为单位的x和y所需的,然后,因为把图像坐标坐标系下的像素为单位的坐标(x,y)转像素坐标系下的坐标(u,v),只需加上图像横纵方向各自的偏移量cx和cy即可(因为图像坐标系的原点是在图像的中央,而像素坐标系的原点是在图像的左上顶点),另外相机的纵横方向的焦距稍有差异,不是同一个f值,所以还区分为fx和fy,至此,稍做推导可以得出相机坐标系下的坐标P(X,Y,Z)转换为图像上的像素坐标的计算公式为:

整理成矩阵运算形式就是:

其中相机内参矩阵就是:

将激光雷达坐标系下的3D点坐标转换到相机图像上的像素坐标的过程就是先将激光雷达坐标系下的3D坐标(Xw,Yw,Zw)(此处假设雷达不动或者我们只关注激光雷达坐标系下的坐标转换到像素坐标,(Xw,Yw,Zw)表示激光雷达坐标系下的坐标,此处的(Xw,Yw,Zw)不是激光雷达坐标而是导航用的世界坐标系下的坐标的话,下面的表示是错的,需要先用global2ego之类参数矩阵将坐标转换到雷达坐标系下),左乘以lidar2camera相机外参矩阵转换到相机坐标系下的3D坐标(Xc,Yc,Zc):

然后如上面所述使用相机本身的内参矩阵将相机坐标系下的3D坐标点转换到像素坐标系下的像素坐标,于是整个计算可以合并表示为(此处的fx、fy、Cx、Cy都是像素为单位的值!):

很多文章里列出连乘公式都漏了这个重要的 ,导致计算出来的像素坐标根本不对(把像素坐标点在图像上画出来看图像上的点投影效果比较直观),包括一些BEV模型的实现代码都犯了这个错误,效果能好才怪!这个转换关系(K是相机内参矩阵)要记住:

这里的Z就是相机坐标系下的3D坐标(Xc,Yc,Zc)的Zc,上面倒数第三个公式里也说明了。那么我们代码实现时,对于普通无畸变平面相机,非常简单,就是 (1/Z) X 相机的内参矩阵 X 相机的外参矩阵(lidar2camera),即可由激光雷达下的3D坐标计算出像素坐标系下的坐标,用我写的经过验证是正确的C++代码作为示例,借助Eigen库实现非常简单:

    Eigen::Vector4f pointVec;pointVec << point3D, 1.0;Eigen::Vector4f cam_point3D =  K * extrinK * pointVec;Eigen::Vector3f point = cam_point3D.head<3>();float x = point.x();float y = point.y();float z = point.z();if (z < 1e-6) {return;}int u = static_cast<int>(x / z);int v = static_cast<int>(y / z);

上面K是4x4奇次相机内参矩阵,extrinK是4x4奇次外参矩阵,算出来的部分u,v值有的可能超出了相机图像的范围,用图像的cols和rows最大值最小值过滤一下就可以了,对于BEV模型,投影到6个相机的图像上使用各个相机各自的内外参矩阵依次做上述计算即可。

对于有畸变的平面相机,则不能使用内参和外参矩阵连乘,而是需要先左乘以外参矩阵把点云3D坐标转到相机坐标系下的坐标(Xc,Yc,Zc)后,把Zc小于等于0的坐标过滤掉,然后需要把Xc和Yc除以Zc,得到未校正的相机坐标系下的2D坐标(Xc/Zc,Yc/Zc),然后根据相机厂家给出的计算公式使用相机的畸变系数对此2D坐标做校正得出校正后的坐标(X,Y),再将此坐标扩展为奇次坐标后转置再左乘以相机的3x3原始内参矩阵,得出像素坐标(u,v),可以参考相机标定之畸变矫正与反畸变计算 - 达达MFZ - 博客园这篇文章给出的去畸变算法的实现,代码如果借助Eigen矩阵运算,可以写得更简洁点,不过他这样写的好处就是比较容易看清楚。车载森云相机的去畸变就是这样的算法,我们借助Eigen库自己实现的代码涉及到商业秘密就不列出来了。

多说一点就是,根据上面的计算公式:

假设我们知道每个像素的深度值Zc的话,可以由下面的公式计算出图像里每个像素对应的相机坐标系下的3D点坐标(Xc,Yc,Zc) :

这就是LSS模型预测每像素的深度后获得对应的3D点坐标的计算原理,从而实现2D到3D的对应转换,进而Splat成BEV。

相关文章:

如何将LiDAR坐标系下的3D点投影到相机2D图像上

将激光雷达点云投影到相机图像上做数据层的前融合&#xff0c;或者把激光雷达坐标系下标注的物体点云的3d bbox投影到相机图像上画出来&#xff0c;都需要做点云3D点坐标到图像像素坐标的转换计算&#xff0c;也就是LiDAR 3D坐标转像素坐标。 看了网上一些文章都存在有错误或者…...

JAVA就业笔记6——第二阶段(3)

课程须知 A类知识&#xff1a;工作和面试常用&#xff0c;代码必须要手敲&#xff0c;需要掌握。 B类知识&#xff1a;面试会问道&#xff0c;工作不常用&#xff0c;代码不需要手敲&#xff0c;理解能正确表达即可。 C类知识&#xff1a;工作和面试不常用&#xff0c;代码不…...

02.04、分割链表

02.04、[中等] 分割链表 1、题目描述 给你一个链表的头节点 head 和一个特定值 x &#xff0c;请你对链表进行分隔&#xff0c;使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。 你不需要 保留 每个分区中各节点的初始相对位置。 2、解题思路 本题要求将链表分隔…...

Excel 中根据患者的就诊时间标记病例为“初诊”或“复诊”

1. 假设&#xff1a; 患者表&#xff1a;包含患者的基本信息&#xff0c;如患者 ID 和患者姓名。 病例表&#xff1a;包含病例信息&#xff0c;如患者 ID、就诊时间和就诊状态。 2. 操作步骤&#xff1a; 合并数据&#xff1a; 确保病例表中有一列包含患者 ID&#xff0c;以…...

遇到“mfc100u.dll丢失”的系统错误要怎么处理?科学修复mfc100u.dll

遇到“mfc100u.dll丢失”的系统错误会非常麻烦&#xff0c;因为mfc100u.dll是Microsoft Visual C 2010 Redistributable Package的重要部分&#xff0c;许多应用程序和游戏在运行时都需要调用这个文件。如果这个文件缺失&#xff0c;可能会导致相关软件或游戏启动失败。面对这种…...

[Linux] 逐层深入理解文件系统 (1)—— 进程操作文件

标题&#xff1a;[Linux] 文件系统 &#xff08;1&#xff09;—— 进程操作文件 个人主页水墨不写bug &#xff08;图片来源于网络&#xff09; 目录 一、进程与打开的文件 二、文件的系统调用与库函数的关系 1.系统调用open() 三、内存中的文件描述符表 四、缓冲区…...

RT-Thread 互斥量的概念

目录 概述 1 互斥量定义 1.1 概念介绍 1.2 线程优先级翻转问题 2 互斥量管理 2.1 结构体定义 2.2 函数接口介绍 2.2.1 rt_mutex_create函数 2.2.2 rt_mutex_delete 函数 2.2.3 初始化和脱离互斥量 概述 本文主要介绍互斥量的概念&#xff0c;实现原理。还介绍RT-Thre…...

6.计算机网络_UDP

UDP的主要特点&#xff1a; 无连接&#xff0c;发送数据之前不需要建立连接。不保证可靠交付。面向报文。应用层给UDP报文后&#xff0c;UDP并不会抽象为一个一个的字节&#xff0c;而是整个报文一起发送。没有拥塞控制。网络拥堵时&#xff0c;发送端并不会降低发送速率。可以…...

Windows应急响蓝安服面试

Windows应急响应 蓝队溯源流程 学习Windows应急首先要站在攻击者的角度去学习一些权限维持和权限提升的方法.,文章中的方法其实和内网攻防笔记有类似l红队教你怎么利用 蓝队教你怎么排查 攻防一体,应急响应排查这些项目就可以 端口/服务/进程/后门文件都是为了权限维持,得到s…...

PCL 点云配准-4PCS算法(粗配准)

目录 一、概述 1.1原理 1.2实现步骤 1.3应用场景 二、代码实现 2.1关键函数 2.1.1 加载点云数据 2.1.2 执行4PCS粗配准 2.1.3 可视化源点云、目标点云和配准结果 2.2完整代码 三、实现效果 3.1原始点云 3.2配准后点云 PCL点云算法汇总及实战案例汇总的目录地址链接…...

12、论文阅读:利用生成对抗网络实现无监督深度图像增强

Towards Unsupervised Deep Image Enhancement With Generative Adversarial Network 摘要介绍相关工作传统图像增强基于学习的图像增强 论文中提出的方法动机和目标网络架构损失函数1) 质量损失2) 保真损失3&#xff09;身份损失4&#xff09;Total Loss 实验 摘要 提高图像的…...

Axure重要元件三——中继器表单制作

亲爱的小伙伴&#xff0c;在您浏览之前&#xff0c;烦请关注一下&#xff0c;在此深表感谢&#xff01; 本节课&#xff1a;中继器表单制作 课程内容&#xff1a;利用中继器制作表单 应用场景&#xff1a;台账、表单 案例展示&#xff1a; 步骤一&#xff1a;建立一个背景区…...

DMAIC赋能智能家居:解锁未来生活新篇章!

从清晨自动拉开的窗帘&#xff0c;到夜晚自动调暗的灯光&#xff0c;每一处细节都透露着科技的温度与智慧的光芒。而在这场智能革命的浪潮中&#xff0c;DMAIC&#xff08;定义Define、测量Measure、分析Analyze、改进Improve、控制Control&#xff09;作为六西格玛管理的核心方…...

代码随想录算法训练营第二天| 209.长度最小的子数组 59.螺旋矩阵II 区间和 开发商购买土地

209. 长度最小的子数组 题目&#xff1a; 给定一个包含正整数的数组 nums 和一个正整数 target &#xff0c;找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 &#xff0c;并返回其长度。如果不存在符合条件的子数组&#xff0c;返回 0。 示例&#xff1a; 示例 1…...

mysql隐藏索引

1. 什么是隐藏索引&#xff1f; 在 MySQL 8 中&#xff0c;隐藏索引&#xff08;Invisible Indexes&#xff09;是指一种特殊类型的索引&#xff0c;它并不真正被删除&#xff0c;而是被标记为“不可见”。当索引被标记为不可见时&#xff0c;查询优化器在生成查询计划时将忽略…...

etcd入门到实战

概述&#xff1a;本文将介绍etcd特性、使用场景、基本原理以及Linux环境下的实战操作 入门 什么是etcd&#xff1f; etcd是一个分布式键值存储数据库 关键字解析&#xff1a; 键值存储&#xff1a;存储协议是 key—value 的形式&#xff0c;类似于redis分布式&#xff1a;…...

Build an Android project and get a `.apk` file on a Debian 11 command line

You can build an Android project and get a .apk file on a Debian 11 command line without using Android Studio. The process involves using the Android SDK command-line tools (sdkmanager, adb, and gradle). Here’s a step-by-step guide to building the ???…...

解读 Java 经典巨著《Effective Java》90条编程法则,第4条:通过私有构造器强化不可实例化的能力

文章目录 【前言】欢迎订阅【解读《Effective Java》】系列专栏java.lang.Math 类的设计经验总结 【前言】欢迎订阅【解读《Effective Java》】系列专栏 《Effective Java》是 Java 开发领域的经典著作&#xff0c;作者 Joshua Bloch 以丰富的经验和深入的知识&#xff0c;全面…...

Vivado HLS学习

视频链接: 6课&#xff1a;数据类型的转换_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1bt41187RW?spm_id_from333.788.videopod.episodes&vd_sourcea75d5585c5297210add71187236ec90b&p6 目录 1.数据类型的转换 2.自动类型转换 2.1隐式数据转换 2.2…...

一款AutoXJS现代化美观的日志模块AxpLogger

简介 Axp Logger是一款基于autox.js的现代化日志模块&#xff0c;具备窗口事件穿透、拖拽和缩放功能。 Axp Logger文档 特性现代化的UI设计支持点击穿透模式&#xff08;不影响脚本运行&#xff09;监听音量-键切换模式支持窗口操作模式窗口拖拽移动窗口自由缩放清空日志关闭日…...

CTF show Web 红包题第六弹

提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框&#xff0c;很难让人不联想到SQL注入&#xff0c;但提示都说了不是SQL注入&#xff0c;所以就不往这方面想了 ​ 先查看一下网页源码&#xff0c;发现一段JavaScript代码&#xff0c;有一个关键类ctfs…...

AI Agent与Agentic AI:原理、应用、挑战与未来展望

文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例&#xff1a;使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例&#xff1a;使用OpenAI GPT-3进…...

【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密

在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...

【决胜公务员考试】求职OMG——见面课测验1

2025最新版&#xff01;&#xff01;&#xff01;6.8截至答题&#xff0c;大家注意呀&#xff01; 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:&#xff08; B &#xff09; A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...

HTML前端开发:JavaScript 常用事件详解

作为前端开发的核心&#xff0c;JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例&#xff1a; 1. onclick - 点击事件 当元素被单击时触发&#xff08;左键点击&#xff09; button.onclick function() {alert("按钮被点击了&#xff01;&…...

vue3+vite项目中使用.env文件环境变量方法

vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量&#xff0c;这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...

Map相关知识

数据结构 二叉树 二叉树&#xff0c;顾名思义&#xff0c;每个节点最多有两个“叉”&#xff0c;也就是两个子节点&#xff0c;分别是左子 节点和右子节点。不过&#xff0c;二叉树并不要求每个节点都有两个子节点&#xff0c;有的节点只 有左子节点&#xff0c;有的节点只有…...

稳定币的深度剖析与展望

一、引言 在当今数字化浪潮席卷全球的时代&#xff0c;加密货币作为一种新兴的金融现象&#xff0c;正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而&#xff0c;加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下&#xff0c;稳定…...

Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)

在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马&#xff08;服务器方面的&#xff09;的原理&#xff0c;连接&#xff0c;以及各种木马及连接工具的分享 文件木马&#xff1a;https://w…...

sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!

简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求&#xff0c;并检查收到的响应。它以以下模式之一…...