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

相对位姿估计

相对位姿估计

示意图

在这里插入图片描述

理论推导

离线数据库:

P的位置 P = [ X , Y , Z ] T P=[X,Y,Z]^{T} P=[X,Y,Z]T

相机内参 k 1 k_{1} k1

安卓手机:

相机内参 k 2 k_{2} k2

两个像素点位置 p 1 和 p 2 p_1和p_2 p1p2

公式一:

s 1 p 1 = K 1 P s_1p_1=K_1P s1p1=K1P s 2 p 2 = K 2 ( R P + t ) s_2p_2=K_2(RP+t) s2p2=K2(RP+t)

**公式二:**归一化平面上的坐标

x 1 = K 1 − 1 p 1 x_1=K_1^{-1}p_1 x1=K11p1 x 2 = K 2 − 1 p 2 x_2=K_2^{-1}p2 x2=K21p2

公式三:

x 2 = R x 1 + t x_2=Rx_1+t x2=Rx1+t

公式四:

t ^ x 2 = t ^ R x 1 \hat{t}x_2=\hat{t}Rx_1 t^x2=t^Rx1

公式五

x 2 T t ^ x 2 = x 2 T t ^ R x 1 x_2^{T}\hat{t}x_2=x_2^{T}\hat{t}Rx_1 x2Tt^x2=x2Tt^Rx1

x 2 T t ^ R x 1 = 0 x_2^{T}\hat{t}Rx_1=0 x2Tt^Rx1=0

公式六:

( K 2 − 1 p 2 ) T t ^ R K 1 − 1 p 1 (K_2^{-1}p_2)^{T}\hat{t}RK_1^{-1}p_1 (K21p2)Tt^RK11p1

结论:

本质矩阵: E = t ^ R E=\hat{t}R E=t^R ---------------------已知相机参数的情况下

基础矩阵: F = K 2 − T E K 1 − 1 F=K_2^{-T}EK_1^{-1} F=K2TEK11 -----------未知相机参数的情况下

伪代码

input:image_src,k_src,image_dst,k_dst
output:R,t
1 feature_detect(image_src,image_dst)---->keypoints and deccriptors
2 feature_match(image_src,image_dst)---->matched_features
3 find_essentialmatrix(matched_keypoints,k_src,k_dst)----->essential_matrix
4 decompose_E(essentialmatrix)----->R,t
5 judge "left or right"

实现代码

