【opencv】示例-asift.cpp 对两张图片之间进行仿射特征比对

ffde010e5d8d369c5d53747b8c02cf7e.png

7306a586d8985056a8b34a7970e25b58.png

#include <opencv2/core.hpp> // 包含OpenCV核心功能的头文件
#include <opencv2/imgproc.hpp> // 包含OpenCV图像处理功能的头文件
#include <opencv2/features2d.hpp> // 包含OpenCV特征检测相关功能的头文件
#include <opencv2/highgui.hpp> // 包含OpenCV的GUI功能,如窗口显示的头文件
#include <opencv2/calib3d.hpp> // 包含OpenCV进行相机标定和三维重建功能的头文件
#include <iostream> // 包含标准输入输出流库的头文件
#include <iomanip> // 包含输入输出流格式设置的头文件using namespace std; // 使用标准命名空间
using namespace cv; // 使用OpenCV命名空间// 声明帮助函数,该函数会输出使用本程序的方式
static void help(char** argv)
{cout<< "This is a sample usage of AffineFeature detector/extractor.\n"<< "And this is a C++ version of samples/python/asift.py\n"<< "Usage: " << argv[0] << "\n"// 以下是该程序的参数说明<< "     [ --feature=<sift|orb|brisk> ]         # Feature to use.\n"<< "     [ --flann ]                            # use Flann-based matcher instead of bruteforce.\n"<< "     [ --maxlines=<number(50 as default)> ] # The maximum number of lines in visualizing the matching result.\n"<< "     [ --image1=<image1(aero1.jpg as default)> ]\n"<< "     [ --image2=<image2(aero3.jpg as default)> ] # Path to images to compare."<< endl;
}// 声明计时器函数,用于计算操作的耗时
static double timer()
{return getTickCount() / getTickFrequency();
}// 程序的主函数,argc是参数数量,argv是参数列表
int main(int argc, char** argv)
{vector<String> fileName; // 存储文件名的字符串向量// 使用OpenCV的命令行解析器解析输入的命令行参数cv::CommandLineParser parser(argc, argv,"{help h ||}""{feature|brisk|}""{flann||}""{maxlines|50|}""{image1|aero1.jpg|}{image2|aero3.jpg|}");// 如果用户请求帮助,调用help函数并退出程序if (parser.has("help")){help(argv);return 0;}// 从解析器中获取输入的参数string feature = parser.get<string>("feature");bool useFlann = parser.has("flann");int maxlines = parser.get<int>("maxlines");// 查找并存储输入的图像文件路径fileName.push_back(samples::findFile(parser.get<string>("image1")));fileName.push_back(samples::findFile(parser.get<string>("image2")));// 检查参数是否有误if (!parser.check()){parser.printErrors();cout << "See --help (or missing '=' between argument name and value?)" << endl;return 1;}// 读取图像,并将其转换为灰度图Mat img1 = imread(fileName[0], IMREAD_GRAYSCALE);Mat img2 = imread(fileName[1], IMREAD_GRAYSCALE);// 确保图像成功加载if (img1.empty()){cerr << "Image " << fileName[0] << " is empty or cannot be found" << endl;return 1;}if (img2.empty()){cerr << "Image " << fileName[1] << " is empty or cannot be found" << endl;return 1;}// 声明特征检测器和描述符匹配器的指针Ptr<Feature2D> backend;Ptr<DescriptorMatcher> matcher;// 根据用户选择初始化特征检测器和匹配器if (feature == "sift"){backend = SIFT::create();if (useFlann)matcher = DescriptorMatcher::create("FlannBased");elsematcher = DescriptorMatcher::create("BruteForce");}else if (feature == "orb"){backend = ORB::create();if (useFlann)matcher = makePtr<FlannBasedMatcher>(makePtr<flann::LshIndexParams>(6, 12, 1));elsematcher = DescriptorMatcher::create("BruteForce-Hamming");}else if (feature == "brisk"){backend = BRISK::create();if (useFlann)matcher = makePtr<FlannBasedMatcher>(makePtr<flann::LshIndexParams>(6, 12, 1));elsematcher = DescriptorMatcher::create("BruteForce-Hamming");}else{cerr << feature << " is not supported. See --help" << endl;return 1;}// 提取特征点和描述符,并进行匹配cout << "extracting with " << feature << "..." << endl;Ptr<AffineFeature> ext = AffineFeature::create(backend);vector<KeyPoint> kp1, kp2;Mat desc1, desc2;ext->detectAndCompute(img1, Mat(), kp1, desc1);ext->detectAndCompute(img2, Mat(), kp2, desc2);cout << "img1 - " << kp1.size() << " features, "<< "img2 - " << kp2.size() << " features"<< endl;cout << "matching with " << (useFlann ? "flann" : "bruteforce") << "..." << endl;double start = timer(); // 开始计时// 匹配特征点,并筛选出好的匹配vector< vector<DMatch> > rawMatches;vector<Point2f> p1, p2;vector<float> distances;matcher->knnMatch(desc1, desc2, rawMatches, 2);// 筛选出好的匹配点for (size_t i = 0; i < rawMatches.size(); i++){const vector<DMatch>& m = rawMatches[i];if (m.size() == 2 && m[0].distance < m[1].distance * 0.75){p1.push_back(kp1[m[0].queryIdx].pt);p2.push_back(kp2[m[0].trainIdx].pt);distances.push_back(m[0].distance);}}// 利用单应性计算匹配点对的状态vector<uchar> status; // 创建一个uchar类型的向量status,用来存储每对匹配点是否是内点的状态vector< pair<Point2f, Point2f> > pointPairs; // 创建一个存储匹配点对(两个图像中匹配的点)的vectorMat H = findHomography(p1, p2, status, RANSAC); // 利用RANSAC算法计算从图像1到图像2的单应性矩阵Hint inliers = 0; // 初始化内点数量计数器// 遍历status向量,统计内点数量并存储这些点对for (size_t i = 0; i < status.size(); i++){// 如果status向量中的元素为true,则表示该匹配点对是内点if (status[i]){pointPairs.push_back(make_pair(p1[i], p2[i])); // 将内点对添加到pointPairs向量中distances[inliers] = distances[i]; // 将对应内点的距离存储到distances向量中// CV_Assert(inliers <= (int)i); // 断言inliers的值应小于等于当前索引,通常用于调试inliers++; // 内点数量加一}}distances.resize(inliers); // 重新调整distances向量的大小以匹配内点的数量// 输出执行时间cout << "execution time: " << fixed << setprecision(2) << (timer()-start)*1000 << " ms" << endl;// 输出内点与匹配点对的比例cout << inliers << " / " << status.size() << " inliers/matched" << endl;// 可视化匹配结果前的准备工作cout << "visualizing..." << endl;vector<int> indices(inliers); // 创建一个大小等于内点数量的整数型向量indices,用于存储排序后的索引// 将distances向量中元素的索引按照距离从小到大排序并存入indices向量cv::sortIdx(distances, indices, SORT_EVERY_ROW+SORT_ASCENDING);// 创建可视化图像并绘制匹配的特征点int h1 = img1.size().height;int w1 = img1.size().width;int h2 = img2.size().height;int w2 = img2.size().width;Mat vis = Mat::zeros(max(h1, h2), w1+w2, CV_8U);img1.copyTo(Mat(vis, Rect(0, 0, w1, h1)));img2.copyTo(Mat(vis, Rect(w1, 0, w2, h2)));cvtColor(vis, vis, COLOR_GRAY2BGR);vector<Point2f> corners(4);corners[0] = Point2f(0, 0);corners[1] = Point2f((float)w1, 0);corners[2] = Point2f((float)w1, (float)h1);corners[3] = Point2f(0, (float)h1);vector<Point2i> icorners;perspectiveTransform(corners, corners, H); // 对图像1的四个角进行单应性变换transform(corners, corners, Matx23f(1,0,(float)w1,0,1,0)); // 将变换后的角点移到图像2的右侧Mat(corners).convertTo(icorners, CV_32S); // 将角落点的类型转化为整数polylines(vis, icorners, true, Scalar(255,255,255)); // 在可视化图像中绘制边界线// 绘制前maxlines个的匹配对for (int i = 0; i < min(inliers, maxlines); i++){int idx = indices[i];const Point2f& pi1 = pointPairs[idx].first;const Point2f& pi2 = pointPairs[idx].second;circle(vis, pi1, 2, Scalar(0,255,0), -1); // 绘制圆点circle(vis, pi2 + Point2f((float)w1,0), 2, Scalar(0,255,0), -1); // 在图像2相应的位置绘制圆点line(vis, pi1, pi2 + Point2f((float)w1,0), Scalar(0,255,0)); // 绘制连线}if (inliers > maxlines)cout << "only " << maxlines << " inliers are visualized" << endl;imshow("affine find_obj", vis); // 显示最终的可视化结果窗口// 当存在更多的匹配时,输出提示信息// Mat vis2 = Mat::zeros(max(h1, h2), w1+w2, CV_8U); // 创建另一个可视化用的空白图像// Mat warp1; // 存储变换后图像的矩阵// warpPerspective(img1, warp1, H, Size(w1, h1)); // 对图像1应用单应性变换// warp1.copyTo(Mat(vis2, Rect(0, 0, w1, h1))); // 将变换后的图像1复制到可视化图像的左半边// img2.copyTo(Mat(vis2, Rect(w1, 0, w2, h2))); // 将图像2复制到可视化图像的右半边// imshow("warped", vis2); // 显示变换后图像与图像2的对比窗口waitKey(); // 等待任意键按下cout << "done" << endl; // 输出完成提示return 0; // 程序结束
}

