Opencv 3.4 中P3P位姿估计算法解析

2023-05-16

先上图,Opencv3.4中用两种算法实现P3P位姿估计问题。一种是基于距离P3P算法问题(算法1:P3P),一种是基于矩阵P3P算法问题(算法2:aP3P),具体推导细节可以参看论文还以整理的本地关键技术文档。此处只对程序进行分析注释,方便以后使用。注意:此处只注释算法2,因为算法1没有完全搞明白(主要是高小山用wu-ritt算法推导我看不太懂)。

外部调用接口函数:

/*  max 注释
*   函数功能:P3P位姿估计的接口函数,此函数可以利用不用的flags值,选择不同的算法。
*             输入3个对应点,返回最多4组有效解
*   参数:
*   [in]    objectPoints                参考坐标系(或世界坐标系)中的3D点,需要3个即可,不要多也不要少。float和double都可以    
*   [in]    imagePoints                 对应3D点在相机相平面上的投影点的图像坐标。需要3个即可,不要多也不要少。注意这个是2D的。float和double都可以
*   [in]    cameraMatrix                相机内参矩阵
*   [in]    distCoeffs                  相机畸变矩阵
*   [out]   rvecs                       输出旋转矩阵,不用声明是多大矩阵-----输出是最多是4个解----每个解的旋转是用旋转向量表示的。------从参考坐标中的点到相机坐标系的点的变换
*   [out]   tvecs                       输出平移矩阵,不用声明多大矩阵------输出最多是4个解。
*   [in]    flags                       选择不同的结算位姿算法,SOLVEPNP_P3P是算法1,采用基于距离PnP算法。SOLVEPNP_AP3P算法2,采用基于矩阵PnP算法。
*
*    返回值:
*            返回解的个数,最大不会超过4个。
*/
int solveP3P(InputArray objectPoints, InputArray imagePoints,	InputArray cameraMatrix, InputArray distCoeffs,	OutputArrayOfArrays rvecs, OutputArrayOfArrays tvecs,int flags);

测试例子:

#include "test_precomp.hpp"

void generate3DPointCloud(std::vector<cv::Point3f>& points, cv::Point3f pmin = cv::Point3f(-1, -1, 5), cv::Point3f pmax = cv::Point3f(1, 1, 10))
{
	cv::RNG rng = cv::theRNG(); // fix the seed to use "fixed" input 3D points

	for (size_t i = 0; i < points.size(); i++)
	{
		float _x = rng.uniform(pmin.x, pmax.x);
		float _y = rng.uniform(pmin.y, pmax.y);
		float _z = rng.uniform(pmin.z, pmax.z);
		points[i] = cv::Point3f(_x, _y, _z);
	}
}

void generateCameraMatrix(cv::Mat& cameraMatrix, cv::RNG& rng)
{
	const double fcMinVal = 1e-3;
	const double fcMaxVal = 100;
	cameraMatrix.create(3, 3, CV_64FC1);
	cameraMatrix.setTo(cv::Scalar(0));
	cameraMatrix.at<double>(0, 0) = rng.uniform(fcMinVal, fcMaxVal);
	cameraMatrix.at<double>(1, 1) = rng.uniform(fcMinVal, fcMaxVal);
	cameraMatrix.at<double>(0, 2) = rng.uniform(fcMinVal, fcMaxVal);
	cameraMatrix.at<double>(1, 2) = rng.uniform(fcMinVal, fcMaxVal);
	cameraMatrix.at<double>(2, 2) = 1;
}

void generateDistCoeffs(cv::Mat& distCoeffs, cv::RNG& rng)
{
	distCoeffs = cv::Mat::zeros(4, 1, CV_64FC1);
	for (int i = 0; i < 3; i++)
		distCoeffs.at<double>(i, 0) = rng.uniform(0.0, 1.0e-6);
}

void generatePose(cv::Mat& rvec, cv::Mat& tvec, cv::RNG& rng)
{
	const double minVal = 1.0e-3;
	const double maxVal = 1.0;
	rvec.create(3, 1, CV_64FC1);
	tvec.create(3, 1, CV_64FC1);
	for (int i = 0; i < 3; i++)
	{
		rvec.at<double>(i, 0) = rng.uniform(minVal, maxVal);
		tvec.at<double>(i, 0) = rng.uniform(minVal, maxVal / 10);
	}
}