import cv2
import numpy as npdef find_keypoints_and_descriptors(image):# 使用SIFT算法检测关键点和计算描述符sift = cv2.SIFT_create()keypoints, descriptors = sift.detectAndCompute(image, None)return keypoints, descriptorsdef match_keypoints(descriptors1, descriptors2):# 使用FLANN匹配器进行关键点匹配FLANN_INDEX_KDTREE = 0index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5)search_params = dict(checks=50)flann = cv2.FlannBasedMatcher(index_params, search_params)matches = flann.knnMatch(descriptors1, descriptors2, k=2)# 保留良好的匹配good_matches = []for m, n in matches:if m.distance < 0.7 * n.distance:good_matches.append(m)return good_matchesdef estimate_relative_pose(keypoints1, keypoints2, good_matches, camera_matrix_src, camera_matrix_dst):# 提取匹配点对应的关键点src_pts = np.float32([keypoints1[m.queryIdx].pt for m in good_matches]).reshape(-1, 1, 2)dst_pts = np.float32([keypoints2[m.trainIdx].pt for m in good_matches]).reshape(-1, 1, 2)# 使用基础矩阵估计相机的相对位姿essential_matrix, _ = cv2.findEssentialMat(src_pts, dst_pts, camera_matrix_src, None, camera_matrix_dst, None, cv2.RANSAC, 0.999, 1.0)# 从基础矩阵中恢复旋转和平移矩阵_, R, t, _ = cv2.recoverPose(essential_matrix, src_pts, dst_pts, camera_matrix_src)return R, tdef determine_camera_direction(t, R):# 打印平移向量print(f"平移向量 t: {t}")# 计算旋转矩阵的欧拉角angles = cv2.Rodrigues(R)[0]yaw = np.arctan2(angles[1, 0], angles[0, 0]) * 180.0 / np.pi# 联合判断相机的方向if t[0] > 0 and yaw > 0:print("相机偏向右侧, 您应该向左转")elif t[0] < 0 and yaw < 0:print("相机偏向左侧,您应该向右转")elif t[0] > 0 and yaw < 0:print("相机偏向右侧, 但是角度偏向左")elif t[0] < 0 and yaw > 0:print("相机偏向左侧, 但是角度偏向右")else:print("相机方向正前方")print(f"X方向平移: {t[0]}, Y方向平移: {t[1]}, Z方向平移: {t[2]}")print(f"Yaw 角度: {yaw}")def main():# 加载两张图片image1 = cv2.imread('/media/k1928-3/028efb59-765e-462b-8aa6-085565fa80eb/hxy/biaoding/weiziguji/DJI_0273.JPG', cv2.IMREAD_GRAYSCALE)image2 = cv2.imread('/media/k1928-3/028efb59-765e-462b-8aa6-085565fa80eb/hxy/biaoding/weiziguji/phone/ori_right.jpg', cv2.IMREAD_GRAYSCALE)# 假设你已知相机内参----数据库相机fx_src = 4282.03fy_src = 2960.54cx_src = 844.20cy_src = 552.00camera_matrix_src = np.array([[fx_src, 0, cx_src],[0, fy_src, cy_src],[0, 0, 1]], dtype=float)# 手机相机fx_dst = 2934.52fy_dst = 2934.89cx_dst = 1466.29cy_dst = 2020.34camera_matrix_dst = np.array([[fx_dst, 0, cx_dst],[0, fy_dst, cy_dst],[0, 0, 1]], dtype=float)# 检测关键点和计算描述符keypoints1, descriptors1 = find_keypoints_and_descriptors(image1)keypoints2, descriptors2 = find_keypoints_and_descriptors(image2)# 匹配关键点good_matches = match_keypoints(descriptors1, descriptors2)# 估计相机的相对位姿R, t = estimate_relative_pose(keypoints1, keypoints2, good_matches, camera_matrix_src, camera_matrix_dst)# 联合判断相机的方向determine_camera_direction(t, R)if __name__ == "__main__":main()

##八点法

