相机姿态估计

4 篇文章 0 订阅

一、相机姿态估计原理

在这里插入图片描述
首先介绍一下什么是世界坐标系和相机坐标系——世界坐标系是自己定义的一个坐标系,这里我定义世界坐标系是X轴垂直屏幕指向人,Y轴水平向右,Z轴竖直向上。相机坐标系有统一的规定,如图所示,x轴平行于相机镜头水平向左,y轴平行于相机镜头向下,z轴垂直于镜头水平指向人。
我们求相机在世界坐标系中的姿态的需求往往就是求一个相机坐标下的点在世界坐标系下的坐标,或者是一个世界坐标系下的点在相机坐标系的坐标。

首先思考一下为什么能在一个确定的世界坐标系下确定相机的姿态(姿态也就是指相机在世界坐标系中的具体位置,包括xyz坐标轴旋转量与平移量)。假如相机坐标系与和世界坐标系相对静止,那么两者之间的关系就是确定的,通过一定的方法肯定可以算出两者之间的关系。这里肯定有人要问算出两者之间的关系需要几个相机,答案是只需要一个(上面的示意图片只是因为我没有单目相机,整个实验过程只用到了左相机)。只用一个相机的前提是必须知道相机的内参,包括内参矩阵和畸变矩阵。至于为什么在知道内参矩阵和畸变矩阵条件下可以用一个相机算出相机的姿态暂时还没完全参透。

在这里插入图片描述
在上图中,小写的xyz是点在相机坐标系中的坐标,大写的XYZ是点在世界坐标系中的坐标。R33是旋转矩阵,T31是平移矩阵,这里非常值得注意的是,坐标的单位要统一,其次是当输入的世界坐标是实际的坐标数值时,计算出来的平移矩阵也是实际的平移量。我们的目标就转变为求旋转矩阵和是平移矩阵。
下面先介绍这两个矩阵:
①旋转矩阵:
在这里插入图片描述
现在要求A到B的旋转矩阵,XB、YB、ZB、XA、YA、ZA分别是指各个坐标轴方向的单位向量。A为世界坐标系,B为相机坐标系。
在这里插入图片描述
在这里插入图片描述
则有
在这里插入图片描述
知道旋转矩阵各项的意义,可以帮助我们大概地判断我们计算出来的旋转矩阵是否正确。
②平移矩阵
现在回到这个图:
在这里插入图片描述
如果要求一个点世界坐标系的点在相机坐标系的坐标,设点在世界坐标系中的坐标是[X;Y;Z] (这里用31的矩阵表示点),那么在求出旋转矩阵后,由R[X;Y;Z]可以得出点在旋转后的世界坐标系中的坐标,此时的世界坐标系变为三个坐标轴分别与相机坐标系三个坐标轴平行的坐标系,如下图所示:
在这里插入图片描述
而其中的▲x,▲y分别是上图中两个坐标系对应轴的距离(z轴也一样,有点难画就不画了)。平移矩阵T=[▲x;▲y;▲z]。通过几何意义我们也可以大概判断计算出来的平移矩阵是否正确。

二、相机姿态估计实现

首先我们需要得到相机的内参,可以通过张正友标定法得到相机的内参矩阵和畸变矩阵。具体步骤这里就不展开了,下面是我的得到的内参矩阵和畸变矩阵:
在这里插入图片描述
相机拍摄图片的分辨率是19201080,相机的像元尺寸是2.2um2.2um。
旋转矩阵和平移矩阵的求取通过Opencv的PnP算法,采用的函数是solvePnP,下面介绍一下这个函数:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
函数的介绍可以在这里找到
通过上面的函数介绍可知,我们需要做的是取得至少4对的匹配点,即图像的二维坐标点和世界坐标系中的三维坐标点。如何比较准确地得出点在世界坐标系中的坐标需要我们好好想一想。由于这里我的世界坐标系比较特殊,我采用了一根碳素杆,在碳素杆上标记一个小白点,让碳素杆平整的一段垂直于屏幕紧靠,紧靠的点在屏幕上的世界坐标可以通过手工测量得出,而小白点的X坐标就是碳素杆平整一段到小白点的距离,YZ坐标值与紧靠的点相同。
从文章开头到现在我们都是求世界坐标系的点到相机坐标系的点的旋转矩阵和平移矩阵,那么如果要求相机坐标系的点到世界坐标系的点的旋转矩阵和平移矩阵,那么我们可以先求出世界坐标系的点到相机坐标系的点的旋转矩阵R和平移矩阵T,然后通过下式求得相机坐标系的点在世界坐标系中的坐标:
在这里插入图片描述
实现代码如下:
这里我的目的是求两个相机的光心的世界坐标。

