OpenCV的undistortPoints和triangulatePoint函数在立体视觉中给出了奇怪的结果

65

我正在尝试获取空间中多个点的3D坐标,但是从undistortPoints()triangulatePoints()中得到了奇怪的结果。

由于两个相机具有不同的分辨率,我分别对它们进行了校准,并获得了0.340.43的RMS误差,然后使用stereoCalibrate()获得更多矩阵,得到了0.708的RMS值,然后使用stereoRectify() 获得其余矩阵。有了这些,我开始处理收集到的坐标,但是结果很奇怪。

例如,输入是:(935, 262),而undistortPoints()输出的一个点是(1228.709125, 342.79841),另一个点是(934, 176)(1227.9016, 292.4686)。这很奇怪,因为这些点都非常靠近帧的中心,变形最小。我没有预料到它们会移动300像素。

当传递给traingulatePoints()时,结果变得更加奇怪-我用尺子测量了现实生活中三个点之间的距离,并计算了每张照片上像素之间的距离。因为这次点在一个相当平坦的平面上,这两个长度(像素和实际)匹配,即| AB | / | BC |在两种情况下都大约是4/9。然而,triangulatePoints()给我带来了超出预期的结果,其中| AB | / | BC |为3/2或4/2。

这是我的代码:

double pointsBok[2] = { bokList[j].toFloat()+xBok/2, bokList[j+1].toFloat()+yBok/2 };
cv::Mat imgPointsBokProper = cv::Mat(1,1, CV_64FC2, pointsBok);

double pointsTyl[2] = { tylList[j].toFloat()+xTyl/2, tylList[j+1].toFloat()+yTyl/2 };
//cv::Mat imgPointsTyl = cv::Mat(2,1, CV_64FC1, pointsTyl);
cv::Mat imgPointsTylProper = cv::Mat(1,1, CV_64FC2, pointsTyl);

cv::undistortPoints(imgPointsBokProper, imgPointsBokProper, 
      intrinsicOne, distCoeffsOne, R1, P1);
cv::undistortPoints(imgPointsTylProper, imgPointsTylProper, 
      intrinsicTwo, distCoeffsTwo, R2, P2);

cv::triangulatePoints(P1, P2, imgWutBok, imgWutTyl, point4D);

double wResult = point4D.at<double>(3,0);
double realX = point4D.at<double>(0,0)/wResult;
double realY = point4D.at<double>(1,0)/wResult;
double realZ = point4D.at<double>(2,0)/wResult;

点之间的角度有点好但通常不是很好:

`7,16816    168,389 4,44275` vs `5,85232    170,422 3,72561` (degrees)
`8,44743    166,835 4,71715` vs `12,4064    158,132 9,46158`
`9,34182    165,388 5,26994` vs `19,0785    150,883 10,0389`

我曾尝试在整个帧上使用undistort(),但结果仍然很奇怪。点B和C之间的距离应该始终保持不变,但这就是我得到的结果:

7502,42     
4876,46 
3230,13 
2740,67 
2239,95 

逐帧分析。

像素距离(底部)与实际距离(顶部)- 应该非常相似:|BC| distance

角度:

ABC angle

此外,undistortPoints()undistort()不应该给出相同的结果吗?(这里有另一组视频)
enter image description here


1
@abarry 关于内参校准,我确实这样做。我单独对每个相机进行校准(因为它们的分辨率和长宽比不同),然后使用之前校准得到的结果对立体系统进行校准。校准后,我立即将undistort()图像应用于两个图像,图像就像一条直线一样。我尝试在同一组视频上使用undistortPoints()和undistort(),上面是图表。 - Petersaber
这个问题有任何更新吗?只是校准问题还是OpenCV问题或其他什么问题? - AndroC
@ancajic 我从来没有发现过。最终用户(研究人员)仍在完成他们之前的项目,整个过程需要太多时间来设置和记录,以至于我不能自己尝试,我还需要另一个人。 - Petersaber
1
在三角测量之前(并在消除畸变之后),您应该使用 stereoRectify 对图像进行校正,以便对应点具有相同的高度,否则视差图将不准确。 - Azad
1
@Petersaber 在去畸变之后,它们不再是矩形的,因此结果会出错。如果您想了解更多示例和解释,请参阅Gary Bradski和Adrian Kaehler的《学习OpenCV》第12章。 - Azad
显示剩余6条评论
1个回答

3

函数cv::undistort可以一次性进行去畸变和投影校正。它执行以下操作:

  1. 撤销相机投影(乘以相机矩阵的逆矩阵)
  2. 应用失真模型以撤销畸变
  3. 旋转提供的旋转矩阵R1/R2
  4. 使用提供的投影矩阵P1/P2将点投影到图像上

如果从cv::stereoCalibrate()传递矩阵R1、P1或R2、P2,则输入点将被去畸变和矫正。矫正意味着以相应点具有相同的y坐标的方式来转换图像。对于图像矫正,没有唯一的解决方案,因为您可以对两个图像应用任何平移或缩放,而不改变相应点的对齐方式。 也就是说,cv::stereoCalibrate()可以相当大地移动投影中心(例如300个像素)。如果您想要纯粹的去畸变,可以传递一个单位矩阵(而不是R1)和原始相机矩阵K(而不是P1)。这应该会导致类似于原始像素坐标的像素坐标。


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