此段C++代码的主要功能是载入两张图像,通过OpenCV库进行特征点检测和匹配,然后通过单应性变换计算两图像之间的匹配关系,并将匹配结果可视化显示出来。用户可以指定不同的特征检测算法(如SIFT、ORB、BRISK等)以及是否使用FLANN库进行近似最邻近搜索而不是暴力匹配。代码结束时还会显示执行时间和匹配对的数量。

终端输出:

img1 - 39607 features, img2 - 24674 features
matching with bruteforce...
execution time: 35513.65 ms
41 / 105 inliers/matched
visualizing...

Ptr<AffineFeature> ext = AffineFeature::create(backend);

4ca2e08198e7ea9eee447b87043f3a19.png

Mat H = findHomography(p1, p2, status, RANSAC);

685a67c444636176a512ab30f8cc05bb.png

2b0f108afb23babef5cea0de1a4e7823.png

仿射特征匹配有哪些应用场景

17122b21c5fca6eac63ed99b0d01660c.png

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

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

相关文章

sqlmap(五)

一、进行文件读写操作 1.1 前提条件 高权限 目录有读写权限 secure_file_priv " " 1.2 测试目标 第一步&#xff1a;用抓包的方式获取请求测试站点的数据包 可以使用Burpsuite 第二步&#xff1a;将抓到的数据包&#xff0c;保存到sqlmap目录下的a.txt 第三步&am…

