基于SIFT图像特征识别的匹配方法比较与实现

这篇具有很好参考价值的文章主要介绍了基于SIFT图像特征识别的匹配方法比较与实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

基于SIFT图像特征识别的匹配方法比较与实现

1 匹配器选择

目前常用的匹配器有 BFMatcher and FlannBasedMatcher

1.1 BFMatcher

BFMatcher 全称是 Brute-Force Matcher(直译即为暴力匹配器)

大致原理:

对于 img1 中的每个描述符, BFMatcher 将其与 img2 中的所有描述符进行比较;它计算两个描述符之间的距离度量(例如,欧几里得距离或汉明距离,默认使用欧几里得距离)并跟踪最接近的匹配,具有最小距离的描述符对被认为是潜在的匹配

用法示例:

创建一个 Brute-Force 匹配器,并使用匹配器对两组描述子进行匹配

// 创建匹配器对象
BFMatcher matcher;
// 使用 K 最近邻匹配方法进行特征匹配
vector<vector<DMatch>> matches;
matcher.knnMatch(descriptors1, descriptors2, matches, 2);
总结结论:

BFMatcher 将尝试所有可能性,这种匹配算法非常慢,匹配所需的时间随着添加的特征数量线性增加,这导致更高的计算成本,所以尤其是对于大型数据集BFMatcher 是一种简单但不一定是最有效的匹配方法

1.2 Flann

Flann 全称是 Fast Library for Approximate Nearest Neighbors(直译即为近似近邻快速库)

大致原理:

FLANN 旨在快速查找近似最近邻,尤其是在高维空间中,它不是详尽地搜索所有数据点,而是使用各种技术来更有效地执行搜索,同时提供相当准确的结果;FLANN 会构建了一个高效的数据结构,用于搜索近似邻居,FLANN 比 BFMatcher 快得多,但它只能找到近似的最近邻,这是一个很好的匹配,但不一定是最好的,可以调整 FLANN 的参数以提高精度,但这将以减慢算法速度为代价(鱼和熊掌不可兼得)

用法示例:

创建一个 FLANN 匹配器,并使用匹配器对两组描述子进行匹配

// 创建匹配器对象
FlannBasedMatcher matcher;
// 使用 K 最近邻匹配方法进行特征匹配
vector<vector<DMatch>> matches;
matcher.knnMatch(descriptors1, descriptors2, matches, 2);
总结结论:

FLANN 在牺牲一些精度的情况下,提供了更快的搜索速度,特别是在高维空间或大型数据集中

1.3 比较总结

  1. 准确度
    • BF 匹配器:BF 匹配提供精确的最近邻搜索,这意味着它可以高精度地找到最接近的匹配项;它适用于精度至关重要的任务,例如某些图像识别或对象跟踪任务
    • FLANN:FLANN 执行近似最近邻搜索,这意味着它会找到可能不是精确最近邻的近似匹配。虽然 FLANN 旨在提供良好的结果,但与 BF 匹配相比,速度的权衡可能会导致结果的准确性稍差
  2. 速度
    • BF 匹配器:BF 匹配简单明了,但计算成本可能很高,尤其是在高维空间或处理大型数据集时;它涉及将一个描述符与所有其他描述符进行比较,导致匹配 N 个关键点的时间复杂度为 O(N^2)
    • FLANN 专为高效的最近邻搜索而设计,特别是在高维空间中。它在速度方面通常优于 BF 匹配;FLANN的算法(KD-Tree、K-Means Tree、LSH等)的选择和参数调整可以进一步优化搜索速度

测试:

SIFT+FLANN+比率测试筛选ratio=0.6 SIFT+BF+比率测试筛选ratio=0.6
效果 基于SIFT图像特征识别的匹配方法比较与实现,CV,算法,c++,SIFT,BFMatcher,FLANN 基于SIFT图像特征识别的匹配方法比较与实现,CV,算法,c++,SIFT,BFMatcher,FLANN
匹配+筛选用时 0.338931秒 0.494063秒

可以看出,两张图片效果基本相同,都有着极高的质量,但是在时间上,FLANN 比较与 BF 快了很多,效率更高

在许多计算机视觉和机器学习应用中,FLANN 是首选,因为它在速度和准确性之间取得了良好的平衡,使其适用于广泛的任务

所以我们选择 FLANN 作为匹配器

2 筛选方法

对于用不同匹配器得出的结果都会出现很多错误匹配,例如下图直接使用BF匹配器进行匹配:

基于SIFT图像特征识别的匹配方法比较与实现,CV,算法,c++,SIFT,BFMatcher,FLANN

