OpenCV相机标定与3D重建(54)解决透视 n 点问题(Perspective-n-Point, PnP)函数solvePnP()的使用

  • 操作系统:ubuntu22.04
  • OpenCV版本:OpenCV4.9
  • IDE:Visual Studio Code
  • 编程语言:C++11

算法描述

根据3D-2D点对应关系找到物体的姿态。
cv::solvePnP 是 OpenCV 库中的一个函数,用于解决透视 n 点问题(Perspective-n-Point, PnP),即通过已知的 3D 点及其对应的 2D 图像点来估计物体的姿态(旋转和平移)。这个函数可以处理任意数量的点对,并且提供了多种算法来求解姿态。

此函数返回旋转和平移向量,这些向量将用物体坐标系表示的3D点变换到相机坐标系中,使用不同的方法:

P3P 方法(SOLVEPNP_P3P, SOLVEPNP_AP3P):需要4个输入点来返回一个唯一解。
SOLVEPNP_IPPE:输入点必须 >= 4 且物体点必须共面。
SOLVEPNP_IPPE_SQUARE:适用于标记姿态估计的特殊情况。输入点的数量必须是4。物体点必须按以下顺序定义:

  • 点 0: [-squareLength / 2, squareLength / 2, 0]
  • 点 1: [ squareLength / 2, squareLength / 2, 0]
  • 点 2: [ squareLength / 2, -squareLength / 2, 0]
  • 点 3: [-squareLength / 2, -squareLength / 2, 0]
    对于所有其他标志,输入点的数量必须 >= 4,且物体点可以是任意配置。

函数原型

bool cv::solvePnP
(
	InputArray 	objectPoints,
	InputArray 	imagePoints,
	InputArray 	cameraMatrix,
	InputArray 	distCoeffs,
	OutputArray 	rvec,
	OutputArray 	tvec,
	bool 	useExtrinsicGuess = false,
	int 	flags = SOLVEPNP_ITERATIVE 
)		

参数

  • 参数objectPoints:物体坐标空间中的物体点数组,格式为 Nx3 的单通道或 1xN/Nx1 的三通道,其中 N 是点的数量。也可以传递 vector。
  • 参数imagePoints:对应的图像点数组,格式为 Nx2 的单通道或 1xN/Nx1 的双通道,其中 N 是点的数量。也可以传递 vector。
  • 参数cameraMatrix:输入的相机内参矩阵 A = [ f x 0 c x 0 f y c y 0 0 1 ] A = \begin{bmatrix} f_x & 0 & c_x \\ 0 & f_y & c_y \\ 0 & 0 & 1 \end{bmatrix} A= fx000fy0cxcy1
  • 参数distCoeffs:输入的畸变系数向量 (k1, k2, p1, p2[, k3[, k4, k5, k6[, s1, s2, s3, s4[, τx, τy]]]]),包含 4、5、8、12 或 14 个元素。如果该向量为空,则假设畸变为零。
  • 参数rvec:输出的旋转向量(见 Rodrigues),与 tvec 一起使用,将模型坐标系中的点变换到相机坐标系中。
  • 参数tvec:输出的平移向量。
  • 参数useExtrinsicGuess:仅用于 SOLVEPNP_ITERATIVE 方法。如果为 true(1),函数会使用提供的 rvec 和 tvec 值作为旋转和平移向量的初始近似值,并进一步优化它们。
  • 参数flags:解决 PnP 问题的方法,详见 calib3d_solvePnP_flags。

