Opencv之特征匹配

博客介绍了图像特征匹配的基本步骤,即提取特征点、计算特征向量和匹配。重点对比了OpenCV中三种特征匹配方法:SIFT、SURF和ORB。SURF是SIFT的改进版,速度快但精度稍差;ORB速度更快,解决了BRIEF部分缺点,但不具备尺度不变性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

 

图像的特征匹配在实际应用中有很多用途,特征匹配,顾名思义,就是要先提取特征点,然后 计算 特征向量,第三步就是匹配了,计算哪两个向量最近。sift的原理有些麻烦,opencv都做好了接口,拿来主义,直接跑一下测试

1 sift 特征匹配

void FeatureDialog::on_pbGoodSIFTMatch_clicked()
{
    if(fileName.isEmpty() || fileName2.isEmpty())
        QMessageBox::warning(this,QString("Warning"),QString("Select the file to match,please"),QMessageBox::Ok);

    cv::Mat src1,src2;

    src1 = cv::imread(fileName.toStdString(),cv::IMREAD_COLOR);
    src2 = cv::imread(fileName2.toStdString(),cv::IMREAD_COLOR);
    //convert to gray
    cv::cvtColor(src1,src1,cv::COLOR_BGR2GRAY);
    cv::cvtColor(src2,src2,cv::COLOR_BGR2GRAY);

    cv::Ptr<cv::xfeatures2d::SiftFeatureDetector> siftDetector = cv::xfeatures2d::SiftFeatureDetector::create();

    std::vector<cv::KeyPoint> keypoints1,keypoints2;
    //
    siftDetector->detect(src1,keypoints1);
    siftDetector->detect(src2,keypoints2);

    cv::Ptr<cv::xfeatures2d::SiftDescriptorExtractor>  siftDescriptor = cv::xfeatures2d::SiftDescriptorExtractor::create();
    cv::Mat imgdescriptor1,imgdescriptor2;
    siftDescriptor->compute(src1,keypoints1,imgdescriptor1);
    siftDescriptor->compute(src2,keypoints2,imgdescriptor2);

    cv::FlannBasedMatcher matcher;
    std::vector<std::vector<cv::DMatch> > matchPoints;
    std::vector<cv::DMatch> goodMatchPoints;
#if 0 //两种方法都可以
    std::vector<cv::Mat> train_desc(1,imgdescriptor1);  //初始化长度为1,内容是imgdescriptor1
    matcher.add(train_desc);
    matcher.train();

    matcher.knnMatch(imgdescriptor2,matchPoints,2);
#else
    matcher.knnMatch(imgdescriptor2,imgdescriptor1,matchPoints,2);//从imgdescriptor1 中找与imgdescriptor2 i个点匹配的2个匹配放到matchpoints中
#endif
    std::cout << "total match points:" << matchPoints.size() << std::endl;
    //为了排除因为图像遮挡和环境混乱而产生误匹配的关键点,sift的作者提出了比较最邻近距离的sift匹配:取一幅图像中的一个sift关键点,并找出其与另一幅图像中欧式距离最近
    //的前两个关键点,在这两个关键点中,如果最近的距离除以次近距离得到的ratio少于阈值T,则接受这一对匹配点。降低T匹配点数会减少,更准确,反之亦然。
    //一般取T在0.4~0.6 ,小于0.4,匹配的点比较少,大于0.6误匹配的点多一些
    for(int i=0;i < matchPoints.size();i++){
        if(matchPoints[i][0].distance < 0.6*matchPoints[i][1].distance){
            goodMatchPoints.push_back(matchPoints[i][0]);
        }
    }

    cv::Mat first_match;
    cv::drawMatches(src2,keypoints2,src1,keypoints1,goodMatchPoints,first_match);//goodMatchPoints是src2到src1,因为生成的matchPoints是src2 到src1


    cv::namedWindow("goodsift match",cv::WINDOW_NORMAL);
    cv::imshow("goodsift match",first_match);
    cv::imwrite("goodsift_match.jpg",first_match);

    cv::waitKey();
    return;
}

 

2.surf特征

 surf特征是sift特征的改进版。具有尺度不变性。

代码上和上述的sift一样,只需要把sift换成surf即可,但是速度确是sift的10倍,精度比sift稍差。