可以看到有数不清的点都进行了匹配,这样的效果非常差,这个时候筛选方法就显得十分重要了,利用好的筛选方法可以帮助我们最大程度上提升图片特征匹配的质量

2.1 距离阈值筛选

距离阈值筛选的原理很简单:它假设距离较近的特征点之间更可能是正确的匹配,而距离较远的特征点之间更可能是错误的匹配

  1. 用BF匹配器找出所有的匹配对

    BFMatcher matcher;
    vector<DMatch>matches;
    matcher.match(descriptors1, descriptors2, matches);
    
  2. 先通过遍历所有的匹配对,找的匹配中的最小距离

    double minDist = 1000;
    for (int i = 0; i < descriptors1.rows; i++)
    {
        double dist = matches[i].distance;
        if (dist < minDist)
        {
            minDist = dist;
        }
    }
    
  3. 再次遍历所有的匹配对,筛选出距离在距离阈值内的匹配

    其中 Multiples 是可设置的倍数,我们用最小距离的 Multiples 倍来当作距离阈值

    vector<DMatch>good_matches;
    for (int i = 0; i < descriptors1.rows; i++)
    {
        double dist = matches[i].distance;
        const float Multiples = 2.5; // 倍数参数
        if (dist < Multiples * minDist)
        {
            good_matches.push_back(matches[i]);
        }
    }
    

测试:SIFT+BF+距离阈值筛选

倍数Multiples 结果图片
Multiples = 2.5 基于SIFT图像特征识别的匹配方法比较与实现,CV,算法,c++,SIFT,BFMatcher,FLANN
Multiples = 2.75 基于SIFT图像特征识别的匹配方法比较与实现,CV,算法,c++,SIFT,BFMatcher,FLANN
Multiples = 3.0 基于SIFT图像特征识别的匹配方法比较与实现,CV,算法,c++,SIFT,BFMatcher,FLANN
Multiples = 3.25 基于SIFT图像特征识别的匹配方法比较与实现,CV,算法,c++,SIFT,BFMatcher,FLANN

2.2 比率测试筛选 Ratio test

比例测试的基本思想是比较最近邻匹配次近邻匹配的距离,并根据它们之间的距离比例来决定是否保留最近邻匹配

基本原理:距离最小的匹配是最近邻匹配,距离第二小的匹配相当于随机噪音,如果最近邻匹配无法与噪音区分开来,那么最近邻匹配就应该被剔除,因为它与噪音一样,没有带来任何有价值的信息

  1. 用BF匹配器找出所有的匹配对

    vector<vector<DMatch>> matches;
    BFMatcher matcher;
    matcher.knnMatch(descriptors1, descriptors2, matches, 2);
    

    注意这里使用 knnMatch 函数,matches 也需要设置为二维数组

    其返回每个查询描述子的前 K 个最佳匹配;K 被设置为 2,即返回每个查询描述子的两个最佳匹配:其中 matches[i][0] 表示第一个最佳匹配(最近的邻居),matches[i][1] 表示第二个最佳匹配(次相似的特征点)

  2. 设置比例参数 ratio,通常设置为 0.5 左右,筛选出最佳匹配与第二最佳匹配有明显区别的,从而丢弃我们不明确的匹配并保留好的匹配

    vector<DMatch> good_matches;
    for (int i = 0; i < matches.size(); ++i)
    {
    	const float ratio = 0.5; // 比例参数
    	if (matches[i][0].distance < ratio * matches[i][1].distance)
    	{
    		good_matches.push_back(matches[i][0]);
    	}
    }
    

测试:SIFT+BF+比率测试筛选

比例ratio 结果图片
ratio = 0.4 基于SIFT图像特征识别的匹配方法比较与实现,CV,算法,c++,SIFT,BFMatcher,FLANN
ratio = 0.5 基于SIFT图像特征识别的匹配方法比较与实现,CV,算法,c++,SIFT,BFMatcher,FLANN
ratio = 0.6 基于SIFT图像特征识别的匹配方法比较与实现,CV,算法,c++,SIFT,BFMatcher,FLANN
ratio = 0.7 基于SIFT图像特征识别的匹配方法比较与实现,CV,算法,c++,SIFT,BFMatcher,FLANN

2.3 比较总结

通过两组测试进行对比,在匹配对数量近似相等的情况下,明显比率测试筛选有着明显的优势,Multiples = 3.25 下已经出现了许多的错误,而 ratio = 0.6 在匹配对数量略大的情况下,保持较高的准确率

ratio = 0.6 Multiples = 3.25
基于SIFT图像特征识别的匹配方法比较与实现,CV,算法,c++,SIFT,BFMatcher,FLANN 基于SIFT图像特征识别的匹配方法比较与实现,CV,算法,c++,SIFT,BFMatcher,FLANN

