不同PNP求解算法性能测试
来源:互联网 发布:广告机发布软件 编辑:程序博客网 时间:2024/05/18 09:14
关键词:OpenCV::solvePnP
文章类型:方法封装、测试
@Author:VShawn(singlex@foxmail.com)
@Date:2016-11-27
@Lab: CvLab202@CSU
前言
今天给大家带来的是一篇关于程序功能、性能测试的文章,读过《相机位姿估计1:根据四个特征点估计相机姿态》一文的同学应该会发现,直接使用OpenCV的solvePnP来估计相机位姿,在程序调用上相当麻烦,从一开始的参数设定到最后将计算出的矩阵转化为相机的位姿参数,需要花费近两百行代码。因此为了更方便地调用程序,今天我就给大家带来一个我自己对solvePnP的封装类PNPSolver,顺便将OpenCV自带的三种求解方法测试一遍。
类的封装
封装的思路我就不写了,由于博客更新速度赶不上我写程序的速度,现在发上来的类已经修改过好几次了,思路也换了几次。不过大的方向没变,目的就是只需要输入参数,输入坐标点后直接可以得到相机在世界坐标系的坐标。
类的调用顺序:
1.初始化PNPSolver类;
2.调用SetCameraMatrix(),SetDistortionCoefficients()设置好相机内参数与镜头畸变参数;
3.向Points3D,Points2D中添加一一对应的特征点对;
4.调用Solve()方法运行计算;
5.从属性Theta_C2W中提取旋转角,从Position_OcInW中提取出相机在世界坐标系下的坐标。
一个典型的调用示例
//初始化PNPSolver类
PNPSolver p4psolver;
//初始化相机参数
p4psolver.SetCameraMatrix(fx, fy, u0, v0);
//设置畸变参数
p4psolver.SetDistortionCoefficients(k1, k2, p1, p2, k3);
//设置特征点的世界坐标
p4psolver.Points3D.push_back(cv::Point3f(0, 0, 0));
//P1三维坐标的单位是毫米
p4psolver.Points3D.push_back(cv::Point3f(0, 200, 0));
//P2
p4psolver.Points3D.push_back(cv::Point3f(150, 0, 0));
//P3
//p4psolver.Points3D.push_back(cv::Point3f(150, 200, 0)); //P4
p4psolver.Points3D.push_back(cv::Point3f(0, 100, 105));
//P5
cout <<
"test2:特征点世界坐标 = "
<< endl << p4psolver.Points3D << endl;
//设置特征点的图像坐标
p4psolver.Points2D.push_back(cv::Point2f(2985, 1688));
//P1
p4psolver.Points2D.push_back(cv::Point2f(5081, 1690));
//P2
p4psolver.Points2D.push_back(cv::Point2f(2997, 2797));
//P3
//p4psolver.Points2D.push_back(cv::Point2f(5544, 2757)); //P4
p4psolver.Points2D.push_back(cv::Point2f(4148, 673));
//P5
cout <<
"test2:图中特征点坐标 = "
<< endl << p4psolver.Points2D << endl;
if
(p4psolver.Solve(PNPSolver::METHOD::CV_P3P) == 0)
cout <<
"test2:CV_P3P方法: 相机位姿→"
<<
"Oc坐标="
<< p4psolver.Position_OcInW <<
" 相机旋转="
<< p4psolver.Theta_W2C << endl;
if
(p4psolver.Solve(PNPSolver::METHOD::CV_ITERATIVE) == 0)
cout <<
"test2:CV_ITERATIVE方法: 相机位姿→"
<<
"Oc坐标="
<< p4psolver.Position_OcInW <<
" 相机旋转="
<< p4psolver.Theta_W2C << endl;
if
(p4psolver.Solve(PNPSolver::METHOD::CV_EPNP) == 0)
cout <<
"test2:CV_EPNP方法: 相机位姿→"
<<
"Oc坐标="
<< p4psolver.Position_OcInW <<
" 相机旋转="
<< p4psolver.Theta_W2C << endl;
方法测试
OpenCV提供了三种方法进行PNP计算,三种方法具体怎么计算的就请各位自己查询opencv documentation以及相关的论文了,我看了个大概然后结合自己实际的测试情况给出一个结论,不一定正确,仅供参考:
方法名
说明
测试结论
CV_P3P
这个方法使用非常经典的Gao方法解P3P问题,求出4组可能的解,再通过对第四个点的重投影,返回重投影误差最小的点。
论文《Complete Solution Classification for the Perspective-Three-Point Problem》
可以使用任意4个特征点求解,不要共面,特征点数量不为4时报错
CV_ITERATIVE
该方法基于Levenberg-Marquardt optimization迭代求解PNP问题,实质是迭代求出重投影误差最小的解,这个解显然不一定是正解。
实测该方法只有用4个共面的特征点时才能求出正确的解,使用5个特征点或4点非共面的特征点都得不到正确的位姿。
只能用4个共面的特征点来解位姿
CV_EPNP
该方法使用EfficientPNP方法求解问题,具体怎么做的当时网速不好我没下载到论文,后面又懒得去看了。
论文《EPnP: Efficient Perspective-n-Point Camera Pose Estimation》
对于N个特征点,只要N>3就能够求出正解。
测试截图:
1.使用四个共面的特征点,显然三种方法都能得到正解,但相互之间略有误差。
2使用四个非共面的特征点,CV_ITERATIVE方法解错了。
3.使用5个特征点求解,只有CV_EPNP能够用
性能测试
最后对三种方法的性能进行测试,通过对test1重复执行1000次获得算法的运行时间,从结果可以看出迭代法显然是最慢的,Gao的P3P+重投影法用时最少,EPNP法其次。
总结
综合以上的测试,推荐使用CV_P3P来解决实际问题,该方法对于有四个特征点的情况限制少、运算速度快。当特征点数大于4时,可以取多组4特征点计算出结果再求平均值,或者为了简单点就直接使用CV_EPNP法。
https://github.com/vshawn/Shawn_pose_estimation_by_opencv/tree/master/%E7%9B%B8%E6%9C%BA%E4%BD%8D%E5%A7%BF%E4%BC%B0%E8%AE%A11_1%EF%BC%9AsolvePnP%E4%BA%8C%E6%AC%A1%E5%B0%81%E8%A3%85%E4%B8%8E%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95
作者:VShawn
出处:http://www.cnblogs.com/singlex/
本文版权归作者所有,欢迎转载,但未经博客作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
- 不同PNP求解算法性能测试
- 求解PNP问题
- PHP不同版本性能测试
- 不同阶段的性能测试
- 在disksim-3.0中安装flashsim,并测试不同FTL算法在不同trace下的性能
- MD5算法性能测试
- PnP
- Nagios整合pnp绘制性能分析图表
- 站在不同视角 感受性能测试
- 使用不同的算法求解0-1背包问题
- 四种不同算法求解0-1背包问题
- Matlab遗传算法性能测试
- FFMPEG sws_scale算法性能测试
- 常见排序算法性能测试
- 测试选择排序算法性能
- Java不同压缩算法的性能比较
- Java不同压缩算法的性能比较
- Java不同压缩算法的性能比较
- cef AutomatedBuildSetup
- [leetcode]598. Range Addition II
- 深入理解javascript原型和闭包(9)——简述【执行上下文】下
- web中鼠标的点击事件
- PHP实战之实现简单的分页
- 不同PNP求解算法性能测试
- web前端开发之几种布局方式之响应式布局
- 126. Word Ladder I & II
- 判断某一天是当年的哪一天
- Linux下安装gnuplot
- 代理模式
- 毫秒转换为天、小时、分、秒
- Eclipse 建立 Java Spring 最简控制台项目
- poj2195Going Home最小费用流