void FeatureDialog::on_pbGoodSURFMatch_clicked()
{
    if(fileName.isEmpty() || fileName2.isEmpty())
        QMessageBox::warning(this,QString("Warning"),QString("Select the file to match,please"),QMessageBox::Ok);

    cv::Mat src1,src2;

    src1 = cv::imread(fileName.toStdString(),cv::IMREAD_COLOR);
    src2 = cv::imread(fileName2.toStdString(),cv::IMREAD_COLOR);
    //convert to gray
    cv::cvtColor(src1,src1,cv::COLOR_BGR2GRAY);
    cv::cvtColor(src2,src2,cv::COLOR_BGR2GRAY);

    cv::Ptr<cv::xfeatures2d::SurfFeatureDetector> surfDetector = cv::xfeatures2d::SurfFeatureDetector::create();

    std::vector<cv::KeyPoint> keypoints1,keypoints2;
    //
    surfDetector->detect(src1,keypoints1);
    surfDetector->detect(src2,keypoints2);

    cv::Ptr<cv::xfeatures2d::SurfDescriptorExtractor>  surfDescriptor = cv::xfeatures2d::SurfDescriptorExtractor::create();
    cv::Mat imgdescriptor1,imgdescriptor2;
    surfDescriptor->compute(src1,keypoints1,imgdescriptor1);
    surfDescriptor->compute(src2,keypoints2,imgdescriptor2);

    cv::FlannBasedMatcher matcher;
    std::vector<std::vector<cv::DMatch> > matchPoints;
    std::vector<cv::DMatch> goodMatchPoints;
#if 0 //两种方法都可以
    std::vector<cv::Mat> train_desc(1,imgdescriptor1);  //初始化长度为1,内容是imgdescriptor1
    matcher.add(train_desc);
    matcher.train();

    matcher.knnMatch(imgdescriptor2,matchPoints,2);
#else
    matcher.knnMatch(imgdescriptor2,imgdescriptor1,matchPoints,2);//从imgdescriptor1 中找与imgdescriptor2 i个点匹配的2个匹配放到matchpoints中
#endif
    std::cout << "total match points:" << matchPoints.size() << std::endl;
    //为了排除因为图像遮挡和环境混乱而产生误匹配的关键点,sift的作者提出了比较最邻近距离的sift匹配:取一幅图像中的一个sift关键点,并找出其与另一幅图像中欧式距离最近
    //的前两个关键点,在这两个关键点中,如果最近的距离除以次近距离得到的ratio少于阈值T,则接受这一对匹配点。降低T匹配点数会减少,更准确,反之亦然。
    //一般取T在0.4~0.6 ,小于0.4,匹配的点比较少,大于0.6误匹配的点多一些
    for(int i=0;i < matchPoints.size();i++){
        if(matchPoints[i][0].distance < 0.6*matchPoints[i][1].distance){
            goodMatchPoints.push_back(matchPoints[i][0]);
        }
    }

    cv::Mat first_match;
    cv::drawMatches(src2,keypoints2,src1,keypoints1,goodMatchPoints,first_match);//goodMatchPoints是src2到src1,因为生成的matchPoints是src2 到src1


    cv::namedWindow("goodsurf match",cv::WINDOW_NORMAL);
    cv::imshow("goodsurf match",first_match);
    cv::imwrite("goodsurf_match.jpg",first_match);

    cv::waitKey();
    return;
}

我们看一下效果还是不错的

 

3.orb

orb是Oriented Brief的简称,特点是速度快,比sift快100倍,比surf快10倍,orb是brief的改进算法,那么brief的缺点如下:

  • 不具备旋转不变性
  • 对噪声敏感
  • 不具备尺度不变性

ORB的改进在于解决了上述的1和2,也就是说对噪声不敏感,具有旋转不变性,但是值得注意的是上面的第三个,ORB不具有尺度不变性。

opencv的测试代码

void FeatureDialog::on_pbORB_clicked()
{
    if(fileName.isEmpty() || fileName2.isEmpty())
        QMessageBox::warning(this,QString("Warning"),QString("Select the file to match,please"),QMessageBox::Ok);

    cv::Mat src1,src2;

    src1 = cv::imread(fileName.toStdString(),cv::IMREAD_COLOR);
    src2 = cv::imread(fileName2.toStdString(),cv::IMREAD_COLOR);
    //convert to gray
    cv::cvtColor(src1,src1,cv::COLOR_BGR2GRAY);
    cv::cvtColor(src2,src2,cv::COLOR_BGR2GRAY);

    cv::Ptr<cv::ORB> orb = cv::ORB::create();
    //cv::ORB orb;
    std::vector<cv::KeyPoint> keypoints1,keypoints2;


    orb->detect(src1,keypoints1);
    orb->detect(src2,keypoints2);

    cv::Mat imgdescriptor1,imgdescriptor2;

    orb->compute(src1,keypoints1,imgdescriptor1);
    orb->compute(src2,keypoints2,imgdescriptor2);

    cv::flann::Index flannIndex(imgdescriptor1,cv::flann::LshIndexParams(12,20,2),cvflann::FLANN_DIST_HAMMING);

    std::vector<cv::DMatch> goodMatchPoints;

    cv::Mat matchIndex(imgdescriptor2.rows,2 , CV_32SC1);
    cv::Mat matchDistance(imgdescriptor2.rows, 2, CV_32FC1);
    flannIndex.knnSearch(imgdescriptor1,matchIndex,matchDistance,2,cv::flann::SearchParams());

    for(int i=0;i<matchDistance.rows;i++){
        if(matchDistance.at<float>(i,0) < 0.6 * matchDistance.at<float>(i,1)){
            cv::DMatch dmatches(i,matchIndex.at<int>(i,0),matchDistance.at<float>(i,0));
            goodMatchPoints.push_back(dmatches);
        }
    }
    cv::Mat first_match;
    cv::drawMatches(src2,keypoints2,src1,keypoints1,goodMatchPoints,first_match);//goodMatchPoints是src2到src1,因为生成的matchPoints是src2 到src1


    cv::namedWindow("orb match",cv::WINDOW_NORMAL);

    cv::imshow("orb match",first_match);
    cv::imwrite("orb_match.jpg",first_match);


    cv::waitKey();
    return;
}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值