Harris角点检测算法详解

Harris角点检测算法详解Harris 角点算法特征点检测广泛应用到目标匹配 目标跟踪 三维重建等应用中 在进行目标建模时会对图像进行目标特征的提取 常用的有颜色 角点 特征点 轮廓 纹理等特征 现在开始讲解常用的特征点检测 其中 Harris 角点检测是特征点检测的基础 提出了应用邻近像素点灰度差值概念 从而进行判断是否为角点 边缘 平滑区域 Harris 角点检测原理是利用移动的窗口在图像中计算灰度变化值

Harris角点算法

特征点检测广泛应用到目标匹配、目标跟踪、三维重建等应用中,在进行目标建模时会对图像进行目标特征的提取,常用的有颜色、角点、特征点、轮廓、纹理等特征。现在开始讲解常用的特征点检测,其中Harris角点检测是特征点检测的基础,提出了应用邻近像素点灰度差值概念,从而进行判断是否为角点、边缘、平滑区域。Harris角点检测原理是利用移动的窗口在图像中计算灰度变化值,其中关键流程包括转化为灰度图像、计算差分图像、高斯平滑、计算局部极值、确认角点。

一、基础知识

图像的变化类型:

Harris角点检测算法详解

在特征点检测中经常提出尺度不变、旋转不变、抗噪声影响等,这些是判断特征点是否稳定的指标。

性能较好的角点:

  1. 检测出图像中“真实”的角点
  2. 准确的定位性能
  3. 很高的重复检测率
  4. 噪声的鲁棒性
  5. 较高的计算效率

角点的类型:

Harris角点检测算法详解

基于图像灰度的方法通过计算点的曲率及梯度来检测角点,避免了第一类方法存在的缺陷,此类方法主要有Moravec算子、Forstner算子、Harris算子、SUSAN算子等。

二、Harris角点原理

1、算法思想

角点原理来源于人对角点的感性判断,即图像在各个方向灰度有明显变化。算法的核心是利用局部窗口在图像上进行移动判断灰度发生较大的变化,所以此窗口用于计算图像的灰度变化为:[-1,0,1;-1,0,1;-1,0,1][-1,-1,-1;0,0,0;1,1,1]。人各个方向上移动这个特征的小窗口,如图3中窗口内区域的灰度发生了较大的变化,那么就认为在窗口内遇到了角点。如图1中,窗口内图像的灰度没有发生变化,那么窗口内就不存在角点;如果窗口在某一个方向移动时,窗口内图像的灰度发生了较大的变化,而在另一些方向上没有发生变化,那么,窗口内的图像可能就是一条直线的线段。

2、数学模型

根据算法思想,构建数学模型,计算移动窗口的的灰度差值。

Harris角点检测算法详解

为了减小计算量,利用泰勒级数进行简化公式:

Harris角点检测算法详解Harris角点检测算法详解

上图中W函数表示窗口函数,M矩阵为偏导数矩阵。对于矩阵可以进行对称矩阵的变化,假设利用两个特征值进行替代,其几何含义类似下图中的表达。在几何

模型中通过判断两个特征值的大小,来判定像素的属性。

Harris角点检测算法详解Harris角点检测算法详解

M为梯度的协方差矩阵 ,在实际应用中为了能够应用更好的编程,定义了角点响应函数R,通过判定R大小来判断像素是否为角点。

R取决于M的特征值,对于角点|R|很大,平坦的区域|R|很小,边缘的R为负值。

Harris角点检测算法详解Harris角点检测算法详解

 

3、算法流程

1.利用水平,竖直差分算子对图像的每个像素进行滤波以求得Ix,Iy,进而求得M中的四个元素的值。

Harris角点检测算法详解

算法源码:

代码中如果array为-1,0,1,-1,0,1,-1,0,1}则是求解X方向的,如果为{-1,-1,-1,0,0,0,1,1,1}为Y方向的,则Ix和Iy求解结束