#include <opencv2\opencv.hpp>
#include <fstream> 
#include <iostream>
#include <vector>
#include <Eigen/Core>
#include <Eigen/SVD>
#include <Eigen/Dense>
#include <Eigen/Geometry>
#include <cmath>
using namespace std;
using namespace cv;
using namespace Eigen;

int main()
{
	Mat rvec_L, tvec_L, rvec_R, tvec_R;
	//左相机的内参矩阵
	Mat cameraMatrix_L = (Mat_<double>(3, 3) << 1492.320675688276, 0, 1042.383048569903,
											   0, 1443.277689279584, 561.8151909811569,
											   0, 0, 1);
	//左相机的畸变矩阵
	Mat disCoeffs_L = (Mat_<double>(1,5) << 0.8855691467581785, -3.76931898492866, 0.001722608150198718, 0.09559525553142016, 8.767109962143531);
	//右相机的内参矩阵
	Mat cameraMatrix_R = (Mat_<double>(3, 3) << 1489.387347765696, 0, 1155.32002834218,
												0, 1446.451497184327, 499.0095775742494,
												0, 0, 1);
	//右相机的畸变矩阵
	Mat disCoeffs_R = (Mat_<double>(1, 5) << 1.010043485302243, -8.566544837424154, -0.002706277601760965, 0.09466761963281151, 32.5513838899965);
	//匹配点的坐标,这里取5对,不要取6对
	vector<Point3d> PointSets = { Point3d(415,115,195),Point3d(415,230,195),Point3d(415,345,195),Point3d(415,115,130),Point3d(415,230,130) };
	vector<Point2f> imgPoints_L = { Point2f(1230,659),Point2f(841,662) ,Point2f(436,683) ,Point2f(1266,893) ,Point2f(824,864) }; 
    vector<Point2f> imgPoints_R = { Point2f(1428,604),Point2f(1039,607) ,Point2f(640,627) ,Point2f(1483,838) ,Point2f(1040,808) }; 
	solvePnP(PointSets, imgPoints_L, cameraMatrix_L, disCoeffs_L, rvec_L, tvec_L);
	solvePnP(PointSets, imgPoints_R, cameraMatrix_R, disCoeffs_R, rvec_R, tvec_R);
	Mat R_L, R_R;
	//转换为旋转矩阵,但是格式仍然是Mat类型
	Rodrigues(rvec_L, R_L);
	Rodrigues(rvec_R, R_R);
	Matrix<double, 3, 3> Matrix_R_L;//世界坐标系到左相机坐标系的旋转矩阵
	Matrix<double, 3, 3> Matrix_R_R;//世界坐标系到右相机坐标系的旋转矩阵
	Matrix<double, 3, 1> Matrix_T_L;//世界坐标系到左相机坐标系的平移矩阵
	Matrix<double, 3, 1> Matrix_T_R;//世界坐标系到右相机坐标系的平移矩阵
	Matrix<double, 3, 1> oL_in_world;//左相机光心在世界坐标系中的坐标
	Matrix<double, 3, 1> oR_in_world;//右相机光心在世界坐标系中的坐标
	Matrix<double, 3, 1> o_in_cameraL;//左相机光心在左相机坐标系中的坐标
	Matrix<double, 3, 1> o_in_cameraR;//右相机光心在右相机坐标系中的坐标
	//光心就是各自相机坐标系的原点
	o_in_cameraL(0, 0) = 0;
	o_in_cameraL(1, 0) = 0;
	o_in_cameraL(2, 0) = 0;
	o_in_cameraR(0, 0) = 0;
	o_in_cameraR(1, 0) = 0;
	o_in_cameraR(2, 0) = 0;
	//将Mat类型的旋转矩阵和平移矩阵转化为Matrix类型
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			Matrix_R_L(i, j) = R_L.at<double>(i, j);
			Matrix_R_R(i, j) = R_R.at<double>(i, j);
		}
		Matrix_T_L(i, 0) = tvec_L.at<double>(i, 0);
		Matrix_T_R(i, 0) = tvec_R.at<double>(i, 0);
	}
	oL_in_world = Matrix_R_L.inverse()*(o_in_cameraL - Matrix_T_L);
	oR_in_world = Matrix_R_R.inverse()*(o_in_cameraR - Matrix_T_R);
	cout << "oL_in_world=" << oL_in_world << endl;
	cout << "oR_in_world=" << oR_in_world << endl;
	return 0;
}