int main()
{
	std::vector<cv::Point3f> points;
	points.resize(500);
	generate3DPointCloud(points);


	std::vector<cv::Mat> rvecs, tvecs;
	cv::Mat trueRvec, trueTvec;
	cv::Mat intrinsics, distCoeffs;

	generateCameraMatrix(intrinsics, cv::RNG());	
	generateDistCoeffs(distCoeffs, cv::RNG());

	generatePose(trueRvec, trueTvec, cv::RNG());

	std::vector<cv::Point3f> opoints;
	opoints = std::vector<cv::Point3f>(points.begin(), points.begin() + 3);

	std::vector<cv::Point2f> projectedPoints;
	projectedPoints.resize(opoints.size());
	projectPoints(cv::Mat(opoints), trueRvec, trueTvec, intrinsics, distCoeffs, projectedPoints);

	std::cout << "intrinsics: " << intrinsics << std::endl;
	std::cout << "distcoeffs: " << distCoeffs << std::endl;
	std::cout << "trueRvec: " << trueRvec << std::endl;
	std::cout << "trueTvec: " << trueTvec << std::endl;

	std::cout << "oPoint: " << opoints << std::endl;
	std::cout << "projectedPoints: " << projectedPoints << std::endl;



	std::cout<<"result numbers A: :"<<solveP3P(opoints, projectedPoints, intrinsics, distCoeffs, rvecs, tvecs, cv::SOLVEPNP_AP3P)<<std::endl;
	//std::cout << "result numbers: :" << solveP3P(opoints, projectedPoints, intrinsics, distCoeffs, rvecs, tvecs, cv::SOLVEPNP_P3P) << std::endl;

	bool isTestSuccess = false;
	double error = DBL_MAX;
	for (unsigned int i = 0; i < rvecs.size() /*&& !isTestSuccess*/; ++i)
	{
		double rvecDiff = cvtest::norm(rvecs[i], trueRvec, cv::NORM_L2);
		double tvecDiff = cvtest::norm(tvecs[i], trueTvec, cv::NORM_L2);
		isTestSuccess = rvecDiff < 1.0e-4 && tvecDiff < 1.0e-4;
		error = std::min(error, std::max(rvecDiff, tvecDiff));
		std::cout << "i: " << i << std::endl;
		std::cout << "error: " << error << std::endl;
		std::cout << "rvec: " << rvecs[i] << std::endl;

	}

	system("pause");
}

算法2中代码描述,下面所描述的不是Opencv外部提供的接口,属于算法的内部实现。---代码在ap3p.h头文件中。


#ifndef P3P_P3P_H
#define P3P_P3P_H

#include "precomp.hpp"

namespace cv {
class ap3p {
private:
    template<typename T>
    void init_camera_parameters(const cv::Mat &cameraMatrix) {
        cx = cameraMatrix.at<T>(0, 2);
        cy = cameraMatrix.at<T>(1, 2);
        fx = cameraMatrix.at<T>(0, 0);
        fy = cameraMatrix.at<T>(1, 1);
    }

    template<typename OpointType, typename IpointType>
    void extract_points(const cv::Mat &opoints, const cv::Mat &ipoints, std::vector<double> &points) {
        points.clear();
        int npoints = std::max(opoints.checkVector(3, CV_32F), opoints.checkVector(3, CV_64F));
        points.resize(5*npoints);
        for (int i = 0; i < npoints; i++) {
            points[i * 5] = ipoints.at<IpointType>(i).x * fx + cx;
            points[i * 5 + 1] = ipoints.at<IpointType>(i).y * fy + cy;
            points[i * 5 + 2] = opoints.at<OpointType>(i).x;
            points[i * 5 + 3] = opoints.at<OpointType>(i).y;
            points[i * 5 + 4] = opoints.at<OpointType>(i).z;
        }
    }

    void init_inverse_parameters();

