solvePNP问题

        OpenCV的solvePnP函数有四种可以选择的算法分别是:

                    

SOLVEPNP_ITERATIVE  适合点在同一平面上的情况
SOLVEPNP_EPNP 

EPnP: Efficient Perspective-n-Point Camera Pose Estimation [91].点需要在不同平面

SOLVEPNP_P3P 

Complete Solution Classification for the Perspective-Three-Point Problem [57].只适用于3点

SOLVEPNP_DLS 

A Direct Least-Squares (DLS) Method for PnP [73].至少四点不在同一平面

我对在同一平面且关于原点和坐标轴对称的点使用solvePnP,后三种算法出现了相机位置无法估计的情况,第一种算法成功估计出了相机位置。

测试投影和solvePnP功能的代码

void testProjection(std::vector &objs, cv::Mat &matrix, cv::Mat &coeff)
{
	//投影
	std::vector projected_pts;
	cv::Mat rvec_test=(cv::Mat_(3,1)<<0.,0.,0.);
	cv::Mat tvec_test=(cv::Mat_(3,1)<<0.,0.,1000.);
	//cv::Mat blank_img(5000,5000,CV_8UC3,cv::Scalar(255,255,255));
	Debug("test project start!");
	Debug("objs");
	Debug(objs);
	cv::projectPoints(objs,rvec_test,tvec_test,matrix,coeff,projected_pts);
	Debug("test project end!");
	Debug("projected_pts");
	Debug(projected_pts);
	
 	 /* for(int i=0;i<5;i++)
	{
		cv::circle(blank_img,projected_pts[i],5,cv::Scalar(0,0,0),-1);
	} 
	cv::imwrite("blank.png",blank_img);
	Debug("Draw Points Completed!"); 
	Debug("start solvePnP"); */
	//PnP
	cv::Mat r_test;
	cv::Mat t_test;
	cv::Mat R_test(3,3,CV_32F);
	cv::solvePnP(objs,projected_pts,matrix,coeff,r_test,t_test,false,CV_ITERATIVE);
	cv::Rodrigues(r_test,R_test);
	cv::Mat cam_pose_pnp;
	Debug("R_test");
	Debug(R_test);
	Debug("t_test");
	Debug(t_test);
	cv::transpose(R_test,R_test);
	cam_pose_pnp=-R_test*t_test;
	Debug("cam_pose_pnp");
	Debug(cam_pose_pnp);
	
}

总结一下:

对于8个点的情况:EPnP表现良好,DLS表现良好,EPnp与Upnp调用的函数接口相同 

对于4个点的情况:P3P表现良好,EPnp表现良好,然而P3P实际输入点数为4个,那么最后一个点用于检核。 

Epnp在4点的时候表现时好时坏,和控制点的选取状况相关。倘若增加为5个点,则精度有着明显提升 

4点的ITERATOR方法取得了很好的效果,甚至比P3P还要好,因为P3P只用三个点参与计算 

也就是说,在控制点对数量较少的情况下(4点),只有P3P可以给出正确结果 

增加一对控制点(变为5对)之后,Epnp的鲁棒性迅速提升,可以得到正确结果,DLS也同样取得了正确结果 

增加到5对控制点后P3P失效,因为只让用4个点,不多不少. 

同样的,5点的ITERATOR方法结果正确。 

结论:使用多于4点的EPnP最为稳妥. 




你可能感兴趣的:(OpenCV)