OpenCV实战(17)——FAST特征点检测

news/2024/5/12 6:25:01/文章来源:https://blog.csdn.net/LOVEmy134611/article/details/128841811

OpenCV实战(17)——FAST特征点检测

    • 0. 前言
    • 1. FAST 特征点检测
    • 2. 自适应特征检测
    • 3. 完整代码
    • 小结
    • 系列链接

0. 前言

Harris 算子根据两个垂直方向上的强度变化率给出了角点(或更一般地说,兴趣点)的数学定义。但使用这种定义需要计算图像导数,计算代价较为高昂,特别是兴趣点检测通常只是更复杂算法的先决步骤。
在本中,我们将学习另一个特征点检测算子 FAST (Features from Accelerated Segment Test)。其专门设计用于快速检测图像中的兴趣点;关键点检测仅基于几个像素的比较。

1. FAST 特征点检测

使用 OpenCV 通用接口进行特征点检测,能够轻松使用任意特征点检测器。本节将介绍 FAST 检测器,顾名思义,其被设计为进行快速计算。

(1) 创建一个关键点向量来存储结果:

std::vector<cv::KeyPoint> keypoints;

(2) 创建一个阈值为 40 的 FAST 检测器:

// FAST 检测器
cv::Ptr<cv::FastFeatureDetector> ptrFAST = new cv::FastFeatureDetector(40);

(3) 检测加载图像的所有关键点:

ptrFAST->detect(image, keypoints);

OpenCV 还提供了一个通用函数来在图像上绘制关键点:

cv::drawKeypoints(image, keypoints, image, cv::Scalar(255, 255, 255), cv::DrawMatchesFlags::DRAW_OVER_OUTIMG);

通过指定绘图标志,将关键点绘制在输入图像上,可以得到以下输出结果:

FAST特征检测结果
当我们将关键点颜色指定为负值时,绘制的每个圆圈将使用不同的随机颜色。
Harris 角点一样,FAST 特征算法源于角点定义,该定义基于特征点周围的图像强度。关键点的检测通过检查以候选点为中心的像素圆进行,如果找到长度大于圆周长 3/4 的连续点(弧),其所有像素都与中心点的强度显着不同,则该候选点为一个关键点。
这是一个可以快速计算的检测过程。此外,在其公式中,该算法使用了一个额外的技巧来进一步加快计算过程。事实上,如果我们首先测试圆上相距 90 度的四个点(例如,上、下、右、左),为了满足检测条件,其中至少三个点都必须比中心像素更亮或更暗,否则,可以立即否定该点,而无需检查圆周上的其他点。这是一个非常高效的检测技巧,因为在实践中,大多数图像点都无法满足此四点检测条件。
要检查像素圆的半径是该方法需要考虑的一个因素,在实践中发现,半径为 3 时检测效果较好,效率也更高,此时,需要考虑圆周上的 16 个像素:
R≈[161215314413051261171098]R\approx\left[ \begin{array}{ccc} & & 16 & 1 & 2 & &\\ & 15 & & & & 3& \\ 14&&&&&&4\\ 13&&&0&&&5\\ 12&&&&&&6\\ & 11 & & & & 7&\\ & & 10 & 9 & 8 & &\\\end{array}\right] R141312151116101092837456

在以上示例中,用于预测试的四个点的像素值为 15913,所需满足条件的连续较暗或较亮的像素点数为 12。但是,可以观察到通过将连续段的长度减少到 9,可以更好的检测到角点在不同图像上的可重复性。这种变体通常称为 FAST-9 角点检测器,这也是 OpenCV 中所采用的。此外,OpenCV 中的 cv::FASTX 函数实现了 FAST 检测器的另一个变体。
一个像素点的强度必须与中心像素的强度相差指定的量才会被视为满足更暗或更亮的检测条件,相差的量使用函数中的阈值参数指定,阈值越大,检测到的角点就越少。
而对于 Harris 特征而言,通常需要对已经检测到的角点进行非极大值抑制。因此,需要定义角点强度度量。也可以考虑以下替代方案,角点强度由中心像素与所识别的连续弧上的像素之间的绝对差之和给出,该算法也可通过直接函数调用实现:

