计算机视觉攻略 笔记10 (描述并匹配局部强度值模式)

描述并匹配局部轻度值模式

本节的主要内容是使用特征描述子来描述兴趣点的邻域

  • 特征描述子通常是一个 N 维的向量,在光照变化和拍摄角度发生微小扭曲时,它描述特征点的方式不会发生变化。通常可以用简单的差值矩阵来比较描述子,例如用欧几里得距离。综上所述,特征描述子是一种非常强大的工具,能进行目标的匹配。

示例程序

#include <iostream>
#include <algorithm>
#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>

using namespace std;

int main(int argc, char** argv) {
    
    
    if(argc != 3)
    {
    
    
        cerr << "don't get the right numbers of image" << endl;
        return -1;
    }
    cv::Mat image1 = cv::imread(argv[1],cv::IMREAD_GRAYSCALE);
    cv::Mat image2 = cv::imread(argv[2],cv::IMREAD_GRAYSCALE);
    if(image1.empty() || image2.empty())
    {
    
    
        cout << "don't get the data of the argv[1]" << endl;
        return -1;
    }
    cv::imshow("Original1", image1);
    cv::imshow("Original2", image2);
    cv::waitKey(0);
    // 定义关键点的容器
    vector<cv::KeyPoint> keypoints1;
    vector<cv::KeyPoint> keypoints2;

    // 定义特征检测器
    //对于 SIFT,调用 cv::SIFT::create 函数即可
    cv::Ptr<cv::Feature2D> ptrFeature2D =
            cv::xfeatures2d::SURF::create(2000.0);
    // 检测关键点
    ptrFeature2D -> detect(image1,keypoints1);
    ptrFeature2D -> detect(image2, keypoints2);

    // 提取描述子
    cv::Mat descriptors1;
    cv::Mat descriptors2;
    ptrFeature2D -> compute(image1, keypoints1, descriptors1);
    ptrFeature2D -> compute(image2, keypoints2, descriptors2);
//    兴趣点描述子的计算结果是一个矩阵(即cv::Mat 实例)
//    ,矩阵的行数等于关键点容器的元素个数。每行是一个 N 维的描述子容器。 SURF
//    描述子的默认尺寸是 64,而 SIFT 的默认尺寸是 128。这个容器用于区分特征点周围的强度值图
//    案。两个特征点越相似,它们的描述子容器就会越接近。注意, SURF 兴趣点并不一定要使用 SURF
//    描述子,SIFT 也一样;检测器和描述子可以任意搭配。
    // 构造匹配器
//    将第一幅图像的每个特征
//    描述子向量与第二幅图像的全部特征描述子进行比较,把相似度最高的一对(即两个描述子向量
//    之间的距离最短)保留下来,作为最佳匹配项。
    cv::BFMatcher matcher(cv::NORM_L2);
    // 匹配两幅图像的描述子
    vector<cv::DMatch> matches;
    matcher.match(descriptors1,descriptors2,matches);

    // 输出结果
    cv::Mat outImage;
    cv::drawMatches(image1, keypoints1,
                    image2, keypoints2,
                    matches,
                    outImage,
                    cv::Scalar(255, 255, 255),
                    cv::Scalar(255, 255, 255));
    cv::imshow("OUT IMAGE", outImage);
    cout << "the keypoints number of image1 : " << keypoints1.size() << endl;
    cout << "the keypoints number of image2 : " << keypoints2.size() << endl;
    cv::waitKey(0);
    return 0;
}

其他容错算法

用任何算法得到的匹配结果都含有相当多的错误匹配项,但有一些策略可以提高匹配的质量。

交叉检查匹配项

   cv::BFMatcher matcher(cv::NORM_L2,
                          true); // 将第二个参数设置位true

比率检验法

#include <iostream>
#include <algorithm>
#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>

using namespace std;

