Opencv 之ORB特征提取与匹配API简介及使用例程

news/2024/7/10 1:47:28 标签: opencv, 人工智能, 计算机视觉, 目标检测

Opencv 之ORB特征提取与匹配API简介及使用例程

  • ORB因其速度较快常被用于视觉SLAM中的位姿估计、视觉里程、图像处理中的特征提取与匹配及图像拼接等领域
  • 本文将详细给出使用例程及实现效果展示

1. API 简介

  • 创建
static Ptr<ORB> cv::ORB::create	(
	int nfeatures = 500,                                   //nfeatures 最终输出最大特征点数目
	float scaleFactor = 1.2f,                            // scaleFactor 金字塔上采样比率
	int nlevels = 8,                                            // nlevels 金字塔层数
	int edgeThreshold = 31,                                // edgeThreshold 边缘阈值
	int firstLevel = 0,
	int WTA_K = 2,                                                // WTA_K这个是跟BRIEF描述子用的
	ORB::ScoreType 	scoreType = ORB::HARRIS_SCORE,        //  scoreType 对所有的特征点进行排名用的方法
	int patchSize = 31,
	int fastThreshold = 20 
)
  • 检测
void cv::Feature2D::detect	(	InputArray 	image,   //输入图像
                                std::vector< KeyPoint > & 	keypoints,    //待搜索特征点
                                InputArray 	mask = noArray()    //操作掩码
                             )	
  • 计算
void cv::Feature2D::compute	(	InputArrayOfArrays 	images,    //输入图像
                                std::vector< std::vector< KeyPoint > > & 	keypoints,
                                OutputArrayOfArrays 	descriptors   //描述子
                            )	
  • 检测与计算
 void cv::Feature2D::detectAndCompute	(	InputArray 	image,
                                            InputArray 	mask,
                                            std::vector< KeyPoint > & 	keypoints,
                                            OutputArray 	descriptors,
                                            bool 	useProvidedKeypoints = false 
                                        )	
  • 绘制特征点
void cv::drawMatches	(	InputArray 	img1,
                            const std::vector< KeyPoint > & 	keypoints1,
                            InputArray 	img2,
                            const std::vector< KeyPoint > & 	keypoints2,
                            const std::vector< DMatch > & 	matches1to2,
                            InputOutputArray 	outImg,
                            const Scalar & 	matchColor = Scalar::all(-1),
                            const Scalar & 	singlePointColor = Scalar::all(-1),
                            const std::vector< char > & 	matchesMask = std::vector< char >(),
                            DrawMatchesFlags 	flags = DrawMatchesFlags::DEFAULT 
                         )	
  • 绘制匹配点对
void cv::drawMatches	(	InputArray 	img1,
                            const std::vector< KeyPoint > & 	keypoints1,
                            InputArray 	img2,
                            const std::vector< KeyPoint > & 	keypoints2,
                            const std::vector< DMatch > & 	matches1to2,
                            InputOutputArray 	outImg,
                            const Scalar & 	matchColor = Scalar::all(-1),
                            const Scalar & 	singlePointColor = Scalar::all(-1),
                            const std::vector< char > & 	matchesMask = std::vector< char >(),
                            DrawMatchesFlags 	flags = DrawMatchesFlags::DEFAULT 
                       )	

2. 特征提取

  • 讲述特征点提取与描述子计算,实现如下:
int main()
{
	Mat img = imread("./data/test3/lena.png");
	if (!img.data || img.empty())
	{
		cout << "图像读取错误!" << endl;
		return -1;
	}

	//创建ORB关键点

	Ptr<ORB> orb = ORB::create(500, 1.2f);
	double t1 = getTickCount();
	vector<KeyPoint>Keypoints;
	Mat descriptions;
#if 0
	//计算ORB关键点
	orb->detect(img, Keypoints);

	//计算ORB描述子
	orb->compute(img, Keypoints, descriptions);
#else
	orb->detectAndCompute(img, cv::Mat(), Keypoints, descriptions);
#endif // 0

	double t2 = (getTickCount() - t1) / getTickFrequency() * 1000;
	cout << "img.size = " << img.size() << " , cost time = " << t2 << "ms\n";

	//绘制特征点
	Mat imgAngle;
	img.copyTo(imgAngle);
	//绘制不含角度和大小的结果
	drawKeypoints(img, Keypoints, img, Scalar(255, 255, 255));
	//绘制含有角度和大小的结果
	drawKeypoints(img, Keypoints, imgAngle, Scalar(255, 255, 255), DrawMatchesFlags::DRAW_RICH_KEYPOINTS);

	//显示结果
	string wname1 = "不含角度和大小的结果", wname2 = "含角度和大小的结果";
	namedWindow(wname1, WINDOW_NORMAL);
	namedWindow(wname2, 0);
	imshow(wname1, img);
	imshow(wname2, imgAngle);
	waitKey(0);

	return 1;
}

