akaze特征匹配怎么去掉不合适的点_SIFT特征点

149198d44e12e685044d0dcb1a69d72f.png

图像特征点检测一直是研究的热点,从早期的harris角点检测开始,一直有很多人关注图像特征点的检测。最早人们关注图像中的角点,主要是因为角点能够代表图像中的一些特征。比如,通过检测两幅图像中的角点,可以实现图像匹配、分类等。

但是,早前的角点检测算法不具有放射不变性,即对于旋转、平移、缩放等图像的适应性不好。此外,光照不变性的性能也比较差。直到SIFT算法横空出世,很好的解决了这方面的问题。SIFT算法算是一个相对有点复杂的算法,对于初学者如果要完全弄懂,可能需要花一些时间。这里我简单介绍下该算法,有兴趣的可以重点研究一下。

Sift算法主要分为以下几个步骤:

(1)建立高斯金字塔,利用高斯差分进行图像极值点检测;

(2)去掉边界和对比度小的极值,拟合函数确定亚像素精度的极值,得到稳定的极值点;

(3)计算极值点16X16邻域范围内梯度直方图,将16X16范围分为16个4X4的像素块,每个块计算8个方向的梯度直方图,得到关键点的128维描述向量并归一化消除光照影响。

(4)图像进行匹配时,通过比较两图中的关键点128维向量的欧式距离找到匹配点。

6b501259048d30fb6d7b437ec2e864b0.png
图1 David Lowe和检测出来的SIFT特征点

英属哥伦比亚大学教授大卫·罗伊(David Lowe)1999年提出SIFT算法,该算法具有光照不变性,放射不变性等特点。而且,找出来的特征点非常稳定。该算法专利属于英属哥伦比亚大学,在opencv3.0以后不能直接使用,需要自己编译opencv扩展库才能调用。但是该算法也有一个缺陷,就是计算速度太慢了,很难满足实时检测的要求,如果要提高速度,对硬件的要求比较高。

SIFT算法除了提出的特征点检测算法比较稳定之外,其实该算法的特征点描述算子也是相当优秀。SIFT的特征点描述算子采用128维的梯度方向向量来描述特征点,由于梯度本身就比较稳定,并且不受光照变化的影响。因此,采用该描述算子可以唯一的表达对应的特征点。2005年Navneet Dalal提出的HOG算法用于行人检测,其提出的HOG描述符应该也是受到SIFT算法的启发。下面以具体的opencv代码来实现SIFT特征点检测。代码上对关键代码进行了注释。要调用SIFT算子,必须自己编译opencv扩展库的源代码。SIFT算法的原文以及公式可以在网上查询,这里就不再介绍了。

#include <iostream>
#include <stdio.h>
#include "opencv2/core.hpp"
#include "opencv2/core/utility.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/features2d.hpp"
#include <features2d/features2d.hpp>
#include "opencv2/imgproc.hpp"
#include"opencv2/flann.hpp"
#include"opencv2/xfeatures2d.hpp"
 
using namespace cv;
using namespace std;
using namespace cv::xfeatures2d;
 
int main(int argc, char** argv)
{
 Mat src1, src2;
 src1 = imread("E:boatimg1.pgm", 0);
 src2 = imread("E:boatimg2.pgm", 0);
 namedWindow("src1", 0);
 namedWindow("src2", 0);
 imshow("src1", src1);
 imshow("src2", src2);
 
 vector<KeyPoint> keyPoint1, keyPoint2;
//创建SIFT变量,可以直接指定一些参数,也可以不指定,采用默认的参数
 //Ptr<Feature2D> sift = xfeatures2d::SIFT::create();
 Ptr<Feature2D> sift = xfeatures2d::SIFT::create(500, 3);
//进行特征点检测
 sift->detect(src1, keyPoint1);
 sift->detect(src2, keyPoint2);
 Mat result1, result2;
//将检测侧的特征点绘制在图像上
 drawKeypoints(src1, keyPoint1, result1, Scalar(0, 255, 0), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);//画出特征点
 namedWindow("src1特征点", 0);
 imshow("src1特征点", result1);
//将检测侧的特征点绘制在图像上
 drawKeypoints(src2, keyPoint2, result2, Scalar(0, 255, 0), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);//画出特征点
 namedWindow("src2特征点", 0);
 imshow("src2特征点", result2);
 
 
 Mat descriptors_1, descriptors_2;
//计算图像上每个特征点的128维描述算子
 sift->compute(src1, keyPoint1, descriptors_1);
 sift->compute(src2, keyPoint2, descriptors_2);
 
 BFMatcher matcher;
 vector<DMatch> matches;
//两幅图像特征点匹配
 matcher.match(descriptors_1, descriptors_2, matches);
 
 Mat img_matches;
//绘制匹配结果
 drawMatches(src1, keyPoint1, src2, keyPoint2, matches, img_matches, Scalar(0, 0, 255), Scalar(0, 0, 255));
 namedWindow("match1", 0);
 imshow("match1", img_matches);
 
 //提取出最佳匹配结果
 nth_element(matches.begin(), matches.begin() + 50, matches.end()); 
 //剔除掉其余的匹配结果
 matches.erase(matches.begin() + 50, matches.end()); 
 Mat img_matches2;
//绘制匹配结果
 drawMatches(src1, keyPoint1, src2, keyPoint2, matches, img_matches2, Scalar(0, 0, 255), Scalar(0, 0, 255));
 namedWindow("match2", 0);
 imshow("match2", img_matches2);
 waitKey(0);
 return 0;
}

b81434a79ae8d1129bfacd2dbb762f38.png
图2 原图

574a3b27b82f58ad32bd62a989a3a3c8.png
图3 特征点

53ef5e63a108db9b3706d0920c8e1acc.png
图4 特征点匹配结果

643e52c26bb1af6ad7c183a127d8921a.png
图5提取出最佳匹配结果

上面的第二张图像相对于第一张图像,有一定的放射变换。但是,可以看出,SIFT算法能够很好的检测出两张图像中的特征点,并且得到很好的匹配结果。由于第一次检测出来的特征点比较多,可能存在有些特征点不匹配的情况。因此,可以过滤掉一些点,只保留最前面匹配结果最好的一些点来匹配。图5是取出的前面50个点匹配的结果。看得出来,SIFT算法还是相当优秀的。在最新的opencv5.0版本中,SIFT算法的专利已经过期了,所以将该算法放在了主仓库里面,可以直接调用,不用编译扩展库了。但是,由于扩展库里面还有其他很多优秀的算法,因此,要把opencv的功能发挥出来,还是要自己编译opencv以及扩展库的源代码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值