复制代码
//C代码 //这里的size/2是为了不把图像边界算进去。 //array也就是3*3的窗口函数为:double dx[9]={-1,0,1,-1,0,1,-1,0,1};或者 //定义垂直方向差分算子并求Iy double dy[9]={-1,-1,-1,0,0,0,1,1,1}; CvMat *mbys(CvMat *mat,int xwidth,int ywidth,double *array,int size1,int size2)//size { int i,j; int i1,j1; int px,py; int m; CvMat *mat1; mat1=cvCloneMat(mat); //为了去除边界,从框体一半开始遍历 for(i=size1/2;i 
     
     
复制代码

求解IX2相对比较简单,像素相乘即可。下面为基于opencv的C++版本,很是简单

复制代码
//构建模板 Mat xKernel = (Mat_ 
    
      (1,3) << -1, 0, 1); Mat yKernel = xKernel.t(); //计算IX和IY Mat Ix,Iy; //可参考filter2d的定义 filter2D(gray, Ix, CV_64F, xKernel); filter2D(gray, Iy, CV_64F, yKernel); //计算其平方 Mat Ix2,Iy2,Ixy; Ix2 = Ix.mul(Ix); Iy2 = Iy.mul(Iy); Ixy = Ix.mul(Iy); 
    
复制代码

2.对M的四个元素进行高斯平滑滤波,为的是消除一些不必要的孤立点和凸起,得到新的矩阵M。

复制代码
//本例中使用5×5的高斯模板 //计算模板参数 //int gausswidth=5; //double sigma=0.8; double *g=new double[gausswidth*gausswidth]; for(i=0;i 
     
     
复制代码

利用opencv接口则是很简单

复制代码
//构建高斯函数 Mat gaussKernel = getGaussianKernel(7, 1); //卷积计算 filter2D(Ix2, Ix2, CV_64F, gaussKernel); filter2D(Iy2, Iy2, CV_64F, gaussKernel); filter2D(Ixy, Ixy, CV_64F, gaussKernel);
复制代码

 

3.接下来利用M计算对应每个像素的角点响应函数R,即:Harris角点检测算法详解

复制代码
//计算cim:即cornerness of image,我们把它称做‘角点量’ CvMat *mat_cim; mat_cim=mbcim(mat_Ix2,mat_Iy2,mat_Ixy,cxDIB,cyDIB); //用来求得响应度 CvMat *mbcim(CvMat *mat1,CvMat *mat2,CvMat *mat3,int xwidth,int ywidth) { int i,j; CvMat *mat; mat=cvCloneMat(mat1); for(i = 0; i 
     
     
}
复制代码

复制代码
//opencv代码
Mat cornerStrength(gray.size(), gray.type()); for (int i = 0; i < gray.rows; i++) { for (int j = 0; j < gray.cols; j++) { double det_m = Ix2.at           (i,j) * Iy2.at             (i,j) - Ixy.at               (i,j) * Ixy.at                 (i,j); double trace_m = Ix2.at                   (i,j) + Iy2.at                     (i,j); cornerStrength.at                       (i,j) = det_m - alpha * trace_m *trace_m; } }                                                        
复制代码

4、局部极大值抑制,同时选取其极大值

复制代码
//-------------------------------------------------------------------------- // 第四步:进行局部非极大值抑制 //-------------------------------------------------------------------------- CvMat *mat_locmax; //const int size=7; mat_locmax=mblocmax(mat_cim,cxDIB,cyDIB,size); // cout< 
    
      max) max=CV_MAT_ELEM(*mat1,double,px,py); } if(max>0) CV_MAT_ELEM(*mat,double,i,j)=max; else CV_MAT_ELEM(*mat,double,i,j)=0; } return mat; } 
    
复制代码

在opencv中应用maxminloc函数

复制代码
// threshold double maxStrength; minMaxLoc(cornerStrength, NULL, &maxStrength, NULL, NULL); Mat dilated; Mat localMax; //默认3*3核膨胀,膨胀之后,除了局部最大值点和原来相同,其它非局部最大值点被 //3*3邻域内的最大值点取代 dilate(cornerStrength, dilated, Mat()); //与原图相比,只剩下和原图值相同的点,这些点都是局部最大值点,保存到localMax compare(cornerStrength, dilated, localMax, CMP_EQ);
复制代码

5.在矩阵R中,同时满足R(i,j)大于一定阈值threshold和R(i,j)是某领域内的局部极大值,则被认为是角点。

