百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

一文搞定opencv中常见的关键点检测算法(附代码)

toyiye 2024-06-21 12:01 9 浏览 0 评论

作者:K.Fire | 来源:计算机视觉工坊

前言

角点时图像中存在物体边缘角落位置的点或者一些特殊位置的点,角点检测(Corner Detection)是计算机视觉系统中获取图像特征的一种方法,是运动检测、图像匹配、视频跟踪、三维重建和目标识别的基础。

本篇文章将介绍opencv中常用的几种角点检测方法的原理和基于C++的实现。


一、Harris角点检测

Harris角点原理:设置一个矩形框,将这个矩形框放置在图像中,将矩形框内像素进行求和,然后移动矩形框,当相邻两次求和得到的值差别较大时,判定矩形框内存在Harris角点。

通常出现的位置:直线的端点处、直线的交点处、直线的拐点处

但是如果按照上述检测原理检测,会很麻烦,很难确定矩形框移动的方向和当框内出现角点时,角点的具体位置。

因此,在程序中一般是用以下方式进行检测:1.定义Harris角点检测函数为:


其中I(x,y)为(x,y)位置的像素值,w(x,y)为矩形框的权重矩阵,定义这个矩阵的原因是:当矩形框内检测到可能存在角点时,权重矩阵中权重更大的位置更有可能是角点。2.将上述公式表示为矩阵形式:

其中M为梯度协方差矩阵,表示为以下公式:


3.然后使用Harris角点评价函数判断矩形框内是否存在角点:

其中det是矩阵的行列式,k是一个自定义的常数,tr是矩阵的迹。使用上述方式计算起来计算消耗比较大,因此换用以下方式进行评价:

其中λ是梯度协方差矩阵M的特征向量,根据这个评价系数,当评价系数值较大时矩形框内有可能存在角点,但当评价系数较小时举行框内一定不存在角点。具体原因如下图所示,当λ1和λ2都是一个较大的值时才能确定一定存在角点,而当其中一个值远远大于另一个时,也会使得R值很大,但这时很有可能位于“边缘”区域,而且评价精度也跟自定义的常数k有很大关系

Harris角点检测的代码如下:

#include <iostream>#include <opencv2/opencv.hpp>using namespace std;using namespace cv;int main(){ /*Harris角点检测*/ string path = "Lena.png"; Mat img = imread(path, 1); Mat img_gray, harris; cvtColor(img, img_gray, COLOR_BGR2GRAY); cornerHarris(img_gray, harris, 2, 3, 0.04);  //归一化便于进行数值比较和结果显示 Mat harrisn; normalize(harris, harrisn, 0, 255, NORM_MINMAX); //将图像数据类型转换为CV_8U harrisn.convertTo(harrisn, CV_8U); //寻找Harris角点 vector<KeyPoint> keyPoints; for (int row = 0; row < harrisn.rows; row++) {  for (int col = 0; col < harrisn.cols; col++)  {   int R = harrisn.at<uchar>(row, col);   if (R > 125)   {    //将角点存入KeyPoints中    KeyPoint keyPoint;    keyPoint.pt.x = row;    keyPoint.pt.y = col;    keyPoints.push_back(keyPoint);   }  } }  drawKeypoints(img, keyPoints, img); imshow("系数矩阵", harrisn); imshow("img", img);  waitKey(0); exit(0); return 0;}

运行结果:

二、Shi-Tomas角点检测

在上一节中介绍的Harris角点计算方法中,最后我们发现存在一个问题:角点检测的精度跟自定义的常数k有很大关系,Shi-Tomas角点检测就是对于Harris角点中的这一问题作出了改善,它重新定义了评价系数计算方式:

根据这个评价函数,评价系数取值为λ1和λ2中的较小值,然后用R与自定义的阈值进行比较,当其中当较小的特征向量都满足条件时,则该点一定为角点

如下图所示,当较小的特征向量都满足条件时,角点区域为图中绿色区域,一定为角点,而图中橙色区域可能位于边缘,灰色区域一定不是角点。

Shi-Tomas角点检测代码如下:

#include <iostream>#include <opencv2/opencv.hpp>using namespace std;using namespace cv;int main(){ /*Shi-Tomas角点检测*/ string path = "Lena.png"; Mat img = imread(path, 1); Mat img_gray; cvtColor(img, img_gray, COLOR_BGR2GRAY);  vector<Point2f> corners; //Shi-Tomas角点检测 goodFeaturesToTrack(img_gray, corners, 100, 0.01, 0.1); //绘制角点 vector<KeyPoint> keyPoints; for (int i = 0; i < corners.size(); i++) {  KeyPoint keyPoint;  keyPoint.pt.x = corners[i].x;  keyPoint.pt.y = corners[i].y;  keyPoints.push_back(keyPoint); } drawKeypoints(img, keyPoints, img); imshow("img", img); waitKey(0); exit(0); return 0;}

运行结果:

三、亚像素级别角点位置优化

通过上面的角点检测算法,虽然能在原图像中检测出角点的位置,但仔细观察函数可以发现检测出的角点坐标都为整数值,这是因为图像是由像素构成的,是一个离散的数据类型,如果我们想要的到更精细的角点坐标,就需要对角点位置进行优化。

优化的原理如下图所示,当一个像素点q是角点时,它在自己的领域附近是一个局部最大值,以q为起点,周围一点p1或p0为终点组成一个向量,并求梯度,此时向量与梯度的积应该是0。

当在opencv中检测出角点后(此时的角点位置时不精确的),我们就根据这个原理不断调整角点q的位置,直到达到一定的精度或迭代次数。

而在实际的计算过程中,通常是通过以下公式进行计算:

就是对q与周围点组成向量与梯度的积求和,当这个和小于一定值时,就判定为达到一定的精度。

亚像素级别角点位置优化代码如下:

#include <iostream>#include <opencv2/opencv.hpp>using namespace std;using namespace cv;int main(){ /*Shi-Tomas角点检测*/ string path = "Lena.png"; Mat img = imread(path, 1); Mat img_gray; cvtColor(img, img_gray, COLOR_BGR2GRAY);  vector<Point2f> corners; //Shi-Tomas角点检测 goodFeaturesToTrack(img_gray, corners, 100, 0.01, 0.1); cout << "检测到的角点数量:" << corners.size() << endl; //绘制角点 vector<KeyPoint> keyPoints; for (int i = 0; i < corners.size(); i++) {  KeyPoint keyPoint;  keyPoint.pt.x = corners[i].x;  keyPoint.pt.y = corners[i].y;  keyPoints.push_back(keyPoint); } drawKeypoints(img, keyPoints, img); //亚像素角点位置优化 vector<Point2f> cornersSub = corners; TermCriteria criteria = TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 40, 0.01); cornerSubPix(img_gray, cornersSub, Size(3, 3), Size(-1, -1), criteria); for (int i = 0; i < corners.size(); i++) {  cout << "第" << to_string(i) << "个检测出的角点坐标: " << corners[i] << "       角点位置优化后: " << cornersSub[i] << endl; } imshow("img", img); waitKey(0); exit(0); return 0;}

运行结果:

可以看到优化后的角点位置出现了小数,说明对其位置进行了优化。

四、FAST角点检测

相比于其他的角点检测方法,FAST角点检测的方法精度比较低,但FAST的优点也非常明显,就像它的名字一样--FAST,就是,它计算速度快,资源消耗少,在具有有限计算资源的情况下(如基于嵌入式设备的SLAM机器人)应用非常广泛。

FAST角点检测的原理如下:

  1. 在图像中任选一点p, 假定其像素值为Ip

  2. 以3为半径画圆,覆盖p点周围的16个像素,如下图所示

  3. 设定阈值t,如果这周围的16个像素中有连续的n个像素的像素值都小于(Ip?t)或大于(Ip+t),那么就判断点p为角点。在OpenCV的实现中n取值为12(16个像素周长的 3/4).

  4. 一种更加快的改进是:首先检测p点周围的四个点,即1,5,9,12四个点中是否有三个点满足超过Ip+t,如果不满足,则直接跳过,如果满足,则继续使用前面的算法,全部判断16个点中是否有12个满足条件

FAST角点检测代码如下:

#include <iostream>#include <opencv2/opencv.hpp>using namespace std;using namespace cv;int main(){ /*FAST角点检测*/ string path = "Lena.png"; Mat img = imread(path, 1); Mat img_gray; cvtColor(img, img_gray, COLOR_BGR2GRAY); vector<KeyPoint> keyPoints; Ptr<FastFeatureDetector> fast = FastFeatureDetector::create(32); //FAST角点检测器,32为阈值,阈值越大,特征点越少 fast->detect(img_gray, keyPoints, Mat());       //FAST角点检测 drawKeypoints(img, keyPoints, img);         //FAST角点绘制 imshow("img", img); waitKey(0); exit(0); return 0;}