注意

  • 关于如何使用 solvePnP 进行平面增强现实的一个示例可以在 opencv_source_code/samples/python/plane_ar.py 找到。

  • 如果你使用的是 Python:

    • Numpy 数组切片不能作为输入,因为 solvePnP 需要连续的数组(在版本 2.4.9 的 modules/calib3d/src/solvepnp.cpp 文件大约第 55 行通过 cv::Mat::checkVector() 断言强制要求)。
    • P3P 算法要求图像点位于形状为 (N,1,2) 的数组中,因为它调用了 undistortPoints(在版本 2.4.9 的 modules/calib3d/src/solvepnp.cpp 文件大约第 75 行),这需要双通道信息。
    • 因此,给定一些数据 D = np.array(…),其中 D.shape = (N,M),为了使用其子集作为例如 imagePoints,必须有效地将其复制到一个新数组中:imagePoints = np.ascontiguousarray(D[:,:2]).reshape((N,1,2))。
  • 方法 SOLVEPNP_DLS 和 SOLVEPNP_UPNP 不能使用,因为当前实现不稳定,有时会给出完全错误的结果。如果你传递了这两个标志中的一个,则会使用 SOLVEPNP_EPNP 方法代替。

  • 在一般情况下,最少需要 4 个点。

  • 对于 SOLVEPNP_P3P 和 SOLVEPNP_AP3P 方法,必须使用恰好 4 个点(前 3 个点用于估计 P3P 问题的所有解,最后一个点用于保留最小化重投影误差的最佳解)。

  • 使用 SOLVEPNP_ITERATIVE 方法且 useExtrinsicGuess=true 时,最少需要 3 个点(3 个点足以计算姿态,但最多有 4 个解)。初始解应接近全局解以收敛。

  • 使用 SOLVEPNP_IPPE 时,输入点必须 >= 4 且物体点必须共面。

  • 使用 SOLVEPNP_IPPE_SQUARE 时,这是一个适用于标记姿态估计的特殊情况。输入点的数量必须是 4。物体点必须按以下顺序定义:

    • 点 0: [-squareLength / 2, squareLength / 2, 0]
    • 点 1: [ squareLength / 2, squareLength / 2, 0]
    • 点 2: [ squareLength / 2, -squareLength / 2, 0]
    • 点 3: [-squareLength / 2, -squareLength / 2, 0]

使用 SOLVEPNP_SQPNP 时,输入点必须 >= 3。

代码示例


#include <iostream>
#include <opencv2/opencv.hpp>
#include <vector>

using namespace cv;
using namespace std;

int main()
{
    // 假设我们有一个已知的 3D 点集 (例如一个正方形的四个角)
    std::vector< Point3f > objectPoints = { Point3f( -1.0f, -1.0f, 0.0f ), Point3f( 1.0f, -1.0f, 0.0f ), Point3f( 1.0f, 1.0f, 0.0f ), Point3f( -1.0f, 1.0f, 0.0f ) };

    // 对应的 2D 图像点 (这些点是从图像中检测到的特征点)
    std::vector< Point2f > imagePoints = { Point2f( 594.0f, 487.0f ), Point2f( 673.0f, 487.0f ), Point2f( 673.0f, 552.0f ), Point2f( 594.0f, 552.0f ) };

    // 相机内参矩阵 (假设已知)
    Mat cameraMatrix = ( Mat_< double >( 3, 3 ) << 718.856, 0, 607.1928, 0, 718.856, 185.2157, 0, 0, 1 );

    // 畸变系数 (假设已知)
    Mat distCoeffs = Mat::zeros( 5, 1, CV_64F );  // 如果没有畸变或忽略畸变,则可以是零矩阵

    // 初始化输出变量
    Mat rvec;  // 旋转向量
    Mat tvec;  // 平移向量

    // 调用 solvePnP 函数
    bool success = solvePnP( objectPoints, imagePoints, cameraMatrix, distCoeffs, rvec, tvec, false, SOLVEPNP_ITERATIVE );

    if ( success )
    {
        cout << "Rotation Vector:\n" << rvec << "\nTranslation Vector:\n" << tvec << endl;

        // 可选:将旋转向量转换为旋转矩阵以更好地理解结果
        Mat rotationMatrix;
        Rodrigues( rvec, rotationMatrix );
        cout << "Rotation Matrix:\n" << rotationMatrix << endl;
    }
    else
    {
        cout << "solvePnP failed." << endl;
    }

    return 0;
}

运行结果

Rotation Vector:
[0.2895361443049176;
 0.01328548677652798;
 -0.008684530349597173]
Translation Vector:
[0.6665924885943908;
 8.493287223698232;
 18.23641869746051]
