你好,我的目标是开发头部跟踪功能,用于飞机(模拟器)驾驶舱,以便提供AR支持民用飞行员降落并在恶劣的视觉条件下飞行。我怎样才能估计与3d到2d点对应的相机姿态(使用opencv)
我的方法是检测其中我知道3D坐标的特征点(在黑暗模拟器LED中),并计算估计的(头戴式相机)姿态[R | t](旋转和平移相连)。
我有问题是估计姿态似乎总是错的,我的3D点(这也是我用来估计姿势)的投影不与2D图像点重叠(或不可见)。
我的问题是:
我怎么能估计相机姿态与一组给定的2D到3D的点对应的。
为什么它不起作用我怎么尝试它,哪里可能是错误的来源?
为了得到在真实生活环境中工作的理论解决方案,测量(3D和2D点以及相机矩阵)必须有多精确?
理论上这种方法对于共面点(x,y轴是否改变)有效吗?
我使用的硬件是爱普生BT-200。
在飞机中,我定义了一个固定的坐标系,我期望我的程序能够进行相对平移和旋转。程序检测(独特)LED的图像坐标并将它们与其对应的3D坐标进行匹配。用我使用open-cv示例android代码(https://github.com/Itseez/opencv/tree/master/samples/android/camera-calibration)获得的相机矩阵,我尝试使用solvePnP估计姿态。
我的相机矩阵和失真稍有变化。以下是我从程序中收到的一些值。我确信我打印出来的圆形图案的圆距与源代码中记载的相同(以米为单位测量)。
下面是一些例子以及我如何创建它的OpenCV Mat。
// protected final double[] DISTORTION_MATRIX_VALUES = new double[]{
// /*This matrix should have 5 values*/
// 0.04569467373955304,
// 0.1402980385369059,
// 0,
// 0,
// -0.2982135315849994
// };
// protected final double[] DISTORTION_MATRIX_VALUES = new double[]{
// /*This matrix should have 5 values*/
// 0.08245931646421553,
// -0.9893762277047577,
// 0,
// 0,
// 3.23553287438898
// };
// protected final double[] DISTORTION_MATRIX_VALUES = new double[]{
// /*This matrix should have 5 values*/
// 0.07444480392067945,
// -0.7817175834131075,
// 0,
// 0,
// 2.65433773093283
// };
protected final double[] DISTORTION_MATRIX_VALUES = new double[]{
/*This matrix should have 5 values*/
0.08909941096327206,
-0.9537960457721699,
0,
0,
3.449728790843752
};
protected final double[][] CAMERA_MATRIX_VALUES = new double[][]{
/*This matrix should have 3x3 values*/
// {748.6595405553738, 0, 319.5},
// {0, 748.6595405553738, 239.5},
// {0, 0, 1}
// {698.1744297982436, 0, 320},
// {0, 698.1744297982436, 240},
// {0, 0, 1}
// {707.1226937511951, 0, 319.5},
// {0, 707.1226937511951, 239.5},
// {0, 0, 1}
{702.1458656346429, 0, 319.5},
{0, 702.1458656346429, 239.5},
{0, 0, 1}
};
private void initDestortionMatrix(){
distortionMatrix = new MatOfDouble();
distortionMatrix.fromArray(DISTORTION_MATRIX_VALUES);
}
private void initCameraMatrix(){
cameraMatrix = new Mat(new Size(3,3), CvType.CV_64F);
for(int i=0;i
cameraMatrix.put(i, 0, CAMERA_MATRIX_VALUES[i]);
}
}
为了估计相机姿势我使用solvePnP(和solvePnPRansac)在几个位置(1,2,3,4)描述。 solvePnP的结果I用作投影的输入(Calib3d.projectPoints)。 concatinated结果的倒数[R | t]我用作估计的姿势。
因为我在生产环境中的成绩太差,我创建了一个测试环境。在这种环境下,我放置了相机(这是因为它的3D形状(它是一个玻璃杯)在桌子边缘稍微向下旋转,这个边缘我用作世界坐标系的纵坐标。我搜索了open-cv坐标系如何定位并找到不同的答案(一个在stackoverflow上,另一个在官方的youtube上讨论opencv)。无论如何,我测试了如果我通过在图像上投影3D点(在该坐标系中描述)获得坐标系,并检查给定的世界形状是否保持恒定。
所以我用z向前走,y向下,x向右走。
为了更接近我的解决方案,我估计了我的测试环境中的姿势。平移矢量输出和欧拉角度输出指的是[R | t]的倒数。因为我使用open-cv坐标系统以对数(我假设指的是飞机坐标系)方程式计算它,所以euler天使可能无法正确显示(它们可能会交换或错误,如果我们考虑顺序)。 (计算发生在我将附上的Pose类中)。但无论如何,即使翻译矢量(相反)出现是错误的(在我的简单测试中)。
在与该图像一个测试我有一个辊(这可能是间距飞机坐标)的30°和50 厘米平移向上。这个出现更合理。所以我假设因为我的观点是共面的,我可能会得到不明确的结果。所以我意识到另一个测试的Z轴改变了一点。但是通过这个测试,即使投影失败了。
对于solvePnP,我尝试了所有不同的求解算法标志和ransac algorithm的不同参数。
也许你能以某种方式帮助我找到我的错误,或向我展示一条解决我最初问题的好路径。我将附上我的调试源码以及许多println语句和调试图像。 此代码包含我的测量点。
感谢您的帮助提前。
1.png
编辑2015年3月22日: 最后,我有能够发现我犯的错误。
我在for循环修改的垫目标,因为OpenCV的作品很多 与呼叫参考,而我不够细心这里。所以用于再投影的tvec和rvec是不正确的。
我在测试环境中的一个要点(在图像 坐标中)由于轴方向的混淆而被标记为错误。
所以我的方法一般是正确的。我在测试数据集中至少没有收到有效的重新投影。不幸的是,OpenCV PnP算法:“ITERATIVE,P3P,EPNP”返回了各种结果,即使使用非常不准确但接近的内部猜测,结果也只是有时是正确的。 P3P algorithm应该提供3种解决方案,但OpenCV只提供一种解决方案。 EPNP应该返回良好的结果,但与EPNP OpenCV返回最差的结果,从我的人的obersation评估。
现在的问题是,如何过滤不准确的值或确保OpenCV函数返回有效的值。 (也许我会修改本机代码以接收3种PnP解决方案)。
的compressed images here(37MB),做节目我目前的结果(迭代的PnP-解算器),以零旋转和75厘米向上的内在猜测。打印输出的x轴向前,y轴向左和z向下,以及相对应的滚动,俯仰和偏航角。
+0
我现在发现,根据y坐标,我的图像点的顺序是错误的。 (我在图像坐标中有一个向上的y轴)。我的价值观变得更接近但仍然不够好。 –
2015-03-17 13:42:42
+1
我现在发现论文和EPNP可用于共面点: P3P:http://www.mmrc.iss.ac.cn/~xgao/paper/ieee.pdf EPNP:http:// cvlabwww .epfl.ch /〜lepetit/papers/lepetit_ijcv08.pdf –
2015-03-17 16:21:23
+0
我将校准示例中的平方尺寸参数从米改为了厘米,但收到了几乎相等的矩阵! –
2015-03-17 17:05:40