从FasterTransformer源码解读开始了解大模型(1.1)一个decoder-only的模型长啥样

从FasterTransformer源码解读开始了解大模型&#xff08;1.1&#xff09;一个decoder-only的模型长啥样 写在前面的话 对于一个没有接触过LLM的初学者来说&#xff0c;如果想要了解一个大模型的推理框架&#xff0c;首先应该知道大模型整个的工作原理是怎样的&#xff0c;知道…

了解自动化机器学习 AutoML

&#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ 自动化机器学习&#xff08;AutoML&#xff09;概述 自动化机器学习&#xff08;AutoML&#xff09;旨在自动化机器学习模型的开发流程&#xff0c;通过简化或去除需要专业知识的复杂步骤&#xff0c;…

CSS面试题常用知识总结day03

大家好我是没钱的君子下流坯&#xff0c;用自己的话解释自己的知识 前端行业下坡路&#xff0c;甚至可说前端已死&#xff0c;我还想在前段行业在干下去&#xff0c;所以从新开始储备自己的知识。 从CSS——>Javascript——>VUE2——>Vuex、VueRouter、webpack——>…

Stale Diffusion、Drag Your Noise、PhysReaction、CityGaussian

本文首发于公众号&#xff1a;机器感知 Stale Diffusion、Drag Your Noise、PhysReaction、CityGaussian Drag Your Noise: Interactive Point-based Editing via Diffusion Semantic Propagation Point-based interactive editing serves as an essential tool to compleme…

Nuxt 3 项目中配置 Tailwind CSS

官方文档&#xff1a;https://www.tailwindcss.cn/docs/guides/nuxtjs#standard 安装 Tailwind CSS 及其相关依赖 执行如下命令&#xff0c;在 Nuxt 项目中安装 Tailwind CSS 及其相关依赖 npm install -D tailwindcss postcss autoprefixerpnpm install -D tailwindcss post…

【cpp】快速排序优化

标题&#xff1a;【cpp】快速排序 水墨不写bug 正文开始&#xff1a; 快速排序的局限性&#xff1a; 虽然快速排序是一种高效的排序算法&#xff0c;但也存在一些局限性&#xff1a; 最坏情况下的时间复杂度&#xff1a;如果选择的基准元素不合适&#xff0c;或者数组中存在大…

Netty 3 - 组件和设计

这里将回顾我们之前章节讲到过的主要概念和组件。 1 Channel 、EventLoop和ChannelFuture Channel —— Socket;EventLoop —— 控制流、多线程处理、并发;ChannelFuture —— 异步通知。 1.1 Channel 接口 基本的I/O操作&#xff08;bind()、connect()、read()和write()&a…