在这里插入图片描述
中间求解的旋转矩阵和平移矩阵如下:
在这里插入图片描述

  • 12
    点赞
  • 67
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论
### 回答1: OpenCV 是一个开源的计算机视觉库,可以用于在计算机中实现图像和视频处理的各种功能。相机姿态指的是相机的位置和方向,即相机在三维空间中的位置和所朝向的方向。利用OpenCV,我们可以实现相机姿态的更新,也就是根据输入的图像或视频序列,估计相机的位置和方向的变化。 要实现相机姿态更新,我们需要使用计算机视觉中的一些技术和方法。首先,我们需要提取图像中的特征点,比如角点或边缘点。这些特征点可以用于后续的特征匹配和姿态估计。 接下来,我们可以使用特征匹配的方法,将当前图像的特征点与参考图像(通常是第一帧)中的特征点进行匹配。这样,我们就可以得到一个特征点对应的关系。 利用这些特征点对应的关系,我们可以使用相机姿态估计算法,例如RANSAC或PnP算法,来估计相机的位置和方向。这些算法可以根据特征点的位置和关系,计算出相机的姿态。 最后,我们可以根据相机姿态的更新结果,将图像进行投影变换,从而实现将三维空间中的点投影到图像上的目的。这个过程常常被用于增强现实和虚拟现实等应用中。 总之,通过使用OpenCV提供的图像处理和计算机视觉功能,我们可以实现相机姿态的更新。具体的实现步骤包括特征提取、特征匹配、姿态估计等。这样,我们就可以根据输入的图像或视频序列,实时地估计相机的位置和方向的变化,并进行相应的图像处理和投影变换。 ### 回答2: OpenCV是一个基于开源的计算机视觉库,可以用于图像处理和计算机视觉任务。在实现相机姿态更新时,需要使用OpenCV的特征点检测和匹配技术,以及相机姿态估计算法。 首先,我们需要使用OpenCV的特征点检测算法,如SIFT、SURF或ORB等,来在图像中提取出特征点和对应的特征描述子。这些特征点可以是图像中的角点、边缘等显著的区域。 接下来,我们需要在不同图像中进行特征点的匹配,找出在不同图像中具有相同特征的点对。通过计算特征描述子的相似性,可以使用OpenCV的特征匹配算法,如FLANN或Brute-Force匹配器。 然后,我们可以使用RANSAC(随机抽样一致性)算法来剔除错误匹配点对,以获得更准确的相机姿态估计。RANSAC是一种迭代算法,通过假设一组点对是内点并根据这个假设计算模型,然后评估内点的数量来对模型进行验证。 最后,通过OpenCV的相机姿态估计算法,如EPnP(解算法)或POSIT(迭代优化算法),可以从匹配点对和相机内外参数中估计相机的姿态。这些算法基于三维-二维点对的几何关系,并利用非线性优化来估计相机的旋转和平移矩阵。 总结起来,要使用OpenCV实现相机姿态更新,首先需要提取特征并匹配特征点,然后通过RANSAC算法剔除错误匹配点对,最后使用相机姿态估计算法计算相机的姿态。这样就可以实现相机姿态的动态更新。 ### 回答3: 相机姿态更新是指在视觉中通过计算相机的位置和方向的变化,从而获取相机的新的姿态信息。OpenCV是一个开源计算机视觉库,可以用于实现相机姿态更新。 首先,相机姿态可以通过计算相机的旋转矩阵和平移矩阵来描述。在OpenCV中,可以使用solvePnP函数来解决这个问题。该函数可以通过提供已知的三维点和对应的二维图像点,来估计相机的旋转矩阵和平移矩阵。 具体步骤如下: 1. 收集到一组已知的三维点和对应的二维图像点。 2. 根据已知的三维点和二维图像点,使用solvePnP函数得出相机的旋转矩阵和平移矩阵。 3. 根据相机的旋转矩阵和平移矩阵,可以得到相机的姿态信息,例如欧拉角(pitch、roll、yaw),或四元数表示。 4. 当相机位置或方向发生变化时,根据新的二维图像点和已知的三维点,可再次使用solvePnP函数来更新相机的旋转矩阵和平移矩阵,从而获取新的姿态信息。 使用OpenCV实现相机姿态更新需要理解计算机视觉和线性代数的相关知识,并且需要适当的图像处理和几何计算技巧。根据应用的具体要求和场景,可以选择不同的方法和算法来实现相机姿态更新。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

F l e

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值