复制代码
cv::Mat cornerMap; // 根据角点响应最大值计算阈值 threshold= qualityLevel*maxStrength; cv::threshold(cornerStrength,cornerTh, threshold,255,cv::THRESH_BINARY); // 转为8-bit图 cornerTh.convertTo(cornerMap,CV_8U);// 和局部最大值图与,剩下角点局部最大值图,即:完成非最大值抑制 cv::bitwise_and(cornerMap,localMax,cornerMap);
imgDst = cornerMap.clone();
复制代码
for( int y = 0; y < cornerMap.rows; y++ ) { const uchar* rowPtr = cornerMap.ptr 
     
       (y); for( int x = 0; x < cornerMap.cols; x++ ) { // 非零点就是角点 if (rowPtr[x]) { points.push_back(cv::Point(x,y)); } } } 
     
复制代码

复制代码

 

 

 

 

 

 

 

 

 

 

 

三、算法源码

1、C版本

里面函数最基础的代码解释和注释

Harris角点检测算法详解  C源码

 

2、基于opencv源码

Harris角点检测算法详解  opencv+C++推荐

 

3、opencv中Harris接口

OpenCV的Hairrs角点检测的函数为cornerHairrs(),但是它的输出是一幅浮点值图像,浮点值越高,表明越可能是特征角点,我们需要对图像进行阈值化。

C++: void cornerHarris(InputArray src, OutputArray dst, int blockSize, int apertureSize, double k, int borderType = BORDER_DEFAULT);

 

  • src – 输入的单通道8-bit或浮点图像。
  • dst – 存储着Harris角点响应的图像矩阵,大小与输入图像大小相同,是一个浮点型矩阵。
  • blockSize – 邻域大小。
  • apertureSize – 扩展的微分算子大。
  • k – 响应公式中的,参数$\alpha$。
  • boderType – 边界处理的类型。
复制代码
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_BINARY); return 0; }
复制代码

 

 

 

 

 

 

 

从上面上间一幅图像我们可以看到,有很多角点都是粘连在一起的,我们下面通过加入非极大值抑制来进一步去除一些粘在一起的角点。

非极大值抑制原理是,在一个窗口内,如果有多个角点则用值最大的那个角点,其他的角点都删除,窗口大小这里我们用3*3,程序中通过图像的膨胀运算来达到检测极大值的目的,因为默认参数的膨胀运算就是用窗口内的最大值替代当前的灰度值。

Harris角点检测算法详解  View Code

 

四、Harris角点性质

 

1、阈值决定检测点数量

增大$\alpha$的值,将减小角点响应值$R$,降低角点检测的灵性,减少被检测角点的数量;减小$\alpha$值,将增大角点响应值$R$,增加角点检测的灵敏性,增加被检测角点的数量
 

2、Harris角点检测算子对亮度和对比度的变化不敏感

这是因为在进行Harris角点检测时,使用了微分算子对图像进行微分运算,而微分运算对图像密度的拉升或收缩和对亮度的抬高或下降不敏感。换言之,对亮度和对比度的仿射变换并不改变Harris响应的极值点出现的位置,但是,由于阈值的选择,可能会影响角点检测的数量。

Harris角点检测算法详解

 

3. Harris角点检测算子具有旋转不变性

Harris角点检测算法详解

Harris角点检测算子使用的是角点附近的区域灰度二阶矩矩阵。而二阶矩矩阵可以表示成一个椭圆,椭圆的长短轴正是二阶矩矩阵特征值平方根的倒数。当特征椭圆转动时,特征值并不发生变化,所以判断角点响应值也不发生变化,由此说明Harris角点检测算子具有旋转不变性。

4. Harris角点检测算子不具有尺度不变性

如下图所示,当右图被缩小时,在检测窗口尺寸不变的前提下,在窗口内所包含图像的内容是完全不同的。左侧的图像可能被检测为边缘或曲线,而右侧的图像则可能被检测为一个角点。

 

Harris角点检测算法详解

五、函数备注

1、compare

功能:两个数组之间或者一个数组和一个常数之间的比较

结构:

void compare(InputArray src1, InputArray src2, OutputArray dst, int cmpop)