import cv2
import numpy as np
import timedef find_keypoints_and_descriptors(image):# 使用SIFT算法检测关键点和计算描述符sift = cv2.SIFT_create()keypoints, descriptors = sift.detectAndCompute(image, None)return keypoints, descriptorsdef match_keypoints(descriptors1, descriptors2):# 使用FLANN匹配器进行关键点匹配FLANN_INDEX_KDTREE = 0index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5)search_params = dict(checks=50)flann = cv2.FlannBasedMatcher(index_params, search_params)matches = flann.knnMatch(descriptors1, descriptors2, k=2)# 保留良好的匹配good_matches = []for m, n in matches:if m.distance < 0.7 * n.distance:good_matches.append(m)return good_matchesdef estimate_relative_pose_eight_point(keypoints1, keypoints2, good_matches, camera_matrix_src, camera_matrix_dst):# 提取匹配点对应的关键点src_pts = np.float32([keypoints1[m.queryIdx].pt for m in good_matches]).reshape(-1, 1, 2)dst_pts = np.float32([keypoints2[m.trainIdx].pt for m in good_matches]).reshape(-1, 1, 2)# 计算基础矩阵fundamental_matrix, _ = cv2.findFundamentalMat(src_pts, dst_pts, cv2.FM_8POINT)# 计算本质矩阵essential_matrix = camera_matrix_dst.T @ fundamental_matrix @ camera_matrix_src# 从本质矩阵中恢复旋转和平移矩阵_, R, t, _ = cv2.recoverPose(essential_matrix, src_pts, dst_pts, camera_matrix_src)return R, tdef determine_camera_direction(t, R):# 打印平移向量print(f"平移向量 t: {t}")# 计算旋转矩阵的欧拉角angles = cv2.Rodrigues(R)[0]yaw = np.arctan2(angles[1, 0], angles[0, 0]) * 180.0 / np.pi# 联合判断相机的方向if t[0] > 0 and yaw > 0:print("人在走廊中轴线左侧, 手机摄像头角度偏右,您应该向右走,应将手机向左偏")elif t[0] < 0 and yaw < 0:print("人在走廊中轴线右侧,手机摄像头角度偏左,您应该向左走,应将手机向右偏")elif t[0] > 0 and yaw < 0:print("人在走廊中轴线左侧, 手机摄像头角度偏左,您应该向右走,应将手机向右偏")elif t[0] < 0 and yaw > 0:print("人在走廊中轴线右侧,手机摄像头角度偏右,您应该向左走,应将手机向左偏")else:print("相机方向正前方")print(f"X方向平移: {t[0]}, Y方向平移: {t[1]}, Z方向平移: {t[2]}")print(f"Yaw 角度: {yaw}")def main():# 加载两张图片image1 = cv2.imread('/media/k1928-3/028efb59-765e-462b-8aa6-085565fa80eb/hxy/biaoding/weiziguji/DJI_0273.JPG', cv2.IMREAD_GRAYSCALE)image2 = cv2.imread('/media/k1928-3/028efb59-765e-462b-8aa6-085565fa80eb/hxy/biaoding/weiziguji/phone/ori_right.jpg', cv2.IMREAD_GRAYSCALE)# 假设你已知相机内参----数据库相机fx_src = 4282.03fy_src = 2960.54cx_src = 844.20cy_src = 552.00camera_matrix_src = np.array([[fx_src, 0, cx_src],[0, fy_src, cy_src],[0, 0, 1]], dtype=float)# 手机相机fx_dst = 2934.52fy_dst = 2934.89cx_dst = 1466.29cy_dst = 2020.34camera_matrix_dst = np.array([[fx_dst, 0, cx_dst],[0, fy_dst, cy_dst],[0, 0, 1]], dtype=float)# 检测关键点和计算描述符keypoints1, descriptors1 = find_keypoints_and_descriptors(image1)keypoints2, descriptors2 = find_keypoints_and_descriptors(image2)# 匹配关键点good_matches = match_keypoints(descriptors1, descriptors2)# 记录开始时间start_time = time.time()# 使用八点法估计相机的相对位姿R, t = estimate_relative_pose_eight_point(keypoints1, keypoints2, good_matches, camera_matrix_src, camera_matrix_dst)# 联合判断相机的方向determine_camera_direction(t, R)# 记录结束时间并计算总时间end_time = time.time()elapsed_time = (end_time - start_time) * 1000  # 转换为毫秒print(f"求解位姿总耗时:{elapsed_time:.6f} 毫秒")if __name__ == "__main__":main()

注意:提取特征的时间是6s,特征匹配的时间是6秒,求解位姿的旋转和平移,所需要的时间不多

相关文章:

相对位姿估计

相对位姿估计 示意图 理论推导 离线数据库&#xff1a; P的位置 P [ X , Y , Z ] T P[X,Y,Z]^{T} P[X,Y,Z]T 相机内参 k 1 k_{1} k1​ 安卓手机&#xff1a; 相机内参 k 2 k_{2} k2​ 两个像素点位置 &#xff1a; p 1 和 p 2 p_1和p_2 p1​和p2​ 公式一&#xff1a;…...

记一次 .NET某工业设计软件 崩溃分析

