相机的位姿在地固坐标系ECEF和ENU坐标系的转换

在地球科学和导航领域,通常使用地心地固坐标系(ECEF,Earth-Centered, Earth-Fixed)和东北天坐标系(ENU,East-North-Up)来描述地球上的位置和姿态。如下图所示:

​地心地固坐标ecef和东北天ENU坐标系

在倾斜摄影测量过程中,通常涉及这两个坐标系的转换,将相机的位姿互转,如果你已经有了相机在地心地固坐标系(ECEF)中的位置 Xecef_cam 和相机的姿态旋转矩阵 R,你可以通过以下步骤将它们转换到东北天坐标系(ENU):

1、计算相机位置在ENU坐标系中的坐标:

首先,将相机位置从ECEF坐标系转换为ENU坐标系。ENU坐标系是相对于参考点的局部坐标系,所以需要提供一个参考点的位置,通常使用地理坐标经纬高来表示。假设你有一个参考点的ECEF坐标为 Xecef_ref。那么,相机位置在ENU坐标系中的坐标 Xenu_cam 可以通过以下方式计算: dXecef = Xecef_cam - Xecef_ref

Xenu_cam = R_ref.T * dXecef

这里,dXecef 是相机位置相对于参考点的ECEF坐标的差值,R_ref.T 是参考点的旋转矩阵的转置,R_ref可以通过计算参考点的经纬度得到,具体形式如下

# 参考点的经纬度
lon = 114.676720
lat = 37.746420
alt = 0  # 参考点的海拔高度(单位:米)
rclat, rclng = np.radians(lat), np.radians(lon) 
rot_ECEF2ENUV = np.array([[-math.sin(rclng),                math.cos(rclng),                              0],[-math.sin(rclat)*math.cos(rclng), -math.sin(rclat)*math.sin(rclng), math.cos(rclat)],[math.cos(rclat)*math.cos(rclng),  math.cos(rclat)*math.sin(rclng),  math.sin(rclat)]])

2、计算相机的ENU坐标系中的姿态:

在ENU坐标系中,相机的姿态表示通常使用方向余弦矩阵(DCM,Direction Cosine Matrix)来表示。DCM可以通过以下方式计算:

DCM_enu = R * R_ref.T

这里,R_ref.T 是参考点的旋转矩阵的转置,同上。 通过这两个步骤,你就可以将相机的位置和姿态从ECEF坐标系转换到ENU坐标系中了。记得要确保使用相同的坐标单位和姿态表示方式。值得注意的是,ENU坐标系是一个局部坐标系,所以转换结果依赖于参考点的选择。

下面是一个Python代码示例

import numpy as np
import mathdef geodetic_to_ecef(lon, lat, alt):a = 6378137.0  # 地球的半长轴(赤道半径,单位:米)f = 1 / 298.257223563  # 扁率lon_rad = np.radians(lon)lat_rad = np.radians(lat)N = a / np.sqrt(1 - (f * (2 - f)) * np.sin(lat_rad)**2)x = (N + alt) * np.cos(lat_rad) * np.cos(lon_rad)y = (N + alt) * np.cos(lat_rad) * np.sin(lon_rad)z = (N * (1 - f)**2 + alt) * np.sin(lat_rad)return np.array([x, y, z])#已知的地固坐标系下的位置和姿态
ecef_x= -2108290.78524083 
ecef_y= 4588675.69211609 
ecef_z= 3883213.009044
#R
ecef_matrix = np.array([[-0.924619168850922, -0.37082528979597, -0.0869942356778073],[0.192895998529247, -0.258938143907446, -0.946436564900771],[0.328436487535772, -0.891874229966031, 0.310949885958594]])# 为了验证的enu坐标系下的正确位置和姿态
enu_x = -5.25326294611772 
enu_y = -88.1162361244917
enu_z = 91.8780135626621			
enu_matrix = np.array([[0.994999772929298, -0.0988252823926444, -0.0144573659655384],[-0.067174196729575, -0.555035783385474,-0.829109707128924],[0.0739126454971252, 0.825935132272315, -0.55889898739748]])# 参考点的经纬度
lon = 114.676720
lat = 37.746420
alt = 0  # 参考点的海拔高度(单位:米)
rclat, rclng = np.radians(lat), np.radians(lon) 
#R_ref
rot_ECEF2ENUV = np.array([[-math.sin(rclng),                math.cos(rclng),                              0],[-math.sin(rclat)*math.cos(rclng), -math.sin(rclat)*math.sin(rclng), math.cos(rclat)],[math.cos(rclat)*math.cos(rclng),  math.cos(rclat)*math.sin(rclng),  math.sin(rclat)]])# 计算参考点的ECEF坐标
Xecef_ref = geodetic_to_ecef(lon, lat, alt)
print('参考点位置-地固坐标系')
print(Xecef_ref)
print('\n')# 相机位置在ECEF坐标系中
Xecef_cam = np.array([ecef_x, ecef_y, ecef_z])  # 计算相机位置在ENU坐标系中的坐标
dXecef = Xecef_cam - Xecef_ref
print('dXecef')
print(dXecef)
print('\n')#Xenu_cam = np.dot(ecef_matrix.T, dXecef)
Xenu_cam = np.dot(dXecef, rot_ECEF2ENUV.T)
print('相机在ENU坐标中的位置')
print(Xenu_cam)
print('\n')# 计算相机的ENU坐标系中的姿态
DCM_enu = np.dot(ecef_matrix, rot_ECEF2ENUV.T)
print('相机在ENU坐标中姿态')
print(DCM_enu)
print('\n')

