学习OpenCV范例(二十)——角点检测算法

2024-06-18 22:48

本文主要是介绍学习OpenCV范例(二十)——角点检测算法,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

原文地址:http://blog.csdn.net/chenjiazhou12/article/details/22683049

本次范例讲的都是检测角点的算法,在这里我们会讲到,harris角点检测,Shi-Tomasi角点检测,FAST角点检测,尺度不变surf检测,尺度不变sift检测,特征点的描述。由于是算法问题,相对来说会比较复杂,而且都是一些比较经典的算法,如果只是纯粹的想要用算法来实现一些功能,那么只要调用OpenCV几个简单的函数就可以了,但是如果想学习一下理论知识,为以后自己的研究有所帮助,而且想理解函数的参数如何改变,那么还是得硬着头皮去看看原理吧,本人也是看了挺久的算法原理,但是还是没有完全理解透,所以在这里只是贴出我看过的比较有用的博客,还有一些自己编译的代码和实现结果,记录一下这个过程,方便以后可以进一步的研究。

1、原理

Harris:Opencv学习笔记(五)Harris角点检测 

Shi-Tomasi:【OpenCV】角点检测:Harris角点及Shi-Tomasi角点检测

FAST:OpenCV学习笔记(四十六)——FAST特征点检测features2D

SIFT:【OpenCV】SIFT原理与源码分析

             特征点检测学习_1(sift算法)

SURF:  特征点检测学习_2(surf算法)

2、代码实现

由于代码量较大,所以只是贴出代码的一部分,如果想要整体代码,可以从下面的链接中找到
http://download.csdn.net/detail/chenjiazhou12/7129327

①、harris角点检测

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:18px;">   //计算角点响应函数以及非最大值抑制  
  2.     void detect(const Mat &image){  
  3.             //opencv自带的角点响应函数计算函数  
  4.             cornerHarris (image,cornerStrength,neighbourhood,aperture,k);  
  5.             double minStrength;  
  6.             //计算最大最小响应值  
  7.             minMaxLoc (cornerStrength,&minStrength,&maxStrength);  
  8.   
  9.             Mat dilated;  
  10.             //默认3*3核膨胀,膨胀之后,除了局部最大值点和原来相同,其它非局部最大值点被  
  11.             //3*3邻域内的最大值点取代  
  12.             dilate (cornerStrength,dilated,cv::Mat());  
  13.             //与原图相比,只剩下和原图值相同的点,这些点都是局部最大值点,保存到localMax  
  14.             compare(cornerStrength,dilated,localMax,cv::CMP_EQ);  
  15.     }</span>  

cornerHarris
功能:Harris角点检测
结构:
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:18px;"void cornerHarris(InputArray src, OutputArray dst, int blockSize, int apertureSize, double k, int borderType=BORDER_DEFAULT )</span>  

src :8位或者32位浮点数单通道图像
dst:保存Harris检测结果的图像,32位单通道,和src有同样的size 
blockSize :邻域大小,相邻像素的尺寸(见关于 cornerEigenValsAndVecs() 的讨论)
apertureSize :滤波器的孔径大小
k :harris 检测器的自由参数
boderType :插值类型

compare
功能:两个数组之间或者一个数组和一个常数之间的比较
结构:
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:18px;">void compare(InputArray src1, InputArray src2, OutputArray dst, int cmpop)</span>  

src1 :第一个数组或者标量,如果是数组,必须是单通道数组。
src2 :第二个数组或者标量,如果是数组,必须是单通道数组。
dst :输出数组,和输入数组有同样的size和type=CV_8UC1
cmpop :
标志指明了元素之间的对比关系
CMP_EQ src1 相等 src2.
CMP_GT src1 大于 src2.
CMP_GE src1 大于或等于 src2.
CMP_LT src1 小于 src2.
CMP_LE src1 小于或等于 src2.
CMP_NE src1 不等于 src2.
如果对比结果为true,那么输出数组对应元素的值为255,否则为0
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:18px;">    //获取角点图  
  2.     Mat getCornerMap(double qualityLevel) {  
  3.             Mat cornerMap;  
  4.             // 根据角点响应最大值计算阈值  
  5.             thresholdvalue= qualityLevel*maxStrength;  
  6.             threshold(cornerStrength,cornerTh,  
  7.             thresholdvalue,255,cv::THRESH_BINARY);  
  8.             // 转为8-bit图  
  9.             cornerTh.convertTo(cornerMap,CV_8U);  
  10.             // 和局部最大值图与,剩下角点局部最大值图,即:完成非最大值抑制  
  11.             bitwise_and(cornerMap,localMax,cornerMap);  
  12.             return cornerMap;  
  13.     }</span>  