一&#xff1a;背景 1. 讲故事 前些天有位朋友找到我&#xff0c;说他的软件在客户那边不知道什么原因崩掉了&#xff0c;从windows事件日志看崩溃在 clr 里&#xff0c;让我能否帮忙定位下&#xff0c;dump 也抓到了&#xff0c;既然dump有了&#xff0c;接下来就上 windbg …...

2020 6.s081——Lab5:Lazy page allocation

再来是千年的千年 不变是眷恋的眷恋 飞越宇宙无极限 我们永不说再见 ——超兽武装 完整代码见&#xff1a;SnowLegend-star/6.s081 at lazy (github.com) Eliminate allocation from sbrk() (easy) 顾名思义&#xff0c;就是去掉sbrk()中调用growproc()的部分。1s完事儿。 Laz…...

华为认证学习笔记:生成树

以太网交换网络中为了进行链路备份&#xff0c;提高网络可靠性&#xff0c;通常会使用冗余链路。但是使用冗余链路会在交换网络上产生环路&#xff0c;引发广播风暴以及MAC地址表不稳定等故障现象&#xff0c;从而导致用户通信质量较差&#xff0c;甚至通信中断。为解决交换网络…...

leetcode 97.交错字符串

思路&#xff1a;LCS 其实也是同一个类型的题目&#xff0c;一般涉及到这种子序列的字符串问题的时候&#xff0c;状态的设置基本上都应该是以...结尾为状态的。这里同样&#xff0c;设置用dp[i][j]为s1,s2字符以i&#xff0c;j结尾能否拼接成s3[ij]。 那么&#xff0c;首先就…...

The Missing Semester ( Shell 工具和脚本 和 Vim)

管道符号 &#xff08;1&#xff09;管道符号 | 将前一个命令的输出作为下一个命令的输入 例如&#xff1a; 以下为 ./semester输出中提取包含 "Last-Modified" 的行并写入文件 last-modified.txt./semester | grep "Last-Modified" > ~/last-modif…...

【Uniapp微信小程序】自定义水印相机、微信小程序地点打卡相机

效果图 template 下方的image图片自行寻找替换&#xff01; <template><view><camerav-if"!tempImagePath && cameraHeight ! 0":resolution"high":frame-size"large":device-position"device":flash"f…...

SimPO: Simple Preference Optimization with a Reference-Free Reward

https://github.com/princeton-nlp/SimPO 简单代码 class simpo(paddle.nn.Layer):def __init__(self):super(OrPoLoss, self).__init__()self.loss paddle.nn.CrossEntropyLoss()def forward(self,neg_logit, neg_lab, pos_logit, pos_lab,beta,gamma):neg_logit paddle.n…...

CDH6.3.2安装文档

前置环境&#xff1a; 操作系统&#xff1a; CentOS Linux release 7.7 java JDK &#xff1a; 1.8.0_231 1、准备工作 准备以下安装包&#xff1a; Cloudera Manager: cloudera-manager-agent-6.3.1-1466458.el7.x86_64.rpm cloudera-manager-daemons-6.3.1-1466458.el…...

Java实战入门:深入解析Java中的 `Arrays.sort()` 方法

文章目录 一、方法定义参数说明返回值 二、使用场景三、实现原理四、示例代码示例一&#xff1a;对整型数组排序示例二&#xff1a;对字符串数组排序示例三&#xff1a;对自定义对象数组排序 五、注意事项六、总结 在Java编程中&#xff0c;Arrays.sort() 方法是一个非常常用的…...

JavaScript的垃圾回收机制

No.内容链接1Openlayers 【入门教程】 - 【源代码示例300】 2Leaflet 【入门教程】 - 【源代码图文示例 150】 3Cesium 【入门教程】 - 【源代码图文示例200】 4MapboxGL【入门教程】 - 【源代码图文示例150】 5前端就业宝典 【面试题详细答案 1000】 文章目录 一、垃圾…...

小程序使用Canvas设置文字竖向排列

