测试基础矩阵

4

我的问题是:

  • 如何确定我的基本矩阵是否正确?
  • 我下面贴的代码是一个良好的尝试吗?

我的最终目标是进行某种三维重建。现在我正在尝试计算基本矩阵,以便可以估计两个摄像机之间的差异。我正在使用ofxCv插件在openFrameworks中完成此操作,但大部分都是纯OpenCV。由于ofxCv也在开发中,很难发布可隔离问题的代码。

我的代码基本上读取了从稍微不同位置(基本上只是将笔记本电脑水平移动一点)拍摄的两个640x480帧。对于它,我已经有了校准矩阵,该矩阵是通过ofxCv的校准代码使用findChessboardCorners获得的。去畸变示例代码似乎表明校准矩阵是精确的。它计算图片之间的光流(使用calcOpticalFlowPyrLK或calcOpticalFlowFarneback),并将这些点对馈送到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));
    }
}

有任何想法吗?我的基础矩阵看起来正确吗,还是我在测试中有错误的想法?


也许有人会发现这很有帮助:基本矩阵估计:误差标准的研究 - Georgy
3个回答

3
如果您想确定您的基础矩阵是否正确,您应该计算误差。使用极线约束方程,您可以检查一个图像中检测到的特征在另一个图像的极线上的位置有多接近。理想情况下,这些点积应该为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。

谢谢你的回答!另外,你知道我应该为findFundamentalMatrix提供多少个点吗?我目前有200个点,但我不确定是否太多了。我正在使用CV_RANSAC。 - noisecapella
使用RANSAC计算基础矩阵需要至少8个点(我相信在这种情况下,RANSAC用于产生良好的匹配,然后应用8点算法(因为给定了至少8个点)):http://docs.opencv.org/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html#findfundamentalmat - rbaleksandar
这个链接坏了。我已经在 GitHub 上查看了 stereo_calib.cpp 的所有历史记录,但是找不到那个神秘的 avgErr - Georgy
avgErr是在代码中的(183+行)。那里没有专门的函数。 - Phann

0
我认为你在计算 F 之前没有移除那些不正确的匹配。另外,我有一个验证 F 的想法,就是在公式 x'Fx=0 中,可以替换几个 x’ 和 x。 KyleFan

这应该是一条注释,而不是一个答案。 - shapiro yaacov

0
我写了一个Python函数来完成这个任务:
def Ferror(F,pts1,pts2):  # pts are Nx3 array of homogenous coordinates.  
    # how well F satisfies the equation pt1 * F * pt2 == 0
    vals = pts1.dot(F).dot(pts2.T)
    err = np.abs(vals)
    print("avg Ferror:",np.mean(err))
    return np.mean(err)

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