简体   繁体   English

只保留好的关键点全景图像拼接 opencv

[英]Keep only the good keypoints panoramic images stitching opencv

I am working on a project regarding the matching of consecutive images in order to find the panoramic image.我正在研究一个关于匹配连续图像以找到全景图像的项目。

I found the keypoints with SIFT and the matches between couple of images using BFMatcher, but after removing the bad matches I am not able to keep the corresponding keypoints, or even to display the matches using cv::drawMatches because the program crashes.我发现了 SIFT 的关键点和使用 BFMatcher 的几个图像之间的匹配,但是在删除了错误的匹配之后,我无法保留相应的关键点,甚至无法使用 cv::drawMatches 显示匹配,因为程序崩溃了。

The inital part of the code is the following, and it works.代码的初始部分如下,它可以工作。

("image" is a vector containing all the images) (“图像”是包含所有图像的向量)

cv::Mat descriptors;
std::vector<cv::KeyPoint> keypoints;

std::vector<cv::Mat> descriptors_array;
std::vector<std::vector<cv::KeyPoint>> keypoints_array, reduced_keypoints_array;

cv::Ptr<cv::Feature2D> sift = cv::xfeatures2d::SIFT::create();
for(int i=0; i<N_images; i++){
    sift->detectAndCompute(image.at(i), cv::Mat(), keypoints, descriptors);
        keypoints_array.push_back(keypoints);
        descriptors_array.push_back(descriptors);
}

std::vector<std::vector<cv::DMatch>> matches_array, 
std::vector<cv::DMatch> matches, good_matches;
cv::Ptr<cv::BFMatcher> matcher = cv::BFMatcher::create(cv::NORM_L2, true);

for(int i=0; i<N_images-1; i++){
    matcher->match(descriptors_array.at(i), descriptors_array.at(i+1), matches, cv::Mat());
    for(int j=0; j<matches.size(); j++){
        if (min_distance > matches.at(j).distance){
            min_distance = matches.at(j).distance;
        }
    }
    for( int k = 0; k <descriptors_array.at(i).rows; k++) {
        if( matches[k].distance < 3*min_distance) {  
            good_matches.push_back(matches[k]);
        }
    } 
    matches_array.push_back(good_matches);
}

I am having problem with this code, when i want to just keep the good keypoints, which corresponds to the matches_array.当我只想保留与matches_array相对应的好的关键点时,我遇到了这段代码的问题。

for(int i=0; i<keypoints_array.size()-1; i++){
    reduced_keypoints_array.push_back(std::vector<cv::KeyPoint>());
    for(int j=0; j<matches_array.at(i).size(); j++){
        reduced_keypoints_array.at(i).push_back(cv::KeyPoint());

        reduced_keypoints_array.at(i).at(j) = keypoints_array.at(i).at(matches_array.at(i).at(j).queryIdx);
    }
}

And here i wanted to display the matches, but it also crashes because my matches are more than the keypoints since I couldn't reduce the number of keypoints.在这里我想显示匹配,但它也崩溃了,因为我的匹配超过了关键点,因为我无法减少关键点的数量。

cv::Mat out;
for(int i=0; i<keypoints_array.size()-1; i++){
    cv::drawMatches(image.at(i), keypoints_array.at(i), image.at(i+1), keypoints_array.at(i+1),matches_array.at(i), out2, cv::Scalar::all(-1),  cv::Scalar::all(-1), std::vector< char >(), cv::DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );

    cv::imshow("matches", out);
    cv::waitKey(0);
}

How can i keep only the corresponding keypoints?我怎样才能只保留相应的关键点? Or just draw the matches without removing the keypoints?或者只是在不删除关键点的情况下绘制比赛?

I edited some parts that I will mark in the code.我编辑了一些我将在代码中标记的部分。 I would not recommend the data structures you are using, since it is very hard to read them.我不推荐您使用的数据结构,因为它们很难阅读。 Consider creating typedefs or structs when you have multiple vectors of vectors.当您有多个向量向量时,请考虑创建typedefsstructs I used ORB since I did not install SIFT at the moment.我使用 ORB,因为我目前没有安装 SIFT。 Here is an example for three images:这是三个图像的示例:

int main(int argc, char** argv)
{
    // Reading my images and insert them into a vector
    std::vector<cv::Mat> image;
    cv::Mat img1 = cv::imread("1.png", cv::IMREAD_GRAYSCALE);
    cv::Mat img2 = cv::imread("2.png", cv::IMREAD_GRAYSCALE);
    cv::Mat img3 = cv::imread("3.png", cv::IMREAD_GRAYSCALE);

    image.push_back(img1);
    image.push_back(img2);
    image.push_back(img3);

    int N_images = (int)image.size();

    cv::Mat descriptors;
    std::vector<cv::KeyPoint> keypoints;

    std::vector<cv::Mat> descriptors_array;
    std::vector<std::vector<cv::KeyPoint>> keypoints_array, reduced_keypoints_array;

    // Here I used ORB
    cv::Ptr<cv::ORB> orb = cv::ORB::create();
    for (int i = 0; i < N_images; i++) {
        orb->detectAndCompute(image.at(i), cv::Mat(), keypoints, descriptors);
        keypoints_array.push_back(keypoints);
        descriptors_array.push_back(descriptors);
    }

    std::vector<std::vector<cv::DMatch>> matches_array;
    std::vector<cv::DMatch> matches, good_matches;
    cv::Ptr<cv::BFMatcher> matcher = cv::BFMatcher::create(cv::NORM_L2, true);

    // I created a vector of pairs of keypoints to push them into an array similar to the good matches
    std::vector<std::pair<cv::KeyPoint, cv::KeyPoint>> good_keypoint_pairs_array;
    std::vector<std::vector<std::pair<cv::KeyPoint, cv::KeyPoint>>> keypoint_pairs_array;

    float min_distance = 1000;

    for (int i = 0; i < N_images-1 ; i++) {
        matcher->match(descriptors_array[i], descriptors_array.at(i + 1), matches, cv::Mat());
        // I left that part out since I got always a number of 0 matches, no matter which min_distance I used
        /*for (int j = 0; j < matches.size(); j++) {
            if (min_distance > matches.at(j).distance) {
                min_distance = matches.at(j).distance;
            }
        }*/
        for (int k = 0; k < descriptors_array.at(i).rows; k++) {
            if (matches[k].distance < 3 * min_distance) {
                good_keypoint_pairs_array.push_back(std::make_pair(keypoints_array.at(i).at(k), keypoints_array.at(i + 1).at(k)));
                good_matches.push_back(matches[k]);
            }
        }
        keypoint_pairs_array.push_back(good_keypoint_pairs_array);
        matches_array.push_back(good_matches);
    }

    cv::Mat out;

    // I create my keypoint vectors to use them for the cv::drawMatches function
    std::vector<cv::KeyPoint> kp_1, kp_2;
    for (int i = 0; i < keypoint_pairs_array.size(); ++i) {
        for (int j = 0; j < keypoint_pairs_array[i].size(); ++j) {
            kp_1.push_back(keypoint_pairs_array[i][j].first);
            kp_2.push_back(keypoint_pairs_array[i][j].second);  

        }
        cv::drawMatches(image.at(i), kp_1, image.at(i + 1), kp_2, matches_array.at(i), out, cv::Scalar::all(-1), cv::Scalar::all(-1), std::vector< char >(), cv::DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);

        cv::imshow("matches", out);
        cv::waitKey(0);
        kp_1.clear();
        kp_2.clear();
    }


}

I am having problem with this code, when i want to just keep the good keypoints, which corresponds to the matches_array.当我只想保留与matches_array相对应的好的关键点时,我遇到了这段代码的问题。

As you already mentioned, it is very important that the size of the std::vector<cv::DMatch> is always similar to the size of the std::vector<cv::KeyPoint> So you have to save your keypoints in the same loop where you use your number of matches as shown.正如您已经提到的, std::vector<cv::DMatch>的大小始终与std::vector<cv::KeyPoint>的大小相似非常重要,因此您必须将关键点保存在如图所示,您使用匹配数量的相同循环。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM