python opencv计算E矩阵分解RT - MKT

news/2026/1/24 1:56:16/文章来源:https://www.cnblogs.com/gooutlook/p/19524432

 

 

 

 

import cv2
import numpy as np# 示例:从特征点匹配恢复相对位姿
def estimate_relative_pose_from_matches(keypoints1, keypoints2, matches, K):"""从特征点匹配估计相对位姿参数:keypoints1: 第一幅图像的关键点列表keypoints2: 第二幅图像的关键点列表matches: 匹配对列表K: 相机内参矩阵"""# 1. 提取匹配点的坐标pts1 = np.float32([keypoints1[m.queryIdx].pt for m in matches])pts2 = np.float32([keypoints2[m.trainIdx].pt for m in matches])# 2. 计算本质矩阵 (使用RANSAC)E, mask_E = cv2.findEssentialMat(pts1, pts2, K, method=cv2.RANSAC, prob=0.999, threshold=1.0)# 3. 从本质矩阵恢复位姿num_inliers, R, t, mask_pose = cv2.recoverPose(E, pts1, pts2, K,mask=mask_E  # 可选:只使用内点)# 4. 统计结果print(f"内点数量: {np.sum(mask_pose)}/{len(matches)}")print(f"旋转矩阵 R:\n{R}")print(f"平移向量 t (单位向量):\n{t}")return R, t, mask_pose# 更完整的示例
def complete_pose_recovery_example():"""完整的位姿恢复示例"""# 模拟数据np.random.seed(42)# 相机内参K = np.array([[800, 0, 320],[0, 800, 240],[0, 0, 1]], dtype=np.float32)# 生成模拟特征点n_points = 100# 3D 点(在相机1的坐标系中)X = np.random.randn(n_points, 3) * 5X[:, 2] += 10  # 确保深度为正# 相机1的位姿(世界坐标系)R1 = np.eye(3)t1 = np.zeros((3, 1))P1 = K @ np.hstack([R1, t1])  # 投影矩阵# 相机2的位姿(相对于相机1)true_R = cv2.Rodrigues(np.array([0.1, 0.2, 0.3]))[0]  # 小旋转true_t = np.array([[0.5], [0.1], [0.2]])  # 平移P2 = K @ np.hstack([true_R, true_t])# 投影到图像平面X_homo = np.hstack([X, np.ones((n_points, 1))])pts1_homo = (P1 @ X_homo.T).Tpts2_homo = (P2 @ X_homo.T).T# 齐次坐标归一化pts1 = pts1_homo[:, :2] / pts1_homo[:, 2:3]pts2 = pts2_homo[:, :2] / pts2_homo[:, 2:3]# 添加噪声pts1 += np.random.randn(*pts1.shape) * 0.5pts2 += np.random.randn(*pts2.shape) * 0.5print("="*60)print("模拟数据恢复相对位姿")print("="*60)print(f"真实旋转矩阵 R:\n{true_R}")print(f"真实平移向量 t:\n{true_t}")print(f"平移向量长度: {np.linalg.norm(true_t):.4f}")# 计算本质矩阵E, mask_E = cv2.findEssentialMat(pts1, pts2, K, method=cv2.RANSAC,prob=0.999,threshold=0.5)print(f"\n计算出的本质矩阵 E:\n{E}")# 恢复位姿num, R, t, mask = cv2.recoverPose(E, pts1, pts2, K, mask=mask_E)print(f"\n恢复的位姿:")print(f"内点数量: {np.sum(mask)}/{n_points}")print(f"旋转矩阵 R:\n{R}")print(f"旋转误差: {np.linalg.norm(R - true_R):.6f}")# 注意:恢复的 t 是单位向量print(f"\n平移向量 t (单位向量):\n{t}")# 需要估计尺度true_t_norm = true_t / np.linalg.norm(true_t)print(f"真实平移向量 (单位化):\n{true_t_norm}")print(f"平移方向误差: {np.linalg.norm(t - true_t_norm):.6f}")return R, t, mask# 处理尺度问题
def estimate_scale_with_depth(R, t, pts1, pts2, K, method='median'):"""估计平移向量的尺度参数:R, t: 恢复的相对位姿 (t 是单位向量)pts1, pts2: 匹配点K: 相机内参method: 尺度估计方法 ('median', 'mean', 'ransac')"""n = len(pts1)# 创建投影矩阵P1 = K @ np.hstack([np.eye(3), np.zeros((3, 1))])P2 = K @ np.hstack([R, t])# 三角测量points_4d = cv2.triangulatePoints(P1, P2, pts1.T, pts2.T)points_3d = points_4d[:3] / points_4d[3]  # 齐次坐标归一化# 计算深度depths1 = points_3d[2, :]  # 在相机1坐标系中的深度# 转换到相机2坐标系points_3d_cam2 = R @ points_3d + tdepths2 = points_3d_cam2[2, :]  # 在相机2坐标系中的深度# 检查正深度valid_mask = (depths1 > 0) & (depths2 > 0)if np.sum(valid_mask) < 5:print("警告: 正深度点太少")return 1.0valid_depths1 = depths1[valid_mask]if method == 'median':scale = np.median(valid_depths1)elif method == 'mean':scale = np.mean(valid_depths1)elif method == 'ransac':# 使用RANSAC鲁棒估计from sklearn.linear_model import RANSACRegressorX = np.ones((len(valid_depths1), 1))y = valid_depths1.reshape(-1, 1)ransac = RANSACRegressor()ransac.fit(X, y)scale = ransac.estimator_.coef_[0]else:scale = 1.0return scale# 实际应用示例
def visual_odometry_example(image1, image2, K):"""视觉里程计示例:估计两帧之间的运动"""import cv2# 1. 特征检测与匹配# 使用ORB特征orb = cv2.ORB_create(nfeatures=1000)# 检测特征点kp1, des1 = orb.detectAndCompute(image1, None)kp2, des2 = orb.detectAndCompute(image2, None)# 匹配特征点bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)matches = bf.match(des1, des2)# 按距离排序matches = sorted(matches, key=lambda x: x.distance)# 提取匹配点坐标pts1 = np.float32([kp1[m.queryIdx].pt for m in matches])pts2 = np.float32([kp2[m.trainIdx].pt for m in matches])# 2. 计算本质矩阵E, mask_E = cv2.findEssentialMat(pts1, pts2, K, method=cv2.RANSAC,prob=0.999,threshold=1.0)# 3. 恢复位姿num, R, t, mask_pose = cv2.recoverPose(E, pts1, pts2, K, mask=mask_E)# 4. 估计尺度(如果有真实尺度信息)# 在实际SLAM中,尺度通常从其他来源获取# 例如:IMU、已知物体尺寸、深度信息等return R, t, mask_pose, matches# 验证 recoverPose 的四种解
def analyze_four_solutions(E, pts1, pts2, K):"""分析从本质矩阵分解的四种可能解"""# 对 E 进行 SVD 分解U, S, Vt = np.linalg.svd(E)# 确保 det(U) > 0, det(V) > 0if np.linalg.det(U) < 0:U = -Uif np.linalg.det(Vt) < 0:Vt = -VtW = np.array([[0, -1, 0],[1, 0, 0],[0, 0, 1]])# 两种可能的旋转R1 = U @ W @ VtR2 = U @ W.T @ Vt# 可能的平移(t 是 E 的零空间向量)t = U[:, 2]t = t.reshape(3, 1)# 四种组合solutions = [(R1, t),(R1, -t),(R2, t),(R2, -t)]# 测试每种解best_solution = Nonebest_score = -1for i, (R, t) in enumerate(solutions):# 创建投影矩阵P1 = K @ np.hstack([np.eye(3), np.zeros((3, 1))])P2 = K @ np.hstack([R, t])# 三角测量points_4d = cv2.triangulatePoints(P1, P2, pts1.T, pts2.T)points_3d = points_4d[:3] / points_4d[3]# 计算在相机前的点数depths1 = points_3d[2, :]points_3d_cam2 = R @ points_3d + tdepths2 = points_3d_cam2[2, :]score = np.sum((depths1 > 0) & (depths2 > 0))print(f"解{i+1}: 正深度点数 = {score}/{len(pts1)}")if score > best_score:best_score = scorebest_solution = (R, t, i+1)print(f"\n最佳解: 解{best_solution[2]}")return best_solution# 主测试
if __name__ == "__main__":print("cv2.recoverPose() 函数详解")print("="*60)# 示例1: 模拟数据print("\n示例1: 模拟数据恢复位姿")R, t, mask = complete_pose_recovery_example()# 示例2: 分析四种解print("\n" + "="*60)print("示例2: 分析四种可能的解")print("="*60)# 创建测试数据np.random.seed(42)K = np.array([[800, 0, 320],[0, 800, 240],[0, 0, 1]])n_points = 50X = np.random.randn(n_points, 3) * 3X[:, 2] += 5# 真实位姿true_R = cv2.Rodrigues(np.array([0.2, 0.1, 0.3]))[0]true_t = np.array([[0.3], [0.1], [0.2]])# 投影P1 = K @ np.hstack([np.eye(3), np.zeros((3, 1))])P2 = K @ np.hstack([true_R, true_t])X_homo = np.hstack([X, np.ones((n_points, 1))])pts1_homo = (P1 @ X_homo.T).Tpts2_homo = (P2 @ X_homo.T).Tpts1 = pts1_homo[:, :2] / pts1_homo[:, 2:3]pts2 = pts2_homo[:, :2] / pts2_homo[:, 2:3]# 计算本质矩阵E, _ = cv2.findEssentialMat(pts1, pts2, K)# 分析四种解best_R, best_t, sol_num = analyze_four_solutions(E, pts1, pts2, K)print(f"\n真实解应该对应解{sol_num}")print(f"旋转误差: {np.linalg.norm(best_R - true_R):.6f}")# 使用 recoverPose 验证print("\n" + "="*60)print("使用 cv2.recoverPose() 验证")print("="*60)num, R_cv, t_cv, mask_cv = cv2.recoverPose(E, pts1, pts2, K)print(f"cv2.recoverPose 选择了解: {np.sum(mask_cv)}/{n_points} 个内点")print(f"旋转矩阵:\n{R_cv}")# 检查是否选择了正确解if np.linalg.norm(R_cv - best_R) < 1e-6:print("✓ cv2.recoverPose 选择了正确解")else:print("✗ cv2.recoverPose 选择了不同解")

  

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

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

