Shi-Tomas角点检测、亚像素级别角点位置优化、ORB特征点、特征点匹配、RANSAC优化特征点匹配、相机模型与投影

news2024/12/26 23:41:26

目录

1、Shi-Tomas角点检测

2、亚像素级别角点位置优化

3、ORB特征点

4、特征点匹配

5、RANSAC优化特征点匹配

6、相机模型与投影


1、Shi-Tomas角点检测

 

//Shi-Tomas角点检测
int test1()
{
	Mat img = imread("F:/testMap/lena.png");
	if (!img.data)
	{
		cout << "读取图像错误, 请确认图像文件是否正确" << endl; 
		return -1;
	}
		
	Mat gray;
	cvtColor(img, gray,COLOR_BGR2GRAY);
	//Detector parametersl
	
	//提取角点
	int maxCorners = 100;//检测角点数目
	double quality_level = 0.01;//质量等级,或者说阈值与最佳角点的比例关系
	double minDistance = 0.04;//两个角点之间的最小欧式距离
	vector<Point2f> corners;
	goodFeaturesToTrack(gray,corners,maxCorners,quality_level, minDistance,Mat(),3,false);
	
	//绘制角点
	vector<KeyPoint> keyPoints;//存放角点的KeyPoint类,用于后期绘制角点时用

	for (int i = 0; i < corners.size(); i++)
	{
		//将角点存放在KeyPoint类中
		KeyPoint keyPoint;
		keyPoint.pt = corners[i];
		keyPoints.push_back(keyPoint);
	}

	//用drawKeypoints()函数绘制角点坐标
	drawKeypoints(img, keyPoints, img);
	imshow("角点结果", img); 
	waitKey(0);
	return 0;
}

 2、亚像素级别角点位置优化

 

//亚像素级别角点位置优化
int test2()
{
	system("color 02");//改变DOS界面颜色
	Mat img = imread("F:/testMap/lena.png", IMREAD_COLOR);
	if (!img.data)
	{
		cout << "读取图像错误,请确认图像文件是否正确" << endl;
		return -1;
	}
	//彩色图像转成灰度图像
	Mat gray;
	cvtColor(img, gray, COLOR_BGR2GRAY);

	//提取角点
	int maxCorners = 100;//检测角点数目
	double quality_level = 0.01;//质量等级,或者说阈值与最佳角点的比例关系
	double minDistance = 0.04;//两个角点之间的最小欧式距离

	vector<Point2f> corners;
	goodFeaturesToTrack(gray, corners, maxCorners, quality_level, minDistance, Mat(), 3, false);

	//计算亚像素级别角点坐标
	vector<Point2f> cornersSub = corners;//角点备份,防止被函数修改
	Size winSize = Size(5, 5);
	Size zeroZone = Size(-1, -1);
	TermCriteria criteria = TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 40, 0.001);
	cornerSubPix(gray, cornersSub, winSize, zeroZone, criteria);

	//输出初始坐标和精细坐标
	for (size_t i = 0; i < corners.size(); i++)
	{
		string str = to_string(i);
		str = "第" + str + "个角点点初始坐标:";
		cout << str << corners[i] << "精细后坐标:" << cornersSub[i] << endl;
	}

	waitKey(0);
	return 0;
}

3、ORB特征点

 

 

 

//ORB特征点
int test3()
{
	Mat img = imread("F:/testMap/lena.png");
	if (!img.data)
	{
		cout << "请确认图像文件名称是否正确" << endl;
		return -1;
	}

	//创建ORB特征点类变量
	Ptr<ORB> orb = ORB::create(500,//特征点数目
		1.2f,//金字塔层级之间的缩放比例
		8,//金字塔图像层数系数
		31,//边缘阈值
		0,//原图在金字塔中的层数
		2,//生成描述子时需要用的像素点数目
		ORB::HARRIS_SCORE,//使用 Harris方法评价特征点
		31,//生成描述子时关键点周围邻域的尺寸
		20//计算 FAST角点时像素值差值的阈值
		);

	//计算ORB关键点
	vector<KeyPoint> Keypoints;
	orb->detect(img, Keypoints);//确定关键点

	//计算ORB描述子
	Mat descriptions;
	orb->compute(img, Keypoints, descriptions);//计算描述子

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

	//显示结果
	imshow("不含角度和大小的结果", img);
	imshow("含有角度和大小的结果", imgAngel);

	waitKey(0);
	return 0;
}

4、特征点匹配

 

 

//特征点匹配
void orb_features(Mat &gray,vector<KeyPoint> &keypionts,Mat &descriptions)
{
	Ptr<ORB> orb = ORB::create(1000,1.2f); 
	orb->detect(gray,keypionts);
	orb->compute(gray,keypionts,descriptions);
}

