opencv成长之路:特征点检测与图像匹配
python opencv 特征点匹配算法
Python是一门功能强大的编程语言,而OpenCV则是一款开放源代码的计算机视观方面的库。
特征点匹配是计算机视觉领域中非常关键和基础的技术之一。
本文将介绍Python和OpenCV中常用的特征点匹配算法。
一、SIFT算法尺度不变特征变换(Scale-Invariant Feature Transform,SIFT)是一种用于提取图像局部特征的算法。
它能够在不同尺度和旋转角度上找到关键点,并且对图像的缩放、旋转保持不变性。
SIFT算法主要分为四个步骤:尺度空间极值检测、关键点定位、关键点方向确定和关键点描述。
在OpenCV中,可以使用cv2.xfeatures2d.SIFT_create()函数来创建SIFT对象,然后调用detectAndCompute()方法来提取关键点和描述符。
二、SURF算法加速稳健特征检测(Speeded-Up Robust Features,SURF)是一种基于Hessian矩阵的特征提取算法。
它比SIFT算法更快速,并且在某些情况下比SIFT算法具有更好的性能。
SURF算法也可以实现尺度和旋转不变性。
在OpenCV中,可以使用cv2.xfeatures2d.SURF_create()函数来创建SURF对象,并同样调用detectAndCompute()方法来提取关键点和描述符。
三、ORB算法Oriented FAST and Rotated BRIEF(ORB)是一种基于FAST关键点检测和BRIEF描述符的算法。
它在速度和性能之间取得了很好的平衡,具有较快的速度和较好的检测性能。
ORB算法对旋转具有不变性,但对于尺度变换的不变性较差。
在OpenCV中,可以使用cv2.ORB_create()函数来创建ORB对象,然后同样调用detectAndCompute()方法来提取关键点和描述符。
四、匹配算法特征点提取之后,就需要进行特征点的匹配。
常用的特征点匹配算法包括暴力匹配、FLANN匹配等。
pythonopencv3基于ORB的特征检测和BF暴力匹配knn匹配flann匹配
pythonopencv3基于ORB的特征检测和BF暴力匹配knn匹配flann匹配Python OpenCV3中的ORB特征检测和BF暴力匹配以及FLANN匹配是计算机视觉中常用的技术,用于在图像中寻找相似的特征点并进行匹配。
下面将详细介绍这些技术以及如何使用它们。
一、ORB特征检测ORB(Oriented FAST and Rotated BRIEF)是一种用于检测图像特征的算法。
它结合了FAST特征检测和BRIEF特征描述子,并对其进行了改进,以便在实时性和准确性之间取得较好的平衡。
使用OpenCV中的ORB特征检测算法需要使用以下步骤:1. 创建ORB对象:使用cv2.ORB_create(方法创建ORB对象。
3. 绘制特征点:使用cv2.drawKeypoints(方法绘制特征点,传入原始图像、特征点和输出图像。
二、BF暴力匹配BF(Brute-Force)暴力匹配是一种简单但较慢的特征点匹配算法。
它通过计算两组特征点之间的欧氏距离,找到距离最近的特征点对。
使用BF暴力匹配算法需要使用以下步骤:1. 创建BFMatcher对象:使用cv2.BFMatcher_create(方法创建BFMatcher对象。
2. 匹配特征点:调用BFMatcher对象的match(方法,传入两组特征描述子,方法将返回最佳匹配的特征点对。
3. 绘制匹配结果:使用cv2.drawMatches(方法绘制匹配结果,传入原始图像和两组特征点。
三、FLANN匹配FLANN(Fast Approximate Nearest Neighbors)是一种快速近似最近邻算法,它可以在大型数据集上进行高效的最近邻。
在图像匹配中,它可以加速特征点匹配的过程。
使用FLANN匹配算法需要使用以下步骤:1. 创建FLANN匹配器:使用cv2.FlannBasedMatcher(方法创建FLANN匹配器对象。
2. 创建索引:调用BFMatcher对象的knnMatch(方法,传入两组特征描述子和最近邻数k,方法将返回最佳匹配的特征点对。
opencv 拼接原理
OpenCV图像拼接的原理主要分为两个阶段:图像对齐/配准(image alignment/Registration)和图像合成/融合(image Compositing)。
在图像对齐/配准阶段,主要包括以下步骤:
1. 特征点检测与图像匹配:这是确定两张需要拼接的图像之间相同部分的关键步骤,通过检测并比对两张图片的特征点来确定如何对齐这两张图片。
2. 计算图像间的变换矩阵:根据特征点的匹配结果,计算出对齐两张图片所需要的仿射变换矩阵。
3. 自动校准:这一步是为了更精确地对齐图像,可能需要进行一些微调。
4. 图像变形:使用上一步计算出的变换矩阵,将一张图片变形为另一张图片的形状。
在图像合成/融合阶段,主要包括以下步骤:
5. 计算接缝:为了使拼接后的图像看起来更自然,需要在两张图片之间创建一个接缝。
这一步会考虑到颜色、亮度等因素,使得接缝处不易被人眼察觉。
6. 图像融合:将接缝处的像素进行特殊处理,使得它们能够融入周围环境,从而得到最终的全景图或多重视图。
此外,OpenCV还提供了Stitcher类及其stitch方法用于实现图像拼接。
这些函数和类使得用户可以方便地调用上述算法,而无需自己编写复杂的代码来实现这些功能。
使用 opencv 中的特征匹配和透视变换
特征匹配和透视变换是计算机视觉领域中的重要技术,它们广泛应用于图像处理、目标识别、机器人导航等领域。
在opencv中,特征匹配和透视变换是两个非常重要的功能模块,能够帮助开发者实现各种复杂的图像处理任务。
本文将为大家介绍opencv中特征匹配和透视变换的相关知识和应用实例。
一、特征匹配特征匹配是计算机视觉领域中的一项基础技术,它的主要作用是在两幅图像中寻找相似的特征点,并将它们进行匹配。
在opencv中,特征匹配主要依靠SIFT(尺度不变特征变换)算法和SURF(加速稳健特征)算法来实现。
这两种算法都能够在图像中提取出关键点和它们的描述子,然后根据描述子的相似度来进行匹配。
特征匹配在图像配准、目标跟踪等领域中有着广泛的应用。
比如在图像配准中,我们可以利用特征匹配来将两幅图像进行配准,使它们在同一坐标系下对齐;在目标跟踪中,我们可以通过特征匹配来实现目标的快速识别和跟踪。
特征匹配是计算机视觉中非常重要的一环,它为图像处理和分析提供了基础支持。
二、透视变换透视变换是一种常用的图像变换技术,它可以将原始图像投影到一个新的空间中,从而实现图像的旋转、放缩、重构等操作。
在opencv 中,透视变换主要依靠透视变换矩阵来实现,该矩阵能够将原始图像的坐标映射到新空间中的坐标。
透视变换在计算机视觉领域中有着广泛的应用。
比如在图像校正中,我们可以利用透视变换来对图像进行校正,使其在视觉上更加真实和准确;在三维重构中,我们可以通过透视变换来还原三维场景的视图,从而实现对场景的深度理解和分析。
透视变换是计算机视觉中一个非常重要的图像处理技术,它为图像的变换和重构提供了重要手段。
三、opencv中的特征匹配和透视变换实例下面我们以一个例子来演示opencv中特征匹配和透视变换的应用。
假设我们有两幅图像A和B,我们希望通过特征匹配和透视变换将图像B对齐到图像A上。
1、我们利用SIFT算法在图像A和B中提取特征点,并计算它们的描述子。
Opencv中特征点提取和特征匹配算法详解(ORBSIFTSURFFAST)
Opencv中特征点提取和特征匹配算法详解(ORBSIFTSURFFAST)OpenCV是一个开源的计算机视觉库,提供了许多用于图像处理和计算机视觉任务的算法和函数。
特征点提取和特征匹配是计算机视觉中常用的任务之一,可以在图像中找到具有独特性质的特征点,并使用这些特征点进行图像匹配、物体识别和姿态估计等任务。
在OpenCV中,有多种特征点提取和特征匹配算法可供选择,其中包括ORB、SIFT、SURF和FAST 等。
ORB(Oriented FAST and Rotated BRIEF)是一种基于FAST角点检测和BRIEF描述符的特征点提取和特征匹配算法。
它的主要优势在于计算速度较快,适用于实时的计算机视觉应用。
ORB算法首先使用FAST角点检测算法在图像中检测角点,然后计算角点的Oriented FAST角度和尺度。
接下来,在每个角点周围的区域中计算二进制描述符,用于描述角点的特征。
最后,使用二进制描述符进行特征匹配,可以使用暴力匹配、近邻算法或FLANN算法等进行匹配。
SIFT(Scale-Invariant Feature Transform)是一种基于尺度不变特征变换的特征点提取和特征匹配算法。
SIFT算法通过构建尺度空间和特征点检测器来提取具有尺度不变性的特征点。
在尺度空间中,SIFT算法使用不同的尺度和方向的高斯滤波器来检测具有独特性质的特征点。
然后,通过计算特征点周围区域的梯度和方向来为每个特征点计算描述符。
最后,可以使用距离度量或RANSAC算法进行特征点的匹配。
SURF(Speeded-Up Robust Features)是一种基于加速鲁棒特征(speeded-up robust features)的特征点提取和特征匹配算法。
SURF算法主要通过构建尺度空间和计算积分图像来加速特征点提取和匹配的过程。
在尺度空间中,SURF算法使用高斯滤波器来检测不同尺度的特征。
然后,通过计算每个特征点周围区域的Haar小波响应来计算特征点的描述符。
OpenCV——SIFT特征检测与匹配
OpenCV——SIFT特征检测与匹配SIFT特征和SURF特征⽐较⽐较项⽬SIFT SURF尺度空间极值检测使⽤⾼斯滤波器,根据不同尺度的⾼斯差(DOG)图像寻找局部极值使⽤⽅形滤波器,利⽤海森矩阵的⾏列式值检测极值,并利⽤积分图加速运算关键点定位通过邻近信息插补来定位与SIFT类似⽅向定位通过计算关键点局部邻域的⽅向直⽅图,寻找直⽅图中最⼤值的⽅向作为关键点的主⽅向通过计算特征点周围像素点x,y⽅向的哈尔⼩波变换,将x、y⽅向⼩波变换的和向量的最⼤值作为特征点⽅向特征描述⼦是关键点邻域⾼斯图像梯度⽅向直⽅图统计结果的⼀种表⽰,是16*8=128维向量是关键点邻域2D离散⼩波变换响应的⼀种表⽰,是16*4=64维向量应⽤中的主要区别通常在搜索正确的特征时更加精确,当然也更加耗时描述⼦⼤部分基于强度的差值,计算更快捷SIFT特征基本介绍SIFT(Scale-Invariant Feature Transform)特征检测关键特征:建⽴尺度空间,寻找极值关键点定位(寻找关键点准确位置与删除弱边缘)关键点⽅向指定关键点描述⼦建⽴尺度空间,寻找极值⼯作原理1. 构建图像⾼斯⾦字塔,求取DOG,发现最⼤与最⼩值在每⼀级2. 构建的⾼斯⾦字塔,每⼀层根据sigma的值不同,可以分为⼏个待级,最少有4个。
关键点定位我们在像素级别获得了极值点的位置,但是更准确的值应该在亚像素位置,如何得到--这个过程称为关键点(准确/精确)定位。
删除弱边缘--通过Hassian矩阵特征值实现,⼩于阈值⾃动舍弃。
关键点⽅向指定求得每⼀层对应图像的梯度,根据给定的窗⼝⼤⼩计算每个⾼斯权重,sigma=scale*1.5, 0-360之间建⽴36个直⽅图Bins找最⾼峰对应的Bin,⼤于max*80%的都保留这样就实现了旋转不变性,提⾼了匹配时候的稳定性⼤约有15%的关键点会有多个⽅向关键点描述⼦拟合多项式插值寻找最⼤Peak得到描述⼦ = 4*4*8=128构造函数cv::xfeatures2d::SIFT::create(int nfeatures = 0,int nOctaveLayers = 3, --⾼斯⾦字塔乘积数double contrastThreshold = 0.04, --对⽐度double edgeThreshold = 10, --边缘阈值,⼀般默认10就⾏double sigma = 1.6)1 #include <opencv2/opencv.hpp>2 #include <opencv2/xfeatures2d.hpp>3 #include <iostream>45using namespace cv;6using namespace cv::xfeatures2d;7using namespace std;89int main(int argc, char** argv) {10 Mat src = imread("test.jpg", IMREAD_GRAYSCALE);11if (src.empty()) {12 printf("could not load image...\n");13return -1;14 }15 namedWindow("input image", CV_WINDOW_AUTOSIZE);16 imshow("input image", src);1718// SIFT特征点检测19int minHessian = 100;20 Ptr<SIFT> detector = SIFT::create(minHessian);//和surf的区别:只是SURF→SIFT21 vector<KeyPoint> keypoints;22 detector->detect(src, keypoints, Mat());//找出关键点2324// 绘制关键点25 Mat keypoint_img;26 drawKeypoints(src, keypoints, keypoint_img, Scalar::all(-1), DrawMatchesFlags::DEFAULT);27 imshow("KeyPoints Image", keypoint_img);2829 waitKey(0);30return0;31 }。
opencv sift 特征点 匹配 指标
SIFT(尺度不变特征变换)是一种用于检测和描述图像中的关键特征点的算法。
在 OpenCV 中,SIFT 算法提供了用于检测和匹配特征点的功能。
以下是一些与OpenCV 中 SIFT 特征点匹配相关的指标和步骤:
SIFT 特征点检测:
1.导入 OpenCV:
2.读取图像:
3.初始化 SIFT 检测器:
4.检测关键点和计算描述符:
SIFT 特征点匹配:
1.使用 BFMatcher 进行特征点匹配:
这里使用的是 Brute-Force 匹配器(BFMatcher),knnMatch返回每个查询描述符的最佳两个匹配。
2.应用比率测试来筛选匹配:
这个比率测试是一种常见的方法,用于剔除不够精确的匹配。
3.可视化匹配结果:
匹配指标:
在进行特征点匹配后,可以使用不同的指标来评估匹配的好坏。
一些常用的指标包括:
•匹配点数量:len(good_matches)给出了匹配的特征点数量。
•匹配比率:通过计算len(good_matches) / len(kp1)或len(good_matches) / min(len(kp1), len(kp2))可以得到匹配比率。
•单应性矩阵(Homography Matrix):如果你要估计两幅图像之间的单应性变换,可以使用cv2.findHomography函数,并根据单应性矩阵计算匹配的准确性。
这些指标可以帮助你评估 SIFT 特征点匹配的性能。
在实际应用中,你可能还需要根据具体的场景和需求进行进一步的评估和优化。
OpenCV实现特征检测和特征匹配方法汇总
OpenCV实现特征检测和特征匹配⽅法汇总⽬录1.SURF2.SIFT3.ORB4.FAST5.Harris⾓点⼀幅图像中总存在着其独特的像素点,这些点我们可以认为就是这幅图像的特征,成为特征点。
计算机视觉领域中的很重要的图像特征匹配就是⼀特征点为基础⽽进⾏的,所以,如何定义和找出⼀幅图像中的特征点就⾮常重要。
这篇⽂章我总结了视觉领域最常⽤的⼏种特征点以及特征匹配的⽅法。
在计算机视觉领域,兴趣点(也称关键点或特征点)的概念已经得到了⼴泛的应⽤,包括⽬标识别、图像配准、视觉跟踪、三维重建等。
这个概念的原理是,从图像中选取某些特征点并对图像进⾏局部分析,⽽⾮观察整幅图像。
只要图像中有⾜够多可检测的兴趣点,并且这些兴趣点各不相同且特征稳定,能被精确地定位,上述⽅法就⼗分有效。
以下是实验⽤的图像:第⼀幅是⼿机抓拍的风景图,第⼆幅是遥感图像。
1.SURF特征检测的视觉不变性是⼀个⾮常重要的概念。
但是要解决尺度不变性问题,难度相当⼤。
为解决这⼀问题,计算机视觉界引⼊了尺度不变特征的概念。
它的理念是,不仅在任何尺度下拍摄的物体都能检测到⼀致的关键点,⽽且每个被检测的特征点都对应⼀个尺度因⼦。
理想情况下,对于两幅图像中不同尺度的的同⼀个物体点,计算得到的两个尺度因⼦之间的⽐率应该等于图像尺度的⽐率。
近⼏年,⼈们提出了多种尺度不变特征,本节介绍其中的⼀种:SURF特征。
SURF全称为“加速稳健特征”(Speeded Up Robust Feature),我们将会看到,它们不仅是尺度不变特征,⽽且是具有较⾼计算效率的特征。
我们⾸先进⾏常规的特征提取和特征点匹配,看看效果如何。
#include "highgui/highgui.hpp"#include "opencv2/nonfree/nonfree.hpp"#include "opencv2/legacy/legacy.hpp"#include <iostream>using namespace cv;using namespace std;int main(){Mat image01 = imread("2.jpg", 1); //右图Mat image02 = imread("1.jpg", 1); //左图namedWindow("p2", 0);namedWindow("p1", 0);imshow("p2", image01);imshow("p1", image02);//灰度图转换Mat image1, image2;cvtColor(image01, image1, CV_RGB2GRAY);cvtColor(image02, image2, CV_RGB2GRAY);//提取特征点SurfFeatureDetector surfDetector(800); // 海塞矩阵阈值,在这⾥调整精度,值越⼤点越少,越精准 vector<KeyPoint> keyPoint1, keyPoint2;surfDetector.detect(image1, keyPoint1);surfDetector.detect(image2, keyPoint2);//特征点描述,为下边的特征点匹配做准备SurfDescriptorExtractor SurfDescriptor;Mat imageDesc1, imageDesc2;pute(image1, keyPoint1, imageDesc1);pute(image2, keyPoint2, imageDesc2);//获得匹配特征点,并提取最优配对FlannBasedMatcher matcher;vector<DMatch> matchePoints;matcher.match(imageDesc1, imageDesc2, matchePoints, Mat());cout << "total match points: " << matchePoints.size() << endl;Mat img_match;drawMatches(image01, keyPoint1, image02, keyPoint2, matchePoints, img_match);namedWindow("match", 0);imshow("match",img_match);imwrite("match.jpg", img_match);waitKey();return 0;}由上⾯的特征点匹配的效果来看,匹配的效果还是相当糟糕的,如果我们拿着这样⼦的匹配结果去实现图像拼接或者物体追踪,效果肯定是极差的。
OpenCV特征提取与图像检索实现(附代码)
OpenCV特征提取与图像检索实现(附代码)“拍立淘”“一键识花”“街景匹配”……不知道大家在使用这些神奇的功能的时候,有没有好奇过它们背后的技术原理?其实这些技术都离不开最基本的图像检索技术。
本篇文章我们就将对这一技术的原理进行介绍,并通过一个简单的Python脚本来实现一个最基本的图像检索demo。
▌图像特征首先我们需要明白图像特征是什么以及它的使用方法。
图像特征是一种简单的图像模式,基于这种模式我们可以描述我们在图像上所看到的内容。
例如,在一张跟猫有关的图片中,猫咪的眼睛就可以作为这幅图像的特征。
特征在(包括但不限于)计算机视觉中的主要作用是将视觉信息转换为向量空间表示。
这种向量空间表示让我们可以利用数学运算对其进行处理,例如通过计算寻找相似向量(这可以用来寻找相似图像或图像中的相似目标)。
▌如何从图像中获取特征?从图像中获取特征的方法有两种,第一种是通过提取图像描述符实现(白盒算法);第二种通过基于神经网络的方法实现(黑盒算法)。
本文主要介绍第一种方法。
特征提取的算法有很多,最常用的有:SURF、ORB、SIFT、BRIEF等。
这些算法大多是基于图像梯度的。
为了简化安装需求,本教程使用的是KAZE描述符,因为其他描述符在python的基础OpenCV库中没有提供。
下面是特征提取器的实现代码:import cv2import numpy as npimport scipyfrom scipy.misc import imreadimport cPickle as pickleimport randomimport osimport matplotlib.pyplot as plt# Feature extractor# 特征提取器def extract_features(image_path, vector_size=32): image = imread(image_path, mode='RGB')try:# Using KAZE, cause SIFT, ORB and other was moved to additional module# which is adding addtional pain during install#此处为了简化安装步骤,使用KAZE,因为SIFT/ORB以及其他特征算子需要安#装额外的模块alg = cv2.KAZE_create()# Finding image keypoints#寻找图像关键点kps = alg.detect(image)# Getting first 32 of them.#计算前32个# Number of keypoints is varies depend on image size and color pallet#关键点的数量取决于图像大小以及彩色调色板# Sorting them based on keypoint response value(bigger is better)#根据关键点的返回值进行排序(越大越好)kps = sorted(kps, key=lambda x:-x.response)[:vector_size]# computing descriptors vector#计算描述符向量kps, dsc = pute(image, kps)# Flatten all of them in one big vector - our feature vector# 将其放在一个大的向量中,作为我们的特征向量dsc = dsc.flatten()# Making descriptor of same size# 使描述符的大小一致# Descriptor vector size is 64#描述符向量的大小为64needed_size = (vector_size * 64)if dsc.size# if we have less the 32 descriptors then just adding zeros# at the end of our feature vector#如果少于32个描述符,则在特征向量后面补零dsc = np.concatenate([dsc,np.zeros(needed_size - dsc.size)])except cv2.error as e:print 'Error: ', ereturn None return dscdef batch_extractor(images_path,pickled_db_path='features.pck'):files = [os.path.join(images_path, p) for p insorted(os.listdir(images_path))]result = {}for f in files:print 'Extracting features from image %s' % fname = f.split('/')[-1].lower()result[name] = extract_features(f)# saving all our feature vectors in pickled file# 将特征向量存于pickled 文件with open(pickled_db_path, 'w') as fp:pickle.dump(result, fp)OpenCV中的大多数特征提取算法的python接口都相同,所以如果你想要使用SIFT特征,只需要用SIFT_create替换KAZE_create就行。
特征点检测与匹配算法
特征点检测与匹配算法引言特征点检测与匹配算法是计算机视觉领域的重要研究方向之一。
它在图像处理、图像识别、目标跟踪等应用中发挥着重要的作用。
本文将从特征点检测的概念出发,逐步介绍特征点检测与匹配算法的原理、常用方法及其应用。
特征点检测概述特征点是图像中具有显著性、稳定性且可重复检测的图像区域。
特征点检测是指在图像中自动寻找这些具有特征性的点,并进行描述和匹配的过程。
特征点检测广泛应用于图像匹配、图像拼接、目标识别等领域。
特征点检测算法原理Harris角点检测算法Harris角点检测算法是一种经典的特征点检测算法。
它通过计算图像中每个像素点的Harris响应函数来判断其是否为角点。
Harris角点检测算法对图像的局部对比度和灰度变化进行了建模,能够检测出图像中的角点。
算法步骤: 1. 计算图像的灰度梯度。
2. 对每个像素计算一个自相关矩阵。
3. 计算自相关矩阵的Harris响应函数。
4. 设置一个阈值,根据Harris响应函数的值判断是否为角点。
SIFT算法尺度不变特征转换(SIFT)算法是一种常用的特征点检测算法。
SIFT算法通过使用高斯差分函数来检测图像中的关键点,并计算关键点的描述子,实现了对旋转、尺度缩放等变换的不变性。
算法步骤: 1. 构建高斯金字塔。
2. 在金字塔的每一层上使用高斯差分函数寻找关键点。
3. 基于关键点的位置和尺度,生成关键点的描述子。
4. 使用描述子进行关键点的匹配。
SURF算法加速稳健特征(SURF)算法是一种基于SIFT算法的改进方法。
SURF算法通过加速计算和改进特征描述子的方式,提高了特征点检测的效率和稳定性。
算法步骤: 1. 使用高斯滤波器构建图像金字塔。
2. 使用盒子滤波器计算图像的Hessian矩阵。
3. 使用Hessian矩阵检测图像中的极值点作为特征点。
4. 根据特征点的尺度和方向计算特征点的描述子。
特征点匹配算法特征点匹配是指在两幅图像之间寻找相同或相似的特征点的过程。
图像处理中的特征点检测与匹配
图像处理是一门研究如何对图像进行自动分析和处理的学科。
在许多图像处理应用中,特征点检测与匹配是一个非常重要的步骤。
特征点是图像中具有独特性质的点,如边缘、角点、纹理等。
检测和匹配这些特征点可以用于图像配准、目标检测、图像识别等多种任务。
特征点检测是指在图像中自动找出具有显著性质的点。
常用的特征点检测算法有Harris角点检测、FAST角点检测、SIFT特征点检测等。
Harris角点检测是一种基于图像灰度变化的角点检测算法,通过计算图像中每个像素的灰度变化与其周围像素的灰度变化的差异来判断是否为角点。
FAST角点检测是一种基于强角度上边缘的响应速度的角点检测算法,通过检测图像中的边缘直线来判断是否为角点。
SIFT 特征点检测是一种基于图像区域的局部特征检测算法,通过计算图像中每个像素的局部梯度方向和幅值来判断是否为特征点。
特征点匹配是指将两幅图像中的特征点进行对应。
常用的特征点匹配算法有最近邻算法、RANSAC算法、随机采样一致性算法等。
最近邻算法是一种简单的特征点匹配算法,通过计算两个特征点之间的欧式距离来找出最相似的点对。
RANSAC算法是一种基于随机采样的一致性算法,通过随机选择一些特征点来计算模型参数,并根据残差误差来判断是否为内点。
随机采样一致性算法是一种改进的RANSAC算法,通过多次迭代和局部优化来提高匹配精度。
特征点检测与匹配在许多图像处理应用中起着重要作用。
在图像配准中,通过检测和匹配图像中的特征点可以实现图像的对齐和重叠,从而得到更好的配准结果。
在目标检测中,通过检测和匹配图像中的特征点可以实现目标的定位和识别,从而实现目标检测和跟踪。
在图像识别中,通过检测和匹配图像中的特征点可以实现对图像内容的理解和推断,从而实现图像识别和分类。
总之,特征点检测与匹配是图像处理中的一个重要研究方向。
通过检测和匹配图像中的特征点,可以实现图像的分析、理解和处理。
特征点检测与匹配在许多图像处理应用中起着重要作用,如图像配准、目标检测、图像识别等。
详解opencvPython特征检测及K-最近邻匹配
详解opencvPython特征检测及K-最近邻匹配鉴于即将启程旅⾏,先上传篇简单的图像检索介绍,与各位⼀起学习opencv的同学共勉⼀.特征检测图⽚的特征主要分为⾓点,斑点,边,脊向等,都是常⽤特征检测算法所检测到的图像特征·1.Harris⾓点检测先将图⽚转换为灰度模式,再使⽤以下函数检测图⽚的⾓点特征:dst=cv2.cornerHarris(src, blockSize, ksize, k[, dst[, borderType]])重点关注第三个参数,这⾥使⽤了Sobel算⼦,简单来说,其取为3-31间的奇数,定义了⾓点检测的敏感性,不同图⽚需要进⾏调试。
k 是 Harris ⾓点检测⽅程中的⾃由参数,取值参数为[0,04,0.06].2.DoG⾓点检测及SIFT特征变换Harris⾓点检测在⾯对图像尺度性发⽣改变时极其容易丢失图像细节,造成检测失误。
因此在检测图像特征时,常常我们需要⼀些拥有尺度不变性的特征检测算法。
DoG⾓点检测即将两幅图像在不同参数下的⾼斯滤波结果相减,得到DoG图。
步骤:⽤两个不同的5x5⾼斯核对图像进⾏卷积,然后再相减的操作。
重复三次得到三个差分图A,B,C。
计算出的A,B,C三个DOG图中求图B中是极值的点。
图B的点在当前由A,B,C共27个点组成的block中是否为极⼤值或者极⼩值。
若满⾜此条件则认为是⾓点。
SIFT对象会使⽤DoG检测关键点,并对每个关键点周围的区域计算特征向量。
事实上他仅做检测和计算,其返回值是关键点信息(关键点)和描述符。
#下列代码即先创建⼀个SIFT对象,然后计算灰度图像sift = cv2.xfeatures2d.SIFT_create()keypoints, descriptor = sift.detectAndCompute(gray, None)#sift对象会使⽤DoG检测关键点,对关键点周围的区域计算向量特征,检测并计算需要注意的是,返回的是关键点和描述符关键点是点的列表描述符是检测到的特征的局部区域图像列表介绍⼀下关键点的属性:pt: 点的x y坐标 size:表⽰特征的直径 angle: 特征⽅向 response: 关键点的强度 octave: 特征所在⾦字塔层级,算法进⾏迭代的时候,作为参数的图像尺⼨和相邻像素会发⽣变化octave属性表⽰检测到关键点所在的层级 ID:检测到关键点的IDSIFT特征不只具有尺度不变性,即使改变旋转⾓度,图像亮度或拍摄视⾓,仍然能够得到好的检测效果。
OpenCV2:特征匹配及其优化
OpenCV2:特征匹配及其优化在中对使⽤OpenCV2进⾏特征匹配的步骤做了⼀个简单的介绍,其匹配出的结果是⾮常粗糙的,在这篇⽂章中对使⽤OpenCV2进⾏匹配的细化做⼀个简单的总结。
主要包括以下⼏个内容:DescriptorMatcherDMatcherKNN匹配计算两视图的基础矩阵F,并细化匹配结果计算两视图的单应矩阵H,并细化匹配结果DescriptorMatcher 和 DMatcherDescriptorMatcher是匹配特征向量的抽象类,在OpenCV2中的特征匹配⽅法都继承⾃该类(例如:BFmatcher,FlannBasedMatcher)。
该类主要包含了两组匹配⽅法:图像对之间的匹配以及图像和⼀个图像集之间的匹配。
⽤于图像对之间匹配的⽅法的声明// Find one best match for each query descriptor (if mask is empty).CV_WRAP void match( const Mat& queryDescriptors, const Mat& trainDescriptors,CV_OUT vector<DMatch>& matches, const Mat& mask=Mat() ) const;// Find k best matches for each query descriptor (in increasing order of distances).// compactResult is used when mask is not empty. If compactResult is false matches// vector will have the same size as queryDescriptors rows. If compactResult is true// matches vector will not contain matches for fully masked out query descriptors.CV_WRAP void knnMatch( const Mat& queryDescriptors, const Mat& trainDescriptors,CV_OUT vector<vector<DMatch> >& matches, int k,const Mat& mask=Mat(), bool compactResult=false ) const;// Find best matches for each query descriptor which have distance less than// maxDistance (in increasing order of distances).void radiusMatch( const Mat& queryDescriptors, const Mat& trainDescriptors,vector<vector<DMatch> >& matches, float maxDistance,const Mat& mask=Mat(), bool compactResult=false ) const;⽅法重载,⽤于图像和图像集匹配的⽅法声明CV_WRAP void match( const Mat& queryDescriptors, CV_OUT vector<DMatch>& matches,const vector<Mat>& masks=vector<Mat>() );CV_WRAP void knnMatch( const Mat& queryDescriptors, CV_OUT vector<vector<DMatch> >& matches, int k,const vector<Mat>& masks=vector<Mat>(), bool compactResult=false );void radiusMatch( const Mat& queryDescriptors, vector<vector<DMatch> >& matches, float maxDistance,const vector<Mat>& masks=vector<Mat>(), bool compactResult=false );DMatcher 是⽤来保存匹配结果的,主要有以下⼏个属性CV_PROP_RW int queryIdx; // query descriptor indexCV_PROP_RW int trainIdx; // train descriptor indexCV_PROP_RW int imgIdx; // train image indexCV_PROP_RW float distance;在图像匹配时有两种图像的集合,查找集(Query Set)和训练集(Train Set),对于每个Query descriptor,DMatch中保存了和其最好匹配的Train descriptor。
cv2.drawmatches原理
cv2.drawmatches原理OpenCV库是计算机视觉领域中广泛使用的开源库,其中cv2模块是该库中最常用的部分之一。
cv2.drawmatches()函数是cv2模块中的一个重要函数,用于将匹配到的特征点在两张图像上进行可视化。
本文将介绍cv2.drawmatches()函数的原理。
一、背景知识在使用cv2.drawmatches()函数之前,需要了解特征点检测和匹配的相关知识。
特征点检测是计算机视觉中的一个重要任务,通过检测图像中的特征点(如角点、边缘等)来描述图像中的关键点。
特征点检测算法有很多种,如SIFT、SURF、ORB等。
匹配则是将两张图像中的特征点进行匹配,以确定它们之间的对应关系。
常用的特征匹配算法有FLANN匹配、暴力匹配等。
二、原理介绍cv2.drawmatches()函数的原理主要包括以下几个步骤:1.特征点检测和匹配:首先使用特征点检测算法在两张输入图像中检测出特征点,并使用匹配算法将它们进行匹配。
2.生成模板图像:根据匹配结果,生成一张模板图像,其中包含了所有匹配到的特征点。
3.绘制匹配结果:在模板图像的基础上,根据实际需要,在源图像上绘制匹配结果。
通常会使用颜色或线条等可视化方式来表示匹配关系。
具体来说,cv2.drawmatches()函数的工作原理如下:*输入参数:该函数需要传入两张待比较的源图像和一张模板图像。
源图像和模板图像都需要是灰度图像或二值图像,以便能够检测到特征点。
*特征点检测和匹配:函数首先对源图像和模板图像进行特征点检测和匹配,生成一个匹配结果列表。
*生成模板图像:根据匹配结果列表,生成一张包含所有匹配到的特征点的模板图像。
通常会使用模板图像中的特征点作为绘制的基础。
*绘制匹配结果:在源图像上绘制匹配结果,通常会使用颜色或线条等可视化方式来表示匹配关系。
具体绘制方式可以通过设置参数进行调整。
*输出结果:绘制完成后,cv2.drawmatches()函数将返回一个包含绘制结果的图像。
OPENCV成长之路(9)特征点检测与图像匹配
OPENCV成长之路(9)特征点检测与图像匹配OpenCV成长之路(9):特征点检测与图像匹配分类:OpenCV成长之路2014-01-0418:40840人阅读评论(3)收藏举报特征点检测与图像匹配称兴趣点、关键点,它是在图像中突出且具有代表意义的一些点,通过这些点我们可以用来识别图像、进行图像配准、进行3D重建等。
本文主要介绍OpenCV中几种定位与表示关键点的函数。
一、Harris角点角点是图像中最基本的一种关键点,它是由图像中一些几何结构的关节点构成,很多都是线条之间产生的交点。
Harris角点是一类比较经典的角点类型,它的基本原理是计算图像中每点与周围点变化率的平均值。
(1)(2)其中I(x+u,y+u)代表了点(x,y)邻域点的灰度值。
通过变换可以将上式变化为一个协方差矩阵求特征值的问题(2),具体数学原理本文不过多描述。
OpenCV的Hairrs角点检测的函数为cornerHairrs(),但是它的输出是一幅浮点值图像,浮点值越高,表明越可能是特征角点,我们需要对图像进行阈值化。
我们使用一张建筑图像来显示:1.int main()2.{3.Mat image=imread("../buliding.png");4.Mat gray;5.cvtColor(image,gray,CV_BGR2GRAY);6.7.Mat cornerStrength;8.cornerHarris(gray,cornerStrength,3,3,0.01);9.threshold(cornerStrength,cornerStrength,0.001,255,THRES H_BINARY);10.return0;11.}首先我们来说明一下cornerHairrs()这个函数参数的意思:前2参数是输入与输出,输入是一个灰度图像,输出是一个浮点图像,第三个参数指定角点分析的邻域,第4个参数实际上在角点求取过程中计算梯度图像的核窗口大小,第5个参数是它原理公式(2)中的一个系数。
OpenCV之特征匹配
OpenCV 之特征匹配OpenCV 中有两种特征匹配⽅法:暴⼒匹配 (Brute force matching) 和 最近邻匹配 (Nearest Neighbors matching)它们都继承⾃ DescriptorMatcher ,是基于特征描述符距离的匹配,根据描述符的不同,距离可以是 欧⽒距离,也可以是 汉明距1 暴⼒匹配⾸先,任取图像 A 的⼀个特征描述符,计算它到图像 B 中所有特征描述符的距离;然后,将所得到的距离进⾏排序;最后,选择距离最短的特征,作为 A-B 的匹配点1.1 BFMatcherBFMatcher 属于 features2d 模块,继承⾃ DescriptorMatcher ,其 create() 函数如下:static Ptr<BFMatcher> create(int normType = NORM_L2, // normType, One of NORM_L1, NORM_L2, NORM_HAMMING, NORM_HAMMING2.bool crossCheck = false // crossCheck); 1) normType 距离类型SIFT 和SURF 的 HOG 描述符,对应欧⽒距离 L1 和 L2;ORB 和 BRISK 的 BRIEF 描述符,对应汉明距 HAMMING ;HAMMING2 则对应当 WTA_K = 3或4 时的 ORB 算法- 欧⽒距离:最常⽤的⼀种距离定义,指的是 n 维空间中,两点之间的实际距离L 1=∑I |src1(I )−src2|L 2=∑I (src1(I )−src2(I ))2- 汉明距离:计算机的异或操作,适⽤于⼆进制串描述符,如 BRIEF 描述符,定义如下:Hamming (a ,b )=n −1∑i =0a i ⊕b i2) crossCheck 交叉核对 - 如果在图像 B 中,特征 f b 是特征 f a 的最佳匹配,并且在图像 A 中,特征 f a 也是特征 f b 的最佳匹配,则称 (f a ,f b ) 为 "good match"1.2 代码⽰例特征匹配步骤如下:读图 -> 提取特征 -> 计算特征描述符 -> 暴⼒匹配 -> 显⽰匹配结果#include "opencv2/highgui.hpp"#include "opencv2/features2d.hpp"using namespace cv;int main(){// 1) readMat img1 = imread("box.png", IMREAD_GRAYSCALE);Mat img2 = imread("box_in_scene.png", IMREAD_GRAYSCALE);if (img1.empty() || img2.empty())return -1;// 2) detect and computePtr<SIFT> sift = SIFT::create();std::vector<KeyPoint> kps1, kps2;Mat desc1, desc2;sift->detectAndCompute(img1, Mat(), kps1, desc1);sift->detectAndCompute(img2, Mat(), kps2, desc2);// 3) matchPtr<BFMatcher> bfmatcher = BFMatcher::create(NORM_L2, true);std::vector<DMatch> matches;bfmatcher->match(desc1, desc2, matches);√()// 4) draw and showMat img_matches;drawMatches(img1, kps1, img2, kps2, matches, img_matches);imshow("BFMatcher", img_matches);waitKey();} crosscheck 分别为 true 和 false:2 最近邻匹配FLANN 是⼀个开源库,全称 Fast Library for Approximate Nearest Neighbors,它实现了⼀系列⾼维向量的近似最近邻搜索算法基于 FLANN 库的最近邻匹配算⼦ FlannBasedMatcher,在特征数据集较⼤或⼀些实时处理领域,其运⾏效率要远⾼于 BFMatcher OpenCV 中 FlannBasedMatcher 的定义如下:// This matcher trains cv::flann::Index on a train descriptor collection and calls its nearest search methods to find the best matches.// So, this matcher may be faster when matching a large train collection than the brute force matcher.class FlannBasedMatcher : public DescriptorMatcher{public:FlannBasedMatcher( const Ptr<flann::IndexParams>& indexParams=makePtr<flann::KDTreeIndexParams>(),const Ptr<flann::SearchParams>& searchParams=makePtr<flann::SearchParams>() );static Ptr<FlannBasedMatcher> create(); 2.1 距离⽐为了进⼀步提⾼特征匹配精度,David Lowe 提出了⼀种最近邻次近邻距离⽐的⽅法:- 取图像 A 的⼀个特征,搜索它到图像 B 距离最近的两个特征,距离分别记为d1和d2,只有当d1d2⼩于某个阈值时,才认为是 "goodmatch""good match" 的概率密度函数 PDF (Probability Density Function) 与最近邻次近邻距离⽐的关系,如下:2.2 代码⽰例取 distance ratio = 0.7,对⽐使⽤和不使⽤距离⽐滤波的匹配效果,代码如下:#include "opencv2/highgui.hpp"#include "opencv2/features2d.hpp"using namespace cv;const float kRatioThresh = 0.7f;int main(){// 1) readMat img1 = imread("box.png", IMREAD_GRAYSCALE);Mat img2 = imread("box_in_scene.png", IMREAD_GRAYSCALE);if (img1.empty() || img2.empty())return -1;// 2) detect feature and compute descriptorPtr<SIFT> sift = SIFT::create();std::vector<KeyPoint> kps1, kps2;Mat desc1, desc2;sift->detectAndCompute(img1, Mat(), kps1, desc1);sift->detectAndCompute(img2, Mat(), kps2, desc2);// 3) FLANN based matcherPtr<FlannBasedMatcher> knnmatcher = FlannBasedMatcher::create();std::vector<std::vector<DMatch> > matches;knnmatcher->knnMatch(desc1, desc2, matches, 2);// 4) filter matches using Lowe's distance ratio teststd::vector<DMatch> good_matches;for (size_t i = 0; i < matches.size(); i++){if (matches[i][0].distance < kRatioThresh*matches[i][1].distance){good_matches.push_back(matches[i][0]);}}// 5) draw and show matchesMat img_matches;drawMatches(img1, kps1, img2, kps2, good_matches, img_matches);imshow("Good Matches", img_matches);waitKey();} 匹配效果对⽐如下:3 应⽤⽰例特征匹配 + 平⾯单应性,在计算机视觉中有很多应⽤,如:透视校正,⽬标定位等3.1 透视校正4.1 中的⽰例,并不是标准的透视校正,因为是⼈拿着标定板旋转不同⾓度,使相机和标定板产⽣了相对的视⾓变换,⽽不是相机和整个场景之间多视图⼏何中,严格意思的透视校正,是指相机在不同的视⾓下,对同⼀场景成不同的像⽽进⾏的视⾓校正,如下图:在得到匹配点对 good_matches 之后,再执⾏如下代码,便可⽤于透视校正// Localize the objectstd::vector<Point2f> obj;std::vector<Point2f> scene;for (size_t i = 0; i < good_matches.size(); i++){// Get the keypoints from the good matchesobj.push_back(kps1[good_matches[i].queryIdx].pt);scene.push_back(kps2[good_matches[i].trainIdx].pt);}// estimate HMat H = findHomography(scene, obj, RANSAC);// warp sceneMat scene_warp;warpPerspective(img2, scene_warp, H, Size(1.35*img2.cols, img2.rows));// showimshow("scene_warp", scene_warp); 校正前后的结果如下:3.2 ⽬标定位得到匹配点对 good_matches 后,再执⾏如下代码,便可⽤于⽬标定位// Localize the objectstd::vector<Point2f> obj;std::vector<Point2f> scene;for (size_t i = 0; i < good_matches.size(); i++){// Get the keypoints from the good matchesobj.push_back(kps1[good_matches[i].queryIdx].pt);scene.push_back(kps2[good_matches[i].trainIdx].pt);}// estimate HMat H = findHomography(obj,scene, RANSAC);// get the corners from the image_1 ( the object to be "detected" )std::vector<Point2f> obj_corners(4);obj_corners[0] = Point2f(0, 0);obj_corners[1] = Point2f((float)img1.cols, 0);obj_corners[2] = Point2f((float)img1.cols, (float)img1.rows);obj_corners[3] = Point2f(0, (float)img1.rows);std::vector<Point2f> scene_corners(4);perspectiveTransform(obj_corners, scene_corners, H);// draw lines between the corners (the mapped object in the scene - image_2 )line(img_matches, scene_corners[0] + Point2f((float)img1.cols, 0), scene_corners[1] + Point2f((float)img1.cols, 0), Scalar(0,255,0)); line(img_matches, scene_corners[1] + Point2f((float)img1.cols, 0), scene_corners[2] + Point2f((float)img1.cols, 0), Scalar(0,255,0)); line(img_matches, scene_corners[2] + Point2f((float)img1.cols, 0), scene_corners[3] + Point2f((float)img1.cols, 0), Scalar(0,255,0)); line(img_matches, scene_corners[3] + Point2f((float)img1.cols, 0), scene_corners[0] + Point2f((float)img1.cols, 0), Scalar(0,255,0)); // show detected matchesimshow("Object detection", img_matches); ⽬标定位结果如下:参考资料OpenCV-Python Tutorials / Feature Detection and Description /OpenCV Tutorials / 2D Features framework (feature2d module) /OpenCV Tutorials / 2D Features framework (feature2d module) /Processing math: 100%。
OpenCvSharp通过特征点匹配图片
OpenCvSharp通过特征点匹配图⽚现在的⼿游基本都是重复操作,⼀个动作要等好久,结束之后继续另⼀个动作.很⿇烦,所以动起了⾃⼰写⼀个游戏辅助的⼼思.这个辅助本⾝没什么难度,就是通过不断的截图,然后从这个截图中找出预先截好的能代表相应动作的按钮或者触发条件的⼩图.找到之后获取该⼦区域的左上⾓坐标,然后通过windows API调⽤⿏标或者键盘做操作就⾏了.这⾥⾯最难的也就是找图了,因为要精准找图,⽽且最好能适应不同的分辨率下找图,所以在模板匹配的基础上,就有了SIFT和SURF的特征点找图⽅式.在写的过程中查找资料,⼤都是C++ 或者python的, 很少有原⽣的C#实现, 所以我就直接拿来翻译过来了(稍作改动).SIFT算法public static Bitmap MatchPicBySift(Bitmap imgSrc, Bitmap imgSub){using (Mat matSrc = imgSrc.ToMat())using (Mat matTo = imgSub.ToMat())using (Mat matSrcRet = new Mat())using (Mat matToRet = new Mat()){KeyPoint[] keyPointsSrc, keyPointsTo;using (var sift = OpenCvSharp.XFeatures2D.SIFT.Create()){sift.DetectAndCompute(matSrc, null, out keyPointsSrc, matSrcRet);sift.DetectAndCompute(matTo, null, out keyPointsTo, matToRet);}using (var bfMatcher = new OpenCvSharp.BFMatcher()){var matches = bfMatcher.KnnMatch(matSrcRet, matToRet, k: 2);var pointsSrc = new List<Point2f>();var pointsDst = new List<Point2f>();var goodMatches = new List<DMatch>();foreach (DMatch[] items in matches.Where(x => x.Length > 1)){if (items[0].Distance < 0.5 * items[1].Distance){pointsSrc.Add(keyPointsSrc[items[0].QueryIdx].Pt);pointsDst.Add(keyPointsTo[items[0].TrainIdx].Pt);goodMatches.Add(items[0]);Console.WriteLine($"{keyPointsSrc[items[0].QueryIdx].Pt.X}, {keyPointsSrc[items[0].QueryIdx].Pt.Y}");}}var outMat = new Mat();// 算法RANSAC对匹配的结果做过滤var pSrc = pointsSrc.ConvertAll(Point2fToPoint2d);var pDst = pointsDst.ConvertAll(Point2fToPoint2d);var outMask = new Mat();// 如果原始的匹配结果为空, 则跳过过滤步骤if (pSrc.Count > 0 && pDst.Count > 0)Cv2.FindHomography(pSrc, pDst, HomographyMethods.Ransac, mask: outMask);// 如果通过RANSAC处理后的匹配点⼤于10个,才应⽤过滤. 否则使⽤原始的匹配点结果(匹配点过少的时候通过RANSAC处理后,可能会得到0个匹配点的结果).if (outMask.Rows > 10){byte[] maskBytes = new byte[outMask.Rows * outMask.Cols];outMask.GetArray(0, 0, maskBytes);Cv2.DrawMatches(matSrc, keyPointsSrc, matTo, keyPointsTo, goodMatches, outMat, matchesMask: maskBytes, flags: DrawMatchesFlags.NotDrawSinglePoints); }elseCv2.DrawMatches(matSrc, keyPointsSrc, matTo, keyPointsTo, goodMatches, outMat, flags: DrawMatchesFlags.NotDrawSinglePoints);return OpenCvSharp.Extensions.BitmapConverter.ToBitmap(outMat);}}}SURF算法public static Bitmap MatchPicBySurf(Bitmap imgSrc, Bitmap imgSub, double threshold = 400){using (Mat matSrc = imgSrc.ToMat())using (Mat matTo = imgSub.ToMat())using (Mat matSrcRet = new Mat())using (Mat matToRet = new Mat()){KeyPoint[] keyPointsSrc, keyPointsTo;using (var surf = OpenCvSharp.XFeatures2D.SURF.Create(threshold,4,3,true,true)){surf.DetectAndCompute(matSrc, null, out keyPointsSrc, matSrcRet);surf.DetectAndCompute(matTo, null, out keyPointsTo, matToRet);}using (var flnMatcher = new OpenCvSharp.FlannBasedMatcher()){var matches = flnMatcher.Match(matSrcRet, matToRet);//求最⼩最⼤距离double minDistance = 1000;//反向逼近double maxDistance = 0;for (int i = 0; i < matSrcRet.Rows; i++){double distance = matches[i].Distance;if (distance > maxDistance){maxDistance = distance;}if (distance < minDistance){minDistance = distance;}}Console.WriteLine($"max distance : {maxDistance}");Console.WriteLine($"min distance : {minDistance}");var pointsSrc = new List<Point2f>();var pointsDst = new List<Point2f>();//筛选较好的匹配点var goodMatches = new List<DMatch>();for (int i = 0; i < matSrcRet.Rows; i++){double distance = matches[i].Distance;if (distance < Math.Max(minDistance * 2, 0.02)){pointsSrc.Add(keyPointsSrc[matches[i].QueryIdx].Pt);pointsDst.Add(keyPointsTo[matches[i].TrainIdx].Pt);//距离⼩于范围的压⼊新的DMatchgoodMatches.Add(matches[i]);}}var outMat = new Mat();// 算法RANSAC对匹配的结果做过滤var pSrc = pointsSrc.ConvertAll(Point2fToPoint2d);var pDst = pointsDst.ConvertAll(Point2fToPoint2d);var outMask = new Mat();// 如果原始的匹配结果为空, 则跳过过滤步骤if (pSrc.Count > 0 && pDst.Count > 0)Cv2.FindHomography(pSrc, pDst, HomographyMethods.Ransac, mask: outMask);// 如果通过RANSAC处理后的匹配点⼤于10个,才应⽤过滤. 否则使⽤原始的匹配点结果(匹配点过少的时候通过RANSAC处理后,可能会得到0个匹配点的结果).if (outMask.Rows > 10){byte[] maskBytes = new byte[outMask.Rows * outMask.Cols];outMask.GetArray(0, 0, maskBytes);Cv2.DrawMatches(matSrc, keyPointsSrc, matTo, keyPointsTo, goodMatches, outMat, matchesMask: maskBytes, flags: DrawMatchesFlags.NotDrawSinglePoints); }elseCv2.DrawMatches(matSrc, keyPointsSrc, matTo, keyPointsTo, goodMatches, outMat, flags: DrawMatchesFlags.NotDrawSinglePoints);return OpenCvSharp.Extensions.BitmapConverter.ToBitmap(outMat);}}}模板匹配public static System.Drawing.Point FindPicFromImage(Bitmap imgSrc, Bitmap imgSub, double threshold = 0.9){OpenCvSharp.Mat srcMat = null;OpenCvSharp.Mat dstMat = null;OpenCvSharp.OutputArray outArray = null;try{srcMat = imgSrc.ToMat();dstMat = imgSub.ToMat();outArray = OpenCvSharp.OutputArray.Create(srcMat);OpenCvSharp.Cv2.MatchTemplate(srcMat, dstMat, outArray, Common.templateMatchModes);double minValue, maxValue;OpenCvSharp.Point location, point;OpenCvSharp.Cv2.MinMaxLoc(OpenCvSharp.InputArray.Create(outArray.GetMat()), out minValue, out maxValue, out location, out point); Console.WriteLine(maxValue);if (maxValue >= threshold)return new System.Drawing.Point(point.X, point.Y);return System.Drawing.Point.Empty;}catch(Exception ex){return System.Drawing.Point.Empty;}finally{if (srcMat != null)srcMat.Dispose();if (dstMat != null)dstMat.Dispose();if (outArray != null)outArray.Dispose();}}。
Python
Python OpenCV学习之特征点检测与匹配详解⽬录背景⼀、Harris⾓点⼆、Shi-Tomasi⾓点检测三、SIFT关键点四、SIFT描述⼦五、SURF六、ORB七、暴⼒特征匹配(BF)⼋、FLANN特征匹配九、图像查找总结背景提取图像的特征点是图像领域中的关键任务,不管在传统还是在深度学习的领域中,特征代表着图像的信息,对于分类、检测任务都是⾄关重要的;特征点应⽤的⼀些场景:图像搜索:以图搜图(电商、教育领域)图像拼接:全景拍摄(关联图像拼接)拼图游戏:游戏领域⼀、Harris⾓点哈⾥斯⾓点检测主要有以下三种情况:光滑区域:⽆论向哪个⽅向移动,衡量系数不变;边缘区域:垂直边缘移动时,衡量系数变化强烈;⾓点区域:不管往哪个⽅向移动,衡量系数变化强烈;函数原型:cornerHarris(img,blockSize,ksize,k)blockSize:检测窗⼝⼤⼩;k:权重系数,⼀般取0.02~0.04之间;代码案例:img = cv2.imread('chess.png')gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)dst = cv2.cornerHarris(gray, 2, 3, 0.04)img[dst > 0.01*dst.max()] = (0, 0, 255)cv2.imshow('harris', img)cv2.waitKey(0)⼆、Shi-Tomasi⾓点检测说明:是Harris⾓点检测的改进,在Harris中需要知道k这个经验值,⽽在Shi-Tomasi不需要;函数原型:goodFeaturesToTrack(img,…)maxCorners:⾓点的最⼤数量,值为0表⽰所有;qualityLevel:⾓点的质量,⼀般在0.01~0.1之间(低于的过滤掉);minDistance:⾓点之间最⼩欧式距离,忽略⼩于此距离的点;mask:感兴趣区域;useHarrisDetector:是否使⽤Harris算法(默认为false)代码案例:img = cv2.imread('chess.png')gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)dst = cv2.goodFeaturesToTrack(gray, 1000, 0.01, 10)dst = np.int0(dst) # 实际上也是np.int64for i in dst:x, y = i.ravel() # 数组降维成⼀维数组(inplace的⽅式)cv2.circle(img, (x, y), 3, (0, 0, 255), -1)cv2.imshow('harris', img)cv2.waitKey(0)本质上和Harris⾓点检测相同,效果会好⼀些,⾓点数量会多⼀些;三、SIFT关键点中⽂简译:与缩放⽆关的特征转换;说明:Harris⾓点检测具有旋转不变性,也就是旋转图像并不会影响检测效果;但其并不具备缩放不变性,缩放⼤⼩会影响⾓点检测的效果;SIFT具备缩放不变性的性质;实现步骤:创建SIFT对象 —— 进⾏检测(sift.detect) —— 绘制关键点(drawKeypoints)代码案例:img = cv2.imread('chess.png')gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)sift = cv2.xfeatures2d.SIFT_create()kp = sift.detect(gray, None) # 第⼆个参数为mask区域cv2.drawKeypoints(gray, kp, img)cv2.imshow('sift', img)cv2.waitKey(0)四、SIFT描述⼦⾸先需要说明,关键点和描述⼦是两个概念;关键点:位置、⼤⼩和⽅向;关键点描述⼦:记录了关键点周围对其有贡献的像素点的⼀组向量值,其不受仿射变换,光照变换等影响;描述⼦的作⽤就是⽤于特征匹配;同时计算关键点和描述⼦的函数(主要使⽤):detectAndCompute(img,…)代码案例:img = cv2.imread('chess.png')gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)sift = cv2.xfeatures2d.SIFT_create()kp, dst = sift.detectAndCompute(gray, None) # 第⼆个参数为mask区域得到的dst即为描述⼦的信息;五、SURF中译:加速的鲁棒性特征检测;说明:SIFT最⼤的缺点是速度慢,因此才会有SURF(速度快);实现步骤与SIFT⼀致,代码如下:surf = cv2.xfeatures2d.SURF_create()kp, dst = surf.detectAndCompute(gray, None) # 第⼆个参数为mask区域cv2.drawKeypoints(gray, kp, img)由于安装的opencv-contrib版本过⾼(有版权问题),已经不⽀持该功能了,在此就不作展⽰了;六、ORB说明:最⼤的优势就是做到实时检测,缺点就是缺失了很多信息(准确性下降);主要是两个技术的结合:FAST(特征点实时检测)+ BRIEE(快速描述⼦建⽴,降低特征匹配时间)使⽤步骤与之前的SIFT⼀致,代码如下:img = cv2.imread('chess.png')gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)orb = cv2.ORB_create()kp, dst = orb.detectAndCompute(gray, None) # 第⼆个参数为mask区域cv2.drawKeypoints(gray, kp, img)cv2.imshow('orb', img)cv2.waitKey(0)可以看出,相⽐于SIFT以及SURF关键点变少了,但是其速度有了很⼤提升;七、暴⼒特征匹配(BF)匹配原理:类似于穷举匹配机制,使⽤第⼀组中每个特征的描述⼦与第⼆组中的进⾏匹配,计算相似度,返回最接近的匹配项;实现步骤:创建匹配器:BFMatcher(normType,crossCheck)进⾏特征匹配:bf.match(des1,des2)绘制匹配点:cv2.drawMatches(img1,kp1,img2,kp2)代码案例:img1 = cv2.imread('opencv_search.png')img2 = cv2.imread('opencv_orig.png')g1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)g2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)sift = cv2.SIFT_create()kp1, dst1 = sift.detectAndCompute(g1, None) # 第⼆个参数为mask区域kp2, dst2 = sift.detectAndCompute(g2, None) # 第⼆个参数为mask区域bf = cv2.BFMatcher_create(cv2.NORM_L1)match = bf.match(dst1, dst2)img3 = cv2.drawMatches(img1, kp1, img2, kp2, match, None)cv2.imshow('result', img3)cv2.waitKey(0)从上图可看出,匹配的效果还是不错的,只有⼀个特征点匹配错误;⼋、FLANN特征匹配优点:在进⾏批量特征匹配时,FLANN速度更快;缺点:由于使⽤的时邻近近似值,所有精度较差;实现步骤与暴⼒匹配法⼀致,代码如下:img1 = cv2.imread('opencv_search.png')img2 = cv2.imread('opencv_orig.png')g1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)g2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)sift = cv2.SIFT_create()kp1, dst1 = sift.detectAndCompute(g1, None) # 第⼆个参数为mask区域kp2, dst2 = sift.detectAndCompute(g2, None) # 第⼆个参数为mask区域index_params = dict(algorithm = 1, trees = 5)search_params = dict(checks=50)flann = cv2.FlannBasedMatcher(index_params, search_params)matchs = flann.knnMatch(dst1, dst2, k=2)good = []for i, (m, n) in enumerate(matchs):if m.distance < 0.7 * n.distance:good.append(m)img3 = cv2.drawMatchesKnn(img1, kp1, img2, kp2, [good], None)cv2.imshow('result', img3)cv2.waitKey(0)上图可以看出,匹配的特征点数量相⽐暴⼒匹配明显变少了,但速度会快很多;九、图像查找实现原理:特征匹配 + 单应性矩阵;单应性矩阵原理介绍:上图中表⽰从两个不同⾓度对原图的拍摄,其中H为单应性矩阵,可通过该矩阵将图像进⾏转换;下⾯使⽤两个函数实现图像查找的功能:findHomography():获得单应性矩阵;perspectivveTransform():仿射变换函数;代码实现如下:img1 = cv2.imread('opencv_search.png')img2 = cv2.imread('opencv_orig.png')g1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)g2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)sift = cv2.SIFT_create()kp1, dst1 = sift.detectAndCompute(g1, None) # 第⼆个参数为mask区域kp2, dst2 = sift.detectAndCompute(g2, None) # 第⼆个参数为mask区域index_params = dict(algorithm = 1, trees = 5)search_params = dict(checks=50)flann = cv2.FlannBasedMatcher(index_params, search_params)matchs = flann.knnMatch(dst1, dst2, k=2)good = []for i, (m, n) in enumerate(matchs):if m.distance < 0.7 * n.distance:good.append(m)if len(good) >= 4:# 获得源和⽬标点的数组srcPts = np.float32([kp1[m.queryIdx].pt for m in good]).reshape(-1, 1, 2)dstPts = np.float32([kp2[m.trainIdx].pt for m in good]).reshape(-1, 1, 2)# 获得单应性矩阵HH, _ = cv2.findHomography(srcPts, dstPts, cv2.RANSAC, 5.0)h, w = img1.shape[:2]pts = np.float32([[0,0], [0, h-1], [w-1, h-1], [w-1, 0]]).reshape(-1, 1, 2)# 进⾏放射变换dst = cv2.perspectiveTransform(pts, H)# 绘制查找到的区域cv2.polylines(img2, [np.int32(dst)], True, (0,0,255))else:print('good must more then 4.')exit()img3 = cv2.drawMatchesKnn(img1, kp1, img2, kp2, [good], None)cv2.imshow('result', img3)cv2.waitKey(0)总结本篇主要介绍了特征点检测和匹配,其中重要的部分时SIFT算法以及FLANN算法;通过所学的知识,可以简单实现⼀个图像查找的功能,也就是找⼦图的功能。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
OpenCV成长之路(9):特征点检测与图像匹配特征点检测与图像匹配称兴趣点、关键点,它是在图像中突出且具有代表意义的一些点,通过这些点我们可以用来识别图像、进行图像配准、进行3D重建等。
本文主要介绍OpenCV中几种定位与表示关键点的函数。
一、Harris角点角点是图像中最基本的一种关键点,它是由图像中一些几何结构的关节点构成,很多都是线条之间产生的交点。
Harris 角点是一类比较经典的角点类型,它的基本原理是计算图像中每点与周围点变化率的平均值。
(1)(2)其中I(x+u,y+u)代表了点(x,y)邻域点的灰度值。
通过变换可以将上式变化为一个协方差矩阵求特征值的问题(2),具体数学原理本文不过多描述。
OpenCV的Hairrs角点检测的函数为cornerHairrs(),但是它的输出是一幅浮点值图像,浮点值越高,表明越可能是特征角点,我们需要对图像进行阈值化。
我们使用一张建筑图像来显示:int main() { Mat image=imread("../buliding.png"); Mat gray; cvtColor(image,gray,CV_BGR2GRAY);Mat cornerStrength;cornerHarris(gray,cornerStrength,3,3,0.01);threshold(cornerStrength,cornerStrength,0.001,255,THRESH_B INARY); return 0; } 首先我们来说明一下cornerHairrs()这个函数参数的意思:前2参数是输入与输出,输入是一个灰度图像,输出是一个浮点图像,第三个参数指定角点分析的邻域,第4个参数实际上在角点求取过程中计算梯度图像的核窗口大小,第5个参数是它原理公式(2)中的一个系数。
从上面的例子的结果我们可以看到,有很多角点都是粘连在一起的,我们下面通过加入非极大值抑制来进一步去除一些粘在一起的角点。
非极大值抑制原理是,在一个窗口内,如果有多个角点则用值最大的那个角点,其他的角点都删除,窗口大小这里我们用3*3,程序中通过图像的膨胀运算来达到检测极大值的目的,因为默认参数的膨胀运算就是用窗口内的最大值替代当前的灰度值。
程序的最后使用了一个画角点的函数将角点显示在图像中,这个函数与本系列第5篇中画角点的函数是一致的。
int main() { Mat image=imread("../buliding.png");Mat gray; cvtColor(image,gray,CV_BGR2GRAY);Mat cornerStrength;cornerHarris(gray,cornerStrength,3,3,0.01); double maxStrength; double minStrength; // 找到图像中的最大、最小值minMaxLoc(cornerStrength,&minStrength,&maxStre ngth); Mat dilated; Mat locaMax; // 膨胀图像,最找出图像中全部的局部最大值点dilate(cornerStrength,dilated,Mat()); // compare是一个逻辑比较函数,返回两幅图像中对应点相同的二值图像compare(cornerStrength,dilated,locaMax,CMP_EQ);Mat cornerMap; double qualityLevel=0.01; double th=qualityLevel*maxStrength; // 阈值计算threshold(cornerStrength,cornerMap,th,255,THRESH_BINARY ); cornerMap.convertTo(cornerMap,CV_8U); //逐点的位运算bitwise_and(cornerMap,locaMax,cornerMap); drawCornerOnImage(image,cornerMap);namedWindow("result"); imshow("result",image); waitKey(); return 0; } void drawCornerOnImage(Mat& image,const Mat&binary){ Mat_<uchar>::const_iteratorit=binary.begin<uchar>();Mat_<uchar>::const_iteratoritd=binary.end<uchar>(); for(inti=0;it!=itd;it++,i++) { if(*it)circle(image,Point(i%image.cols,i/image.cols),3,Scalar(0,255,0) ,1); } } 现在我们得到的效果就比默认的函数得到的结果有相当的改善。
由于cornerHarris的一些缺点,OpenCV提供了另一个相似的函数GoodFeaturesToTrack()它用角点间的距离限制来防止角点粘连在一起。
goodFeaturesToTrack(image,corner,500, // 最多检测到的角点数0.01, // 阈值系数10); // 角点间的最小距离它可以得到与上面基本一致的结果。
二、FAST特征点harris特征在算法复杂性上比较高,在大的复杂的目标识别或匹配应用上效率不能满足要求,OpenCV提供了一个快速检测角点的类FastFeatureDetector,而实际上FAST并不是快的意思,而是Features from Accelerated Segment Test,但这个算法效率确实比较高,下面我们来看看这个类的用法。
OpenCV里为角点检测提供了统一的接口,通过类下面的detect方法来检测对应的角点,而输出格式都是vector<KeyPoint>。
vector<KeyPoint> keypoints; FastFeatureDetector fast( // 定义检测类40); //40是检测的阈值fast.detect(image,keypoints);drawKeypoints(image,keypoints,image,Scalar(255,0,0), DrawMatchesFlags::DRAW_OVER_OUTIMG); 其中drawKeypoints是OpenCV提供的在图像上画角点的函数。
它的参数可以让我们选择用不同的方式标记出特征点。
三、尺度不变的SURF特征surf特征是类似于SIFT特征的一种尺度不变的特征点,它的优点在于比SIFT效率要高,在实际运算中可以达到实时性的要求,关于SURF的原理这里就不过多的介绍,网络上这类的文章很多。
类似于FAST特征点的求法,SURF也可以使用通用接口求得,而SURF特征的类为SurfFeatureDetector,类似的SIFT 特征点的检测类为SiftFeatureDetector。
#include <opencv2/core/core.hpp> #include<opencv2/highgui/highgui.hpp> #include<opencv2/nonfree/features2d.hpp> using namespacecv; int main() { Matimage=imread("../buliding.png");vector<KeyPoint> keypoints;SurfFeatureDetector surf(2500.);surf.detect(image,keypoints);drawKeypoints(image,keypoints,image,Scalar(255,0,0), DrawMatchesFlags::DRAW_RICH_KEYPOINTS); namedWindow("result"); imshow("result",image); waitKey(); return 0; } 这里有一个值得说明的问题是:OpenCV2.4版本后好像把SurfFeatureDetector这个类的定义移到了头文件nonfree/features2d.hpp中,所以头文件中要加入该文件,并且要把opencv_nonfree24xd.lib加入属性表的链接器熟悉的输入中,其中x换成你当前opencv的版本号。
最终的显示效果如下:四、SURF特征的描述在图像配准中,特征点的描述往往不是位置这么简单,而是使用了一个N维向量来描述一个特征点,这些描述子之间可以通过定义距离公式来比较相近程度。
SurfDescriptorExtractor 是一个提取SURF特征点以及其描述的类。
下面是一个宽景图像的拼接配准的例子:#include <opencv2/core/core.hpp> #include<opencv2/highgui/highgui.hpp> #include<opencv2/nonfree/features2d.hpp> #include<opencv2/legacy/legacy.hpp> using namespace cv; int main() { Mat image1=imread("../b1.png");Mat image2=imread("../b2.png"); // 检测surf特征点vector<KeyPoint> keypoints1,keypoints2; SurfFeatureDetector detector(400);detector.detect(image1, keypoints1);detector.detect(image2, keypoints2); // 描述surf特征点SurfDescriptorExtractor surfDesc; Matdescriptros1,descriptros2;pute(image1,keypoints1,descriptros1); pute(image2,keypoints2,descriptros2); // 计算匹配点数BruteForceMatcher<L2<float>>matcher;vector<DMatch> matches;matcher.match(descriptros1,descriptros2,matches);std::nth_element(matches.begin(),matches.begin()+24,matches.e nd()); matches.erase(matches.begin()+25,matches.end()); // 画出匹配图Mat imageMatches;drawMatches(image1,keypoints1,image2,keypoints2,matches, imageMatches,Scalar(255,0,0));namedWindow("image2"); imshow("image2",image2); waitKey(); return 0; } 程序中我们选择了25个配准点,得到最后的匹配如下:。