[ORB/BEBLID] 利用OpenCV(C++)实现尺度不变性与角度不变性的特征找图算法
本文只发布于利用OpenCV实现尺度不变性与角度不变性的特征找图算法和知乎
一般来说,利用OpenCV实现找图功能,用的比较多的是模板匹配(matchTemplate)。笔者比较喜欢里面的NCC算法。但是模板有个很明显的短板,面对尺度改变,角度改变的目标就无能为力了。因此本文旨在做到模板匹配做不到的这两点上。
当然也有人利用模板匹配实现上面的功能,但是方法之无语,效率之低下让我不禁想起了三体中的一句话:
“成吉思汗的骑兵,攻击速度与二十世纪的装甲部队相当;北宋的床弩,射程达一千五百米,与二十世纪的狙击步枪差不多;但这些仍不过是古代的骑兵与弓弩而已,不可能与现代力量抗衡。基础理论决定一切,未来史学派清楚地看到了这一点。而你们,却被回光返照的低级技术蒙住了眼睛。你们躺在现代文明的温床中安于享乐,对即将到来的决定人类命运的终极决战完全没有精神上的准备。”
本文并不涉及ORB或者BEBLID算法的具体实现,想了解的同学请移步论文。本文撰自一名非计算机系大一新生,有不到处还请见谅。
从特征匹配开始
特征匹配首先是需要获得特征点。通过特征检测算法,获得特征点后利用匹配器,或是计算汉明距离或是计算余弦距离,将两个图上的点连接在一起。
看笔者往期文章浅谈OpenCV的多对象匹配透明图像的实现,以及如何匹配半透明控件,在这篇文章中用的是SURF算法。但是这个算法并不支持角度不变性。
笔者在阅读OpenCV-mobile的readme的时候意外了解到ORB算法。简单查找一下资料,了解到ORB(Oriented FAST and Rotated BRIEF)算法满足以下特点
- 支持尺度不变性和角度不变性
- 速度很快,甚至比特征匹配(NCC)还快(i9 13900hx)
- 开源,免费,无专利
- 目前最快速稳定的特征点检测和提取算法
ORB = Oriented FAST(特征点) + Rotated BRIEF(特征描述)
在2020年提出了一个效果更好也更快的特征描述算法Boosted Efficient Binary Local Image Descriptor(笔者不清楚他算法这有没有专利,但是这个算法在nonfree里,如果需要商业化请慎用,或者替换回BRIEF算法)
代码实现
cv::Ptr<cv::ORB> orb = cv::ORB::create(nKeypoints); //寻找nKeypoints个特征点
cv::Ptr<cv::xfeatures2d::BEBLID> beblid = cv::xfeatures2d::BEBLID::create(0.75f, cv::xfeatures2d::BEBLID::SIZE_256_BITS);//用256个比特来描述特征
std::vector<cv::KeyPoint> src_keypoints, target_keypoints;
cv::Mat src_descriptors, target_descriptors;
orb->detect(src_mat, src_keypoints);
orb->detect(target_mat, target_keypoints);
beblid->compute(src_mat, src_keypoints, src_descriptors);
beblid->compute(target_mat, target_keypoints, target_descriptors);
cv::BFMatcher matcher(cv::NORM_HAMMING, true);//利用汉明距离的匹配器
std::vector<cv::DMatch> matches;
matcher.match(target_descriptors, src_descriptors, matches);
std::vector<cv::Point2d> matched_target, matched_src;
for(auto &match : matches)
{
if(match.distance > max_distance)
break;
matched_target.push_back(target_keypoints[match.queryIdx].pt);
matched_src.push_back(src_keypoints[match.trainIdx].pt);
}
这里创建了ORB和BEBLID对象,并且对目标图片完成了匹配,将彼此能够匹配的点对应存放到了matched_target和matched_src里。
从透视变换继续
虽然我们这里成功建立了模板图和目标图的特征点对点关系,然而,很多时候我们想要的是特征匹配提供的那种更为直接的反映在目标图里的坐标。
如何将离散的的点集转换为模板在目标图上的大致区域,成了我们需要解决的一个问题。这里我使用的方法是findHomography和perspectiveTransform。
findHomography 计算多个二维点对之间的最优单映射变换矩阵H(3行3列)。使用最小均方误差或RANSAC方法。比较好解释的是最小均方误差方法,但是为了效果笔者用的是RANSAC方法。关于这个矩阵作用,大家可以去B站上看3blue1brown的系列视频《线性代数的本质》。我们获取到这个矩阵,就可以估计出模板图怎么变化到目标图上。同理模板的四个角的坐标也可以通过这个矩阵变换到目标图上的坐标,就得到了模板在目标图上的大致位置和边界。
perspectiveTransform 透视变换,就是完成坐标的变换过程。
代码实现
cv::Mat H = cv::findHomography(matched_src, matched_target, cv::RANSAC);
std::vector<cv::Point2f> obj_corners(4);
obj_corners[0] = cv::Point2f(0, 0);
obj_corners[1] = cv::Point2f((float)target_mat.cols, 0);
obj_corners[2] = cv::Point2f((float)target_mat.cols, (float)target_mat.rows);
obj_corners[3] = cv::Point2f(0, (float)target_mat.rows);
std::vector<cv::Point2f> buf_corners(4);
cv::perspectiveTransform(obj_corners, buf_corners, H);
效果展示
缩放 | 压扁 | 旋转 |
---|---|---|
![]() |
![]() |
![]() |
可以发现实现的效果非常好。
还能更强?
这里只实现了单个目标的检测匹配,事实上这个算法不止步于此,我们可以使用KMeans算法,实现对于一个图片上多个目标一次检测。也可以多个图片同时匹配。但是鉴于时间,和笔者不容乐观的数学分析成绩,以及即将到来的数论期中考试,为了不被踢出强基计划,下次有时间再说吧。
[ORB/BEBLID] 利用OpenCV(C++)实现尺度不变性与角度不变性的特征找图算法的更多相关文章
- 利用OpenCV实现图像拼接Stitching模块讲解
https://zhuanlan.zhihu.com/p/71777362 1.1 图像拼接基本步骤 图像拼接的完整流程如上所示,首先对输入图像提取鲁棒的特征点,并根据特征描述子完成特征点的匹配,然后 ...
- 如何利用OpenCV自带的级联分类器训练程序训练分类器
介绍 使用级联分类器工作包括两个阶段:训练和检测. 检测部分在OpenCVobjdetect 模块的文档中有介绍,在那个文档中给出了一些级联分类器的基本介绍.当前的指南描述了如何训练分类器:准备训练数 ...
- #利用openCV裁脸
#利用openCV裁脸import cv2 def draw_rects(img, rects): for x, y, w, h in rects: cv2.rectangle(img, (x, y) ...
- 利用OpenCV给图像添加中文标注
利用OpenCV给图像添加中文标注 : 参考:http://blog.sina.com.cn/s/blog_6bbd2dd101012dbh.html 和https://blog.csdn.net/ ...
- 利用opencv作透明重叠人群密度热度图
在作热度图的时候我们经常需要将热度图调整透明度后叠加在原图上达到更好的展示效果.比如检测人气密度的热度图: (来自sensetime) 一般作图的时候会第一时间想到matplotlib,因为可以很方便 ...
- python利用opencv去除水印方法
OpenCV(Open Source Computer Vision Library)是一个跨平台计算机视觉库,实现了图像处理和计算机视觉方面的很多通用算法 在python中可以利用opencv来去除 ...
- 图像滑动窗口 利用opencv和matlab
1.利用opencv实现图像滑动窗口操作 功能:利用opencv实现图像滑动窗口操作(即利用已知尺寸的窗口遍历整幅图像,形成许多子图像) vs2015+opencv3.1 2016.10 函数实现 ...
- 利用opencv源代码和vs编程序训练分类器haartraining.cpp
如需转载请注明本博网址:http://blog.csdn.net/ding977921830/article/details/47733363. 一 训练框架 训练人脸检測分类器须要三个步骤: (1 ...
- C# 利用 OpenCV 进行视频捕获 (笔记)
原文:C# 利用 OpenCV 进行视频捕获 (笔记) 简介 这个项目是关于如何从网络摄像头或者视频文件(*.AVI)中捕获视频的,这个项目是用C#和OPENCV编写的. 这将有助于那些喜欢C#和Op ...
- 双三次插值C代码(利用opencv)
双三次插值C代码(利用opencv) phasecubic2.cpp D:\文件及下载相关\文档\Visual Studio 2010\Projects\phasecubic2\phasecubic2 ...
随机推荐
- VS Code好用插件: Easy Less
插件 编译less并输出CSS文件 输出文件
- node.js中kafka的封装和高并发消费限流优雅降级以及egg-kafka的封装说明
HI!,你好,我是zane,zanePerfor是一款我开发的一个前端性能监控平台,现在支持web浏览器端和微信小程序端. 我定义为一款完整,高性能,高可用的前端性能监控系统,这是未来会达到的目的,现 ...
- 使用synapse搭建matrix去中心化加密通信服务
前言 首先必须介绍下Matrix.Matrix是一个开源.可交互.去中心化的实时通信服务框架.使用Matrix可以搭建安全的通信服务器,配合支持 Matrix 的客户端可以实现个人.团队间的实时聊天交 ...
- [loki]轻量级日志聚合系统loki快速入门
前言 简述:loki是由grafana开源的日志聚合系统,相较于ELK.EFK更轻量. loki特性: 不对日志进行全文索引.通过存储压缩非结构化日志和仅索引元数据,Loki 操作起来会更简单,更省成 ...
- Linux:通过命令查找日志文件中的某字段
工作中有用到,做个记录. 1. 查询某字段,显示行号: cat -n file_name|grep '查找字段' [root@ZWZF-CWY-LZY-12 CWY]# cat -n nohup.ou ...
- Baby_python 反编译
ok,直接pyc直接反编译 逻辑清楚 拿到flag直接搞 结果提交给错了我把前缀改成flag{}这种格式也给错真是摸不着头脑 难道是base64解密错误?? 找了另外一个网站 ???这个是啥?? 与之 ...
- [ABC150F] Xor Shift
2023-03-10 题目 题目传送门 翻译 翻译 难度&重要性(1~10):6 题目来源 AtCoder 题目算法 KMP,Z函数 解题思路 首先是按位确定,令 \(t(i,j)\) 表示 ...
- Vue【原创】基于【日历组件Calendar】的【节假日管理】功能整合
基于日历组件(lilo-calendar)的节假日管理功能整合. 效果图: 完整代码: 1 <template> 2 <div class="root-calendar&q ...
- AtCoder ABC183F Confluence
题意 \(n\)个人,每个人属于一个班级\(ci\),这些人会有些小团体(并查集) 两种操作: \(1\) \(a\) \(b\),将\(a\)所在的集体和\(b\)所在的集体合并 \(2\) \(x ...
- 想让你的工作轻松高效吗?揭秘Java + React导出Excel/PDF的绝妙技巧!
前言 在B/S架构中,服务端导出是一种高效的方式.它将导出的逻辑放在服务端,前端仅需发起请求即可.通过在服务端完成导出后,前端再下载文件完成整个导出过程.服务端导出具有许多优点,如数据安全.适用于大规 ...