相关文章

python opencv计算F矩阵分解RT - MKT

python opencv计算F矩阵分解RT import cv2 import numpy as np from scipy.spatial.transform import Rotation as Rdef improved_decompose_homography():"""改进的单应性矩阵分解,处理尺度问题"…

科研论文提取难?MinerU+LaTeX_OCR部署实战案例

科研论文提取难&#xff1f;MinerULaTeX_OCR部署实战案例 科研人员每天面对大量PDF格式的论文&#xff0c;但真正能“读懂”它们的工具却不多。多栏排版、嵌套表格、复杂公式、矢量图混排——这些在人类眼里一目了然的内容&#xff0c;对传统PDF解析工具来说却是连环陷阱。复制…

大面积修复卡顿?fft npainting lama性能优化建议

大面积修复卡顿&#xff1f;FFT NPainting LAMA性能优化建议 在使用 FFT NPainting LAMA 进行图像大面积修复时&#xff0c;不少用户反馈&#xff1a;标注一大片区域后点击“ 开始修复”&#xff0c;界面长时间卡在“执行推理…”状态&#xff0c;等待30秒甚至超过1分钟仍无响…

亲自动手试了Qwen-Image-2512,AI修图竟如此简单

亲自动手试了Qwen-Image-2512&#xff0c;AI修图竟如此简单 你有没有过这样的经历&#xff1a;刚拍完一张风景照&#xff0c;却发现右下角有个碍眼的水印&#xff1b;辛苦做的产品图&#xff0c;客户临时要求把LOGO换成新版本&#xff1b;或者想给老照片换背景&#xff0c;又不…

为什么Qwen3-4B部署慢?镜像免配置优化教程提升启动效率

为什么Qwen3-4B部署慢&#xff1f;镜像免配置优化教程提升启动效率 1. 真实体验&#xff1a;从点击部署到能用&#xff0c;等了整整7分23秒 你是不是也遇到过这样的情况——在镜像平台点下“一键部署”Qwen3-4B-Instruct-2507&#xff0c;然后盯着进度条发呆&#xff1a;模型…

FSMN VAD社区贡献指南:如何参与二次开发

FSMN VAD社区贡献指南&#xff1a;如何参与二次开发 1. 为什么FSMN VAD值得你投入时间参与开发&#xff1f; FSMN VAD是阿里达摩院FunASR项目中开源的语音活动检测&#xff08;Voice Activity Detection&#xff09;模型&#xff0c;以轻量、高精度、低延迟著称。它仅1.7MB大…

Llama3-8B对话体验最佳实践:Open-WebUI参数调优部署教程

Llama3-8B对话体验最佳实践&#xff1a;Open-WebUI参数调优部署教程 1. 为什么选Llama3-8B&#xff1f;轻量与能力的黄金平衡点 你是不是也遇到过这些情况&#xff1a;想本地跑个大模型&#xff0c;但显卡只有RTX 3060&#xff0c;装完Llama3-70B直接爆显存&#xff1b;或者试…

告别手动输入!用cv_resnet18_ocr-detection自动识别发票内容

告别手动输入&#xff01;用cv_resnet18_ocr-detection自动识别发票内容 在财务、行政和中小企业日常运营中&#xff0c;发票处理是高频却低效的重复劳动&#xff1a;一张张扫描、截图、再逐字录入系统&#xff0c;平均耗时3-5分钟/张&#xff0c;出错率高&#xff0c;月底扎堆…

有源蜂鸣器PWM频率配置:完整指南

以下是对您提供的博文《有源蜂鸣器PWM频率配置&#xff1a;完整技术分析指南》的 深度润色与专业重构版本 。本次优化严格遵循您的全部要求&#xff1a; ✅ 彻底去除AI腔调与模板化结构&#xff08;如“引言/概述/总结”等机械分节&#xff09; ✅ 所有内容以 真实嵌入式工…

Qwen3-4B部署教程:3步完成GPU算力适配,支持256K长文本处理

Qwen3-4B部署教程&#xff1a;3步完成GPU算力适配&#xff0c;支持256K长文本处理 1. 这个模型到底能做什么&#xff1f; 你可能已经听说过Qwen系列&#xff0c;但Qwen3-4B-Instruct-2507不是简单升级——它是一次面向真实工作流的深度打磨。这不是一个“参数堆出来”的模型&…

Llama3与Qwen-Image多模态对比:文本生成vs图像生成实战评测

Llama3与Qwen-Image多模态对比&#xff1a;文本生成vs图像生成实战评测 在AI应用落地过程中&#xff0c;一个常被忽略的关键事实是&#xff1a;文本模型和图像模型根本不是同一类工具——就像锤子和画笔&#xff0c;各自擅长的领域截然不同。但很多人仍习惯把Llama3和Qwen-Ima…

NewBie-image-Exp0.1生成失败?数据类型冲突修复全流程指南

NewBie-image-Exp0.1生成失败&#xff1f;数据类型冲突修复全流程指南 你是不是刚打开NewBie-image-Exp0.1镜像&#xff0c;运行python test.py后却只看到一串红色报错&#xff1f; 最常见的就是这行&#xff1a;TypeError: float object cannot be interpreted as an integer&…

Qwen3-4B-Instruct响应不一致?温度参数调优实战指南

Qwen3-4B-Instruct响应不一致&#xff1f;温度参数调优实战指南 1. 为什么你总感觉Qwen3-4B-Instruct“忽冷忽热” 你是不是也遇到过这些情况&#xff1a; 同一个提示词&#xff0c;第一次生成逻辑清晰、条理分明&#xff1b;第二次却答非所问、自相矛盾&#xff1b;让它写一…

NewBie-image-Exp0.1降本部署案例:节省环境配置时间90%实操手册

NewBie-image-Exp0.1降本部署案例&#xff1a;节省环境配置时间90%实操手册 你是不是也经历过——为了跑通一个动漫生成模型&#xff0c;花整整两天配环境&#xff1a;装CUDA版本对不上、PyTorch和Diffusers版本冲突、源码报错找不到原因、模型权重下到一半断连……最后发现&a…

FSMN-VAD部署全流程:从环境配置到Web界面调用详细步骤

FSMN-VAD部署全流程&#xff1a;从环境配置到Web界面调用详细步骤 1. 这不是“语音识别”&#xff0c;而是更底层的“听觉开关” 你有没有遇到过这样的问题&#xff1a;一段5分钟的会议录音&#xff0c;真正说话的时间可能只有2分半&#xff0c;中间夹杂着大量咳嗽、翻纸、键…

实测分享:我用Open-AutoGLM做了这些神奇操作

实测分享&#xff1a;我用Open-AutoGLM做了这些神奇操作 摘要&#xff1a;这不是一篇理论堆砌的教程&#xff0c;而是一份真实、有温度、带细节的实测手记。我用Open-AutoGLM在真实手机上完成了12个日常任务&#xff0c;从点外卖到跨平台同步消息&#xff0c;全程记录卡点、惊喜…

YOLOE功能测评:文本/视觉/无提示三种模式对比

YOLOE功能测评&#xff1a;文本/视觉/无提示三种模式对比 你有没有遇到过这样的场景&#xff1a;在工业质检现场&#xff0c;突然要识别一种从未标注过的缺陷类型&#xff1b;在智能仓储中&#xff0c;客户临时要求新增“可折叠快递箱”这一类别&#xff1b;又或者在科研图像分…

深入解析电感的作用与电源稳定性关系

以下是对您原文的 深度润色与专业重构版博文 ,严格遵循您的全部要求: ✅ 彻底去除AI痕迹,语言自然如资深工程师口吻; ✅ 打破“引言-概述-总结”模板,以真实工程痛点切入、层层递进; ✅ 所有技术点均融合于逻辑流中,无生硬分节,标题生动贴切; ✅ 关键参数、公式…

开发者必看:GPEN人像增强镜像一键部署实操手册

开发者必看&#xff1a;GPEN人像增强镜像一键部署实操手册 你是否遇到过这样的问题&#xff1a;手头有一张模糊、有噪点、带压缩痕迹的人像照片&#xff0c;想快速修复却卡在环境配置上&#xff1f;装CUDA版本不对、PyTorch和numpy版本冲突、face检测模型下载失败……折腾两小…

GPEN更新日志解读:20260104版本新增功能实战演示

GPEN更新日志解读&#xff1a;20260104版本新增功能实战演示 1. 这次更新到底带来了什么&#xff1f; 你可能已经注意到&#xff0c;GPEN图像肖像增强工具在2026年1月4日悄悄完成了一次重要升级。这次不是小修小补&#xff0c;而是围绕真实用户反馈做的深度打磨——它变得更聪…