使用OpenCV对图片进行特征点检测和匹配(C++)
背景
最近从不同网站下载了非常多的动漫壁纸,其中有一些内容相同,但是大小、背景颜色、色调、主人公的位置不同(例子如下)。正因为如此,基础的均方误差、直方图检测等方法很难识别出这些相似的图片。


思路
OpenCV中有很多用来对特征点进行检测和计算的函数,这些函数能够利用像素点及其周围的灰度检测其是否是图像中的特征点,并计算出它的信息,比如ORB、SIFT、SURF、AKANA。同时OpenCV还有一些利用特征点的信息对特征点进行匹配的算法,比如BF、FLANN。我们可以先把参与匹配的每个图片的特征点和信息计算出来,然后对图片两两进行特征点匹配,如果两幅图片匹配上的特征点数量超过一个定值,即认为这两个图片相似。这种方法因为是直接对图像的特征进行考虑,因此对于大小、色调、主人公的位置不同的相似图片也能很好的匹配。
对于特征点检测,这些算法分为两类,一类输出的特征点信息是二进制串,包括ORB、AKANA等,一类输出的特征点信息是浮点数,包括SIFT、SURF,但是SIFT和SURF这两个算法是有专利的,商用要付钱,所以OpenCV把它们放进了Contrib扩展包里面,如果你用的是python版的OpenCV,必须下载3.4.2.16版本的opencv-contrib-python才能用OpenCV里的SIFT和SURF函数。我用的是C++版本的OpenCV,你需要下载OpenCV的源码和OpenCV-contrib扩展包然后自己编译,很麻烦,所以我选择的是ORB。对于特征点匹配,FLANN不论效率还是效果都比BF好很多(当然也有可能是我BF没用对),但是网上很多教程(包括OpenCV自己的文档)都是ORB配BF,SIFT配FLANN,StackOverflow也有人问ORB怎么搭配FLANN使用,有的回答直接说特征点信息是整数的算法不能搭配FLANN,但幸好这个问题下的另一个人给出了FLANN搭配ORB时的参数,(https://stackoverflow.com/questions/43830849/opencv-use-flann-with-orb-descriptors-to-match-features)这也说明了这个问题还是被很多人忽视的,毕竟当今世界是深度学习的天下,很少人去关注这些传统算法了。
这个程序效率比较低,需要进行一些优化。首先我们用于求特征点和匹配的图片应该是原图的灰度图经过缩小后的版本,同时注意这个操作不要用cv::resize完成,不然会慢很多,直接在imread的时候指定第二个参数为cv::IMREAD_REDUCE_COLOR_4可以在读入图片的同时缩小。当然,瓶颈还是在那个两两匹配的二重循环里,为了减少FLANN的操作,我先预处理出图像各个通道的平均值,用这个值来大致表示这个图像的色调,在二重循环中,如果两个图片的平均值相差太大(我设置的是60),就认为它们不相似,不进行特征点匹配,当然这样会导致多出不少漏网之鱼,不过实践证明这样做大部分相似的图片还是不会被筛掉的,而且速度也提高了很多。
代码
#include <io.h>
#include <ctime>
#include <vector>
#include <opencv2/opencv.hpp> bool judge(cv::Scalar &a, cv::Scalar &b, int num) {
return std::abs(a[0] - b[0]) < num && std::abs(a[1] - b[1]) < num && std::abs(a[2] - b[2]) < num; } int main() { clock_t start = clock(); //计时开始
std::vector <cv::String> filelist;
typedef std::tuple <cv::String, cv::String, int> data;
std::vector <std::vector <cv::KeyPoint>> kplist;
std::vector <cv::Mat> deslist;
std::vector <cv::Scalar> averagebgr;
std::vector <data> same; _finddata_t fd;
intptr_t pf = _findfirst("D:/image/*.??g", &fd); filelist.push_back(cv::String("D:/宋奕欣/") + fd.name);
while (!_findnext(pf, &fd)) filelist.push_back(cv::String("D:/image/") + fd.name);
_findclose(pf); //列举出图片,这里用的是io.h里的_findfirst和_findnext,通配符.??g筛选出.jpg和.png的文件 cv::Ptr <cv::ORB> orb = cv::ORB::create();
for (auto i : filelist) {
cv::Mat imgo = cv::imread(i, cv::IMREAD_REDUCED_COLOR_4);
averagebgr.push_back(cv::mean(imgo)); //求各通道平均值
cv::Mat img; cv::cvtColor(imgo, img, cv::COLOR_BGR2GRAY);
std::vector<cv::KeyPoint> kp; cv::Mat des; //kp是特征点,des是特征点的信息
orb->detectAndCompute(img, cv::Mat(), kp, des);
kplist.push_back(kp);
deslist.push_back(des);
} std::cout << "Successfully found keypoints." << std::endl; cv::FlannBasedMatcher flann(cv::makePtr<cv::flann::LshIndexParams>(, , )); //这个cv::makePtr<cv::flann::LshIndexParams>(12, 20, 2)就是使FLANN能搭配ORB的参数,默认构造函数指定的是随机KD树算法,只能用于SIFT和SURF
for (int i = ; i < filelist.size(); i++)
for (int j = i + ; j < filelist.size(); j++) { if (!judge(averagebgr[i], averagebgr[j], )) continue; std::vector<cv::KeyPoint> kpl, kps; cv::Mat desl, dess;
kpl = kplist[i]; desl = deslist[i];
kps = kplist[j]; dess = deslist[j]; std::vector <std::vector <cv::DMatch> > matches; flann.knnMatch(dess, desl, matches, );
std::vector <cv::DMatch> good;
for (auto k : matches) {
if (k.size() > && k[].distance < 0.5 * k[].distance) good.push_back(k[]); //knnMatch的k=2时,每个Dmatch会返回distance最小的两组匹配,当最小的这两组的distance相差足够大时,较小的那一组才可能是合法匹配
} if (good.size() > ) same.push_back(std::make_tuple(filelist[i], filelist[j], good.size())); // cv::Mat img; cv::drawMatches(imgs, kps, imgl, kpl, good, img, cv::Scalar(0, 255, 0));
// cv::imshow("img", img); cv::waitKey();
} std::sort(same.begin(), same.end(), [](data x, data y) {
return std::get<>(x) > std::get<>(y);
}); //把匹配的图片按匹配的特征点数排序
for (data i : same) {
std::cout << std::get<>(i) << ' ' << std::get<>(i) << ' ' << std::get<>(i) << std::endl;
} std::cout << (double)(clock() - start) / CLOCKS_PER_SEC << std::endl;
system("pause");
return ;
}
使用OpenCV对图片进行特征点检测和匹配(C++)的更多相关文章
- OPENCV图像特征点检测与FAST检测算法
前面描述角点检测的时候说到,角点其实也是一种图像特征点,对于一张图像来说,特征点分为三种形式包括边缘,焦点和斑点,在OPENCV中,加上角点检测,总共提供了以下的图像特征点检测方法 FAST SURF ...
- Surf算法特征点检测与匹配
Speeded Up Robust Features(SURF,加速稳健特征),是一种稳健的局部特征点检测和描述算法.最初由Herbert Bay发表在2006年的欧洲计算机视觉国际会议(Europe ...
- SIFT特征点检测与匹配
SIFT的步骤如下: (1) 尺度空间极值检测(Scale-space Extrema Detection) 也就是在多尺度高斯差分(Difference of Gauss)空间中检测极值点(3x3x ...
- OpenCV计算机视觉学习(13)——图像特征点检测(Harris角点检测,sift算法)
如果需要处理的原图及代码,请移步小编的GitHub地址 传送门:请点击我 如果点击有误:https://github.com/LeBron-Jian/ComputerVisionPractice 前言 ...
- OpenCV特征点检测匹配图像-----添加包围盒
最终效果: 其实这个小功能非常有用,甚至加上只有给人感觉好像人脸检测,目标检测直接成了demo了,主要代码如下: // localize the object std::vector<Point ...
- [OpenCV]基于特征匹配的实时平面目标检测算法
一直想基于传统图像匹配方式做一个融合Demo,也算是对上个阶段学习的一个总结. 由此,便采购了一个摄像头,在此基础上做了实时检测平面目标的特征匹配算法. 代码如下: # coding: utf-8 ' ...
- OpenCV特征点检测------ORB特征
OpenCV特征点检测------ORB特征 ORB是是ORiented Brief的简称.ORB的描述在下面文章中: Ethan Rublee and Vincent Rabaud and Kurt ...
- python+OpenCV 特征点检测
1.Harris角点检测 Harris角点检测算法是一个极为简单的角点检测算法,该算法在1988年就被发明了,算法的主要思想是如果像素周围显示存在多于一个方向的边,我们认为该点为兴趣点.基本原理是根据 ...
- OpenCV特征点检测------Surf(特征点篇)
Surf(Speed Up Robust Feature) Surf算法的原理 ...
随机推荐
- 重学 Java 设计模式:实战享元模式「基于Redis秒杀,提供活动与库存信息查询场景」
作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 程序员的上下文是什么? 很多时候一大部分编程开发的人员都只是关注于功能的实现,只 ...
- http的几种请求方法
1.HTTP请求方法有以下8种方法:OPTIONS.GET.HEAD.POST.PUT.DELETE.TRACE和CONNECT. GET GET请求会显示请求指定的资源.一般来说GET方法应该只用于 ...
- 为什么启动线程是start方法?
为什么启动线程是start方法 十年可见春去秋来,百年可证生老病死,千年可叹王朝更替,万年可见斗转星移. 凡人如果用一天的视野,去窥探百万年的天地,是否就如同井底之蛙? 背景:启动线程是start ...
- C#数据结构与算法系列(九):栈实现综合计算器(中缀表达式)
1.问题介绍 2.实现思路 3.代码实现 第一个版本(采用这个) public class ArrayStack { private int _maxSize; private int[] _arr; ...
- Latex文件本机能正常编译,但在另一台电脑不能编译的解决方法
问题:同样的文件在台式机能编译出正常的PDF文件,但发现在另一个电脑上不能编译出PDF文件. \documentclass[preprint,10pt,5p,times,twocolumn]{elsa ...
- C++ vector迭代器访问二维数组
#include<iostream> #include<vector> int main(){ std::vector<int> arr(); // 创建一维数组 ...
- SSH网上商城一
Java高级项目之SSH网上商城项目实战: 1.采用目前最主流的三大框架开发即Struts2+Spring+Hibernate框架整合开发.2.通过AJAX技术提供良好的用户体验.3.提供了邮箱激活的 ...
- 实战:IDEA运行速度调优
序言 可能大家觉得系统调优一般都是针对服务端应用而言的,普通Java开发人员很少有机会实践.今天就通用一个Java开发人员日常工作中经常使用的开发工具开做一次调优实战. 我在日常工作中的主要IDE工具 ...
- 【转载】张一鸣:为什么 BAT 挖不走我们的人才?
很多企业失败的时候,总说是政策的变化.市场的变化.消费者需求的变化.技术发展的变化等等,导致了失败,其实这都是瞎说,归根结底还是人的原因,都是因为你招的人不行.可见,人才对于一个企业的重要性. 互联网 ...
- 6.30集训模拟赛4(炸裂的一天qwq)
T1浇水: 题目描述 在一条长n米,宽m米米的长方形草地上放置着k个喷水装置.假设长方形草地的坐标范围为[ 0 , 0 ] ~ [ n , m ],那么第 i 个喷水装置的位置为(ai,m/2),也就 ...