确定外部照相机用带OpenCV的世界空间物体的OpenGL(Determine extrinsic

2019-07-22 04:14发布

我使用OpenCV中和了openFrameworks(即OpenGL的),从图像计算的相机(世界变换和投影矩阵)(后来,几个图像进行三角测量)。

对于OpenCV中的目的,“平面图”成为与0,0,0世界的中心目标(即棋盘)。 世界/楼层位置是已知的,所以我需要让投影信息(失真系数,FOV等)和摄像机的外在坐标。

我已映射这些平面布置图的点的视图位到在归一化的视图空间我的2D图像([0,0]是左上。[1,1]是右下图)。

对象(平面图/世界分)是XZ平面,-y,所以我转换为OpenCV的xy平面(这里不知道是否Z-UP为负或正...),因为它需要是平面

ofMatrix4x4 gWorldToCalibration(
    1, 0, 0, 0,
    0, 0, 1, 0,
    0, 1, 0, 0,
    0, 0, 0, 1
    );

我通过1,1为IMAGESIZE到calibrateCamera。 标志CV_CALIB_FIX_ASPECT_RATIO|V_CALIB_FIX_K4|CV_CALIB_FIX_K5 calibrateCamera成功运行,给了我一个小错误(通常约为0.003 )。

使用calibrationMatrixValues我得到一个合理的FOV,通常50度左右,所以我敢肯定的内在特性是正确的。

我们计算出相机的外在世界空间变换...我不认为我需要使用solvePnP因为我只有一个对象(虽然我想这一切之前,与它带回来了相同的结果)

//  rot and trans output...
cv::Mat& RotationVector = ObjectRotations[0];
cv::Mat& TranslationVector = ObjectTranslations[0];

//  convert rotation to matrix
cv::Mat expandedRotationVector;
cv::Rodrigues(RotationVector, expandedRotationVector);

//  merge translation and rotation into a model-view matrix
cv::Mat Rt = cv::Mat::zeros(4, 4, CV_64FC1);
for (int y = 0; y < 3; y++)
   for (int x = 0; x < 3; x++) 
        Rt.at<double>(y, x) = expandedRotationVector.at<double>(y, x);
Rt.at<double>(0, 3) = TranslationVector.at<double>(0, 0);
Rt.at<double>(1, 3) = TranslationVector.at<double>(1, 0);
Rt.at<double>(2, 3) = TranslationVector.at<double>(2, 0);
Rt.at<double>(3, 3) = 1.0;

现在我有一个旋转和变换矩阵,但它是列为主(我相信作为对象是完全倾斜,如果我不转,以上代码看起来列为主向我)

//  convert to openframeworks matrix AND transpose at the same time
ofMatrix4x4 ModelView;
for ( int r=0;  r<4;    r++ )
    for ( int c=0;  c<4;    c++ )
        ModelView(r,c) = Rt.at<double>( c, r ); 

之前,使用矩阵的反交换我的飞机回到我的坐标空间(Y向上)。

//  swap y & z planes so y is up
ofMatrix4x4 gCalibrationToWorld = gWorldToCalibration.getInverse();
ModelView *= gCalibrationToWorld;

不知道如果我需要做到这一点...我没有否定了飞机,当我把它们放进校准...

//  invert y and z planes for -/+ differences between opencv and opengl
ofMatrix4x4 InvertHandednessMatrix(
    1,  0,  0, 0,
    0,  -1, 0, 0,
    0,  0,  -1, 0,
    0,  0,  0,  1
    );
ModelView *= InvertHandednessMatrix;

最后,模型视图是相对与相机对象,我想颠倒它是相机相对到物体(0,0,0)

ModelView = ModelView.getInverse();

这导致在错误的地方摄像头,并旋转错误。 这不是离谱,相机是Y平面的右侧,翻译不是大错特错了,我认为这完全取决于正确的方式....只是不正确呢。 油漆绘制蓝色圆圈是我期待的相机可以。

我已经经历了这么回答,该文档了十几次的负荷了,但并不完全找到什么合适的,我敢肯定,我已经谈过了,我需要空间的转换,明智的,但也许我错过了一些明显? 或做错误的顺序的东西吗?

更新1 -世界空天飞机......我改变了我的世界空间地板平面XY(Z高达)来匹配OpenCV的输入。 (gWorldToCalibration现在是单位矩阵)。 旋转仍然是错的,和投影输出是一样的,但我认为现在的翻译是正确的(这当然是上的标记正确的一面)

UPDATE2 -真正的图像大小 ,我与图像尺寸进入摄像机标定打; 看到,因为我使用的是1,1这是标准化的,但IMAGESIZE参数是整数,我想这可能是显著......我猜它(红色框是投影视图空间点带z相交= 0地板面)没有任何失真校正,这里是结果(唯一改变的是IMAGESIZE从1.1至640,480。我通过640,480加倍重视自己的标准化输入视空间COORDS太) 我要去尝试,并添加失真校正,看它是否排队完美 ...

Answer 1:

要检查的第一件事是验证标记给出估计内在和外在相机矩阵图像上正确地重新投影。 然后,你可以找到在全球画幅相机位置,看它是否与标记位置一致。 (使用的坐标系中的OpenCV。)一个做到这一点,有没有太多的东西可以去错了。 既然你想点就趴在XZ平面,你需要坐标的只是一个单一的转变。 依我之见,你gWorldToCalibration矩阵做到这一点。 然后改造既适用于标志和摄像头的位置,并确认标记是在正确的地方。 然后相机位置也将是正确的(除非出现了一些问题坐标系统的霸道,但是很容易纠正)。



Answer 2:

至少现在我处理我的编辑2(IMAGESIZE必须的东西比1,1更大)的,因为它产生的结果大部分修复,更像是我期待了。

我可能有东西倒过来的那一刻,但这产生不错的效果。



Answer 3:

我觉得你应该采取gWorldToCalibration的倒数

ofMatrix4x4 gCalibrationToWorld = gWorldToCalibration.getInverse();

在这里,我贴的代码,这是做或多或少你想要什么OpenCV- OpenGL的COS 。 这是一个在C,但应该在C ++类似。



文章来源: Determine extrinsic camera with opencv to opengl with world space object