OpenCV计算变换与重投影的矩阵说明
2017-06-18 11:40
316 查看
本篇博客主要讨论opencv中两个函数中几何变换(矩阵)的对应关系,以下函数接口摘自opencv-2.4.8官方文档
1.Finds an object pose from 3D-2D point correspondences.
2.Projects 3D points to an image plane.
根据说明,可以看出,函数
函数
在空间几何变换中,很多时候会涉及到由坐标A变换到B或B变换到A类似容易弄混的情况(即一些矩阵和其逆矩阵具有不同应用场景的特性),一旦把变换矩阵的对象弄反,结果将南辕北辙。本文将通过代码实验的方式来验证,上述两个函数在所给变换一致(即
首先,给出小孔相机模型和一组3D点
camara=⎡⎣⎢⎢⎢fx000fy0cxcy1⎤⎦⎥⎥⎥(1)
这里为了直观说明坐标值,我们取fx、fy、cx、cy均为100
像素坐标系Op和相机坐标系Oc的转换公式如下:
x=(u−cx)∗fx/z,y=(v−cy)∗fy/z(2)
则
假设这四个3D点在空间中进行了统一的运动M(rvec,tvec),导致其在成像平面上的投影像素坐标发生了变化,变成了如下四个点:
对比可以看出,正方形面积缩小到了原来的1/4,长宽变为了原来的一半,可以直观地想象出来,这四个点所进行的运动即垂直远离成像平面,移动到了原来距离二倍的位置。使用本文引用的第一个函数,求出这个过程中的几何变换
输出结果:
结果里
然后来看看我们引用的第二个函数,第二个函数涉及到重投影,就是说,假如没有这个大小为1的位移,我们通过公式(2)即可由3D坐标得到2D坐标,但正是由于这个位移,因此需要引入几何变换(‘重’投影),我们要验证的是第一个函数计算得到的运动参数
结果如下:
和前面所给2D坐标一致,证明这两个函数的运动参数对应即可得到一致的坐标关系。
机器视觉里面,需要计算变换时,常常是相机在运动,而并非观测点在运动,而在文中所讨论的两个函数里,3D空间坐标系实际上是依照相机坐标系建立的,因此将相机视作静止,认为观测点在运动,因而这里得到的几何变换未必能直接拿来使用,相机运动的情况请参考另一篇博文 讨论opencv位姿估计结果与实际运动轨迹的关系(涉及变换矩阵与其逆矩阵)。
完整代码如下:
若有内容需要讨论,欢迎发邮件至gxsheen@foxmail.com
1.Finds an object pose from 3D-2D point correspondences.
bool solvePnP(InputArray objectPoints, InputArray imagePoints, InputArray cameraMatrix, InputArray distCoeffs, OutputArray rvec, OutputArray tvec, bool useExtrinsicGuess=false, int flags=ITERATIVE )
2.Projects 3D points to an image plane.
void projectPoints(InputArray objectPoints, InputArray rvec, InputArray tvec, InputArray cameraMatrix, InputArray distCoeffs, OutputArray imagePoints, OutputArray jacobian=noArray(), double aspectRatio=0 )
根据说明,可以看出,函数
solvepnp接收一组对应的3D坐标和2D坐标,计算得到两组坐标对应的几何变换(旋转矩阵
rvec,平移矩阵
tvec);
函数
projectPoints与之相反,根据所给的3D坐标和已知的几何变换来求解投影后的2D坐标。
在空间几何变换中,很多时候会涉及到由坐标A变换到B或B变换到A类似容易弄混的情况(即一些矩阵和其逆矩阵具有不同应用场景的特性),一旦把变换矩阵的对象弄反,结果将南辕北辙。本文将通过代码实验的方式来验证,上述两个函数在所给变换一致(即
tvec和
rvec相同)的情况下,所关联的空间点2D、3D坐标是否一致。
首先,给出小孔相机模型和一组3D点
camara=⎡⎣⎢⎢⎢fx000fy0cxcy1⎤⎦⎥⎥⎥(1)
这里为了直观说明坐标值,我们取fx、fy、cx、cy均为100
cv::Mat camera = ( cv::Mat_<double>(3,3) << 100 , 0 , 100 , 0 , 100 , 100 , 0 , 0 , 1 ); std::vector<cv::Point3f> totalPre; totalPre.push_back(cv::Point3f(-1,-1,1)); totalPre.push_back(cv::Point3f(-1,1,1)); totalPre.push_back(cv::Point3f(1,-1,1)); totalPre.push_back(cv::Point3f(1,1,1));
像素坐标系Op和相机坐标系Oc的转换公式如下:
x=(u−cx)∗fx/z,y=(v−cy)∗fy/z(2)
则
totalPre中的四个点可以看作是相机光心正前方距离为1处(此处不考虑单位,需要单位时,保证各处尺度一致即可)一个2*2的正方形的四个角点,其在成像平面上的像素坐标为(0,0)、(0,200)、(200,0)、(200,200)
假设这四个3D点在空间中进行了统一的运动M(rvec,tvec),导致其在成像平面上的投影像素坐标发生了变化,变成了如下四个点:
std::vector<cv::Point2f> totalPost; totalPost.push_back(cv::Point2f(50,50)); totalPost.push_back(cv::Point2f(50,150)); totalPost.push_back(cv::Point2f(150,50)); totalPost.push_back(cv::Point2f(150,150));
对比可以看出,正方形面积缩小到了原来的1/4,长宽变为了原来的一半,可以直观地想象出来,这四个点所进行的运动即垂直远离成像平面,移动到了原来距离二倍的位置。使用本文引用的第一个函数,求出这个过程中的几何变换
cv::Mat rvec,tvec; cv::solvePnP(totalPre,totalPost,camera,cv::Mat(),rvec,tvec); //由于这个过程中实际上没有发生旋转,因此输出平移信息观察结果 cout << "total PnP result : " << tvec << endl;
输出结果:
total PnP result : [-7.035697327650722e-17; -7.035697327650722e-17; 1]
结果里
tvec的前两个维度近似为0,第三个维度为1,表示在z方向(成像平面法向)位移为1,也就是说传给函数的这几个3D坐标向前运动位移为1,和我们的直观认识一致。
然后来看看我们引用的第二个函数,第二个函数涉及到重投影,就是说,假如没有这个大小为1的位移,我们通过公式(2)即可由3D坐标得到2D坐标,但正是由于这个位移,因此需要引入几何变换(‘重’投影),我们要验证的是第一个函数计算得到的运动参数
tvec和
rvec直接代入第二个函数,是否就能得到运动后的2D坐标,代码如下:
vector<cv::Point2f> reProjection; cv::projectPoints(totalPre,rvec,tvec,camera,cv::Mat(),reProjection); for (auto i:reProjection) cout << i.x << " " << i.y << endl;
结果如下:
50 50 50 150 150 50 150 150
和前面所给2D坐标一致,证明这两个函数的运动参数对应即可得到一致的坐标关系。
机器视觉里面,需要计算变换时,常常是相机在运动,而并非观测点在运动,而在文中所讨论的两个函数里,3D空间坐标系实际上是依照相机坐标系建立的,因此将相机视作静止,认为观测点在运动,因而这里得到的几何变换未必能直接拿来使用,相机运动的情况请参考另一篇博文 讨论opencv位姿估计结果与实际运动轨迹的关系(涉及变换矩阵与其逆矩阵)。
完整代码如下:
cv::Mat camera = ( cv::Mat_<double>(3,3) << 100 , 0 , 100 , 0 , 100 , 100 , 0 , 0 , 1 );
std::vector<cv::Point2f> totalPost;
std::vector<cv::Point3f> totalPre;
totalPre.push_back(cv::Point3f(-1,-1,1));
totalPre.push_back(cv::Point3f(-1,1,1));
totalPre.push_back(cv::Point3f(1,-1,1));
totalPre.push_back(cv::Point3f(1,1,1));
totalPost.push_back(cv::Point2f(50,50));
totalPost.push_back(cv::Point2f(50,150));
totalPost.push_back(cv::Point2f(150,50));
totalPost.push_back(cv::Point2f(150,150));
cv::Mat rvec,tvec; cv::solvePnP(totalPre,totalPost,camera,cv::Mat(),rvec,tvec); //由于这个过程中实际上没有发生旋转,因此输出平移信息观察结果 cout << "total PnP result : " << tvec << endl;
vector<cv::Point2f> reProjection; cv::projectPoints(totalPre,rvec,tvec,camera,cv::Mat(),reProjection); for (auto i:reProjection) cout << i.x << " " << i.y << endl;
若有内容需要讨论,欢迎发邮件至gxsheen@foxmail.com
相关文章推荐
- opencv3计算变换矩阵getAffineTransform函数和进行仿射变换warpAffine函数-滚动条
- opencv3计算变换矩阵getAffineTransform函数和进行仿射变换warpAffine函数
- (转)从零实现3D图像引擎:(13)把宽高比、透视投影矩阵、屏幕变换矩阵说透
- 视锥和投影矩阵,视口变换
- OpenGL学习-3-键盘事件注册以及投影矩阵变换练习代码
- OpenCV,计算两幅图像的单应矩阵
- opencv中矩阵计算的一些函数
- opengl中GL_MODELVIEW下的变换矩阵的说明
- 利用OpenCV计算图像的垂直和水平积分投影
- opencv计算矩阵与数值的乘积,矩阵与矩阵的乘积
- OpenCV,计算两幅图像的单应矩阵
- 利用OpenCV计算图像的垂直和水平积分投影
- OpenCV_颜色直方图的计算、显示、处理、对比及反向投影【转】
- 巧用OpenCV计算图片序列(矩阵)的直方图
- osg::NodeVisitor中计算一个节点对应的世界变换矩阵、法向量、顶点坐标
- OpenCV_颜色直方图的计算、显示、处理、对比及反向投影
- 将投影矩阵P利用QR分解分解出摄像机内外参数(Opencv)
- OpenCV - 计算矩阵(cv::Mat)的特征值和特征向量
- 使用OpenCV2.x计算图像的水平和垂直积分投影
- 利用OpenCV计算图像的垂直和水平积分投影