运行结果

# 正确的位置和姿态

enu_x =-5.25326294611772

enu_y =-88.1162361244917

enu_z =91.8780135626621

enu_matrix = np.array([[0.994999772929298,-0.0988252823926444,-0.0144573659655384],[-0.067174196729575,-0.555035783385474,-0.829109707128924],[0.0739126454971252,0.825935132272315,-0.55889898739748]])

可以看到,转换正确

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/42586.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux内核的两种安全策略:基于inode的安全与基于文件路径的安全

实现系统安全的策略 在Linux中,一切且为文件,实现系统安全的策略主要可分为两种:基于inode的安全、基于文件路径的安全。 基于inode的安全 为文件引入安全属性,安全属性不属于文件内容,它是文件的元数据&#xff0c…

EV PV AC SPI CPI TCPI

SPI EV / PV CPI EV / ACCPI 1.25 SPI 0.8 PV 10 000 BAC 100 000EV PV * SPI 10 000 * 0.8 8000 AC EV / CPI 8000 / 1.25 6400TCPI (BAC - EV) / (BAC -AC) (100 000 - 8 000) / (100 000 - 6 400) 92 000 / 93 600 0.98290598

RabbitMQ面试题

1. 什么是MQ MQ 就是消息队列。是软件和软件进行通信的中间件产品 2. MQ的优点 异步处理 - 相比于传统的串行、并行方式,提高了系统吞吐量。 应用解耦 - 系统间通过消息通信,不用关心其他系统的处理。 流量削锋 - 可以通过消息队列长度控制请求量…

Selenium webdriver_manager根据浏览器版本自动下载对应驱动程序

前言 webdriver_manager是什么? webdriver_manager 是 Python 中的一个库,用于管理 Web 驱动程序。它的作用是自动下载和设置不同浏览器(如 Chrome、Firefox、Edge 等)的 Web 驱动程序,以便在自动化测试中使用这些浏…

每日一题:leetcode1338 3n块披萨

给你一个披萨,它由 3n 块不同大小的部分组成,现在你和你的朋友们需要按照如下规则来分披萨: 你挑选 任意 一块披萨。Alice 将会挑选你所选择的披萨逆时针方向的下一块披萨。Bob 将会挑选你所选择的披萨顺时针方向的下一块披萨。重复上述过程…

SCSS 学习笔记 和 vscode下载live sass compiler插件配置

1、下载livelive sass compiler插件并配置 // 在 已有代码 下面 添加下面 代码,一般刚刚下载打开最后一行是:// "liveSassCompile.settings.autoprefix": [],// 所以直接 把下面复制进去保存就行"liveSassCompile.settings.autoprefix&qu…

MySQL:在MySQL中实现toStartOfQuarter和toStartOfWeek等函数

文章目录 在 MySQL 中实现 ClickHouse 日期函数:toStartOfYear/toStartOfQuarter/toStartOfMonth/toMonday/toStartOfWeektoStartOfYeartoStartOfQuartertoStartOfMonthtoStartOfWeek/toMonday 在 MySQL 中实现 ClickHouse 日期函数:toStartOfYear/toSta…

基于Java+SpringBoot+Vue的乌鲁木齐南山冰雪旅游服务网站【源码+论文+演示视频+包运行成功】

博主介绍:✌csdn特邀作者、博客专家、java领域优质创作者、博客之星,擅长Java、微信小程序、Python、Android等技术,专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推…