    double fx, fy, cx, cy;
    double inv_fx, inv_fy, cx_fx, cy_fy;
public:
	// 3个初始化构造函数的目的是获取相机内参数,并且计算相机内参矩阵的逆。---------用于求解论文中的bearing measurement
    ap3p() : fx(0), fy(0), cx(0), cy(0), inv_fx(0), inv_fy(0), cx_fx(0), cy_fy(0) {}

    ap3p(double fx, double fy, double cx, double cy);

    ap3p(cv::Mat cameraMatrix);



	/*  max 注释
	*   函数功能:此处的位姿估计只返回一个解,并且此处输入的是4个点---注意并不是solveP3P所调用。调用顺序为①-->④-->③
	*   参数:
	*   [out]   R                输出单个旋转矩阵
	*   [out]   tvec             输出单个平移向量
	*   [in]    opoints          输入3D点---4个
	*   [in]    ipoints          输入2D点---4个
	*
	*    返回值:
	*            成功返回true,失败返回false
	*/
    ① bool solve(cv::Mat &R, cv::Mat &tvec, const cv::Mat &opoints, const cv::Mat &ipoints);

	/*  max 注释
	*   函数功能:此处的位姿估计只返回最多4个解,是solveP3P所调用。调用顺序为②-->③
	*   参数:
	*   [out]   R                输出最多4个旋转矩阵
	*   [out]   tvec             输出最多4平移向量
	*   [in]    opoints          输入3D点---3个
	*   [in]    ipoints          输入2D点---3个
	*
	*    返回值:
	*            成功返回true,失败返回false
	*/
    ② int solve(std::vector<cv::Mat> &Rs, std::vector<cv::Mat> &tvecs, const cv::Mat &opoints, const cv::Mat &ipoints);

    ③ int solve(double R[4][3][3], double t[4][3],
              double mu0, double mv0, double X0, double Y0, double Z0,
              double mu1, double mv1, double X1, double Y1, double Z1,
              double mu2, double mv2, double X2, double Y2, double Z2);

    ④ bool solve(double R[3][3], double t[3],
               double mu0, double mv0, double X0, double Y0, double Z0,
               double mu1, double mv1, double X1, double Y1, double Z1,
               double mu2, double mv2, double X2, double Y2, double Z2,
               double mu3, double mv3, double X3, double Y3, double Z3);