bitwise_and
功能:计算两个数组或数组和常量之间与的关系
结构:
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:18px;">void bitwise_and(InputArray src1, InputArray src2, OutputArray dst, InputArray mask=noArray())</span>  

src1 :第一个输入的数组或常量
src2 :第二个输入的数组或常量
dst :输出数组,和输入数组有同样的size和type
mask :可选择的操作掩码,为8位单通道数组,指定了输出数组哪些元素可以被改变,哪些不可以
操作过程为:
\texttt{dst} (I) =  \texttt{src1} (I)  \wedge \texttt{src2} (I) \quad \texttt{if mask} (I) \ne0
\texttt{dst} (I) =  \texttt{src1} (I)  \wedge \texttt{src2} \quad \texttt{if mask} (I) \ne0
\texttt{dst} (I) =  \texttt{src1}  \wedge \texttt{src2} (I) \quad \texttt{if mask} (I) \ne0
如果为多通道数组,每个通道单独处理

②、Shi-Tomasi检测

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:18px;">void goodFeaturesDetect()  
  2. {  
  3.     // 改进的harris角点检测方法  
  4.     vector<Point> corners;  
  5.     goodFeaturesToTrack(image,corners,  
  6.         200,  
  7.         //角点最大数目  
  8.         0.01,  
  9.         // 质量等级,这里是0.01*max(min(e1,e2)),e1,e2是harris矩阵的特征值  
  10.         10);  
  11.     // 两个角点之间的距离容忍度  
  12.     harris().drawOnImage(image,corners);//标记角点  
  13.         imshow (winname,image);  
  14.       
  15. }</span>  

goodFeaturesToTrack
功能:确定图像的强角点
结构:
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:18px;">void goodFeaturesToTrack(InputArray image, OutputArray corners, int maxCorners, double qualityLevel, double minDistance, InputArray mask=noArray(), int blockSize=3, bool useHarrisDetector=falsedouble k=0.04 )</span>  

image :输入8位或32为单通道图像
corners :输出检测到的角点
maxCorners :返回的角点的最大值,如果设置的值比检测到的值大,那就全部返回
qualityLevel :最大最小特征值的乘法因子。定义可接受图像角点的最小质量因子
minDistance :限制因子,两个角点之间的最小距离,使用 Euclidian 距离
mask :ROI:感兴趣区域。函数在ROI中计算角点,如果 mask 为 NULL,则选择整个图像。 必须为单通道的灰度图,大小与输入图像相同。mask对应的点不为0,表示计算该点。
blockSize :邻域大小,相邻像素的尺寸(见关于 cornerEigenValsAndVecs() 的讨论)
useHarrisDetector :是否使用Harris检测器 (见关于 cornerHarris() 或 cornerMinEigenVal()的讨论).
k :Harris检测器的自由参数
1、该函数在原图像的每一个像素点使用cornerMinEigenVal()或者cornerHarris()来计算角点
2、对检测到的角点进行非极大值抑制(在3*3的领域内极大值被保留)
3、对检测到的角点进行阈值处理,小于阈值,则被删除
4、对最终得到的角点进行降序排序
5、删除离强角点距离比minDistance近的角点

③、FAST检测

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:18px;">void fastDetect()  
  2. {     
  3.     //快速角点检测  
  4.     vector<KeyPoint> keypoints;  
  5.     FastFeatureDetector fast(40,true);  
  6.     fast.detect (image,keypoints);  
  7.     drawKeypoints (image,keypoints,image,Scalar::all(255),DrawMatchesFlags::DRAW_OVER_OUTIMG);  
  8.     imshow (winname,image);  
  9. }</span>  

FastFeatureDetector 类
这个类是FeatureDetector类继承过来的
构造函数
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:18px;">FastFeatureDetector( int threshold=1, bool nonmaxSuppression=true );</span>  

threshold:检测阈值
nonmaxSuppression:非极大值抑制

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:18px;">void FeatureDetector::detect(const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask=Mat() ) const</span>  
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:18px;">void FeatureDetector::detect(const vector<Mat>& images, vector<vector<KeyPoint>>& keypoints, const vector<Mat>& masks=vector<Mat>() ) const</span>  

