如何从里程计/TF数据获取投影矩阵?

4

我希望能够将我的视觉里程计结果与KITTI数据集提供的地面真实值进行比较。 对于每个地面真实值中的帧,我有一个投影矩阵。 例如:

1.000000e+00 9.043683e-12 2.326809e-11 1.110223e-16 9.043683e-12 1.000000e+00 2.392370e-10 2.220446e-16 2.326810e-11 2.392370e-10 9.999999e-01 -2.220446e-16

以下是自述文件提供的说明:
行i代表左相机坐标系(即z朝前)的第i个位姿,使用一个3x4的变换矩阵。这些矩阵按行对齐顺序存储(第一个条目对应于第一行),并将第i个坐标系中的点投影到第一个(= 0th)坐标系中。因此,平移部分(第4列的3x1向量)对应于左相机坐标系在第i帧中与第一个(= 0th)帧的位姿。
但是我不知道如何为自己生成相同类型的数据。 我在每个帧中拥有以下内容:
Tf变换从init_camera(从(0,0,0)固定的相机)到正在移动的左侧相机。因此我有平移向量和四元数旋转。 里程计数据:姿态和扭矩 相机校准参数
有了这些数据,我该如何与groundtruth进行比较? 因此,我需要找到从上述数据中获取的投影矩阵,但不知道如何做到这一点。
从大局上来看,我想获得投影矩阵或知道如何分解提供的ground truth投影矩阵,以便比较我的数据的变换。
有人可以帮我吗?
谢谢。
2个回答

6

您确定需要投影矩阵吗?一个相机投影矩阵通常是一个3x4的矩阵,将R 3 中的(齐次)点投影到图像平面上的R 2 中的(齐次)点,直到某个比例为止(参见wikipedia entry)。听起来您想要将计算的视觉里程与KITTI网站提供的真实里程进行比较;在这种情况下,您将比较您的VO估计的刚性变换矩阵与KITTI真实变换矩阵。

如果您使用的是“原始”数据集,则“地面真实值”是由OXTS数据记录提供的-即组合的IMU和GPS数据。此数据位于全局框架中,并且需要更多工作才能与您的数据进行比较。但是,听起来您正在使用里程基准数据;地面真实变换已经在左侧相机的框架中,这应该使任务变得更容易(我将讨论这个)。

由于您没有指定语言,我会更加通用地讲述,但是ROS提供了C++(tf和Eigen)和Python(transformations.py)工具来执行任务,例如将四元数转换为旋转矩阵...
您有一个表示为四元数的平移和旋转:t和q。您可以将四元数转换为旋转矩阵(通常为“sxyz”形式),反之亦然。KITTI数据被指定为3x4矩阵,并且这是旋转矩阵与平移向量连接在一起的结果(即第4列为tgt)。
r11 r12 r13 t1
r21 r22 r23 t2
r31 r32 r33 t3 您可以通过计算L2范数来简单地计算翻译误差:||t - tgt||。计算旋转误差要困难一些;一种方法是使用Eigen中的QuaternionBase :: angularDistance()函数,因为两个测量应该在相同的坐标系中。为此,需要使用Eigen或transformations.py库将“ground truth”旋转矩阵转换为四元数。

请记住,这是里程计框架中的误差-即第i个估计姿势相对于初始姿势框架中的第i个基准真实姿势的误差。有时,比较帧间平均误差也很有用,特别是由于里程计随时间会发生显著漂移,即使算法在平均情况下在帧之间相对精确。

总结:

  • 将旋转矩阵转换为四元数以计算角度误差(注意坐标系),
  • 并使用公式||t - tgt||计算翻译误差。
  • 同样,请留意您的坐标系。

感谢@grumpy_robot提供这个好答案。现在我的想法更加清晰了。所以,如果我理解正确,我不需要将我的里程计结果转换为投影矩阵吗?只需要将真实值转换为旋转和平移,这样我就可以计算两者的误差了?实际上,我为什么想要投影矩阵,因为它们在CPP中提供了一个工具来执行与地面真实值的评估,并且在自述文件中告诉我们“您的提交结果必须使用相同的数据格式提供。” - lilouch
我不太理解这句话的意思:“请记住,这是在里程计坐标系下的误差 - 也就是你第 i 次估计位姿相对于初始位姿的第 i 次实际位姿的误差。有时,比较逐帧平均误差也很有用。”你能再解释一遍吗?你是说误差是与第一帧比较的,对吗?谢谢! - lilouch
@lilouch,是的,您只需要以相同的格式输出您的里程计信息(即一个3x4行主矩阵,其中“前面”3x3块是旋转,最后一列是平移)。浏览开发套件的源代码,如果您以那种形式提供输出(即每帧一个文件,每行12个数字),它会正确地计算误差。至于第二个问题,是的,我的意思是误差与第一帧进行比较,就像您所说的那样。我自己在没有注意正确的坐标框架时经常犯错误。 - grumpy_robot
感谢您的准确指导 @grumpy_robot。 关于您所说的,是有点棘手,因为在标准数据中,他们为每个帧提供信息,但是当我运行算法时,并不是所有帧都会有这些信息。我有时间戳,但不确定是否适用于标准数据。我会尽力尝试并及时向您报告! - lilouch

0

我对计算机视觉不是很熟悉,但可以参考sensor_msgs/CameraInfo Messageimage_geometry::PinholeCameraModel Class的文档。

大致应该是这样:

void imageCallback([...], const sensor_msgs::CameraInfoConstPtr& info_msg) {
  // initialize cam_model with sensor_msgs::CameraInfo
  image_geometry::PinholeCameraModel cam_model_;
  cam_model_.fromCameraInfo(info_msg);

  // get the projection matrix
  cv::Matx34d projection_matrix;
  projection_matrix = cam_model_.projectionMatrix();
}

是的,我看过这个函数。我没有测试它,因为在我看来(如果我错了请指出),在这种情况下,投影不会改变,对吗?因为我的意思是相机信息由于相机的配置而对于每个帧都是相同的。而在每一帧中,投影矩阵可能会不同。 可以测试。 - lilouch
иҖҢдё”еӣ дёәжҲ‘зҡ„camera_infoдёӯе·Із»ҸеҢ…еҗ«дәҶзӣёжңәеҸӮж•°зҡ„жҠ•еҪұзҹ©йҳөпјҢжүҖд»Ҙд№ҹеҸҜд»ҘдҪҝз”Ёе®ғгҖӮ - lilouch
很抱歉,就像我之前告诉你的那样,我并不是很实用(这只是一个“长评论”,为了清晰起见而写的答案)。请等待其他答案或尝试在http://answers.ros.org/上提问。 - alextoind
谢谢你的回答,Alex =)。 - lilouch

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接