	// 此处完全按照论文的计算步骤来的,程序非常清晰,可以参考论文
    // This algorithm is from "Tong Ke, Stergios Roumeliotis, An Efficient Algebraic Solution to the Perspective-Three-Point Problem" (Accepted by CVPR 2017)
    // See https://arxiv.org/pdf/1701.08237.pdf
    // featureVectors: 3 bearing measurements (normalized) stored as column vectors
    // worldPoints: Positions of the 3 feature points stored as column vectors
    // solutionsR: 4 possible solutions of rotation matrix of the world w.r.t the camera frame
    // solutionsT: 4 possible solutions of translation of the world origin w.r.t the camera frame
    int computePoses(const double featureVectors[3][3], const double worldPoints[3][3], double solutionsR[4][3][3],
                     double solutionsT[4][3]);

};
}
#endif //P3P_P3P_H


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Opencv 3.4 中P3P位姿估计算法解析 的相关文章

  • 如何在没有 OpenCv Manager 的情况下运行 OpenCV 代码

    我正在使用 OpenCV4Android 版本 2 4 10 并在 Samsung Galayx GT I9300 上测试我的代码 我遇到的问题是 我必须从 Play 商店下载 Opencv Manager 以便我的 opencv 代码运行
  • 针对不同相机(RGB 和红外)的 StereoCalibrate

    我在校准两个摄像头时遇到问题 第一个是 RGB 第二个是红外 它们有不同的分辨率 我调整了大小并裁剪了更大的图像 焦距等等 例子 RGB 1920x1080 Infrared 512x424 如何相互校准它们 我应该在stereoCalib
  • 构建 OpenCV 时出错 :: MonitorFromRect 未在此范围内声明

    我试图建立OpenCV version 2 4 8与它一起使用CodeBlocks and MinGw 我按照以下指示进行操作here http kevinhughes ca tutorials opencv install on wind
  • 使用 Azure 机器学习检测图像中的符号

    4年前我发帖这个问题 https stackoverflow com q 6999920 411094不幸的是 得到的一些答案超出了我的技能水平 我刚刚参加了一次构建巡演会议 他们在会上谈论了机器学习 这让我想到了使用 ML 来解决我的问题
  • 附加信息:OpenCV:使用 c# 的不同大小的对象

    目前 我的 EmguCV c 代码面临问题 我试图从数据库中识别我的图像 但它不起作用 一旦检测到我的脸 它就会崩溃 然后会出现此错误 附加信息 OpenCV 不同大小的对象 我尝试寻找这个错误 但我一无所知 这是我的代码 Action f
  • OpenCV 中“IplImage”和“CvMat”的全称是什么?

    有一个IplImage and CvMat在 OpenCV 中 他们的全名是什么 IPL in IplImage代表英特尔处理库 这是Intel维护OpenCV时的残余 CV in cvMat代表计算机视觉矩阵 这是图形中常用的数据结构 I
  • 如何计算立体视觉的基本矩阵

    我正在尝试编写一些代码来计算基本矩阵以确定立体图像之间的关系 我从大多数人推荐的 Hartley 和 Zisserman 书开始 但它没有任何实际示例 并且示例代码是在 MATLAB 中 而我没有 然后我切换到这个比较实用 里面有实际例子
  • 将线性数组转换为二维矩阵

    我有一个浮点指针 数组 它代表一个图像 它的元素计数和索引具有宽度 高度 图像不像矩阵 其原点位于左上角 相反 它的原点位于左下角 就像在笛卡尔坐标系中一样 达到最大宽度后 它从左侧开始下一行 所以我想有效地将 这个数组转换为二维矩阵 可选
  • 在 Android 中使用 OpenCV 查找图像匹配

    我正在尝试构建一个 Android 应用程序 该应用程序可以比较设备相机拍摄的照片 以在一组图像中找到匹配项 我已经在 Android Studio 上配置了 OpenCV 但仅此而已 有人可以通过链接到资源或建议教程来提供帮助吗 Open
  • Haar训练时正样本和负样本使用多少张图片?

    我已经阅读了大量有关 Haar 训练的内容 但我不清楚应该为正样本集和负样本集使用多少图像 我看到建议使用很多图像 有些人推荐数千张 我也不清楚正负样本图像的数量是否应该相同 这是关于 Haar 训练的最佳教程 你试过这个吗 http no
  • 使用 cv2 在 python 中创建多通道零垫

    我想用 cv2 opencv 包装器在 python 中创建一个多通道 mat 对象 我在网上找到了一些例子 其中 c Mat zeros 被 numpy zeros 替换 这看起来不错 但似乎没有多通道类型适合 看代码 import cv
  • 如何在 OpenCV 中将 Float Mat 写入文件

    我有一个矩阵 Mat B 480 640 CV 32FC1 包含浮点值 我想将此矩阵写入一个可以打开的文件Notepad https en wikipedia org wiki Windows Notepad or 微软Word https
  • 使用 OpenCV 和 Python 叠加两个图像而不丢失颜色强度

    如何叠加两个图像而不损失两个图像的颜色强度 我有图像1和图像2 2 我尝试使用 0 5 alpha 和 beta 但它给我的合并图像的颜色强度只有一半 dst cv2 addWeighted img1 0 5 img2 0 5 0 但是当我
  • 在OpenCV中将YUV转换为BGR或RGB

    我有一个电视采集卡 其输入内容为 YUV 格式 我在这里看到了与此问题类似的其他帖子 并尝试尝试所述的所有可能的方法 但它们都没有提供清晰的图像 目前最好的结果是 OpenCVcvCvtColor scr dst CV YUV2BGR 函数
  • python openCV 中的人口普查变换

    我开始在一个与立体视觉相关的项目中使用 openCV 和 python 我找到了关于使用 openCV 在 C 中进行人口普查转换的文档页面 link http docs opencv org 3 1 0 d2 d7f namespacec
  • 从凸点获取角点

    我编写了算法来提取图像中显示的点 它们形成凸形 我知道它们的顺序 如何从这些点中提取角点 顶部 3 个和底部 3 个 我正在使用opencv 如果你已经有了物体的凸包 并且该包包含角点 那么你需要做的就是简化包直到它只有 6 个点 有很多方
  • 如何识别与我的对象相关的轮廓并找到它们的几何质心

    问题陈述和背景信息 EDIT 约束 法兰上的红色会随着时间的推移而变化 所以我此时不会尝试使用颜色识别来识别我的对象 除非它足够强大 此外 外部照明也可能是一个因素 因为将来这将是在室外区域 我有 RGB 深度相机 有了它 我就能捕捉到这个
  • 使用 openCV 对图像中的子图像进行通用检测

    免责声明 我是计算机视觉菜鸟 我看过很多关于如何在较大图像中查找特定子图像的堆栈溢出帖子 我的用例有点不同 因为我不希望它是具体的 而且我不确定如何做到这一点 如果可能的话 但我感觉应该如此 我有大量图像数据集 有时 其中一些图像是数据集的
  • 如何将 Opencv VideoWriter 与 GStreamer 结合使用?

    我正在尝试使用 Opencv VideoWriter 传输 h264 流 以使用 VideoCapture 将其传输到网络上的另一台电脑上 但是 我被困在 VideoWriter 上 执行此代码会返回错误 并且 out isOpened 始
  • OpenCV:将垫子除以标量的最简单方法是什么

    我认为标题中已经包含了很多内容 显然我可以迭代和划分 但我认为有一种内置的方法 我看见cvConvertScale但这不适用于类型cv Mat 我知道标量乘法的缩放运算 cv Mat M float alpha cv Mat Result