int main(int argc, char** argv) {
    
    
    if(argc != 3)
    {
    
    
        cerr << "don't get the right numbers of image" << endl;
        return -1;
    }
    cv::Mat image1 = cv::imread(argv[1],cv::IMREAD_GRAYSCALE);
    cv::Mat image2 = cv::imread(argv[2],cv::IMREAD_GRAYSCALE);
    if(image1.empty() || image2.empty())
    {
    
    
        cout << "don't get the data of the argv[1]" << endl;
        return -1;
    }
    cv::imshow("Original1", image1);
    cv::imshow("Original2", image2);
    cv::waitKey(0);
    // 定义关键点的容器
    vector<cv::KeyPoint> keypoints1;
    vector<cv::KeyPoint> keypoints2;

    // 定义特征检测器
    //对于 SIFT,调用 cv::SIFT::create 函数即可
    cv::Ptr<cv::Feature2D> ptrFeature2D =
            cv::xfeatures2d::SURF::create(2000.0);
    // 检测关键点
    ptrFeature2D -> detect(image1,keypoints1);
    ptrFeature2D -> detect(image2, keypoints2);

    // 提取描述子
    cv::Mat descriptors1;
    cv::Mat descriptors2;
    ptrFeature2D -> compute(image1, keypoints1, descriptors1);
    ptrFeature2D -> compute(image2, keypoints2, descriptors2);
//    兴趣点描述子的计算结果是一个矩阵(即cv::Mat 实例)
//    ,矩阵的行数等于关键点容器的元素个数。每行是一个 N 维的描述子容器。 SURF
//    描述子的默认尺寸是 64,而 SIFT 的默认尺寸是 128。这个容器用于区分特征点周围的强度值图
//    案。两个特征点越相似,它们的描述子容器就会越接近。注意, SURF 兴趣点并不一定要使用 SURF
//    描述子,SIFT 也一样;检测器和描述子可以任意搭配。
    // 构造匹配器
//    将第一幅图像的每个特征
//    描述子向量与第二幅图像的全部特征描述子进行比较,把相似度最高的一对(即两个描述子向量
//    之间的距离最短)保留下来,作为最佳匹配项。

    cv::BFMatcher matcher(cv::NORM_L2);
    vector<vector<cv::DMatch> > matches;
    vector<cv::DMatch> newMatches;
    matcher.knnMatch(descriptors1,descriptors2, matches, 2); // 找出k个最佳匹配项

    // 执行比率检验法
    double ratio = 0.85;
    vector<vector<cv::DMatch> >::iterator it;
    for (it = matches.begin(); it != matches.end(); ++it)
    {
    
    
        // 第一个最佳匹配项 / 第二个最佳匹配项
        if((*it)[0].distance / (*it)[1].distance < ratio)
        {
    
    
            newMatches.push_back((*it)[0]);
        }
    }// newMatches是最新的匹配项集合

    // 输出结果
    cv::Mat outImage;
    cv::drawMatches(image1, keypoints1,
                    image2, keypoints2,
                    newMatches,
                    outImage,
                    cv::Scalar(255, 255, 255),
                    cv::Scalar(255, 255, 255));
    cv::imshow("OUT IMAGE", outImage);
    cout << "the keypoints number of image1 : " << keypoints1.size() << endl;
    cout << "the keypoints number of image2 : " << keypoints2.size() << endl;
    cout << "the number of newMatches : " << newMatches.size() << endl;
    cv::waitKey(0);
    return 0;
}

匹配差值的阈值化

#include <iostream>
#include <algorithm>
#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>

using namespace std;

int main(int argc, char** argv) {
    
    
    if(argc != 3)
    {
    
    
        cerr << "don't get the right numbers of image" << endl;
        return -1;
    }
    cv::Mat image1 = cv::imread(argv[1],cv::IMREAD_GRAYSCALE);
    cv::Mat image2 = cv::imread(argv[2],cv::IMREAD_GRAYSCALE);
    if(image1.empty() || image2.empty())
    {
    
    
        cout << "don't get the data of the argv[1]" << endl;
        return -1;
    }
    cv::imshow("Original1", image1);
    cv::imshow("Original2", image2);
    cv::waitKey(0);
    // 定义关键点的容器
    vector<cv::KeyPoint> keypoints1;
    vector<cv::KeyPoint> keypoints2;

    // 定义特征检测器
    //对于 SIFT,调用 cv::SIFT::create 函数即可
    cv::Ptr<cv::Feature2D> ptrFeature2D =
            cv::xfeatures2d::SURF::create(2000.0);
    // 检测关键点
    ptrFeature2D -> detect(image1,keypoints1);
    ptrFeature2D -> detect(image2, keypoints2);

    // 提取描述子
    cv::Mat descriptors1;
    cv::Mat descriptors2;
    ptrFeature2D -> compute(image1, keypoints1, descriptors1);
    ptrFeature2D -> compute(image2, keypoints2, descriptors2);
//    兴趣点描述子的计算结果是一个矩阵(即cv::Mat 实例)
//    ,矩阵的行数等于关键点容器的元素个数。每行是一个 N 维的描述子容器。 SURF
//    描述子的默认尺寸是 64,而 SIFT 的默认尺寸是 128。这个容器用于区分特征点周围的强度值图
//    案。两个特征点越相似,它们的描述子容器就会越接近。注意, SURF 兴趣点并不一定要使用 SURF
//    描述子,SIFT 也一样;检测器和描述子可以任意搭配。

    cv::BFMatcher matcher(cv::NORM_L2);
    // 指定范围的匹配
    float maxDist = 0.25;
    vector<vector<cv::DMatch> > matches;
    matcher.radiusMatch(descriptors1, descriptors2, matches, maxDist);

    // 输出结果
    cv::Mat outImage;
    cv::drawMatches(image1, keypoints1,
                    image2, keypoints2,
                    matches,
                    outImage,
                    cv::Scalar(255, 255, 255),
                    cv::Scalar(255, 255, 255));
    cv::imshow("OUT IMAGE", outImage);
    cout << "the keypoints number of image1 : " << keypoints1.size() << endl;
    cout << "the keypoints number of image2 : " << keypoints2.size() << endl;
    cout << "the number of newMatches : " << matches.size() << endl;
    cv::waitKey(0);
    return 0;
}

猜你喜欢

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