Rotation Matrix:
[0.999874917527441, 0.01047321277960457, 0.01185162915241468;
 -0.006653461772789516, 0.9583398410008748, -0.2855529383439369;
 -0.01434854508064377, 0.2854383663148514, 0.9582896526048779]

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

‌OCP英文全称是什么

在数据库领域&#xff0c;OCP全称为Oracle Certified Professional&#xff0c;是Oracle公司提供的Oracle数据库中级认证&#xff0c;专门针对数据库管理员(Database Administrator&#xff0c;简称DBA)和数据库开发人员。以下是关于OCP认证的详细介绍&#xff1a; 认证领域与…

MyBatis实现数据库的CRUD

本文主要讲解使用MyBatis框架快速实现数据库中最常用的操作——CRUD。本文讲解的SQL语句都是MyBatis基于注解的方式定义的&#xff0c;相对简单。 Mybatis中#占位符和$拼接符的区别 “#”占位符 在使用MyBatis操作数据库的时候&#xff0c;可以直接使用如下SQL语句删除一条数…

微调神经机器翻译模型全流程

MBART: Multilingual Denoising Pre-training for Neural Machine Translation 模型下载 mBART 是一个基于序列到序列的去噪自编码器&#xff0c;使用 BART 目标在多种语言的大规模单语语料库上进行预训练。mBART 是首批通过去噪完整文本在多种语言上预训练序列到序列模型的方…

RTX 5090 加持,科研服务器如何颠覆 AI 深度学习构架?

RTX 5090作为英伟达旗舰级GPU&#xff0c;凭借Ada Lovelace架构&#xff0c;融合创新的SM多单元流处理器、第三代RT Core与第四代Tensor Core&#xff0c;打造出极为强劲的计算体系。其24GB GDDR6X显存搭配1TB/s带宽&#xff0c;能以极低延迟和超高吞吐量处理大规模张量数据&am…

【2025最新】机器学习类计算机毕设选题80套,适合大数据,人工智能

【2025最新】机器学习类型计算机毕设选题 1-10套 基于Spring Boot的物流管理系统的设计与实现 基于机器学习的虚假招聘信息的分析与预测 基于机器学习的影响数据科学家职业变动因素的分析与预测 基于Spring Boot的历史文物交流平台的设计与实现 基于机器学习的肥胖影响因素的分…

【PPTist】幻灯片放映

放映功能的代码都在 src/hooks/useScreening.ts&#xff0c;我们看一下 从当前页开始 放映的功能。 // 进入放映状态&#xff08;从当前页开始&#xff09; const enterScreening () > {enterFullscreen()screenStore.setScreening(true) }首先是 enterFullscreen()&#…

MySQL 16 章——变量、流程控制和游标

一、变量 在MySQL数据库的存储过程和存储函数中&#xff0c;可以使用变量来存储查询或计算的中间结果数据&#xff0c;或者输出最终的结果数据 在MySQL数据库中&#xff0c;变量分为系统变量和用户自定义变量 &#xff08;1&#xff09;系统变量 1.1.1系统变量分类 变量由…

T-SQL编程

目录 1、T-SQL的元素 1.1 标识符 1. 常规标识符 2. 分隔标识符 1.2 变量 1. 全局变量 2. 局部变量 1.3 运算符 1. 算数运算符 2. 赋值运算符 3. 位运算符 4. 比较运算符 5. 逻辑运算符 6. 字符串连接运算符 7. 一元运算符 8. 运算符的优先级和结合性 1.4 批处…

2024 China Collegiate Programming Contest (CCPC) Zhengzhou Onsite 基础题题解

L. Z-order Curve 思路&#xff1a;这题目说了&#xff0c;上面那一行&#xff0c;只有在偶数位才有可能存在1&#xff0c;那么一定存在这样的数&#xff0c;0 ,1,100, 10000,那么反之&#xff0c;我们的数列是行的二倍&#xff0c;因此会出现10,1000,100000这样的数&#xff0…

Unity2D初级背包设计后篇 拓展举例与不足分析