运行结果如下:

FAST的缺点也很明显:

  1. 不具备尺度不变性

  2. 不具备旋转不变性

  3. 容易受到噪声影响

ORB特征点检测中专门针对上述缺点做了改进,使得FAST在保持运算速度快的优势下,更加鲁棒。

五、ORB特征点检测

ORB的全称是ORiented Brief,它是将FAST角点检测与BRIEF特征描述结合并进行了改进:

(1)由于要解决BRIEF算法的旋转不变性,则需要计算特征点的主方向。ORB中利用重心来计算,如下(其中(x,y)是特征邻域内的点):

  • 计算图像的矩


  • 计算矩形区域的质心

  • 连接FAST角点与质心得到方向向量

得到的θ值就是FAST特征点的主方向.

(2) BRIEF描述子,它是一种二进制编码的描述子,摈弃了利用区域灰度直方图描述特征点的传统方法,大大的加快了特征描述符建立的速度。

以特征点为中心,取SxS的邻域窗口。在窗口内随机选取一对(两个)点,比较二者像素的大小,进行如下二进制赋值。


在窗口中随机选取n对随机点,将其进行旋转,后进行判别,然后重复上述步骤的二进制赋值,形成一个二进制编码,这个编码就是对特征点的描述,即特征描述子。(一般N=256)

ORB特征点检测代码如下:

#include <iostream>#include <opencv2/opencv.hpp>using namespace std;using namespace cv;int main(){ /*ORB特征点检测*/ string path = "Lena.png"; Mat img = imread(path, 1); Mat img_gray; cvtColor(img, img_gray, COLOR_BGR2GRAY); vector<KeyPoint> keyPoints; Ptr<ORB> orb = ORB::create(500,      //特征点数目        1.2f,     //金字塔层级间的缩放比例        8,      //金字塔图像层数系数        31,      //边缘阈值        0,      //原图像在金字塔中的层级        2,      //生成描述子时需要用的像素点数目        ORB::HARRIS_SCORE,  //使用Harris方法评价特征点        31,      //生成描述子时关键点周围邻域的尺寸        20      //计算FAST角点时像素值差值的阈值        ); //ORB特征点检测器 orb->detect(img_gray, keyPoints, Mat());       //ORB特征点检测 Mat descriptors; orb->compute(img_gray, keyPoints, descriptors);      //ORB描述子计算 drawKeypoints(img, keyPoints, img);           //ORB特征点绘制:不含有角度和大小 //drawKeypoints(img, keyPoints, img, DrawMatchesFlags::DRAW_RICH_KEYPOINTS); //ORB特征点绘制:含有角度和大小 imshow("img", img); waitKey(0); exit(0); return 0;}

运行结果:


总结

非常常用且经典的特征检测算法还有SIFT和SUFT算法,这两种算法都是申请专利的,不能商用,在opencv中实现时需要先配置opencv_contrib拓展包,然后包含<xfeatures2d.hpp>头文件,然后初始化方式与ORB检测类似Ptr

关于SIFT特征点检测可以看一下这篇文章(https://blog.csdn.net/wuzhongqiang/article/details/123969628)

其他的检测方法就不过多展开,大家可以在网上自己找一下资料进行学习。

—END—

目前工坊已经建立了3D视觉方向多个社群,包括SLAM、工业3D视觉、自动驾驶方向,细分群包括:[工业方向]三维点云、结构光、机械臂、缺陷检测、三维测量、TOF、相机标定、综合群;[SLAM方向]多传感器融合、ORB-SLAM、激光SLAM、机器人导航、RTK|GPS|UWB等传感器交流群、SLAM综合讨论群;[自动驾驶方向]深度估计、Transformer、毫米波|激光雷达|视觉摄像头传感器讨论群、多传感器标定、自动驾驶综合群等。[三维重建方向]NeRF、colmap、OpenMVS等。除了这些,还有求职、硬件选型、视觉产品落地等交流群。大家可以添加小助理微信: dddvisiona,备注:加群+方向+学校|公司, 小助理会拉你入群。

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码