cv::FAST(image,     // 输入图像keypoints,  // 输出关键点向量40,         // 阈值false);     // 是否使用非极大值抑制

但是,推荐使用 cv::FeatureDetector 接口,提高应用程序的灵活性。
FAST 特征点检测算法实现了非常快的兴趣点检测,因此,当程序需要效率优先时,应该首选该算法,例如,在实时视觉跟踪或对象识别应用程序中,必须在实时视频流中跟踪或匹配多个特征点。
为了改进特征点的检测,OpenCV 提供使用许多类适配器,以更好地控制关键点的提取。

2. 自适应特征检测

如果希望更好地控制特征点的数量,可以使用 cv::FeatureDetector 类的子类 cv::DynamicAdaptedFeatureDetector,其可以指定检测的兴趣点数量,在 FAST 特征检测器中用法如下:

cv::DynamicAdaptedFeatureDetector fastD(new cv::FastAdjuster(40),   // 特征检测器150,                        // 最少特征数量200,                        // 最大特征数量50);                        // 最大迭代次数
fastD->detect(image, keypoints);

然后迭代地检测兴趣点,每次迭代后,检查检测到的兴趣点数量,并相应地调整检测器阈值以产生更多或更少的点;重复此过程,直到检测到的兴趣点数位于指定的区间内。
通过指定最大迭代次数,避免过多检测耗费太多时间。要以通用方式实现此方法,使用的 cv::FeatureDetector 类必须实现 cv::AdjusterAdapter 接口,该类包括一个 tooFew 方法和一个 tooMany 方法,这两个方法都会修改检测器的内部阈值以产生更多或更少的关键点;此外,还有一个断言方法,当检测器阈值仍然可以调整时返回 true
虽然可以使用 cv::DynamicAdaptedFeatureDetector 类获得适当数量的特征点,但是这需要以降低效率为代价;此外,该类无法保证一定会在指定的迭代次数内获得所需数量的特征点。
可以看到,我们将动态分配对象的地址作为参数传递,以指定适配器类将使用的特征检测器。我们无需手动释放分配的内存来避免内存泄漏,这是因为指针会被转移到 cv::Ptr<FeatureDetector> 参数,它会自动释放所指向的对象。
另一个有用的类适配器是 cv::GridAdaptedFeatureDetector 类,它会在图像上定义网格,然后,可以限制每个单元格包含的最大元素数量,以将检测到的关键点散布在图像上。在检测图像中的关键点时,通常会在特定纹理区域中看到集中的兴趣点。例如,在以上图像的眼睛周围检测到非常密集的 FAST 特征点,通过使用此类适配器可以改进检测结果:

cv::GridAdaptedFeatureDetector fastG(new cv::FastFeatureDetector(10),   // 特征检测器1200,                              // 最大特征点数量5,                                 // 网格行数2);                                // 网格列数
fastG->detect(image, keypoints);

类适配器通过使用提供的 cv::FeatureDetector 对象检测每个单元格上的特征点,还可以指定最大总特征点数,在每个单元格中只保留强度最大的数个点,以免超过指定的最大值。
cv::PyramidAdaptedFeatureDetector 适配器可以在图像金字塔上应用特征检测器,结果组合在关键点的输出向量中:

cv::PyramidAdaptedFeatureDetector fastP(new cv::FastFeatureDetector(60),   // 特征检测器3);                                // 金字塔层数
fastP->detect(image, keypoints);

每个点的坐标通过原始图像坐标指定,此外设置 cv::Keypoint 类的 size 属性,以便在原始分辨率的一半处检测到的点的大小是原始图像中检测到的点的大小的两倍。将 cv::drawKeypoints 函数中的 flag 参数设为 cv::DrawMatchesFlags::DRAW_RICH_KEYPOINTS,可以令绘制的半径等于关键点 size 属性。

3. 完整代码

头文件 (harrisDetector.h) 完整代码参考 Harris 特征点检测一节,主函数文件 (fastCorners.cpp) 完整代码如下所示:

#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/xfeatures2d.hpp>#include "harrisDetector.h"int main() {// 读取图像cv::Mat image = cv::imread("1.png", 0);if (!image.data) return 0;cv::transpose(image, image);cv::flip(image, image, 0);cv::namedWindow("Original");cv::imshow("Original",image);std::vector<cv::KeyPoint> keypoints;// FAST 特征image = cv::imread("1.png", 0);cv::transpose(image, image);cv::flip(image, image, 0);keypoints.clear();// FAST 检测器cv::Ptr<cv::FastFeatureDetector> ptrFAST = cv::FastFeatureDetector::create(40);ptrFAST->detect(image, keypoints);cv::drawKeypoints(image, keypoints, image, cv::Scalar(255, 255, 255), cv::DrawMatchesFlags::DRAW_OVER_OUTIMG);std::cout << "Number of keypoints (FAST): " << keypoints.size() << std::endl;cv::namedWindow("FAST");cv::imshow("FAST",image);// 未使用非极大值抑制的 FAST 特征image = cv::imread("1.png", 0);cv::transpose(image, image);cv::flip(image, image, 0);keypoints.clear();ptrFAST->setNonmaxSuppression(false);ptrFAST->detect(image, keypoints);cv::drawKeypoints(image, keypoints, image, cv::Scalar(255, 255, 255), cv::DrawMatchesFlags::DRAW_OVER_OUTIMG);cv::namedWindow("FAST Features (all)");cv::imshow("FAST Features (all)",image);// 读取图像image = cv::imread("1.png", 0);cv::transpose(image, image);cv::flip(image, image, 0);int total(100);         // 关键点数量int hstep(5), vstep(3); // 4x3 的网格int hsize(image.cols/hstep), vsize(image.rows/vstep);int subtotal(total/(hstep*vstep));  // 每个网格中的关键点数量cv::Mat imageROI;std::vector<cv::KeyPoint> gridpoints;std::cout << "Grid of " << vstep << " by " << hstep << " each of size " << vsize << " by " << hsize << std::endl;// 使用低阈值探测ptrFAST->setThreshold(20);// 非极大值抑制ptrFAST->setNonmaxSuppression(true);keypoints.clear();for (int i=0; i<vstep; i++) {for (int j=0; j<hstep; j++) {// 在当前网格上创建ROIimageROI = image(cv::Rect(j*hsize, i*vsize, hsize, vsize));// 在网格中检测关键点gridpoints.clear();ptrFAST->detect(imageROI, gridpoints);std::cout << "Number of FAST in grid " << i << "," << j << ": " << gridpoints.size() << std::endl;if (gridpoints.size()>subtotal) {for (auto it=gridpoints.begin(); it!=gridpoints.end()+subtotal; ++it) {std::cout << "  " << it->response << std::endl;}}// 获取最强 FAST 特征auto itEnd(gridpoints.end());if (gridpoints.size()>subtotal) {std::nth_element(gridpoints.begin(), gridpoints.end()+subtotal, gridpoints.end(),[](cv::KeyPoint& a, cv::KeyPoint& b) {return a.response>b.response;});itEnd = gridpoints.begin() + subtotal;}// 添加到全局关键点向量for (auto it=gridpoints.begin(); it!=itEnd; ++it) {it->pt += cv::Point2f(j*hsize, i*vsize);keypoints.push_back(*it);std::cout << " " << it->response << std::endl;}}}cv::drawKeypoints(image, keypoints, image, cv::Scalar(255, 255, 255), cv::DrawMatchesFlags::DRAW_RICH_KEYPOINTS);cv::namedWindow("FAST Features (grid)");cv::imshow("FAST Features (grid)", image);cv::waitKey();return 0;
}

小结

为了解决 Harris 角点检测算法计算代价较为高昂的缺点,特征点检测算子 FAST (Features from Accelerated Segment Test) 被专门设计用于快速检测图像中的角点。本节,我们介绍了如何使用通用接口调用 OpenCV 中的 FAST 特征点检测算法。

系列链接

OpenCV实战(1)——OpenCV与图像处理基础
OpenCV实战(2)——OpenCV核心数据结构
OpenCV实战(3)——图像感兴趣区域
OpenCV实战(4)——像素操作
OpenCV实战(5)——图像运算详解
OpenCV实战(6)——OpenCV策略设计模式
OpenCV实战(7)——OpenCV色彩空间转换
OpenCV实战(8)——直方图详解
OpenCV实战(9)——基于反向投影直方图检测图像内容
OpenCV实战(10)——积分图像详解
OpenCV实战(11)——形态学变换详解
OpenCV实战(12)——图像滤波详解
OpenCV实战(13)——高通滤波器及其应用
OpenCV实战(14)——图像线条提取
OpenCV实战(15)——轮廓检测详解
OpenCV实战(16)——角点检测详解

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

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

相关文章

Delphi 彻底搞懂 Unix/Linux 时间格式及平台间转换

目录 一、TDateTime 时间格式 二、Unix/Linux的日期和时间格式 三、Delphi中操作Unix/Linux格式的日期和时间 1. TDateTime 转 Unix/Linux格式 2. Unix/Linux格式 转 TDateTime 3. 与腾讯、阿里等平台&#xff08;简称&#xff1a;平台&#xff09;时间转换 四、Delphi…

秋招笔试知识点

1、计算出结构体大小&#xff08;对齐规则&#xff09; struct st { char name; int age; double money; }s; 规则&#xff08;字节对齐&#xff09; 1、 char 从0开始&#xff0c;0是任何数字的整数倍 int 是4个字节&#xff0c;4开始 double 是8个字节&#xff0c;从8开…

人人开源快速搭建后台(踩过的大坑,已解决)

目录 一、renrenfast后端代码导入idea后pom文件中的plugins报错 二、后端yaml配置出现问题 三、启动后端出现404 四、在vscode终端上运行 npm 会询问 “你要如何打开这个文件“ 五、npm install失败 一、renrenfast后端代码导入idea后pom文件中的plugins报错 亲测有效 谷…

ToBeWritten之汽车信息安全威胁建模

也许每个人出生的时候都以为这世界都是为他一个人而存在的&#xff0c;当他发现自己错的时候&#xff0c;他便开始长大 少走了弯路&#xff0c;也就错过了风景&#xff0c;无论如何&#xff0c;感谢经历 转移发布平台通知&#xff1a;将不再在CSDN博客发布新文章&#xff0c;敬…

itop-3568开发板驱动学习笔记(9)高级字符设备(三)信号驱动 IO

《【北京迅为】itop-3568开发板驱动开发指南.pdf》 学习笔记 文章目录应用层信号机制应用层开启异步通知驱动层异步通知接口实验代码信号驱动 IO 不需要像 poll 一样查询设备的状态&#xff0c;一旦设备有目标事件发生&#xff0c;就会触发 SIGIO 信号&#xff0c;然后处理信号…

Eyeshot .NET 2023.1 Crack

概述 Eyeshot 是.NET 的 CAD 控件。它本身支持Windows Forms和Windows Presentation Foundation。它随附四个不同的Visual Studio工具箱项目&#xff1a;用于 2D 和 3D 几何创建或编辑的设计、用于自动生成 2D 视图的 绘图、使用线性静态分析进行几何验证的模拟以及用于CNC刀具…

MySQL学习笔记(十八)—— 事务基本知识

1. 数据库事务概述 存储引擎支持请况 SHOW ENGINES; # 命令来查看当前 MySQL 支持的存储引擎都有哪些&#xff0c;以及这些存储引擎是否支持事务。能看出在 MySQL 中&#xff0c;只有InnoDB 是支持事务的。 基本概念 事务&#xff1a;一组逻辑操作单元&#xff0c;使数据从一…

4.8 Beijing Rust Meetup | Call For Presenters

如果你有兴趣参与探讨Rust作为一种强调性能、安全和并发性的编程语言的各种应用、实践和无限可能性的头脑风暴&#xff0c;就一定不能错过这场来自达坦科技、南京大学、CloudWeGo、华为等技术专家带来的关于Rust编程语言相关应用的线下Meetup。我们的主题是Rust &#x1f4a1;X…

stable diffusion成为生产力工具(一):制作购物车图标icon

S&#xff1a;你安装stable diffusion就是为了看小姐姐么&#xff1f; I &#xff1a;当然不是&#xff0c;当然是为了公司的发展谋出路~~ 预先学习&#xff1a; 安装webui《Windows安装Stable Diffusion WebUI及问题解决记录》。运行使用时问题《Windows使用Stable Diffusion时…

nodejs微服务:微服务集群

搭建Grpc微服务集群 某单一的微服务&#xff0c;比如&#xff1a;micro_a, 部署在一台机器上挂掉后, 不管是微服务机器挂掉还是consul_client挂掉&#xff0c;都会导致整个微服务不可访问&#xff0c;这时候我们就需要进行微服务的集群也就是 micro_a 的微服务不能部署到一台机…

基于html+css的盒子旋转

准备项目 项目开发工具 Visual Studio Code 1.44.2 版本: 1.44.2 提交: ff915844119ce9485abfe8aa9076ec76b5300ddd 日期: 2020-04-16T16:36:23.138Z Electron: 7.1.11 Chrome: 78.0.3904.130 Node.js: 12.8.1 V8: 7.8.279.23-electron.0 OS: Windows_NT x64 10.0.19044 项目…

Java多线程编程—wait/notify机制

文章目录1. 不使用wait/notify机制通信的缺点2. 什么是wait/notify机制3. wait/notify机制原理4. wait/notify方法的基本用法5. 线程状态的切换6. interrupt()遇到方法wait()7. notify/notifyAll方法8. wait(long)介绍9. 生产者/消费者模式10. 管道机制11. 利用wait/notify实现…

Bert的MLM任务loss原理

bert预训练有MLM和NSP两个任务&#xff0c;其中MLM是类似于“完形填空”的方式&#xff0c;对一个句子里的15%的词进行mask&#xff0c;通过双向transformerfeedforwardrediual_addlayer_norm完成对每个词的embedding编码&#xff0c;然后对mask的这个词进行预测&#xff0c;预…

【记录Bug】IDEA提示“Error:java: 错误: 不支持发行版本 17”

项目场景&#xff1a; 开发工具&#xff1a;IDea 后端框架&#xff1a;SpringBoot 问题描述 在rebuild或运行项目时提示“Error:java: 错误: 不支持发行版本 17”。 这个错误表明你的IDEA版本不支持使用Java 17。你需要将项目编译运行环境设置为更低版本的Java&#xff0c;或…

总结MySQL、Redis的优化措施与使用 mysql_upgrade升级数据结构

目录 一.MySQL数据库优化 二.Redis优化 三.MySQL创建测试账号报错 一.MySQL数据库优化 遵循MySQL层优化的五个原则: 减少数据访问&#xff0c;返回更少的数据&#xff0c;减少交互次数减少服务器CPU开销&#xff0c;利用更多资源。理解SQL优化原理并进行SQL优化&#xff0c…

力扣:字符串中的第一个唯一字符(C++实现)

题目部分&#xff1a; 解题思路&#xff1a; 方案一&#xff1a; 首先认真审题的小伙伴们一定会发现就是题目给了提示只包含小写字母&#xff0c;也就是说我们的排查范围是小写的26个字母。为了怕有的友友们一时短路想不起来&#xff0c;我就其按照顺序列出来吧。 即&#x…

[架构之路-157]-《软考-系统分析师》- 9-信息系统规划-2-少量人力进行项目初步调研(系统分析师的首要任务)与可行性研究报告

目录 9 . 3 初步调查 1. 初步调查的目标 9.4可行性研究 9.4.1可行性评价准则 1 . 经济可行性&#xff08;钱的可行性&#xff09; 2 . 技术可行性&#xff08;能力可行性&#xff09; 3 . 法律可行性&#xff08;社会&#xff09; 4 . 用户使用可行性&#xff08;用户&…

洛谷P2822:组合数问题 ←(帕斯卡法则+取模+前缀和)

【题目来源】https://www.luogu.com.cn/problem/P2822【题目描述】 组合数​表示的是从n个物品中选出m个物品的方案数。举个例子&#xff1a;从(1,2,3)三个物品中选择两个物品可以有(1,2)&#xff0c;(1,3)&#xff0c;(2,3) 这三种选择方法。根据组合数的定义&#xff0c;我们…

属性配置的宏(修改宏IntDir)

项目属性页码 拷贝下 常见宏列表 下表描述了可用宏的常用子集&#xff1b;还有很多没有在这里列出。 转到“宏”对话框&#xff0c;查看项目中的所有属性及其当前值。 有关如何创建 MSBuild 属性定义以及如何在 .props、.targets 和 .vcxproj 文件中将其用作宏的详细信息&am…

面向对象编程(进阶)7:面向对象特征三:多态性

一千个读者眼中有一千个哈姆雷特。 目录 7.1 多态的形式和体现 7.1.1 对象的多态性 举例&#xff1a; 7.1.2 多态的理解 7.1.3 举例 1、方法内局部变量的赋值体现多态 2、方法的形参声明体现多态 3、方法返回值类型体现多态 7.2 为什么需要多态性(polymorphism)&#x…