所以最终我们选择比率测试筛选的筛选方法

3 特征点匹配实现(SIFT)

步骤1:导入必要的库和头文件

首先,导入必要的OpenCV库和头文件,设置图片路径:

#include<opencv2/opencv.hpp>
#include<iostream>
 
#define IMG_PATH1 "test_img\\1\\B23.jpg"
#define IMG_PATH2 "test_img\\1\\B24.jpg"
#define SAVE_PATH "test_img\\1\\img_matches.jpg"

using namespace std;
using namespace cv;
步骤2:加载图像

加载两幅要进行特征点匹配的图像。确保图像文件存在,并将它们放在项目目录下,或者根据您的文件路径进行适当的更改。

Mat img1 = imread(IMG_PATH1, IMREAD_GRAYSCALE);
Mat img2 = imread(IMG_PATH2, IMREAD_GRAYSCALE);
if (img1.empty() || img2.empty())
{
    cout << "Can't read image" << endl;
    return -1;
}
步骤3:创建SIFT检测器

创建SIFT检测器对象,可以选择不同的参数,例如最大特征点数量、尺度等。在本例中,我们使用默认参数。

Ptr<SIFT> sift = SIFT::create();

Ptr 是 OpenCV 提供的智能指针类,用于管理动态分配的对象,帮助防止内存泄漏和减少手动内存管理的负担

Ptr 主要用于管理 OpenCV 中的各种对象,例如图像、特征检测器、匹配器等;它可以自动跟踪和管理对象的引用计数,当对象不再需要时,会自动释放对象的内存,以确保资源被正确释放

步骤4:检测关键点和计算描述子

使用SIFT检测器在两幅图像中检测关键点,并计算它们的描述子。

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

sift->detectAndCompute(img1, noArray(), keypoints1, descriptors1);
sift->detectAndCompute(img2, noArray(), keypoints2, descriptors2);

KeyPoint 是 OpenCV 中用于表示图像中关键点的类,关键点通常用于描述图像中的特征,例如角点、边缘、斑点等;KeyPoint 包含了关键点的位置、尺度、方向和响应等信息,它是计算机视觉中常用的数据结构之一

KeyPoint 类的主要成员包括:

  1. pt:一个 Point2f 类型的成员,表示关键点在图像中的二维坐标位置(x,y)
  2. size:一个浮点数,表示关键点的尺度,尺度通常表示关键点的特征区域大小
  3. angle:一个浮点数,表示关键点的方向,通常用于指示关键点的主要方向
  4. response:一个浮点数,表示关键点的响应值,响应值通常用于评估关键点的质量
  5. octave:一个整数,表示关键点所在的金字塔层级(octave),这是与尺度空间相关的信息
  6. class_id:一个整数,可用于标识关键点所属的类别或其他信息

detectAndCompute 是 OpenCV 中常用的函数,通常与特征检测和描述子计算相关。这个函数结合了特征检测和描述子计算两个步骤,用于从图像中检测关键点并计算关键点的描述子;它的主要作用是在一次操作中完成这两个关键的计算步骤,以提高计算效率和代码简洁性

其中第二参数是 mask 掩膜,抠出指定区域,我们先不用设置为空参数noArray() 或者 Mat()

descriptors 描述子通常是一个二维矩阵(或多维矩阵),是一个 Mat 对象,其中每一行代表一个关键点的描述子,描述子的维度取决于特征检测算法和配置参数,在 SIFT 中,描述子通常是128维的向量

步骤5:特征点匹配

创建一个Brute-Force匹配器,并使用匹配器对两组描述子进行匹配。

// 创建匹配器对象
FlannBasedMatcher matcher;
// 使用 K 最近邻匹配方法进行特征匹配
vector<vector<DMatch>> matches;
matcher.knnMatch(descriptors1, descriptors2, matches, 2);

DMatch 是 OpenCV 中用于存储特征匹配信息的结构体,它包含了两个特征点之间(一对)的匹配信息,包括以下成员:

  1. queryIdx:特征描述子在查询图像中的索引,这个索引对应于查询图像中的一个特征点
  2. trainIdx:特征描述子在训练图像中的索引,这个索引对应于训练图像中的一个特征点
  3. distance:描述了两个特征描述子之间的距离或相似性度量,通常,距离越小,表示两个特征点越相似
步骤6:筛选匹配点

筛选匹配点以获取最佳匹配,可以使用阈值来过滤掉不好的匹配

