-
2021-11-16 11:58:02
//#include "opencv2/nonfree/nonfree.hpp" //#include "opencv2/nonfree/features2d.hpp" //#include "opencv2/legacy/legacy.hpp" #include <opencv2/xfeatures2d.hpp> #include <opencv2/opencv.hpp> #include <iostream> using namespace cv; using namespace std; int main() { //读取图像 Mat img01=imread("2.jpg"); Mat img02=imread("4.jpg"); imshow("original image1",img01); imshow("original image2",img02); //SIFT特征检测 SiftFeatureDetector detector; //定义特点点检测器 vector<KeyPoint> keypoint01,keypoint02;//定义两个容器存放特征点 detector.detect(img01,keypoint01); detector.detect(img02,keypoint02); //在两幅图中画出检测到的特征点 Mat out_img01; Mat out_img02; drawKeypoints(img01,keypoint01,out_img01); drawKeypoints(img02,keypoint02,out_img02); imshow("特征点图01",out_img01); imshow("特征点图02",out_img02); //提取特征点的特征向量(128维) SiftDescriptorExtractor extractor; Mat descriptor01,descriptor02; extractor.compute(img01,keypoint01,descriptor01); extractor.compute(img02,keypoint02,descriptor02); //匹配特征点,主要计算两个特征点特征向量的欧式距离,距离小于某个阈值则认为匹配 BruteForceMatcher<L2<float>> matcher; vector<DMatch> matches; Mat img_matches; matcher.match(descriptor01,descriptor02,matches); drawMatches(img01,keypoint01,img02,keypoint02,matches,img_matches); imshow("误匹配消除前",img_matches); //RANSAC 消除误匹配特征点 主要分为三个部分: //1)根据matches将特征点对齐,将坐标转换为float类型 //2)使用求基础矩阵方法 findFundamentalMat,得到RansacStatus //3)根据RansacStatus来将误匹配的点也即RansacStatus[i]=0的点删除 //根据matches将特征点对齐,将坐标转换为float类型 vector<KeyPoint> R_keypoint01,R_keypoint02; for (size_t i=0;i<matches.size();i++) { R_keypoint01.push_back(keypoint01[matches[i].queryIdx]); R_keypoint02.push_back(keypoint02[matches[i].trainIdx]); //这两句话的理解:R_keypoint1是要存储img01中能与img02匹配的特征点, //matches中存储了这些匹配点对的img01和img02的索引值 } //坐标转换 vector<Point2f>p01,p02; for (size_t i=0;i<matches.size();i++) { p01.push_back(R_keypoint01[i].pt); p02.push_back(R_keypoint02[i].pt); } //利用基础矩阵剔除误匹配点 vector<uchar> RansacStatus; Mat Fundamental= findFundamentalMat(p01,p02,RansacStatus,FM_RANSAC); vector<KeyPoint> RR_keypoint01,RR_keypoint02; vector<DMatch> RR_matches; //重新定义RR_keypoint 和RR_matches来存储新的关键点和匹配矩阵 int index=0; for (size_t i=0;i<matches.size();i++) { if (RansacStatus[i]!=0) { RR_keypoint01.push_back(R_keypoint01[i]); RR_keypoint02.push_back(R_keypoint02[i]); matches[i].queryIdx=index; matches[i].trainIdx=index; RR_matches.push_back(matches[i]); index++; } } Mat img_RR_matches; drawMatches(img01,RR_keypoint01,img02,RR_keypoint02,RR_matches,img_RR_matches); imshow("消除误匹配点后",img_RR_matches); imwrite("result.jpg", img_RR_matches); waitKey(0); }
更多相关内容 -
sift特征提取与匹配C++范例(基于opencv、VS17)
2020-05-21 22:58:08sift特征提取与匹配C++代码,1000行完整代码,超详细注释,基本每五行一注释,有少许BUG。 1.提取特征点算法(包括尺度空间的极值探测、关键点的精确定位、确定关键点的主方向、关键点的描述); 2.匹配算法 3.运行... -
SIFT 算法 C++ 代码实现(非常实用)
2022-01-07 18:11:52该工程主要是对 SIFT 算法的具体实现,代码中注释非常详细易懂、没有之一,非常适合小伙伴们学习哦!!! -
opencv实现的SIFT特征提取与匹配算法
2015-06-18 22:21:37用opencv+VS2012实现的SIFT特征提取与匹配算法,已编译通过,直接打开就能运行 -
使用C++的OpenCV进行SIFT特征检测与匹配
2022-04-19 02:02:17Python版本写多了,感受下C++版本目录
直接上代码吧:
demo.c
#include <iostream> #include <opencv2/highgui.hpp> #include <opencv2/core.hpp> #include <opencv2/xfeatures2d.hpp> int main() { int64 t1, t2; double tkpt, tdes, tmatch_bf, tmatch_knn; // 1. 读取图片 const cv::Mat image1 = cv::imread("../../images/1.png", 0); //Load as grayscale const cv::Mat image2 = cv::imread("../../images/2.png", 0); //Load as grayscale std::vector<cv::KeyPoint> keypoints1; std::vector<cv::KeyPoint> keypoints2; cv::Ptr<cv::SiftFeatureDetector> sift = cv::SiftFeatureDetector::create(); // 2. 计算特征点 t1 = cv::getTickCount(); sift->detect(image1, keypoints1); t2 = cv::getTickCount(); tkpt = 1000.0*(t2-t1) / cv::getTickFrequency(); sift->detect(image2, keypoints2); // 3. 计算特征描述符 cv::Mat descriptors1, descriptors2; t1 = cv::getTickCount(); sift->compute(image1, keypoints1, descriptors1); t2 = cv::getTickCount(); tdes = 1000.0*(t2-t1) / cv::getTickFrequency(); sift->compute(image2, keypoints2, descriptors2); // 4. 特征匹配 cv::Ptr<cv::DescriptorMatcher> matcher = cv::DescriptorMatcher::create(cv::DescriptorMatcher::BRUTEFORCE); // cv::BFMatcher matcher(cv::NORM_L2); // (1) 直接暴力匹配 std::vector<cv::DMatch> matches; t1 = cv::getTickCount(); matcher->match(descriptors1, descriptors2, matches); t2 = cv::getTickCount(); tmatch_bf = 1000.0*(t2-t1) / cv::getTickFrequency(); // 画匹配图 cv::Mat img_matches_bf; drawMatches(image1, keypoints1, image2, keypoints2, matches, img_matches_bf); imshow("bf_matches", img_matches_bf); // (2) KNN-NNDR匹配法 std::vector<std::vector<cv::DMatch> > knn_matches; const float ratio_thresh = 0.7f; std::vector<cv::DMatch> good_matches; t1 = cv::getTickCount(); matcher->knnMatch( descriptors1, descriptors2, knn_matches, 2); for (auto & knn_matche : knn_matches) { if (knn_matche[0].distance < ratio_thresh * knn_matche[1].distance) { good_matches.push_back(knn_matche[0]); } } t2 = cv::getTickCount(); tmatch_knn = 1000.0*(t2-t1) / cv::getTickFrequency(); // 画匹配图 cv::Mat img_matches_knn; drawMatches( image1, keypoints1, image2, keypoints2, good_matches, img_matches_knn, cv::Scalar::all(-1), cv::Scalar::all(-1), std::vector<char>(), cv::DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS ); cv::imshow("knn_matches", img_matches_knn); cv::waitKey(0); cv::Mat output; cv::drawKeypoints(image1, keypoints1, output); cv::imwrite("sift_image1_keypoints.jpg", output); cv::drawKeypoints(image2, keypoints2, output); cv::imwrite("sift_image2_keypoints.jpg", output); std::cout << "图1特征点检测耗时(ms):" << tkpt << std::endl; std::cout << "图1特征描述符耗时(ms):" << tdes << std::endl; std::cout << "BF特征匹配耗时(ms):" << tmatch_bf << std::endl; std::cout << "KNN-NNDR特征匹配耗时(ms):" << tmatch_knn << std::endl; return 0; }
CMakeLists.txt
cmake_minimum_required(VERSION 3.22) project(demo) find_package(OpenCV REQUIRED) IF(UNIX) SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS} -g -O0 -Wall -Wextra -Wunused-variable -DDEBUG -D_DEBUG") SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS} -O0 -g -Wall -Wextra -Wunused-variable -DDEBUG -D_DEBUG") ENDIF(UNIX) set(CMAKE_CXX_STANDARD 20) add_executable(demo main.cpp) target_link_libraries(demo ${OpenCV_LIBS})
效果
注
其他算法如SURF、AKAZE等可类似修改,但注意SIFT这些是浮点数特征描述符,而ORB这些是二进制特征描述符,因此在特征匹配时注意区分是L2还是Hamming。
-
SIFT特征匹配算法原理过程
2022-03-25 11:08:30尺度不变特征变换匹配算法 ScaleInvariantFeatureTransform(SIFT) 是一种电脑视觉的算法用来侦测与描述影像中的局部性特征,它在空间尺度中寻找极值点,并提取出其位置、尺度、旋转不变量,此算法由DavidLowe在1999...尺度不变特征变换匹配算法 Scale Invariant Feature Transform(SIFT) 是一种电脑视觉的算法用来侦测与描述影像中的局部性特征,它在空间尺度中寻找极值点,并提取出其位置、尺度、旋转不变量,此算法由 David Lowe在1999年所发表,2004年完善总结。
基本步骤:
- 尺度空间的极值检测
- 删除不好的极值点,留下来的就是特征点
- 特征方向幅值
- 特征点描述
step1:差分高斯金字塔
图像金字塔、高斯金字塔、差分高斯金字塔
step1.5:尺度空间的极值检测
图像金字塔、高斯金字塔、差分高斯金字塔尾部
step2:删除不好的极值点
(求导链接)
step3-去除边缘效应
由于DoG函数在图像边缘有较强的边缘响应,而边缘上的极值点抗噪性较差,因此我们还需要排除边缘响应。为什么边缘上的点不好呢?一方面图像边缘上的点是很难定位的,具有定位歧义性;另一方面这样的点很容易受到噪声的干扰而变得不稳定。
怎么消除这些在边缘的极值点呢?
假设图像像素如图所示,边缘位置像素值急剧变化
一个定义不好的高斯差分算子的极值在横跨边缘的地方有较大的主曲率(红色),而在垂直边缘的方向有较小的主曲率(紫色)。
对于分布在边缘上附近的极值点,它们的较大的主曲率和较小的主曲率之比,一般情况下要比非边缘点的比值大
根据这种思想,我们可以设一个比值的阈值,当比值大于这个阈值就认为极值点在边缘上。
参考公式:--------------------------------------------------------------------------------
-------------------------------------------------------------------------------------
step4-确定关键点(极值点)方向
为什么要确定方向,确定啥方向?
为了使描述符具有旋转不变性,需要利用图像的局部特征为给每一个关键点分配一个基准方向。这样就算目标旋转,其他特征都相对与基准方向,并不会因为目标旋转而改变。那么怎么求这个基准方向呢?
统计的是以该特征点为圆心,以该特征点所在的高斯图像的尺度 σ 的4.5倍为半径的范围内像素点。
在此区域内做1.5σ的高斯滤波(高斯加权,离圆心也就是关键点近的幅值所占权重较高).
当关键点有两个方向,一个主方向,一个辅方向(梯度幅值>=80%主方向梯度幅值),
那么把这个关键点看成两个关键点,只不过这两个关键点的坐标和σ一样,只是方向不一样.
至此,我们计算出的带有位置、尺度和方向的关键点也就是sift特征点。
关键点描述
step5. 关键点描述
现在我们算出来的特征点,都是在固定在图片坐标系中的特征描述。我们需要脱离图片坐标系的固定限制,提取出特征点的局部描述,这样就可以与其他图片的相似的部分去作对比,我们来看看怎么提取局部描述子。
生成局部描述符的思路就是:通过对关键点的周围区域分块,计算块内的梯度直方图,生成具有独特性的向量,这个向量应该是该区域图像信息的一种抽象,并且具有唯一性。
-
c++实现的sift算法
2014-05-25 15:28:42c++实现的sift 算法 kdtree bbf -
opencv实现的sift算法源码,包含了图像的SIFT特征提取,详细讲解SIFT关键点的提取过程,图像间的基于SIFT...
2018-11-06 22:43:43opencv实现的SIFT算法源码,包含图像的SIFT特征提取算法,以及图像之间的基于SIFT特征的匹配算法 -
C++ OpenCV4.5版本SIFT特征检测及匹配
2021-05-25 00:51:18学更好的别人,做更好的自己。——《微卡智享》本文长度为2739字,预计阅读6分钟前言关于SIFT的特征点检测在《C++ OpenCV特征提取之SIFT特征检测》有介绍过,在OpenCV4....学更好的别人,
做更好的自己。
——《微卡智享》
本文长度为2739字,预计阅读6分钟
前言
关于SIFT的特征点检测在《C++ OpenCV特征提取之SIFT特征检测》有介绍过,在OpenCV4.5版本中SIFT做是算法优化,也移到主仓库中了,并且有朋友也留言问了4.5版本下的DEMO。
所以这篇就做一下OpenCV4.5版本的SIFT特征点检测及匹配。
实现效果
两张原图
匹配的效果
代码实现
微卡智享
# 实现流程 1 定义检测的特征点个数,用SIFT进行特征检测 2 对检测完的两个图做特征向量的提取 3 使用BFMatch进行匹配,筛选出好的结果 4 画出匹配的特征点 01
SIFT特征检测
以前版本中使用SIFT需要引入xfeatures2d.hpp,而现在就不用了。
旧版本
新版本
02
特征向量的提取
接下来就是计算特征点描述符,特征向量的提取
特征向量提取
03
使用BFMatch匹配
提取完特征向量后,对两个特征向量进行匹配,然后通过匹配的结果计算出向量的最大和最小距离。
特征匹配及计算最大最小距离
04
筛选好的匹配结果
最后就是根据最大最小的距离,从匹配的点中筛选出好的结果,再展示出来。
筛选结果绘制图像
完整代码
#include<iostream> #include<opencv2/opencv.hpp> #include"CvUtils.h" using namespace std; using namespace cv; int main(int argc, char** argv) { Mat src = imread("E:/DCIM/hrd/h1.jpg"); CvUtils::MatResize(src); CvUtils::SetShowWindow(src, "src", 10, 20); imshow("src", src); Mat src2 = imread("E:/DCIM/hrd/h3.jpg"); CvUtils::MatResize(src2); CvUtils::SetShowWindow(src2, "src2", 300, 20); imshow("src2", src2); //定义Sift的基本参数 int numFeatures = 500; //创建detector存放到KeyPoints中 Ptr<SIFT> detector = SIFT::create(numFeatures); vector<KeyPoint> keypoints, keypoints2; detector->detect(src, keypoints); detector->detect(src2, keypoints2); //打印Keypoints cout << "Keypoints:" << keypoints.size() << endl; cout << "Keypoints2:" << keypoints2.size() << endl; Mat drawsrc, drawsrc2; drawKeypoints(src, keypoints, drawsrc); CvUtils::SetShowWindow(drawsrc, "drawsrc", 10, 20); imshow("drawsrc", drawsrc); drawKeypoints(src2, keypoints2, drawsrc2); CvUtils::SetShowWindow(drawsrc2, "drawsrc2", 300, 20); imshow("drawsrc2", drawsrc2); //计算特征点描述符,特征向量提取 Mat dstSIFT, dstSIFT2; Ptr<SiftDescriptorExtractor> descriptor = SiftDescriptorExtractor::create(); descriptor->compute(src, keypoints, dstSIFT); descriptor->compute(src2, keypoints2, dstSIFT2); cout << dstSIFT.cols << endl; cout << dstSIFT2.rows << endl; //进行BFMatch暴力匹配 BFMatcher matcher(NORM_L2); //定义匹配结果变量 vector<DMatch> matches; //实现描述符之间的匹配 matcher.match(dstSIFT, dstSIFT2, matches); //定义向量距离的最大值与最小值 double max_dist = 0; double min_dist = 1000; for (int i = 1; i < dstSIFT.rows; ++i) { //通过循环更新距离,距离越小越匹配 double dist = matches[i].distance; if (dist > max_dist) max_dist = dist; if (dist < min_dist) min_dist = dist; } cout << "min_dist=" << min_dist << endl; cout << "max_dist=" << max_dist << endl; //匹配结果筛选 vector<DMatch> goodMatches; for (int i = 0; i < matches.size(); ++i) { double dist = matches[i].distance; if (dist < 2 * min_dist) goodMatches.push_back(matches[i]); } cout << "goodMatches:" << goodMatches.size() << endl; Mat result; //匹配特征点天蓝色,单一特征点颜色随机 drawMatches(src, keypoints, src2, keypoints2, goodMatches, result, Scalar(255, 255, 0), Scalar::all(-1)); CvUtils::SetShowWindow(result, "Result", 100, 20); imshow("Result", result); waitKey(0); return 0; }
源码地址
https://github.com/Vaccae/OpenCVDemoCpp.git
这个Demo我也整合到OpenCV练习Demo中了,GitHub上不去的朋友,可以击下方的原文链接跳转到码云的地址,关注【微卡智享】公众号,回复【源码】可以下载我的所有开源项目。
完
扫描二维码
获取更多精彩
微卡智享
「 往期文章 」
-
SIFT特征2-基于OpenCV和C++的算法实现
2017-05-18 10:25:40SIFT:尺度不变特征变换匹配算法详解 本章将要讲解的内容如下所示: 1)SIFT算法的简介 2)SIFT算法的实现细节 3)SIFT算法的应用领域 4)SIFT算法的改进与扩展 一 SIFT算法的简介 1)传统的特征... -
sift匹配算法Match
2017-09-13 15:19:34sift匹配算法Matchsift匹配算法Matchsift匹配算法Matchsift匹配算法Matchsift匹配算法Matchsift匹配算法Match -
c++ opencv4.3 sift匹配
2020-11-04 12:59:42c++ opencv4.3 sift匹配 main.cpp int main() { vector<KeyPoint> keypoints1, keypoints2; Mat img1,img2,descriptors1, descriptors2; int numFeatures = 500;//特征点最大个数 int numlines = 50;//... -
SIFT算法代码实现(C++、opencv3版本)
2018-08-13 01:55:41/* 反馈回原图像大小,特征点的位置 */ float sx, sy; /* 金字塔中特征点的位置*/ int octave, level; /*金字塔中,特征点所在的阶梯、层次*/ float scale, ori, mag; /*所在层的绝对尺度absolute_... -
surf,sift算法配准,利用Ransac去除误匹配,c++源码
2018-09-14 10:44:57在windows上利用OpenCV和vs2010实现了sift和surf粗配准,利用Ransac实现精确配准,C++源码,可以运行。 -
【Shi-Tomasi角点检测+SIFT特征匹配】OpenCV&C++实现
2019-11-06 19:14:15在进行SIFT特征提取时,由于会提取数量较多的尺度空间特征点,会导致特征向量提取和特征点匹配环节的用时较长。在三维测量等应用条件下,角点是进行测量的关键点,因此采用Shi-Tomasi或Harris角点检测提取关键的特征... -
SIFT算法的C++实现源代码
2012-04-27 16:04:32用C++编写的SIFT算法,非常合理的阈值,效果很好的sift实现。 -
基于C++的基本库实现SIFT特征提取与匹配
2022-05-08 10:51:24基于C++的基本库实现了SIFT特征提取与匹配,不需调用如OpenCV等库函数。本代码基于ezSIFT代码,在其基础上进行了一定程度的简化优化,同时调整了代码结构并添加了注释。 -
SIFT算法,实现两张图片的特征提取与特征匹配
2021-04-22 22:11:22SIFT算法用时是:1秒 img1的特征描述矩阵大小[]特征向量个数: 特征向量的维数: 128 img2的特征描述矩阵大小[]特征向量个数: 特征向量的维数: 128 匹配的个数: 最大距离: 最小距离: goodMatch个数: 匹配率: -
sift 算法 C++
2014-04-10 13:03:04经典的sift算法,可以用于特征提取和配准,小伙伴们加油!!! -
SIFT特征提取C++
2011-10-31 22:14:28Sift是David Lowe于1999年提出的局部特征描述子,可以处理两幅图像之间发生平移、旋转、仿射变换情况下的匹配问题,具有良好的不变性和很强的匹配能力。SIFT算法是一种提取局部特征的算法,也是一种模式识别技术,其... -
main_SURF拼接_surf特征匹配_c++surf实现_VS2019_
2021-09-30 09:44:07c++,vs2019,surf实现图像拼接 -
RobHess的SIFT-RANSAC算法源码图像特征点匹配
2017-09-22 10:41:06RobHess的SIFT-RANSAC算法源码图像特征点匹配,综合各大程序自己修改的! 支持平台opencv1.0以上,3.0一下的! 本人使用的是opencv2.43+VS2013!! -
sift特征匹配C源码
2018-09-14 10:38:42sift算法,使用C语言实现的源码,在windows上使用vs2010上可以运行,需要配置OpenCV使用 -
sift算法特征点如何匹配?
2021-01-14 23:22:17题主应该是如果只是想知道SIFT是怎么在两幅图像间进行匹配的话,下面是我总结的四种匹配方法,希望对题主了解SIFT匹配过程有帮助。一般在词袋模型中,为了提高检索的精度,你可以通过很多的trick来提高其精度(mAP),... -
OpenCV3.0实现SIFT特征提取+RANSAC剔除误匹配点
2018-11-21 16:22:10OpenCV3.0实现SIFT特征提取+RANSAC剔除误匹配点,首先进行提取SIFT特征点。然后再通过RANSAC剔除误匹配点 -
Sift特征点提取+匹配代码实现
2022-02-14 16:23:56#include"opencv2/opencv.hpp" #include"opencv2/xfeatures2d.hpp" using namespace std; using namespace cv; int main() ... Mat src1 = imread("image1.png");... Mat src2 = imread("image2.... sift = cv::xfeatur -
Harris、Fast、ORB、SIFT、SIFT+Lowe's、SURF、SURF+Lowe's七种图像特征匹配算法
2022-03-14 08:25:06自己论文里需要用的算法,这里放上来的是验证后可用的版本,包括sln文件、cpp文件,小白也能用。环境win10+VS2017+Opencv2.4.13,配置环境不懂的可以在百度上搜索,Openc版本建议和我一致,新版的因为版权过期删掉了... -
OpenCv-C++-SIFT特征检测
2018-11-27 22:14:16尺度不变特征转换(Scale-invariant feature transform或SIFT)是一种电脑视觉的算法用来侦测与描述影像中的局部性特征,它在空间尺度中寻找极值点,并提取出其位置、尺度、旋转不变量,此算法由 David Lowe在19... -
图像特征提取与匹配之SIFT算法
2018-09-17 22:27:57推荐阅读: David G. Lowe, "Distinctive image features from scale-invariant keypoints,...sift图像特征提取与匹配算法代码(友人,onezeros博客): http://blog.csdn.net/onezeros/archive/2011/01/05/6117704.aspx
-
<em>SIFT特征匹配算法</em>用<em>C语言</em>实现的<em>SIFT特征匹配算法</em>,不用配置GSL库,会<em>C语言</em>的人都能看懂,<em>SIFT</em>的函数用<em>C语言</em>重新实现,每
-
<em>sift特征匹配算法</em><em>sift特征匹配算法</em>
-
<em>SIFT特征匹配算法</em>-<em>SIFT</em>.rar<em>SIFT特征匹配算法</em>-<em>SIFT</em>.rar <em>SIFT</em>:Scale Invariant Feature Transform <em>SIFT特征匹
-
<em>SIFT特征</em>提取与<em>匹配算法</em>Rob Hess的<em>SIFT算法</em>代码,用OPENCV2.4.0实现,用于图像<em>特征</em>提取与拼接
-
<em>sift</em>图像<em>匹配算法</em>原版<em>sift算法</em>,已验证,效果非常好,用于两幅图片的<em>匹配</em>