计算机视觉攻略 笔记12 (计算图形对的基础矩阵)

计算图形对的基础矩阵

(心中若有梦,便不顾风雨兼程)奥利给
本节将探讨同一场景的两幅图像之间的投影关系。可以移动相机,从两个视角拍摄两幅照片;也可以使用两个相机,分别对同一个场景拍摄照片。如果这两个相机被刚性基线分割,我们就称之为立体视觉。

对极约束

在这里插入图片描述
在这里插入图片描述

公式推导

在第一帧坐标系下:
P的空间位置在这里插入图片描述
由针孔相机模型可知,两个像素点p1,p2的像素位置为在这里插入图片描述
这里K为相机内参矩阵,R,t为两个坐标系的相机运动。具体来说,这里计算的是R21和t21因为它们把第一个坐标系下的坐标转换到第二个坐标系下。
在使用齐次坐标时,一个向量将等于它自身乘上任意的非零常数。这种相等关系为尺度意义下相等。在这里插入图片描述
上述投影关系可写为
在这里插入图片描述
现在取在这里插入图片描述
这里的x1,x2,是两个像素点在归一化平面上的坐标,将上式代入投影关系方程,得在这里插入图片描述
所以
在这里插入图片描述
两边同乘以t^。相当于等式两侧同时与t做外积。
在这里插入图片描述
两侧同时左乘xT2在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 如果两幅图像之间有一定数量的已知匹配点,就可以利用方程组来计算图像对的基础矩阵。这样的匹配项至少要有 7 对。

示例程序

#include <iostream>
#include <vector>
#include <opencv2/core/core.hpp>
#include </home/jlm/3rdparty/opencv/opencv_contrib/modules/xfeatures2d/include/opencv2/xfeatures2d.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <opencv2/calib3d/calib3d.hpp>
using namespace std;

int main(int argc, char** argv) {
    
    
    cv::Mat image1 = cv::imread("church01.jpg",0);
    cv::Mat image2 = cv::imread("church03.jpg", 0);
    if(!image1.data || !image2.data)
    {
    
    
        return 0;
    }

    cv::imshow("Right Image", image1);
    cv::imshow("Left Image", image2);

    vector<cv::KeyPoint> keypoints1;
    vector<cv::KeyPoint> keypoints2;
    cv::Mat descriptors1, descriptors2;

    cv::Ptr<cv::Feature2D> ptrFeature2D = cv::xfeatures2d::SIFT::create(74);

    ptrFeature2D -> detectAndCompute(image1, cv::noArray(), keypoints1, descriptors1);
    ptrFeature2D -> detectAndCompute(image2, cv::noArray(), keypoints2, descriptors2);

    cout << "Number of SIFT points(1): " << keypoints1.size() << endl;
    cout << "Number of SIFT points(2): " << keypoints2.size() << endl;

    cv::Mat imageKP;
    cv::drawKeypoints(image1, keypoints1,imageKP, cv::Scalar(255, 255, 255), cv::DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
    cv::imshow("Right SIFT Features", imageKP);
    cv::drawKeypoints(image2, keypoints2, imageKP, cv::Scalar(255, 255, 255), cv::DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
    cv::imshow("Left SIFT Features", imageKP);

    cv::BFMatcher matcher(cv::NORM_L2, true);
    vector<cv::DMatch> matches;
    matcher.match(descriptors1, descriptors2, matches);

    cout << "Number of matched points: " << matches.size() << endl;

    // Manually select few Matches
    vector<cv::DMatch> selMatches;

    selMatches.push_back(matches[2]);
    selMatches.push_back(matches[5]);
    selMatches.push_back(matches[16]);
    selMatches.push_back(matches[19]);
    selMatches.push_back(matches[14]);
    selMatches.push_back(matches[34]);
    selMatches.push_back(matches[29]);

    // Draw the selected matches
    cv::Mat imageMatches;
    cv::drawMatches(image1, keypoints1,
                    image2, keypoints2,
                    selMatches,
                    imageMatches,
                    cv::Scalar(255, 255, 255),
                    cv::Scalar(255, 255, 255),
                    vector<char>(),
                            2);
    cv::imshow("Matches", imageMatches);
    vector<int> pointIndexes1;
    vector<int> pointIndexes2;
//    for(vector<cv::DMatch>::const_iterator it = selMatches.begin();
//    it != selMatches.end(); ++it)
//    {
    
    
//        pointIndexes1.push_back(it -> queryIdx);
//        pointIndexes2.push_back(it -> trainIdx);
//    }

    vector<cv::Point2f> selPoints1, selPoints2;
    cv::KeyPoint::convert(keypoints1, selPoints1, pointIndexes1);
    cv::KeyPoint::convert(keypoints2, selPoints2, pointIndexes2);

    // check by drawing the points
    vector<cv::Point2f>::const_iterator it = selPoints1.begin();
    while( it != selPoints1.end())
    {
    
    
        cv::circle(image1, *it,3,cv::Scalar(255, 255, 255), 2);
        ++it;
    }
    it = selPoints2.begin();
    while (it != selPoints2.end())
    {
    
    
        cv::circle(image2, *it, 3, cv::Scalar(255, 255, 255), 2);
        ++it;
    }
    cv::Mat fundamental = cv::findFundamentalMat(selPoints1,
                                                 selPoints2,
                                                 cv::FM_7POINT);
    cout << "F-Matrix size= " << fundamental.rows << "," << fundamental.cols << endl;
    cv::Mat fund(fundamental,cv::Rect(0, 0, 3, 3));
    vector<cv::Vec3f> lines1;
    cv::computeCorrespondEpilines(selPoints1,
                                  1,    // in image1 (can also be 2)
                                  fund,     // F Matrix
                                  lines1);  // vector of epipolar lines
     cout << "size of F matrix: " << fund.rows << "x" << fund.cols << endl;

     // for all epipolar lines
     for (std::vector<cv::Vec3f>::const_iterator it = lines1.begin();
     it != lines1.end(); ++it)
     {
    
    
         // draw the epipolar line between first and last column
         cv::line(image2,cv::Point(0, -(*it)[2]/(*it)[1]),
                  cv::Point(image2.cols, -((*it)[2] + (*it)[0]*image2.cols)/(*it)[1]),
                  cv::Scalar(255, 255, 255));
     }
     // draw the left points corresponding epipolar lines in left image
     vector<cv::Vec3f> lines2;
     cv::computeCorrespondEpilines(cv::Mat(selPoints2), 2, fund, lines2);
     for(auto it = lines2.begin(); it != lines2.end(); ++it){
    
    
         // draw the epipolar line between first and last column
         cv::line(image1, cv::Point(0, -(*it)[2]/(*it)[1]),
                  cv::Point(image1.cols, -((*it)[2]+(*it)[0]*image1.cols)/(*it)[1]),
                  cv::Scalar(255, 255, 255));
     }

     // combine both images
     cv::Mat both(image1.rows, image1.cols+image2.cols, CV_8U);
     image1.copyTo(both.colRange(0, image1.cols));
     image2.copyTo(both.colRange(image1.cols, image1.cols+image2.cols));

     cv::imshow("Epilines", both);
     cv::waitKey();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/jlm7689235/article/details/108101301