2

我的问题是:测试的基本矩阵

  • 我如何找出如果我的基本矩阵是正确的?
  • 我是否将这个代码发布到下面的一个很好的努力?

我的最终目标是进行某种3D重建。现在我试图计算基本矩阵,以便我可以估计两台摄像机之间的差异。我在openFrameworks中使用ofxCv插件来做到这一点,但大多数情况下它只是纯OpenCV。因为xCv也在开发中,所以很难发布隔离问题的代码。

我的代码基本上读取了我的网络摄像头从略微不同的位置拍摄的两个640x480帧(基本上只是将笔记本电脑水平移动一点点)。我已经有了一个校准矩阵,从xCv的校准码中获得,它使用findChessboardCorners。不失真的示例代码似乎表明校准矩阵是准确的。它计算图片之间的光流(calcOpticalFlowPyrLKcalcOpticalFlowFarneback),并将这些点对提供给findFundamentalMatrix

为了测试基本矩阵是否有效,我将它分解为旋转和平移矩阵。然后,我将旋转矩阵乘以第二幅图像的点,以查看相机之间的旋转差异。我认为任何差异都应该很小,但是我有很大的差异。

这里是我最后的代码根本和旋转矩阵,如果它可以帮助:

fund: [-8.413948689969405e-07, -0.0001918870646474247, 0.06783422344973795; 
    0.0001877654679452431, 8.522397812179886e-06, 0.311671691674232; 
    -0.06780237856576941, -0.3177275967586101, 1] 
R: [0.8081771697692786, -0.1096128431920695, -0.5786490187247098; 
    -0.1062963539438068, -0.9935398408215166, 0.03974506055610323; 
    -0.5792674230456705, 0.02938723035105822, -0.8146076621848839] 
t: [0, 0.3019063882496216, -0.05799044915951077; 
    -0.3019063882496216, 0, -0.9515721940769112; 
    0.05799044915951077, 0.9515721940769112, 0] 

这里是我的代码部分,第二张照片后发生:

const ofImage& image1 = images[images.size() - 2]; 
    const ofImage& image2 = images[images.size() - 1]; 

    std::vector<cv::Point2f> points1 = flow->getPointsPrev(); 
    std::vector<cv::Point2f> points2 = flow->getPointsNext(); 

    std::vector<cv::KeyPoint> keyPoints1 = convertFrom(points1); 
    std::vector<cv::KeyPoint> keyPoints2 = convertFrom(points2); 

    std::cout << "points1: " << points1.size() << std::endl; 
    std::cout << "points2: " << points2.size() << std::endl; 


    fundamentalMatrix = (cv::Mat)cv::findFundamentalMat(points1, points2); 
    cv::Mat cameraMatrix = (cv::Mat)calibration.getDistortedIntrinsics().getCameraMatrix(); 
    cv::Mat cameraMatrixInv = cameraMatrix.inv(); 
    std::cout << "fund: " << fundamentalMatrix << std::endl; 

    essentialMatrix = cameraMatrix.t() * fundamentalMatrix * cameraMatrix; 

    cv::SVD svd(essentialMatrix); 
    Matx33d W(0,-1,0, //HZ 9.13 
      1,0,0, 
      0,0,1); 

    cv::Mat_<double> R = svd.u * Mat(W).inv() * svd.vt; //HZ 9.19 

    std::cout << "R: " << (cv::Mat)R << std::endl; 
    Matx33d Z(0, -1, 0, 
      1, 0, 0, 
      0, 0, 0); 
    cv::Mat_<double> t = svd.vt.t() * Mat(Z) * svd.vt; 
    std::cout << "t: " << (cv::Mat)t << std::endl; 

    Vec3d tVec = Vec3d(t(1,2), t(2,0), t(0,1)); 

    Matx34d P1 = Matx34d(R(0,0), R(0,1), R(0,2), tVec(0), 
      R(1,0), R(1,1), R(1,2), tVec(1), 
      R(2,0), R(2,1), R(2,2), tVec(2)); 
    ofMatrix4x4 ofR(R(0,0), R(0,1), R(0,2), 0, 
      R(1,0), R(1,1), R(1,2), 0, 
      R(2,0), R(2,1), R(2,2), 0, 
      0, 0, 0, 1); 
    ofRs.push_back(ofR); 

    cv::Matx34d P(1,0,0,0, 
        0,1,0,0, 
        0,0,1,0); 

    for (int y = 0; y < image1.height; y += 10) { 
     for (int x = 0; x < image1.width; x += 10) { 
      Vec3d vec(x, y, 0); 

      Point3d point1(vec.val[0], vec.val[1], vec.val[2]); 
      Vec3d result = (cv::Mat)((cv::Mat)R * (cv::Mat)vec); 
      Point3d point2 = result; 


      mesh.addColor(image1.getColor(x, y)); 
      mesh.addVertex(ofVec3f(point1.x, point1.y, point1.z)); 

      mesh.addColor(image2.getColor(x, y)); 
      mesh.addVertex(ofVec3f(point2.x, point2.y, point2.z)); 
     } 
    } 

任何想法?我的基础矩阵看起来是否正确,或者我在测试时有错误的想法?

回答

2

如果你想知道你的基本矩阵是否正确,你应该计算错误。 使用极线约束方程,您可以检查一幅图像中检测到的特征与另一幅图像的极线之间的接近程度。理想情况下,这些点积应该总和为0,因此,校准误差计算为绝对距离之和(SAD)。 SAD的平均值被报告为立体声校准错误。基本上,您正在计算相应极线的image_left(可能是棋盘角)计算出的特征的SAD。这个错误是在像素^ 2中测量的,任何低于1的值都是可以接受的。

OpenCV有代码示例,看看Stereo Calibrate cpp文件,它会告诉你如何计算这个错误。 https://code.ros.org/trac/opencv/browser/trunk/opencv/samples/c/stereo_calib.cpp?rev=2614 看“avgErr”行260-269

ANKUR

+0

感谢您的回答!另外,你知道我应该提供多少点的球场号码吗?findFundamentalMatrix?我目前有200分,但我不确定这是否太高。我使用CV_RANSAC – noisecapella

+0

使用RANSAC计算基本矩阵需要最少8点(我相信在这种情况下,RANSAC用于产生良好匹配,然后应用8点算法(由于给定的最小值8分)):http://docs.opencv.org/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html#findfundamentalmat – rbaleksandar

0

我认为你没有删除您使用之前再计算F. 这是不正确的比赛我也有关于如何验证一个想法F,从x'Fx = 0开始,可以在公式中替换几个x'和x。

KyleFan

+0

这应该是一个评论,而不是答案 –