在这里插入图片描述

3. 特征匹配

  • 暴力匹配实现:
#include<iostream>
#include<opencv2/opencv.hpp>
#include<vector>

using namespace std;
using namespace cv;

int main()
{
	//灰度格式读取
	Mat img1, img2;
	img1 = imread("./data/test3/1.jpg",IMREAD_GRAYSCALE);
	img2 = imread("./data/test3/2.jpg",0);
	if (img1.empty() || img2.empty())
	{
		cout << "img.empty!!!\n";
		return -1;
	}
	//提取orb特征点
	vector<KeyPoint>Keypoints1, Keypoints2;
	Mat descriptions1, descriptions2;

	//计算特征点
	orb_features(img1, Keypoints1, descriptions1);
	orb_features(img2, Keypoints2, descriptions2);

	//特征点匹配
	vector<DMatch>matches; 
	BFMatcher matcher(NORM_HAMMING); //定义特征点匹配的类,使用汉明距离
	matcher.match(descriptions1, descriptions2, matches);
	cout << "matches = " << matches.size() << endl;

	//通过汉明距离筛选匹配结果
	double min_dist = 10000, max_dist = 0;
	for (int i = 0; i < matches.size(); ++i)
	{
		double dist = matches[i].distance;
		min_dist = min_dist < dist ? min_dist : dist;
		max_dist = max_dist > dist ? max_dist : dist;
	}
	//输出计算的最大、最小距离
	cout << "min_dist = " << min_dist << endl;
	cout << "max_dist = " << max_dist << endl;

	//通过距离提出误差大的点
	vector<DMatch>goodmatches;
	for (int i = 0; i < matches.size(); ++i)
	{
		if (matches[i].distance <= MAX(1.8 * min_dist, 30)) //需调参
		{
			goodmatches.push_back(matches[i]);
		}
	}
	cout << "good_min = " << goodmatches.size() << endl;

	//绘制结果
	Mat outimg, outimg1;
	drawMatches(img1, Keypoints1, img2, Keypoints2, matches, outimg);
	drawMatches(img1, Keypoints1, img2, Keypoints2, goodmatches, outimg1);
	string wname1 = "未筛选结果", wname2 = "最小汉明距离筛选";
	namedWindow(wname1, WINDOW_NORMAL);
	namedWindow(wname2, 0);
	imshow(wname1, outimg);
	imshow(wname2, outimg1);
	waitKey(0);

	return 1;
}

其效果如下:

在这里插入图片描述

在这里插入图片描述

  • 最近邻匹配实现如下:
if (descriptions1.type() != CV_32F)
	{
		descriptions1.convertTo(descriptions1, CV_32F);
		descriptions2.convertTo(descriptions2, CV_32F);
	}
	//特征点匹配
	vector<DMatch>matches;
	FlannBasedMatcher matcher; //定义特征点匹配的类,使用汉明距离
	matcher.match(descriptions1, descriptions2, matches);
	cout << "matches = " << matches.size() << endl;

	//通过汉明距离筛选匹配结果
	double min_dist = 10000, max_dist = 0;
	for (int i = 0; i < matches.size(); ++i)
	{
		double dist = matches[i].distance;
		min_dist = min_dist < dist ? min_dist : dist;
		max_dist = max_dist > dist ? max_dist : dist;
	}
	//输出计算的最大、最小距离
	cout << "min_dist = " << min_dist << endl;
	cout << "max_dist = " << max_dist << endl;

	//通过距离提出误差大的点
	vector<DMatch>goodmatches;
	for (int i = 0; i < matches.size(); ++i)
	{
		if (matches[i].distance <= 0.6 * max_dist) //需调参
		{
			goodmatches.push_back(matches[i]);
		}
	}
	cout << "good_min = " << goodmatches.size() << endl;

其效果如下:
在这里插入图片描述
在这里插入图片描述

  • RANSAC优化匹配
void ransac(vector<DMatch>matches, vector<KeyPoint>queryKeyPoint,
	vector<KeyPoint>trainKeyPoint, vector<DMatch>& matches_ransac)
{
	//定义保存匹配点对坐标
	vector<Point2f>srcPoints(matches.size()), dstPoints(matches.size());
	//保存从关键点中提取到的匹配点对坐标
	for (int i = 0; i < matches.size(); ++i)
	{
		srcPoints[i] = queryKeyPoint[matches[i].queryIdx].pt;
		dstPoints[i] = trainKeyPoint[matches[i].trainIdx].pt;
	}
	//匹配点对RANSAC过滤
	vector<int>inlierMask(srcPoints.size());
	findHomography(srcPoints, dstPoints, RANSAC, 5, inlierMask);

	//手动保留RANSAC过滤后的匹配点对
	for (int i = 0; i < inlierMask.size(); ++i)
	{
		if (inlierMask[i])
			matches_ransac.push_back(matches[i]);
	}
}