在需要使用的js页面引入js文件,传入对应参数即可 /** * 文本竖向排列 */ function drawTextVertical(context, text, x, y) {var arrText text.split();var arrWidth arrText.map(function (letter) {return 26; // 字体间距,需要自定义可以自己加参数,根据传入参数进行…...

GPT-4o:重塑人机交互的未来

一个愿意伫立在巨人肩膀上的农民...... 一、推出 在人工智能&#xff08;AI&#xff09;领域&#xff0c;自然语言处理&#xff08;NLP&#xff09;技术一直被视为连接人类与机器的桥梁。近年来&#xff0c;随着深度学习技术的快速发展&#xff0c;NLP领域迎来了前所未有的变革…...

大语言模型拆解——Tokenizer

1. 认识Tokenizer 1.1 为什么要有tokenizer&#xff1f; 计算机是无法理解人类语言的&#xff0c;它只会进行0和1的二进制计算。但是呢&#xff0c;大语言模型就是通过二进制计算&#xff0c;让你感觉计算机理解了人类语言。 举个例子&#xff1a;单1&#xff0c;双2&#x…...

Linux自动挂载服务autofs讲解

1.产生原因 2.配置文件讲解 总结&#xff1a;配置客户端&#xff0c;先构思好要挂载的目录如&#xff1a;/abc/cb 然后在autofs.master中编辑&#xff1a; /abc&#xff08;要挂载的主目录&#xff09; /etc/qwe&#xff08;在这个文件里去找要挂载的副目录&#xff0c;这个名…...

堆结构知识点复习——玩转堆结构

前言:堆算是一种相对简单的数据结构&#xff0c; 本篇文章将详细的讲解堆中的知识点&#xff0c; 包括那些我们第一次学习堆的时候容易忽略的内容&#xff0c; 本篇文章会作为重点详细提到。 本篇内容适合已经学完C语言数组和函数部分的友友们观看。 目录 什么是堆 建堆算法…...

JS数据类型运算符标准库

目录 数据类型运算符标准库对象Object对象属性描述对象Array对象包装对象Boolean对象Number对象String对象Math对象Date对象...

单片机之从C语言基础到专家编程 - 4 C语言基础 - 4.13数组

C语言中&#xff0c;有一类数据结构&#xff0c;它可以存储一组相同类型的元素&#xff0c;并且可以通过索引访问这些元素&#xff0c;没错&#xff0c;这类数据结构就是数组。数组可以说是C语言中非常重要的数据结构之一了。使用数组可以是程序逻辑更加清晰&#xff0c;也更加…...

【码银送书第二十期】《游戏运营与出海实战:策略、方法与技巧》

市面上的游戏品种繁杂&#xff0c;琳琅满目&#xff0c;它们是如何在历史的长河中逐步演变成今天的模式的呢&#xff1f;接下来&#xff0c;我们先回顾游戏的发展史&#xff0c;然后按照时间轴来叙述游戏运营的兴起。 作者&#xff1a;艾小米 本文经机械工业出版社授权转载&a…...

String 类

目录&#xff1a; 一. 认识 String 类 二. String 类的基本用法 三. String对象的比较 四.字符串的不可变性 五. 认识 StringBuffer 和 StringBuilder 一. 认识 String 类&#xff1a; 在C语言中已经涉及到字符串了&#xff0c;但是在C语言中要表示字符串只能使用字符数组或者…...

Alerter终极声音设置指南:为Android通知添加音频反馈的完整教程

Alerter终极声音设置指南&#xff1a;为Android通知添加音频反馈的完整教程 【免费下载链接】Alerter Tapadoo/Alerter: 是一个简单易用的 Android 通知和进度条控件库。适合对 Android 开发、用户界面以及想要在 Android 应用中显示通知和进度条的开发者。 项目地址: https:…...

数据库智能运维:利用PyTorch LSTM预测数据库性能瓶颈

数据库智能运维&#xff1a;利用PyTorch LSTM预测数据库性能瓶颈 1. 引言&#xff1a;当数据库遇上AI预测 凌晨三点&#xff0c;运维工程师小李被刺耳的报警声惊醒——核心数据库又崩溃了。这已经是本月第三次因为性能瓶颈导致的业务中断&#xff0c;每次损失都超过百万。传统…...

Qwen3-ASR-1.7B实战教程:结合Punctuation Restoration模型提升标点准确率

Qwen3-ASR-1.7B实战教程&#xff1a;结合Punctuation Restoration模型提升标点准确率 语音识别技术已经相当成熟&#xff0c;但识别结果往往缺少标点符号&#xff0c;让长文本阅读变得困难。本文将教你如何将Qwen3-ASR-1.7B语音识别模型与标点恢复技术结合&#xff0c;获得既准…...

云容笔谈在自媒体内容生产中的提效实践:日更国风配图效率提升300%

云容笔谈在自媒体内容生产中的提效实践&#xff1a;日更国风配图效率提升300% 1. 自媒体内容创作的痛点与挑战 作为自媒体创作者&#xff0c;每天最头疼的就是配图问题。特别是做国风内容的账号&#xff0c;既要保持东方美学韵味&#xff0c;又要保证日更频率&#xff0c;传统…...

TensorFlow实战:用CIFAR-10数据集训练你的第一个图像分类模型(附完整代码)

TensorFlow图像分类实战&#xff1a;从零构建CIFAR-10卷积神经网络的完整指南 当第一次接触图像分类任务时&#xff0c;许多开发者会被复杂的网络结构和数据处理流程所困扰。本文将带你用TensorFlow构建一个能识别10类常见物体的卷积神经网络&#xff0c;从数据加载到模型评估&…...

多任务学习进阶:从MMoE到PLE的模型演进与实战解析

1. 多任务学习基础与核心挑战 多任务学习&#xff08;Multi-Task Learning, MTL&#xff09;是机器学习领域的一个重要分支&#xff0c;它让单个模型同时学习多个相关任务。想象一下&#xff0c;你正在教一个学生同时学习数学和物理。如果这两个学科有共同的基础概念&#xff0…...

快速部署MinerU镜像:开箱即用的PDF提取方案,告别繁琐配置

快速部署MinerU镜像&#xff1a;开箱即用的PDF提取方案&#xff0c;告别繁琐配置 1. 引言&#xff1a;为什么你需要一个“开箱即用”的PDF提取工具&#xff1f; 如果你曾经尝试过从一份复杂的PDF文档里提取文字、表格和公式&#xff0c;你大概率经历过这样的痛苦&#xff1a;…...

LoRA训练助手入门解析:为什么权重排序对LoRA训练效果影响显著

LoRA训练助手入门解析&#xff1a;为什么权重排序对LoRA训练效果影响显著 1. 认识LoRA训练助手 如果你正在尝试训练自己的AI绘画模型&#xff0c;可能会遇到一个常见问题&#xff1a;为什么同样的图片&#xff0c;用不同的标签训练出来的效果差距那么大&#xff1f;这就是我们…...

OpCore-Simplify:三步解决黑苹果配置难题的零代码自动化工具

OpCore-Simplify&#xff1a;三步解决黑苹果配置难题的零代码自动化工具 【免费下载链接】OpCore-Simplify A tool designed to simplify the creation of OpenCore EFI 项目地址: https://gitcode.com/GitHub_Trending/op/OpCore-Simplify 问题诊断&#xff1a;黑苹果配…...

Java结构化并发崩溃了?手把手教你用VirtualThread+StructuredTaskScope定位线程泄漏与作用域越界(附JDK21真机调试录屏)

第一章&#xff1a;Java结构化并发崩溃了&#xff1f;手把手教你用VirtualThreadStructuredTaskScope定位线程泄漏与作用域越界&#xff08;附JDK21真机调试录屏&#xff09;Java 21 正式引入结构化并发&#xff08;Structured Concurrency&#xff09;&#xff0c;其核心组件 …...