image :输入图片
images :输入图片组
keypoints :第一个为检测到的keypoints,第二个为检测到的keypoints组
mask :可选的操作掩码,指定哪些keypoints,必须是8位二值化有非零元素的感兴趣区域
masks :多个操作掩码,masks[i]对应images[i]
drawKeypoints
功能:绘制特征关键点.
结构:
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:18px;"void drawKeypoints(const Mat& image, const vector<KeyPoint>& keypoints, Mat& outImg, const Scalar& color=Scalar::all(-1), int flags=DrawMatchesFlags::DEFAULT )</span>  

image :原图片
keypoints :得到的keypoints
outImg :输出图片,它的内容依赖于flags的值
color :keypoints的颜色
flags :标志画在输出图像的特征,flags是由DrawMatchesFlags定义的
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:18px;">struct DrawMatchesFlags  
  2. {  
  3.     enum  
  4.     {  
  5.         DEFAULT = 0, // 会创建一个输出矩阵,两张源文件,匹配结果,  
  6.                      // <span style="font-family: Arial, Helvetica, sans-serif;">和keypoints将会被绘制在输出图像中</span>  
  7.                      // 对于每一个keypoints点,只有中心被绘制,  
  8.                      // 不绘制半径和方向  
  9.         DRAW_OVER_OUTIMG = 1, // 不创建输出图像,匹配结构绘制在已经存在的输出图像中  
  10.         NOT_DRAW_SINGLE_POINTS = 2, // 单独的keypoints点不被绘制  
  11.         DRAW_RICH_KEYPOINTS = 4 // 对于每一个keypoints点,半径和方向都被绘制  
  12.     };  
  13. };</span>  

④、SIFT检测

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:18px;">void siftDetect()  
  2. {  
  3.     vector<KeyPoint> keypoints;  
  4.     SiftFeatureDetector sift(0.03,10);  
  5.     sift.detect(image,keypoints);  
  6.     drawKeypoints(image,keypoints,image,Scalar(255,255,255),DrawMatchesFlags::DRAW_RICH_KEYPOINTS);  
  7.     imshow (winname,image);  
  8. }</span>  

SiftFeatureDetector
结构:
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:18px;">   SiftFeatureDetector( double threshold, double edgeThreshold,  
  2.                          int nOctaves=SIFT::CommonParams::DEFAULT_NOCTAVES,  
  3.                          int nOctaveLayers=SIFT::CommonParams::DEFAULT_NOCTAVE_LAYERS,  
  4.                          int firstOctave=SIFT::CommonParams::DEFAULT_FIRST_OCTAVE,  
  5.                          int angleMode=SIFT::CommonParams::FIRST_ANGLE );</span>  

threshold:过滤掉较差的特征点的对阈值。threshold越大,返回的特征点越少。
edgeThreshold:过滤掉边缘效应的阈值。edgeThreshold越大,特征点越多

⑤、SURF检测

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:18px;">void surfDetect()  
  2. {  
  3.     vector<KeyPoint> keypoints_1, keypoints_2;  
  4.      Mat descriptors_1, descriptors_2;  
  5.      //-- Step 1: Detect the keypoints using SURF Detector  
  6.     SurfFeatureDetector surf(2500);  
  7.     surf.detect(image,keypoints_1);  
  8.     surf.detect(image2,keypoints_2);  
  9.     //-- Step 2: Calculate descriptors (feature vectors)  
  10.     SurfDescriptorExtractor extractor;  
  11.     extractor.compute( image, keypoints_1, descriptors_1 );  
  12.     extractor.compute( image2, keypoints_2, descriptors_2 );  
  13.     //-- Step 3: Matching descriptor vectors with a brute force matcher  
  14.     BruteForceMatcher< L2<float> > matcher;  
  15.     std::vector< DMatch > matches;  
  16.     matcher.match( descriptors_1, descriptors_2, matches );  
  17.     nth_element(matches.begin(),matches.begin()+24,matches.end());  
  18.     matches.erase(matches.begin()+25,matches.end());  
  19.     //-- Draw matches  
  20.     Mat img_matches;  
  21.     drawMatches( image, keypoints_1, image2, keypoints_2, matches, img_matches,Scalar(255,255,255) );  
  22.     drawKeypoints(image,keypoints_1,image,Scalar(255,255,255),DrawMatchesFlags::DRAW_RICH_KEYPOINTS);  
  23.     //-- Show detected matches  
  24.     imshow("Matches", img_matches );  
  25.     imshow (winname,image);  
  26. }</span>  