如果对比结果为true,那么输出数组对应元素的值为255,否则为0

复制代码
//获取角点图 Mat getCornerMap(double qualityLevel) { Mat cornerMap; // 根据角点响应最大值计算阈值 thresholdvalue= qualityLevel*maxStrength; threshold(cornerStrength,cornerTh, thresholdvalue,255,cv::THRESH_BINARY); // 转为8-bit图 cornerTh.convertTo(cornerMap,CV_8U); // 和局部最大值图与,剩下角点局部最大值图,即:完成非最大值抑制 bitwise_and(cornerMap,localMax,cornerMap); return cornerMap; }
复制代码

2、bitwise_and(位运算函数)

功能:计算两个数组或数组和常量之间与的关系

结构:

void bitwise_and(InputArray src1, InputArray src2, OutputArray dst, InputArray mask=noArray())

操作过程为:

如果为多通道数组,每个通道单独处理

 

 

 

3、filter2D

OpenCV中的内部函数filter2D可以直接用来做图像卷积操作

void filter2D(InputArray src, OutputArray dst, int ddepth, InputArray kernel, Point anchor=Point(-1,-1), double delta=0, int borderType=BORDER_DEFAULT )

六、参考文章 

 

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

2、尺度空间理论

3、图像特征检测:Harris

4、图像特征ppt经典版

5、图像特征ppt经典版

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/178791.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月26日 下午4:29
下一篇 2026年3月26日 下午4:29


相关推荐

  • WAP网站推广

    WAP网站推广WAP 网站该如何推广呢 做 WAP 首要的目的就是赚钱 别说我俗 我说的是是绝对的真理 哪个做 WAP 的 伟大 到不是为了赚钱 我一直在主做联盟 赢点 WAP 世纪应该是做的人比较多的了 不过都太扣量了 而且广告有很多重复 服务态度也不是很好 客服人员都是爱理不理 后来开始做了一些新的平台 当然不是指那些小平台 而是行业里面比较新的有一定规模的 我目前刚选择了个某联盟做的广告 当初做主

    2026年3月20日
    2
  • rcnn算法原理_十大算法R实现

    rcnn算法原理_十大算法R实现R-CNN算法原理对于一张图片当中多个目标,多个类别的时候。前面的输出结果是不定的,有可能是以下有四个类别输出这种情况。或者N个结果,这样的话,网络模型输出结构不定所以需要一些他的方法解决目标检测(多个目标)的问题,试图将一个检测问题简化成分类问题①:目标检测-Overfeat模型滑动窗口目标检测的暴力方法是从左到右、从上到下滑动窗口,利用分类识别目标。为了在不同观察距离处检测…

    2025年10月4日
    4
  • VS 2015专业版密钥

    VS 2015专业版密钥vs 天试用期到了 会弹出提醒 在弹框选择使用密钥激活 输入密钥并应用 然后重启 vs 专业版密钥 HMGNV WCYXV X7G9W YCX63 B98R2 企业版密钥 HM6NR QXX7C DFW2Y 8B82K WTYJV

    2026年3月17日
    2
  • 利用webpack-chain配置happypack和DllReferencePlugin

    利用webpack-chain配置happypack和DllReferencePlugin好久不发博文 最近主要是攻考试去了 积累的几篇文章都懒得写 今天抽空写一下 webpack 的打包优化 由于我的框架是基于 vue admin template 做的 框架用的是 webpack chain 命令做的 所以也导致了我做 webpack 优化走了不少弯路 我的优化主要做了 happypack 多线程打包和 DllReference 抽离依赖库 1 先介绍 happypack 的步骤 1 安装相关插件 os 和 happypack 安装的命令根据自己喜欢 我用的是 yarnaddos 和 yarn

    2026年3月26日
    2
  • resnet34\resnet101网络结构图

    resnet34\resnet101网络结构图注释 7x7conv 3 gt 64 2 表示 7×7 大小的卷积核 3 64 表示输入输出通道 2 表示输出为原来的 1 2 x2 表示类似的结构还有两个

    2026年3月18日
    2
  • 阿里云服务器ECS 实例操作(系统选择说明)

    阿里云服务器ECS 实例操作(系统选择说明)

    2021年7月5日
    74

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号