//*************************RANSAC*******************************************
//main函数中放在暴力匹配代码后:
    //特征点匹配
	vector<DMatch>matches; 
	BFMatcher matcher(NORM_HAMMING); //定义特征点匹配的类,使用汉明距离
	matcher.match(descriptions1, descriptions2, matches);
	cout << "matches = " << matches.size() << endl;

	//通过汉明距离筛选匹配结果
	double min_dist = 10000, max_dist = 0;
	for (int i = 0; i < matches.size(); ++i)
	{
		double dist = matches[i].distance;
		min_dist = min_dist < dist ? min_dist : dist;
		max_dist = max_dist > dist ? max_dist : dist;
	}
	//输出计算的最大、最小距离
	cout << "min_dist = " << min_dist << endl;
	cout << "max_dist = " << max_dist << endl;

	//通过距离提出误差大的点
	vector<DMatch>goodmatches;
	for (int i = 0; i < matches.size(); ++i)
	{
		if (matches[i].distance <= MAX(1.8 * min_dist, 30)) //需调参
		{
			goodmatches.push_back(matches[i]);
		}
	}
	cout << "good_min = " << goodmatches.size() << endl;

	//RANSAC优化:
	vector<DMatch>good_ransac;
	ransac(goodmatches, Keypoints1, Keypoints2, good_ransac);
	cout << "good_ransac = " << good_ransac.size() << endl;
	Mat output_;
	drawMatches(img1, Keypoints1, img2, Keypoints2, good_ransac, output_);
	namedWindow("ransac", 0);
	imshow("ransac", output_);

在这里插入图片描述


http://www.niftyadmin.cn/n/4938624.html

相关文章

微服务相关面试题

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱写博客的嗯哼&#xff0c;爱好Java的小菜坤 &#x1f525;如果感觉博主的文章还不错的话&#xff0c;请&#x1f44d;三连支持&#x1f44d;一下博主哦 &#x1f4dd;社区论坛&#xff1a;希望大家能加入社区共同进步…

Redis_缓存1_缓存类型

14.redis缓存 14.1简介 穿透型缓存&#xff1a; 缓存与后端数据交互在一起&#xff0c;对服务端的调用隐藏细节。如果从缓存中可以读到数据&#xff0c;就直接返回&#xff0c;如果读不到&#xff0c;就到数据库中去读取&#xff0c;从数据库中读到数据&#xff0c;也是先更…

Mr. Cappuccino的第62杯咖啡——Spring之Bean的生命周期

Spring之Bean的生命周期 Aware接口项目结构项目代码运行结果源代码使用场景 InitializingBean接口项目结构项目代码运行结果源代码 BeanFactoryPostProcessor接口项目结构项目代码运行结果源代码 Bean的生命周期项目结构项目代码运行结果源代码 Aware接口 实现Aware接口是为了…

【杂谈】聊聊我是如何从Java转入Web3的

我先说说我基本的一个情况吧&#xff1a; 我是之前是一位从业了传统web2行业三年的Java开发&#xff0c;在2018年尾才开始去关注区块链的&#xff0c;之前虽然也有混迹在币圈&#xff0c;但是没怎么关注到币圈的内在运行逻辑。 后面因为当时元宇宙和Web3的概念特别火&a…

Python|OpenCV-绘制图形和添加文字的方法(2)

前言 本文是该专栏的第2篇,后面将持续分享OpenCV计算机视觉的干货知识,记得关注。 OpenCV作为一个强大的计算机视觉功能库,除了能解决图像处理和计算机视觉任务之外,它还有着非常丰富的图像绘制功能。可以说,不论是在计算机视觉任务中标记目标领域,还是在图像上绘制一些…

R语言生存分析(机器学习)(2)——Enet(弹性网络)

弹性网络&#xff08;Elastic Net&#xff09;:是一种用于回归分析的统计方法&#xff0c;它是岭回归&#xff08;Ridge Regression&#xff09;和lasso回归&#xff08;Lasso Regression&#xff09;的结合&#xff0c;旨在克服它们各自的一些限制。弹性网络能够同时考虑L1正则…

golang官方限流器rate包实践

日常开发中&#xff0c;对于某些接口有请求频率的限制。比如登录的接口、发送短信的接口、秒杀商品的接口等等。 官方的golang.org/x/time/rate包中实现了令牌桶的算法。 封装限流器可以将ip、手机号这种的作为限流器组的标识。 接下来就是实例化限流器和获取令牌函数的实现…

Vue编写表单常用操作(过滤和排序)

目录 HTML代码&#xff1a; js代码&#xff1a; 效果展示&#xff1a; 此次的编写代码可以直接使用 HTML代码&#xff1a; <body><div id"app"><div v-for"(value,key) in person">{{key}}--{{value}}</div><div>商品名…