MVCC 是否彻底解决了事物的隔离性 ?

目录 1. 什么是 MVCC 2. MVCC 是否彻底解决了事物的隔离性 3. MySQL 中如何实现共享锁和排他锁 4. MySQL 中如何实现悲观锁和乐观锁 1. 什么是 MVCC MVCC(Multi-Version Concurrency Control,多版本并发控制)是一种多版本并发控制机制&…

webpack 和 ts 简单配置及使用

如何使用webpack 与 ts结合使用 新建项目 ,执行项目初始化 npm init -y会生成 {"name": "tsdemo01","version": "1.0.0","description": "","main": "index.js","scripts&…

Spring的ApplicationEvent简单使用

ApplicationEvent以及Listener是Spring为我们提供的一个事件监听、订阅的实现,内部实现原理是观察者设计模式,设计初衷也是为了系统业务逻辑之间的解耦,提高可扩展性以及可维护性。事件发布者并不需要考虑谁去监听,监听具体的实现…

自动驾驶数据集汇总

1.Nuscenes 数据集链接:nuScenes nuscenes数据集下有多个任务,涉及Detection(2D/3D)、Tracking、prediction、激光雷达分割、全景任务、规划控制等多个任务; nuScenes数据集是一个具有三维目标注释的大型自动驾驶数…

【ARM 嵌入式 编译系列 10.3 -- GNU elfutils 工具小结】

文章目录 什么是 GNU elfutils?GNU elfutils 常用工具有哪些?objcopy 常用参数有哪些?GNU binutils和GNU elfutils区别是什么?上篇文章:ARM 嵌入式 编译系列 10.2 – 符号表与可执行程序分离详细讲解 什么是 GNU elfutils? GNU elfutils是一个开源的工具集,用于处理ELF…

2023-8-15差分矩阵

题目链接&#xff1a;差分矩阵 #include <iostream>using namespace std;const int N 1010;int n, m, q; int a[N][N], b[N][N];void insert(int x1, int y1, int x2, int y2, int c) {b[x1][y1] c;b[x1][y2 1] - c;b[x2 1][y1] - c;b[x2 1][y2 1] c; }int main…

基于SOLIDWORKS配置功能建立塑料模具标准件库

在塑料模具的设计过程中&#xff0c;建立其三维模型对于后续进行CAE分析和CAM加工是非常重要的。除了型腔和型芯以外&#xff0c;塑料模具中的标准件很多&#xff0c;如推杆、导柱、导套、推板、限位钉等&#xff0c;这些对于不同的产品是需要反复调用的。目前&#xff0c;我国…

汽车OTA活动高质量发展的“常”与“新”

伴随着车主的频繁崔更&#xff0c;车企除了卷硬件、拼价格&#xff0c;逐渐将精力转移到汽车全生命周期的常用常新。时至下半年&#xff0c;车企OTA圈愈发热闹&#xff0c;以新势力、新实力为代表新一代车企&#xff0c;OTA运营活动逐渐进入高质量发展期。 所谓高质量&#xf…

记录--webpack和vite原理

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 前言 每次用vite创建项目秒建好&#xff0c;前几天用vue-cli创建了一个项目&#xff0c;足足等了我一分钟&#xff0c;那为什么用 vite 比 webpack 要快呢&#xff0c;这篇文章带你梳理清楚它们的原理…

FFmpeg 静态库编译错误汇总

今天使用静态库编译发现 了错误 这个只有在arm64 的编译上 存在 。armeabi-v7a不存在问题 ld: error: relocation R_AARCH64_ADD_ABS_LO12_NC cannot be used against symbol ff_cos_16384; recompile with -fPIC 解决方案列举汇总 有很多 大家如果有同样的问题可以一一测试。…

c++ 虚函数

虚函数的作用就是当一个类继承另一个类时&#xff0c;两个类有同名函数&#xff0c;当你使用指针调用时你希望使用子类的函数而不是父类的函数&#xff0c;那么请使用 virutal 和 override 关键词 看代码&#xff1a; #include <iostream> #include <string> #in…

Kotlin开发笔记:集合和逆变协变

Kotlin开发笔记&#xff1a;集合和逆变协变 Kotlin中的集合 基本的集合类型 Kotlin中的集合类型和Java差不多&#xff0c;不过有些在名称上可能有出入&#xff0c;下面是Kotlin中的一些基本集合类型&#xff1a; 类型介绍Pair两个值的元组Triple三个值的元组Array经过索引的…