int test1()
{
	Mat img1, img2;
	img1 = imread("F:/testMap/box.png");
	img2 = imread("F:/testMap/box_in_scen.png");
	if (!(img1.data && img2.dataend))
	{
		cout << "读取图像错误,请确认图像文件是否正确" << endl;
		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 = 0, max_dist = 10000;
	for (int i = 0; i < matches.size(); i++)
	{
		double dist = matches[i].distance;
		if (dist < min_dist) min_dist = dist;
		if (dist > max_dist) max_dist = dist;
	}
	//输出所有匹配结果中最大韩明距离和最小汉明距离
	cout << "min_dist=" << min_dist << endl;
	cout << "max_dist=" << max_dist << endl;

	//将汉明距离较大的匹配点对删除
	vector<DMatch>good_matches;
	for (int i = 0; i < matches.size(); i++)
	{
		if (matches[i].distance <= max(2 * min_dist, 20.0))
		{
			good_matches.push_back(matches[i]);
		}
	}
	cout << "good_min=" << good_matches.size() << endl;//剩余特征点数目

	//绘制匹配结果
	Mat outimg, outimg1;
	drawMatches(img1, Keypoints1, img2, Keypoints2, matches, outimg);
	drawMatches(img1, Keypoints1, img2, Keypoints2, good_matches, outimg1);

	imshow("未筛选结果", outimg);
	imshow("最小汉明距离筛选", outimg1);

	waitKey(0);
	return 0;
}


5、RANSAC优化特征点匹配

 

 

void match_min(vector<DMatch> matches, vector<DMatch> & good_matches)//最小汉明距离
{
	double min_dist = 10000, max_dist = 0;
	for (int i = 0; i < matches.size(); i++)
	{
		double dist = matches[i].distance;
		if (dist < min_dist)  min_dist = dist;
		if (dist > max_dist)  max_dist = dist;
	}
	cout << "min_dist=" << min_dist << endl;
	cout << "max_dist=" << max_dist << endl;
	for (int i = 0; i < matches.size(); i++)
	{
		if (matches[i].distance <= max(2 * min_dist, 20.0))
		{
			good_matches.push_back(matches[i]);
		}
	}
}
//RANSAC算法实现
void ransac(vector<DMatch>matches, vector <KeyPoint> queryifeyPoint, vector<KeyPoint> trainieyPoint, vector<DMatch> &kmatches_ransac)
{
	//定义保存匹配点对坐标
	vector<Point2f> srcPoints(matches.size()), dstPoints(matches.size());
	//保存从关键点中提取到的匹配点对的坐标
	for (int i = 0; i < matches.size(); i++)
	{
		srcPoints[i] = queryifeyPoint[matches[i].queryIdx].pt;
		dstPoints[i] = trainieyPoint[matches[i].trainIdx].pt;
	}

	//匹配点对进行RANSAC过滤
	vector<int> inliersMask(srcPoints.size());
	// Mat homography;
	//homography = findHomography(srcPoints, dstPoints, RANSAC, 5, inliersMask); 
	findHomography(srcPoints, dstPoints, RANSAC, 5, inliersMask);
	//手动的保留RANSAC过滤后的匹配点对
	for (int i = 0; i < inliersMask.size(); i++)
	{
		if (inliersMask[i])
		{
			kmatches_ransac.push_back(matches[i]);
		}
	}
}
int test5()
{
	Mat img1, img2;
	img1 = imread("F:/testMap/box.png");
	img2 = imread("F:/testMap/box_in_scen.png");
	if (!(img1.data && img2.dataend))
	{
		cout << "读取图像错误,请确认图像文件是否正确" << endl;
		return -1;
	}
	//提取ORB特征点
	vector<KeyPoint> Keypoints1, Keypoints2;
	Mat descriptions1, descriptions2;
	//计算特征点
	orb_features(img1, Keypoints1, descriptions1);
	orb_features(img2, Keypoints2, descriptions2);

	//特征点匹配
	vector<DMatch> matches, good_min, good_ransac;
	BFMatcher matcher(NORM_HAMMING);
	matcher.match(descriptions1, descriptions2, matches);
	cout << "matches=" << matches.size() << endl;

	//最小汉明距离
	match_min(matches, good_min);
	cout << "good_min=" << good_min.size() << endl;

	//用ransac算法筛选匹配结果
	ransac(good_min, Keypoints1, Keypoints2, good_ransac);
	cout << "good_matches.size=" << good_ransac.size() << endl;

	//绘制匹配结果
	Mat outimg, outimg1, outimg2;
	drawMatches(img1,Keypoints1,img2,Keypoints2, matches,outimg); 
	drawMatches(img1, Keypoints1, img2, Keypoints2, good_min, outimg1);
	drawMatches(img1,Keypoints1,img2,Keypoints2, good_ransac,outimg2); 
	imshow("未筛选结果", outimg);
	imshow("最小汉明距离筛选", outimg1) ;
	imshow("ransac筛选",outimg2);

	waitKey(0);
	return 0;
}

6、相机模型与投影

 

 

 

//相机模型与投影
int test4()
{
	//输入计算得到的内参矩阵和畸变矩阵
	Mat cameraMatrix = (Mat_<float>(3,3) << 532.016297,0,332.172519,0,531.565159,233.388075,0, 0,1);
	Mat distCoeffs = (Mat_<float>(1,5) << -0.285188,0.080097,0.001274,-0.002415,0.106579);
	
	//代码清单10-10中计算的第一张图像相机坐标系与世界坐标系之间的关系
	Mat rvec = (Mat_<float>(1,3)<<-1.977853,-2.002220,0.130029);
	Mat tvec = (Mat_<float>(1,3) <<-26.88155,-42.79936,159.19703);
	
	//生成第一张图像中内角点的三维世界坐标
	Size boardSize = Size(9, 6);
	Size squareSize = Size(10,10);//棋盘格每个方格的真实尺寸
	vector<Point3f> PointSets;
	
	for (int j = 0; j < boardSize.height; j++)
	{
		for (int k = 0; k < boardSize.width; k++)
		{
			Point3f realPoint;
			//假设标定板为世界坐标系的z平面,即z=0
			realPoint.x = j*squareSize.width;
			realPoint.y = k*squareSize.height; 
			realPoint.z = 0;
			PointSets.push_back(realPoint);
		}
	}

	//根据三维坐标和相机与世界坐标系时间的关系估计内角点像素坐标
	vector<Point2f>imagePoints;
	projectPoints(PointSets,rvec,tvec,cameraMatrix, distCoeffs, imagePoints);
	for(int i = 0; i < imagePoints.size(); i++)
	{
		cout << "第" << to_string(i) << "个点的坐标" << imagePoints[i] << endl;
	}
		


	waitKey(0);
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/758303.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python结巴中文分词笔记

&#x1f4da; jieba库基本介绍 &#x1f310; jieba库概述 Jieba是一个流行的中文分词库&#xff0c;它能够将中文文本切分成词语&#xff0c;并对每个词语进行词性标注。中文分词是自然语言处理的重要步骤之一&#xff0c;它对于文本挖掘、信息检索、情感分析等任务具有重要…

2023年Java最新面试题

由【后端面试题宝典】提供 和 equals 的区别是什么&#xff1f; 对于基本类型&#xff0c;比较的是值&#xff1b;对于引用类型&#xff0c;比较的是地址&#xff1b;equals不能用于基本类型的比较&#xff1b;如果没有重写equals&#xff0c;equals就相当于&#xff1b;如果重…

带记忆的Transformer模块

MEMORIZING TRANSFORMERS 返回论文和资料目录 论文地址 1.导读 谷歌去年做的一个工作。内容很简单&#xff0c;在Transformer模块中加入了一层记忆层&#xff0c;结果表明这个方法可以帮助模型提高在NLP任务上的表现&#xff1a;generic webtext (C4), math papers (arXiv),…

C# IEnumerator 用法

一、概述 IEnumerator 是所有非泛型枚举器的基接口。 其泛型等效项是 System.Collections.Generic.IEnumerator<T> 接口。 C# 语言的 foreach 语句&#xff08;在 Visual Basic 中为 for each&#xff09;隐藏了枚举数的复杂性。 因此&#xff0c;建议使用 foreach 而不…

掘金量化—Python SDK文档—1.快速开始

掘金量化终端是一款为专业量化投资打造的功能齐备的落地式终端&#xff0c;集成了策略开发到实盘的模块化功能&#xff0c;打通研究、仿真和绩效链路、兼容多种编程语言&#xff0c;易于使用、性能可靠&#xff0c;能够帮助量化投资者提高策略开发效率、减少 IT 投入。 掘金量…

AI 智能对话 - 基于 ChatGLM2-6B 训练对话知识库

前情提要 怎么将 AI 应用到工作中呢&#xff1f;比如让 AI 帮忙写代码&#xff0c;自己通过工程上的思维将代码整合排版&#xff0c;我挺烦什么代码逻辑严谨性的问题&#xff0c;但是我又不得不承认这样的好处&#xff0c;我们要开始将角色转换出来&#xff0c;不应该是一个工…

Understanding Cascade Left Joins and Writing Complex Queries

文章目录 a left join b left join cuser casesql query execution order In SQL, the left join is a powerful tool for combining data from multiple tables based on a common column. In this blog post, we will explore the concept of cascade left joins, providing …

面试之MySQL中的mvcc

首先需要知道什么是 MVCC? MVCC 多版本并发控制。MVCC就是通过数据行的多个版本管理来实现数据库的并发控制。这项技术是的InnoDB的事务隔离级别下执行一致性读 有了保证。换言之&#xff0c;就是为了查询一些正在被一个事务更新的行。并且可以看到他们被更新之前的值。查询在…

【excel细碎小知识点】

目录索引 &符号的用法&#xff1a;实例演示&#xff1a; 数字显示和位数的区别&#xff1a;分列功能的妙用&#xff1a;什么叫做常规类型&#xff1a; &符号的用法&#xff1a; **连接字符串:**转化后都是文本字符串类型。你可以通过修改数据类型进行更多可能的操作 实…

高等数学❤️第一章~第二节~极限❤️极限的概念与性质~极限的性质详解

【精讲】高等数学中极限的性质解析 博主&#xff1a;命运之光的主页 专栏&#xff1a;高等数学 目录 【精讲】高等数学中极限的性质解析 导言 一、基本性质 二、四则运算 三、极限存在性 四、唯一性 五、其他性质 必需记忆知识点 例题&#xff08;用于熟悉高等数学中…

wordpress怎么更改主题自带的页脚或设置不显示?

本文直接提供改原主题代码的方式进行修改 首先我们进入站点的后台&#xff0c;依次点击外观---->主题文件编辑器 然后确定自己的主题是不是想要更改的&#xff0c;之后找到footer.php文件进行修改 可以自己去找一些合适的主题代码复制进去 如果想要不显示&#xff0c;可以…

《面试1v1》大厂的Kafka使用场景

&#x1f345; 作者简介&#xff1a;王哥&#xff0c;CSDN2022博客总榜Top100&#x1f3c6;、博客专家&#x1f4aa; &#x1f345; 技术交流&#xff1a;定期更新Java硬核干货&#xff0c;不定期送书活动 &#x1f345; 王哥多年工作总结&#xff1a;Java学习路线总结&#xf…

按键控制led变化

文章目录 按键控制led变化一、简介二、代码三、仿真代码四、仿真结果五、总结 按键控制led变化 一、简介 使用按键控制开发板上一个led灯的亮灭&#xff0c;当按键按下的时候led灯就亮&#xff0c;当再一次按下按键的时候led就不亮了。由于按键存在抖动&#xff0c;按键松开的…

linux中常见命令(1)

目录 1. less命令 2. cut 命令 3. head和tail命令 4. awk命令 5. tr命令 6. sed 命令 7. uniq 命令 1. less命令 用法&#xff1a;less [option]<filename>##同时打开多个文件 less <filename1> <filename2> <filename3> 点按“q”退出less。利…

再开源一款轻量内存池

前两天已开源线程池&#xff0c;开源一款轻量线程池项目&#xff0c;本节继续开源另一个孪生兄弟&#xff1a;内存池。 本节的线程池与内存池代码解析会在我的星球详细讲解。 内存池&#xff1a;https://github.com/Light-City/light-memory-pool 线程池&#xff1a;https://gi…

Vue-组件基础(上)

一、目标 能够说出什么是单页面应用程序和组件化开发能够说出.vue单文件组件的组成部分能够知道如何注册vue的组件能够知道如何声明组件的props属性能够知道如何在组件中进行样式绑定 二、目录 单页面应用程序vite的基本使用组件化开发思想vue组件的构成组件的基本使用封装组…

await、async、事件循环(宏任务、微任务队列执行顺序)

1 async、await 2 浏览器进程、线程 3 宏任务、微任务队列 4 Promise面试题解析 5 throw、try、catch、finally 异步函数-异步函数的写法 // 普通函数// function foo() {}// const bar function() {}// const baz () > {}// 生成器函数// function* foo() {}// 异步函…

效果超过deepsort,yolov5+bytetrack

目录 1. Motivation 2. BYTE 3. ByteTrack 4.完整代码实现 ByteTrack: Multi-Object Tracking by Associating Every Detection Box 沿着多目标跟踪&#xff08;MOT&#xff09;中tracking-by-detection的范式&#xff0c;我们提出了一种简单高效的数据关联方法BYTE。 利用…

git : 从入门到进阶(实战问题对策)

目录 0. 前言 1. git stash: 暂时保存本地修改 0. 前言 记录日常git使用过程中碰到的一些常见问题的解决&#xff0c;以及一些常用技巧。作为自己作为git使用者的从入门到进阶的成长过程。不求完备但求简洁实用。动态更新。。。 1. git stash: 暂时保存本地修改 多人工作的项…

Linux自主学习 - 多线程的创建(#include<pthread.h>)

备注&#xff1a;vscode通过ssh连接虚拟机中的ubuntu&#xff0c;ubuntu-20.04.3-desktop-amd64.iso 函数pthread_create() // pthread.h中的函数pthread_create()extern int pthread_create (pthread_t *__restrict __newthread, // 线程标识符const pthread_attr_t *…