Unity2D初级背包设计中篇 MVC分层撰写(万字详解)-CSDN博客、 如果你已经搞懂了中篇&#xff0c;那么对这个背包的拓展将极为简单&#xff0c;我就在这里举个例子吧 目录 1.添加物品描述信息 2.拓展思路与不足分析 1.没有删除只有丢弃功能&#xff0c;所以可以添加垃圾桶 2.格…

vue(七) vue进阶

目录 第一课&#xff1a;Vue方法、计算机属性及侦听器 一、数组变化侦测 方法1&#xff1a;变更方法 方法2&#xff1a;替换一个数组 例子&#xff1a;小Demo:合并两个数组 二、计算属性 1.基础&#xff08;不推荐&#xff09; 2.使用计算属性来完成案例 3.使用函数的方…

Spring Boot 2 学习指南与资料分享

Spring Boot 2 学习资料 Spring Boot 2 学习资料 Spring Boot 2 学习资料 在当今竞争激烈的 Java 后端开发领域&#xff0c;Spring Boot 2 凭借其卓越的特性&#xff0c;为开发者们开辟了一条高效、便捷的开发之路。如果你渴望深入学习 Spring Boot 2&#xff0c;以下这份精心…

YangQG 面试题汇总

一、交叉链表 问题&#xff1a; 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点&#xff0c;返回 null 。 解题思想&#xff1a; 双指针 备注&#xff1a;不是快慢指针&#xff0c;如果两个长度相…

fastapi 使用

参考&#xff1a; https://fastapi.tiangolo.com/zh/tutorial/first-steps/https://fastapi.tiangolo.com/zh/tutorial/first-steps/ FastAPI 用于基于标准 Python 类型提示使用 Python 构建 API&#xff0c;使用 ASGI 的标准来构建 Python Web 框架和服务器。所有简单理解&a…

2024年度漏洞态势分析报告,需要访问自取即可!(PDF版本)

2024年度漏洞态势分析报告&#xff0c;需要访问自取即可!(PDF版本),大家有什么好的也可以发一下看看

泛目录和泛站有什么差别

啥是 SEO 泛目录&#xff1f; 咱先来说说 SEO 泛目录是啥。想象一下&#xff0c;你有一个巨大的图书馆&#xff0c;里面的书架上摆满了各种各样的书&#xff0c;每一本书都代表着一个网页。而 SEO 泛目录呢&#xff0c;就像是一个超级图书管理员&#xff0c;它的任务就是把这些…

k8s基础(6)—Kubernetes-存储

Kubernetes-存储概述 k8s的持久券简介 Kubernetes的持久卷&#xff08;PersistentVolume, PV&#xff09;和持久卷声明&#xff08;PersistentVolumeClaim, PVC&#xff09;为用户在Kubernetes中使用卷提供了抽象。PV是集群中的一块存储&#xff0c;PVC是对这部分存储的请求。…

深度学习-卷积神经网络反向传播梯度公式推导

这篇文章非常棒&#xff0c;单样本单通道的反向传播梯度公式推导我都理解了。为了防止找不到原网页&#xff0c;所以特复制于此 参考&#xff1a; https://zhuanlan.zhihu.com/p/640697443

论文笔记(四十七)Diffusion policy: Visuomotor policy learning via action diffusion(下)

Diffusion policy: Visuomotor policy learning via action diffusion&#xff08;下&#xff09; 文章概括5. 评估5.1 模拟环境和数据集5.2 评估方法论5.3 关键发现5.4 消融研究 6 真实世界评估6.1 真实世界Push-T任务6.2 杯子翻转任务6.3 酱汁倒入和涂抹任务 7. 实际双臂任务…

C#学习笔记 --- 简单应用

1.operator 运算符重载&#xff1a;使自定义类可以当做操作数一样进行使用。规则自己定。 2.partial 分部类&#xff1a; 同名方法写在不同位置&#xff0c;可以当成一个类使用。 3.索引器&#xff1a;使自定义类可以像数组一样通过索引值 访问到对应的数据。 4.params 数…