随机推荐

  • 利用ANTLR生成C++描述的分析程序

    摘要 ANTLR xff08 ANother Tool for Language Recognition xff09 是一种基于 LL xff08 k xff09 文法的语法分析程序 xff08 以下简称分析器 xff09 生成工具 其生成
  • eclipse中遇到的JSP文件无法保存问题

    xfeff xfeff 提示设置的编码不包含在某个编码中 首先要保证自己写的编码名字正确 xff0c 因为如果编码拼写错误 xff0c 也不可以保存 然后 xff0c 解决方法如下 xff1a 在 Window 菜单里面找到 Prefere
  • 在 word 中 mathType 菜单灰色,无法使用

    问题 xff1a 在 word 中安装的 mathType 菜单是灰色的 xff0c 不能使用 解决方法 xff1a 把 C Program Files x86 Common Files microsoft shared VBA VBA6
  • 基本遗传算法(GA)的算法原理、步骤、及Matlab实现

    算法原理 遗传算法可以用来求函数的极值 xff08 1 xff09 用二进制编码来离散自变量 xff0c 码长根据离散精度来确定 码长为 l o g 2 xff08 m a x m i n 精 度 43 1 xff08 2 xff09 交叉
  • 机器人工具箱 V9.10(Robotics Toolbook) (1):建立机器人模型

    机器人学工具箱 xff08 Robotics Toolbook for Matlab 是matlab中专门用于机器人仿真的工具箱 xff0c 在机器人建模 轨迹规划 控制 可视化方面使用非常方便 创建机器人的两个最重要的函数是 xff1a
  • 机器人动力学方程的性质

    一个 n 连杆的机器人的动力学方程含有很多项 特别是全部是转动关节的机械臂 让人看着害怕 但是 机器人动力学方程含有一些有助于开发控制算法的重要性质 其中最重要的是反对称性 无源性 有界性和参数的线性性 反对称性 skew aymmetry
  • LaTEX、 Aurora、 markdown常用数学符号

    在用 LaTEX 的时候 xff0c 公式排版中经常用到各种数学符号 xff0c 平时在编写 word 文档时 xff0c 应用 Aurora 编辑公式时也经常用到 xff0c 就是在CSDN 中用markdwon 编辑公式的时候也要用到
  • 机器人(机械臂)动力学建模方法(Newton-Euler equation)

    牛顿 欧拉公式 xff08 Newton Euler equation xff09 根据中间连杆上的力 力矩平衡关系上推断出来的 它的解具有递归的形式 xff0c 前向递归用于连杆的速度 加速度的传递 xff0c 后向递归用于力的传递 参数
  • 基于重力补偿的 PD 控制

    PD 控制是常规的控制方法 xff0c 设计简单 xff0c 用李雅普诺夫方法证明简单 xff0c 不需要系统的模型 xff0c 是无模型控制中的基本方法 令 q T q T 为系统的状态向量 xff0c 其中 xff1a q 61 q d
  • 矩阵的 Jordan 标准型

    如果把矩阵化成对角矩阵 xff0c 关于矩阵的函数计算问题就会大大简化 但一般的矩阵未必与对角矩阵相似 矩阵的标准型有多重 xff0c Jordan xff08 约当 xff09 标准型是最接近对角矩阵的形式 xff0c 在控制理论中经常用
  • 滑膜控制的基本原理

    滑动模态的定义 人为设定一经过平衡点的相轨迹 xff0c 通过适当设计 xff0c 系统状态点沿着此相轨迹渐近稳定到平衡点 xff0c 或形象地称为滑向平衡点的一种运动 xff0c 滑动模态的 滑动 二字即来源于此 滑模控制的优点 xff1
  • 基于策略的设计 vs 多继承

    基于策略的设计是对多继承的超越 基于策略的设计 xff08 Policy Based Design xff09 包含两个重要的部分 xff1a 策略类 xff08 Policy Classes xff09 和一个具有极大张力的核心 许 多人
  • linux 如何以树形结构显示文件目录结构

    linux 如何以树形结构显示文件目录结构 1 linux 如何显示文件信息 一般可用 ls 命令来查看文件的信息 xff1a ls OPTION FILE 如 xff1a ls 显示所有文件 ls 1 显示所有文件 xff08 按行显示
  • ROS学习(五):package.xml 文件

    package xml 文件 和 manifest 文件类似 xff0c 描述功能包的属性 xff0c 包括功能包的名字 版本号 作者 维护者 通行证 以及所以来的功能包 http wiki ros org catkin package x
  • ROS Gazebo(一):安装与使用

    gazebo 可以主要用来进行机器人动力学的仿真 一 安装和开始 完整安装时已经安装好 xff08 ros kinetic desktop full ros jade desktop full xff0c ros indigo deskto
  • 如何在window系统VS中设置boost编程环境

    在windows系统中设置boost编程非常简单 xff1a 1 下载boost软件包 网址 xff1a http www boost org 最新版 xff1a http www boost org users history versi
  • 个人信用报告机构查询中有:深圳前海微众银行股份有限公司,为什么???

    最近 xff0c 网上各路专家纷纷现身解读新版征信 xff0c 我就查询了一下自己的 xff0c 发现一条被 深圳前海微众银行股份有限公司 查询的记录 xff0c 不理解 xff0c 惊讶带恐慌 随后查询了一下相关的知识 查询报告流程 ht
  • 各种平板显示技术比较

    各种平板显示技术简介 CRT发展历史 CRT xff08 Cathode Ray Tube xff09 即阴极射线管 xff0c 作为成像器件 xff0c 它是实现最早 应用最为广泛的一种显示技术 阴极射线管 xff08 CRT xff09
  • k8s网络与本地开发环境网络互通方案(一)

    现状 k8s集群内是有一套完整网络环境 我们不能直接通过IP访问到k8s集群内的pod 或者service 只能通过nodeport 或者ingress 才能访问到服务 痛点 开发人员进行微服务开发的时候需要通过服务发现进行Pod级服务的直
  • Opencv 3.4 中P3P位姿估计算法解析

    先上图 xff0c Opencv3 4中用两种算法实现P3P位姿估计问题 一种是基于距离P3P算法问题 xff08 算法1 xff1a P3P xff09 xff0c 一种是基于矩阵P3P算法问题 xff08 算法2 xff1a aP3P