首页 > 编程语言 >一文搞定opencv中常见的关键点检测算法(附代码)

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

时间:2024-04-01 15:01:02浏览次数:22  
标签:gray 搞定 img 检测 角点 FAST opencv ORB 关键点

作者: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检测类似Ptrsift = SIFT::create。

关于SIFT特征点检测可以看一下这篇文章(https://blog.csdn.net/wuzhongqiang/article/details/123969628?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522168786332316800186532255%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=168786332316800186532255&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~rank_v31_ecpm-2-123969628-null-null.142%5Ev88%5Econtrol_2,239%5Ev2%5Einsert_chatgpt&utm_term=opencv%20sift%E7%89%B9%E5%BE%81%E7%82%B9%E5%8C%B9%E9%85%8Dc%2B%2B&spm=1018.2226.3001.4187)

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

—END—

高效学习3D视觉三部曲

第一步 加入行业交流群,保持技术的先进性

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

图片


添加小助理微信: dddvisiona,拉你入群

第二步 加入知识星球,问题及时得到解答

针对3D视觉领域的视频课程(三维重建、三维点云、结构光、手眼标定、相机标定、激光/视觉SLAM、自动驾驶等)、源码分享、知识点汇总、入门进阶学习路线、最新paper分享、疑问解答等进行深耕,更有各类大厂的算法工程人员进行技术指导。与此同时,星球将联合知名企业发布3D视觉相关算法开发岗位以及项目对接信息,打造成集技术与就业、项目对接为一体的铁杆粉丝聚集区,6000+星球成员为创造更好的AI世界共同进步,知识星球入口:「3D视觉从入门到精通」

学习3D视觉核心技术,扫描查看,3天内无条件退款

图片

高质量教程资料、答疑解惑、助你高效解决问题

第三步 系统学习3D视觉,对模块知识体系,深刻理解并运行

如果大家对3D视觉某一个细分方向想系统学习[从理论、代码到实战],推荐3D视觉精品课程学习网址:www.3dcver.com

基础课程:

[1]面向三维视觉算法的C++重要模块精讲:从零基础入门到进阶

[2]如何学习相机模型与标定?(代码+实战)

[3]ROS2从入门到精通:理论与实战

工业3D视觉方向课程:

[1](第二期)从零搭建一套结构光3D重建系统[理论+源码+实践]

[2] 保姆级线结构光(单目&双目)三维重建系统教程

[3]机械臂抓取从入门到实战课程(理论+源码)

[4]三维点云处理:算法与实战汇总

[5]彻底搞懂基于Open3D的点云处理教程!

[6]3D视觉缺陷检测教程:理论与实战!

SLAM方向课程:

[1]如何高效学习基于LeGo-LOAM框架的激光SLAM?

[1]彻底剖析激光-视觉-IMU-GPS融合SLAM算法:理论推导、代码讲解和实战

[2](第二期)彻底搞懂基于LOAM框架的3D激光SLAM:源码剖析到算法优化

[3]彻底搞懂视觉-惯性SLAM:VINS-Fusion原理精讲与源码剖析

[4]彻底剖析室内、室外激光SLAM关键算法和实战(cartographer+LOAM+LIO-SAM)

[5]ORB-SLAM3理论讲解与代码精析(第2期)

视觉三维重建

[1]彻底搞透视觉三维重建:原理剖析、代码讲解、及优化改进)

自动驾驶方向课程:

[1] 深度剖析面向自动驾驶领域的车载传感器空间同步(标定)

[2]面向自动驾驶领域目标检测中的视觉Transformer

[3]单目深度估计方法:算法梳理与代码实现

[4]面向自动驾驶领域的3D点云目标检测全栈学习路线!(单模态+多模态/数据+代码)

[5]如何将深度学习模型部署到实际工程中?(分类+检测+分割)

标签:gray,搞定,img,检测,角点,FAST,opencv,ORB,关键点
From: https://blog.csdn.net/weixin_46788581/article/details/137233048

相关文章

  • 玩转云端 | AccessOne实用窍门之三步搞定门户网站防护与加速
    随着互联网的飞速发展,网站建设已成为企事业单位推广、提供服务的重要途径之一。在数字技术快速迭代的当下,如何在保障网站安全的前提下提供高效服务,是企事业单位需要着重考虑的内容。网站安全防护是网站建设后不容忽视的一环,若不法分子通过网站漏洞进行攻/击,轻则导致企业服务中断,......
  • python opencv计算图片rgb平均值
    pythonopencv计算图片rgb平均值importcv2importnumpyasnp#读取图像3_202403281448172_20240328165448image=cv2.imread('3_20240328144817.jpg')#确保图像读取成功ifimageisnotNone:#OpenCV读取图像为BGR格式,我们需要转换为RGB#rgb_......
  • opencv 画轮廓
    1、读取图片2、转为灰度图片3、滤波降噪4、二值化5、形态学处理,开闭运算,腐蚀填充6、画轮廓,外接矩形,计算面积等基于4.0.9.80opencv版本 importcv2ascvimportnumpyasnpdefshow(img,title):cv.imshow(title,img)cv.waitKey()cv.destro......
  • Cursor:你的前端“超能力”助手,一句话搞定HTML、CSS、JS!
    一、简介Cursor,不仅仅是一个开发工具,更是你前端路上的“超级英雄”!它融合了GPT-4的AI智慧,能听懂你的“心声”,一键将你的创意转化为神奇的HTML、CSS和JavaScript代码。告别繁琐的编码工作,让Cursor成为你创意的翅膀,带你飞翔在前端的世界!链接:Cursor官网二、功能亮点1、一......
  • Python之Opencv进阶教程(2):统计图片灰度级别的像素数量
    1、什么是灰度像素数量在OpenCV中,可以使用**cv2.calcHist()**函数来计算图像的直方图。直方图是一种图形统计表,用于表示图像中每个灰度级别(或颜色通道)的像素数量或密度分布。以下是一个示例代码,演示了如何使用OpenCV计算和绘制图像的直方图:2、代码importcv2ascvimpor......
  • Python之Opencv进阶教程(1):图片模糊
    1、Opencv提供了多种模糊图片的方法加载原始未经模糊处理的图片importcv2ascvimg=cv.imread('../Resources/Photos/girl.jpg')cv.imshow('girl',img)1.1平均值关键代码#Averaging平均值a......
  • Python之Opencv教程(5):识别视频中的人脸
    1、识别效果2、识别代码importcv2ascvdefface_detect_demo(img):#将图片灰度gray=cv.cvtColor(img,cv.COLOR_BGR2GRAY)#加载特征数据face_detector=cv.CascadeClassifier("data//haarcascade_frontalface_alt.xml")fac......
  • Python之Opencv教程(2):图像边缘检测
    1、什么是边缘检测OpenCV中的边缘检测是一种常见的图像处理技术,用于检测图像中物体边缘的位置。常用的边缘检测算法包括Sobel算子、Scharr算子、Laplacian算子和Canny边缘检测算法等。下面将介绍使用OpenCV实现这些边缘检测算法的方法。2、边缘检测的作用边缘检测是图像......
  • 1.java openCV4.x 入门-环境搭建
    专栏简介......
  • Spring 一文彻底搞定循环依赖
    Spring解读循环依赖一.前言Spring是怎么解决循环依赖问题第一级缓存存放的是完全初始化完成的可以直接使用的对象,第二级缓存存放的是经过后置处理器处理(即代理过)的对象,第三级缓存村放的是刚实例化好没有经过后置处理器处理(即没有被代理过)的对象。二.什么是循环依赖......