免注册,ChatGPT可即时访问了!

AI又有啥进展&#xff1f;一起看看吧 Apple进军个人家用机器人 Apple在放弃自动驾驶汽车项目并推出混合现实头显后&#xff0c;正在进军个人机器人领域&#xff0c;处于开发家用环境机器人的早期阶段 报告中提到了两种可能的机器人设计。一种是移动机器人&#xff0c;可以跟…

鸿蒙OS元服务开发:【(Stage模型)学习窗口沉浸式能力】

一、体验窗口沉浸式能力说明 在看视频、玩游戏等场景下&#xff0c;用户往往希望隐藏状态栏、导航栏等不必要的系统窗口&#xff0c;从而获得更佳的沉浸式体验。此时可以借助窗口沉浸式能力&#xff08;窗口沉浸式能力都是针对应用主窗口而言的&#xff09;&#xff0c;达到预…

二叉堆解读

在数据结构和算法中&#xff0c;二叉堆是一种非常重要的数据结构&#xff0c;它被广泛用于实现优先队列、堆排序等场景。本文将介绍二叉堆的基本概念、性质、操作以及应用场景。 一、基本概念 二叉堆是一种特殊的完全二叉树&#xff0c;它满足堆性质&#xff1a;对于每个节点…

电子商务平台中大数据的应用|主流电商平台大数据采集API接口

(一)电商平台物流管理中大数据的应用 电商平台订单详情订单列表物流信息API接口应用 电子商务企业对射频识别设备、条形码扫描设备、全球定位系统及销售网站、交通、库存等管理软件数据进行实时或近实时的分析研究,提高物流速度和准确性。部分电商平台已建立高效的物流配送网…

【STL】vector的底层原理及其实现

vector的介绍 vector是一个可变的数组序列容器。 1.vector的底层实际上就是一个数组。因此vector也可以采用连续存储空间来存储元素。也可以直接用下标访问vector的元素。我们完全可以把它就当成一个自定义类型的数组使用。 2.除了可以直接用下标访问元素&#xff0c;vector还…

掌握数据相关性新利器:基于R、Python的Copula变量相关性分析及AI大模型应用探索

在工程、水文和金融等各学科的研究中&#xff0c;总是会遇到很多变量&#xff0c;研究这些相互纠缠的变量间的相关关系是各学科的研究的重点。虽然皮尔逊相关、秩相关等相关系数提供了变量间相关关系的粗略结果&#xff0c;但这些系数都存在着无法克服的困难。例如&#xff0c;…

解决win7作为虚拟机无法复制粘贴共享文件的问题

win7作为虚拟机经常会出现无法与主机的剪切板共享、文件共享。 归根结底是win7虚拟机里面没有安装VMware Tools 能够成功安装vmware tools的条件&#xff1a; 1&#xff09;win7版本为win7 sp1及以上 2&#xff09;安装KB4490628&#xff0c;KB4474419补丁 因此下面来详细介绍…

【LeetCode题解】2192. 有向无环图中一个节点的所有祖先+1026. 节点与其祖先之间的最大差值

文章目录 [2192. 有向无环图中一个节点的所有祖先](https://leetcode.cn/problems/all-ancestors-of-a-node-in-a-directed-acyclic-graph/)思路&#xff1a;BFS记忆化搜索代码&#xff1a; 思路&#xff1a;逆向DFS代码&#xff1a; [1026. 节点与其祖先之间的最大差值](https…

为什么说AI的尽头是生物制药?

AI的尽头究竟是什么&#xff1f;有投资者说是光伏&#xff0c;也有投资者说是电力&#xff0c;而英伟达给出的答案则是生物制药。 在英伟达2023年投资版图中&#xff0c;除AI产业根基算法与基础建设外&#xff0c;生物制药是其重点布局的核心赛道。英伟达医疗保健副总裁Kimber…

FastEI论文阅读

前言 研究FastEI&#xff08;Ultra-fast and accurate electron ionization mass spectrum matching for compound identification with million-scale in-silico library&#xff09;有很长时间了&#xff0c;现在来总结一下&#xff0c;梳理一下认知。PS&#xff1a;为什么要…

【LeetCode: 21. 合并两个有序链表 + 链表】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

axios快速入门

一、环境配置 1.1概述 上古浏览器页面在向服务器请求数据时&#xff0c;因为返回的是整个页面的数据&#xff0c;页面都会强制刷新一下&#xff0c;这对于用户来讲并不是很友好。并且我们只是需要修改页面的部分数据&#xff0c;但是从服务器端发送的却是整个页面的数据&#…