SurfFeatureDetector
构造函数
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:18px;">SurfFeatureDetector( double hessianThreshold = 400., int octaves = 3,  
  2.                          int octaveLayers = 4 );</span>  

hessianThreshold:阈值
octaves:金字塔组数
octaveLayers:金字塔中每组的层数

SurfDescriptorExtractor
功能:来封装的用于计算特征描述子的类,构造SURE描述子提取器

compute
功能:根据检测到的图像(第一种情况)或者图像集合(第二种情况)中的关键点(检测子)计算描述子.
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:18px;">void DescriptorExtractor::compute(const Mat& image, vector<KeyPoint>& keypoints, Mat& descriptors) const  
  2. void DescriptorExtractor::compute(const vector<Mat>& images, vector<vector<KeyPoint>>& keypoints, vector<Mat>& descriptors) const</span>  

image :输入图像.
images :输入图像集.
keypoints:输入的特征关键点. 
descriptors:计算特征描述子

BruteForceMatcher< L2<float> >
功能:暴力搜索特征点匹配. 对于第一集合中的特征描述子, 这个匹配寻找了在第二个集合中最近的特征描述子. 这种特征描述子匹配支持 masking permissible特征描述子集合匹配.
它是一个模板类,<>中的参数表示匹配的方式

DMatch
功能:用于匹配特征关键点的特征描述子的类:查询特征描述子索引, 特征描述子索引, 训练图像索引, 以及不同特征描述子之间的距离.

match
功能:给定查询集合中的每个特征描述子,寻找最佳匹配.
结构:
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:18px;"void DescriptorMatcher::match(const Mat& queryDescriptors, const Mat& trainDescriptors, vector<DMatch>& matches, const Mat& mask=Mat() ) const  
  2.  void DescriptorMatcher::match(const Mat& queryDescriptors, vector<DMatch>& matches, const vector<Mat>& masks=vector<Mat>() )</span>  

queryDescriptors :特征描述子查询集.
trainDescriptors :待训练的特征描述子集.
matches :匹配特征描述子类
mask – 特定的在输入查询和训练特征描述子集之间的可允许掩码匹配,指定哪些可以被匹配
masks – masks集. 每个 masks[i] 特定标记出了在输入查询特征描述子和存储的从第i个图像中提取的特征描述子集
第二个方法的trainDesctiptors由DescriptorMatcher::add给出。

nth_element
功能:nth_element作用为求第n小的元素,并把它放在第n位置上,下标是从0开始计数的,也就是说求第0小的元素就是最小的数。

erase
功能:移除参数1和参数2之间的元素,返回下一个元素

drawMatches
功能:给定两幅图像,绘制寻找到的特征关键点及其匹配
结构:
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:18px;">void drawMatches(const Mat& img1, const vector<KeyPoint>& keypoints1, const Mat& img2, const vector<KeyPoint>& keypoints2, const vector<DMatch>& matches1to2, Mat& outImg, const Scalar& matchColor=Scalar::all(-1), const Scalar& singlePointColor=Scalar::all(-1), const vector<char>& matchesMask=vector<char>(), int flags=DrawMatchesFlags::DEFAULT )</span>  

img1 :第一张原图片
keypoints1 :第一张得到的关键点
img2 :第二张图片
keypoints2 :第二张得到的关键点
matches :匹配点
outImg :输出图片,它的内容依赖于flags的值
matchColor :匹配线的颜色,如果为-1,则颜色随机分配
singlePointColor :单独点,没有匹配到的点的颜色,如果为-1,则颜色随机分配
matchesMask :掩码,表示哪些匹配值被绘制出来,如果为空,表示所有匹配点都绘制出来
flags :和上面drawkeypoints中的flags一样

3、运行结果

  
                    图1、Harris                                       图2、Shi-Tomasi
  
                 图3、FAST                                                 图4、SIFT

                图5、SURF

                                      图6、匹配结果
源代码下载地址:
http://download.csdn.net/detail/chenjiazhou12/7129327

这篇关于学习OpenCV范例(二十)——角点检测算法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1073279

相关文章

51单片机学习记录———定时器