// 存储较好的匹配
vector<DMatch> good_matches;
for (int i = 0; i < matches.size(); ++i) {
    const float ratio = 0.5; // 比例参数
    // 仅保留比例参数内的较好匹配
    if (matches[i][0].distance < ratio * matches[i][1].distance) {
        good_matches.push_back(matches[i][0]);
    }
}
步骤7:绘制匹配结果

绘制匹配结果,将特征点匹配可视化。文章来源地址https://www.toymoban.com/news/detail-706527.html

// 绘制好的匹配结果并保存
Mat img_matches;
drawMatches(img1, keypoints1, img2, keypoints2, good_matches, img_matches);
imwrite("test_img\\img_matches.jpg", img_matches);

// 显示匹配结果的窗口
namedWindow("matches", WINDOW_NORMAL);
imshow("matches", img_matches);

// 等待用户按下任意键以关闭窗口
waitKey(0);
完整测试代码:
#include<opencv2/opencv.hpp>
#include<iostream>
#include <chrono> // 用于测试耗时
#define IMG_PATH1 "test_img\\1\\B23.jpg"
#define IMG_PATH2 "test_img\\1\\B24.jpg"
#define SAVE_PATH "test_img\\1\\img_matches.jpg"

using namespace std;
using namespace cv;
using namespace chrono; // 用于测试耗时

int main()
{
	Mat img1 = imread(IMG_PATH1, IMREAD_GRAYSCALE);
	Mat img2 = imread(IMG_PATH2, IMREAD_GRAYSCALE);
	if (img1.empty() || img2.empty())
	{
		cout << "Can't read image" << endl;
		return -1;
	}

	Ptr<SIFT> sift = SIFT::create();
	vector<KeyPoint> keypoints1, keypoints2;
	Mat descriptors1, descriptors2;

	sift->detectAndCompute(img1, noArray(), keypoints1, descriptors1);
	sift->detectAndCompute(img2, noArray(), keypoints2, descriptors2);
	
	//auto start = system_clock::now();	
	
	//--------------
	// BF+knn
	//--------------
	//vector<vector<DMatch>> matches;
	//cv::BFMatcher matcher;
	//matcher.knnMatch(descriptors1, descriptors2, matches, 2);
	//vector<DMatch> good_matches;
	//for (int i = 0; i < matches.size(); ++i)
	//{
	//	const float ratio = 0.6; // 比例参数
	//	if (matches[i][0].distance < ratio * matches[i][1].distance)
	//	{
	//		good_matches.push_back(matches[i][0]);
	//	}
	//}


	//--------------
	// FLANN+knn
	//--------------
	FlannBasedMatcher matcher;
	vector<vector<DMatch>> matches;
	matcher.knnMatch(descriptors1, descriptors2, matches, 2);
	vector<cv::DMatch> good_matches;
	for (int i = 0; i < matches.size(); ++i)
	{
		const float ratio = 0.8; // 比例参数
		if (matches[i][0].distance < ratio * matches[i][1].distance)
		{
			good_matches.push_back(matches[i][0]);
		}
	}
	
	//--------------
	// BF + 距离阈值筛选
	//--------------
	//BFMatcher matcher;
	//vector<DMatch>matches;
	//matcher.match(descriptors1, descriptors2, matches);
	//
	//double minDist = 1000;
	//for (int i = 0; i < descriptors1.rows; i++)
	//{
	//	double dist = matches[i].distance;

	//	if (dist < minDist)
	//	{
	//		minDist = dist;
	//	}
	//}

	//vector<DMatch>good_matches;
	//for (int i = 0; i < descriptors1.rows; i++)
	//{
	//	double dist = matches[i].distance;
	//	const float Multiples = 2.5; // 倍数参数
	//	if (dist < Multiples * minDist)
	//	{
	//		good_matches.push_back(matches[i]);
	//	}
	//}
    
    
	//auto end = system_clock::now();
	//auto duration = duration_cast<microseconds>(end - start);
	//cout << "花费了"
	//	 << double(duration.count()) * microseconds::period::num / microseconds::period::den
	//	 << "秒" << endl;
    
	Mat img_matches;
	drawMatches(img1, keypoints1, img2, keypoints2, good_matches, img_matches);

	imwrite(SAVE_PATH, img_matches);
	namedWindow("matches", WINDOW_NORMAL);
	imshow("matches", img_matches);
	waitKey(0);
}