文章目录 前言一、定时器介绍二、STC89C52定时器资源三、定时器框图四、定时器模式五、定时器相关寄存器六、定时器练习 前言 一个学习嵌入式的小白~ 有问题评论区或私信指出~ 提示:以下是本篇文章正文内容,下面案例可供参考 一、定时器介绍 定时器介绍:51单片机的定时器属于单片机的内部资源,其电路的连接和运转均在单片机内部完成。 定时器作用: 1.用于计数系统,可

问题:第一次世界大战的起止时间是 #其他#学习方法#微信

问题:第一次世界大战的起止时间是 A.1913 ~1918 年 B.1913 ~1918 年 C.1914 ~1918 年 D.1914 ~1919 年 参考答案如图所示

[word] word设置上标快捷键 #学习方法#其他#媒体

word设置上标快捷键 办公中,少不了使用word,这个是大家必备的软件,今天给大家分享word设置上标快捷键,希望在办公中能帮到您! 1、添加上标 在录入一些公式,或者是化学产品时,需要添加上标内容,按下快捷键Ctrl+shift++就能将需要的内容设置为上标符号。 word设置上标快捷键的方法就是以上内容了,需要的小伙伴都可以试一试呢!

AssetBundle学习笔记

AssetBundle是unity自定义的资源格式,通过调用引擎的资源打包接口对资源进行打包成.assetbundle格式的资源包。本文介绍了AssetBundle的生成,使用,加载,卸载以及Unity资源更新的一个基本步骤。 目录 1.定义: 2.AssetBundle的生成: 1)设置AssetBundle包的属性——通过编辑器界面 补充:分组策略 2)调用引擎接口API

Javascript高级程序设计(第四版)--学习记录之变量、内存

原始值与引用值 原始值:简单的数据即基础数据类型,按值访问。 引用值:由多个值构成的对象即复杂数据类型,按引用访问。 动态属性 对于引用值而言,可以随时添加、修改和删除其属性和方法。 let person = new Object();person.name = 'Jason';person.age = 42;console.log(person.name,person.age);//'J

大学湖北中医药大学法医学试题及答案,分享几个实用搜题和学习工具 #微信#学习方法#职场发展

今天分享拥有拍照搜题、文字搜题、语音搜题、多重搜题等搜题模式,可以快速查找问题解析,加深对题目答案的理解。 1.快练题 这是一个网站 找题的网站海量题库,在线搜题,快速刷题~为您提供百万优质题库,直接搜索题库名称,支持多种刷题模式:顺序练习、语音听题、本地搜题、顺序阅读、模拟考试、组卷考试、赶快下载吧! 2.彩虹搜题 这是个老公众号了 支持手写输入,截图搜题,详细步骤,解题必备

vcpkg安装opencv中的特殊问题记录(无法找到opencv_corexd.dll)

我是按照网上的vcpkg安装opencv方法进行的(比如这篇:从0开始在visual studio上安装opencv(超详细,针对小白)),但是中间出现了一些别人没有遇到的问题,虽然原因没有找到,但是本人给出一些暂时的解决办法: 问题1: 我在安装库命令行使用的是 .\vcpkg.exe install opencv 我的电脑是x64,vcpkg在这条命令后默认下载的也是opencv2:x6

《offer来了》第二章学习笔记

1.集合 Java四种集合:List、Queue、Set和Map 1.1.List:可重复 有序的Collection ArrayList: 基于数组实现,增删慢,查询快,线程不安全 Vector: 基于数组实现,增删慢,查询快,线程安全 LinkedList: 基于双向链实现,增删快,查询慢,线程不安全 1.2.Queue:队列 ArrayBlockingQueue:

硬件基础知识——自学习梳理

计算机存储分为闪存和永久性存储。 硬盘(永久存储)主要分为机械磁盘和固态硬盘。 机械磁盘主要靠磁颗粒的正负极方向来存储0或1,且机械磁盘没有使用寿命。 固态硬盘就有使用寿命了,大概支持30w次的读写操作。 闪存使用的是电容进行存储,断电数据就没了。 器件之间传输bit数据在总线上是一个一个传输的,因为通过电压传输(电流不稳定),但是电压属于电势能,所以可以叠加互相干扰,这也就是硬盘,U盘

代码随想录算法训练营:12/60

非科班学习算法day12 | LeetCode150:逆波兰表达式 ,Leetcode239: 滑动窗口最大值  目录 介绍 一、基础概念补充: 1.c++字符串转为数字 1. std::stoi, std::stol, std::stoll, std::stoul, std::stoull(最常用) 2. std::stringstream 3. std::atoi, std