到了这里,关于基于SIFT图像特征识别的匹配方法比较与实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • OpenCV Python – 使用SIFT算法实现两张图片的特征匹配

    1.要实现在大图中找到任意旋转、缩放等情况下的小图位置,可以使用特征匹配算法,如 SIFT (尺度不变特征变换) 或 SURF (加速稳健特征)。这些算法可以在不同尺度和旋转情况下寻找匹配的特征点 2.我们使用了 SIFT 算法检测和匹配特征点,然后使用 RANSAC 算法计算透视变换矩阵

    2024年02月06日
    浏览(49)
  • 机器学习图像特征提取—SIFT特征提取原理及代码实现

    目录 1 SIFT简介 2 SIFT原理及特点 2.1 SIFT算法特点 2.2 SIFT特征检测 3 SIFT代码实现        SIFT,即尺度不变特征变换(Scale-invariant feature transform,SIFT),是用于图像处理领域的一种描述。这种描述具有尺度不变性,可在图像中检测出关键点,是一种局部特征描述子。       SIF

    2024年02月06日
    浏览(44)
  • 学习笔记:Opencv实现图像特征提取算法SIFT

    2023.8.19 为了在暑假内实现深度学习的进阶学习,特意学习一下传统算法,分享学习心得,记录学习日常 SIFT的百科: SIFT = Scale Invariant Feature Transform, 尺度不变特征转换 全网最详细SIFT算法原理实现_ssift算法_Tc.小浩的博客-CSDN博客 在环境配置中要配置opencv: pip install opencv-c

    2024年02月12日
    浏览(47)
  • SIFT算法 特征匹配

    一、SIFT算法 参考链接 【OpenCV】SIFT原理与源码分析 DOG尺度空间构造(Difference of Gaussian) 首先是对原特征图下采样可以得到金字塔形状的多分辨率空间,作为特征金字塔,该特征金字塔可以方便提取出不同尺度的特征(感觉这里也可以叫多尺度空间) 多尺度空间:利用高斯

    2024年02月04日
    浏览(32)
  • OpenCV(图像处理)-基于Python-特征检测-特征点匹配

    图像特征就是指有意义的图像区域,具有独特性,易于识别性,比如角点、斑点以及高密度区。而为什么角点具有重要的特征呢? 看下图: 观察ABD三张图片,我们不容易得知图像的位置,而CEF三张图我们特别容易找到它们在原图中对应的位置,这是因为ABD比较平滑,我们不

    2024年02月03日
    浏览(54)
  • SIFT 算法 | 如何在 Python 中使用 SIFT 进行图像匹配

    人类通过记忆和理解来识别物体、人和图像。你看到某件事的次数越多,你就越容易记住它。此外,每当一个图像在你的脑海中弹出时,它就会将该项目或图像与一堆相关的图像或事物联系起来。如果我告诉你我们可以使用一种称为 SIFT 算法的技术来教机器做同样的事情呢?

    2024年02月13日
    浏览(42)
  • 计算机视觉项目实战-基于特征点匹配的图像拼接

    😊😊😊 欢迎来到本博客 😊😊😊 本次博客内容将继续讲解关于OpenCV的相关知识 🎉 作者简介 : ⭐️⭐️⭐️ 目前计算机研究生在读。主要研究方向是人工智能和群智能算法方向。目前熟悉深度学习(keras、pytorch、yolo),python网页爬虫、机器学习、计算机视觉(OpenCV)、

    2024年02月02日
    浏览(50)
  • 【图像处理】SIFT角点特征提取原理

            提起在OpenCV中的特征点提取,可以列出Harris,可以使用SIFT算法或SURF算法来检测图像中的角特征点。本篇围绕sift的特征点提取,只是管中窥豹,而更多的特征点算法有: Harris Stephens / Shi–Tomasi 角点检测算法 Förstner角点检测器; 多尺度 Harris 算子 水平曲线曲率法

    2024年02月07日
    浏览(42)
  • 无人机航拍图像匹配——SIFT算法实践(含代码)

    SIFT(Scale-Invariant Feature Transform)算法是由David Lowe于1999年提出的一种用于图像处理和计算机视觉中的特征提取和匹配方法。它在航拍图像匹配中具有重要的意义,主要体现在以下几个方面: 尺度不变性 :航拍图像通常具有大范围的尺度变化,例如拍摄距离目标较远或较近的

    2024年02月04日
    浏览(49)
  • opencv 进阶16-基于FAST特征和BRIEF描述符的ORB(图像匹配)

    在计算机视觉领域,从图像中提取和匹配特征的能力对于对象识别、图像拼接和相机定位等任务至关重要。实现这一目标的一种流行方法是 ORB(Oriented FAST and Rotated Brief)特征检测器和描述符。ORB 由 Ethan Rublee 等人开发,结合了两种现有技术的优势——FAST(加速分段测试特征

    2024年02月11日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包