Harris角点检测学习

1.角点的定义与性质

      角点是一种局部特征,具有旋转不变性和不随光照条件变化而变化的特点,一般将图像中曲率足够高或者曲率变化明显的点作为角点。检测得到的角点特征通常用于图像匹配、目标跟踪、运动估计等方面。

 

2.Harris角点

1)定性描述

      该算法中,将图像分为平坦区域、边缘、角点三部分。平坦区域中像素灰度在各个方向上变换都很小,边缘上的像素灰度在某个方向变化很大,但是在另一些方向变化很小;位于角点上的像素灰度则在各个方向上的变化都比较大。这是通过人眼观察得到的直观感受。

2)量化的数学表达

      不同区域像素的变化与相似性是相反的关系:变化越大,相似性越小,反之亦然。所以我们可以使用相似性度量其变化程度。图像I(x,y)在中心(x,y)处区域W(x,y)与相对中心(x,y)移动了△x/△y之后的区域相关性可以通过自相关函数给出

      w(u,v)是加权函数,可选取常数或者高斯加权函数(一般选取后者)

      看到delta标志就会想到泰勒展开式简化,简化流程如下:

 

      所以之前的相似性度量可以近似表达为一个二次项函数

 

      其本质是一个椭圆函数,椭圆的主方向就是图像变化率最大的主要方向。而椭圆的大小又是由M(x,y)的特征值决定的。

 

      套用这套理论到平坦区域、边缘、角点上,则表示为:

(1)边缘;椭圆狭长,一个特征值大、另一个特征值小

(2)平坦区域;两个特征值都很小

(3)角点;两个特征值都很大

 

      所以求出矩阵M(x,y)的两个特征值可以用于检测角点,但是计算量太大。Harris角点检测中避免直接求取特征值,而是利用M(x,y)的性质来计算两个特征值的相对大小

 

      只有两个特征值都比较大的情况下R取值才比较大

 

3.算法流程

      根据前面的描述,只要计算出图像中各个像素对应的R,并根据一个设定的阈值二值化处理即可得到角点。为了滤除局部区域的非极大值,可以使用非极大值抑制法做进一步的处理。算法整理流程如下:

 

4.opencv实现

       个人使用的开发环境是是opencv_2.4.13+vs2012,现将代码贴出

 1 #include <iostream>
 2 #include <core/core.hpp>
 3 #include <highgui/highgui.hpp>
 4 #include <features2d/features2d.hpp>
 5 #include <imgproc/imgproc.hpp>
 6 
 7 using namespace std;
 8 using namespace cv;
 9 
10 int main(int argc, char* argv[])
11 {
12     /* 1.以bmp格式读取图片,注意该图片此时应该放置于.sln所在目录 */
13     Mat image = imread("../church01.jpg", 0);
14     if(!image.data)
15         return 0;
16 
17     namedWindow("originalImage");
18     imshow("originalImage", image);
19     
20     /* 2.计算图像沿x/y方向一阶导数 */
21     Mat xKernel = (Mat_<double>(1,3) << -1, 0, 1);
22     Mat yKernel = xKernel.t();
23 
24     Mat Ix, Iy;
25     filter2D(image, Ix, CV_64F, xKernel);
26     filter2D(image, Iy, CV_64F, yKernel);
27     
28     /* 3.计算矩阵M中的各项 */
29     Mat Ix2, Iy2, Ixy;
30     Ix2 = Ix.mul(Ix);
31     Iy2 = Iy.mul(Iy);
32     Ixy = Ix.mul(Iy);
33 
34     /* 注意这里使用的是一阶高斯滤波而非二阶,尚未
35      * 理解其原因
36      */
37     Mat gaussKernel = getGaussianKernel(7,1);
38     filter2D(Ix2, Ix2, CV_64F, gaussKernel);
39     filter2D(Iy2, Iy2, CV_64F, gaussKernel);
40     filter2D(Ixy, Ixy, CV_64F, gaussKernel);
41 
42     /* 4.根据公式计算R矩阵 */
43     Mat cornerStrength(image.size(), CV_64F);
44     float alpha = 0.1f;
45     int rows, cols;
46     rows = image.rows;
47     cols = image.cols;
48     for(int i = 0; i < rows; i++)
49     {
50         for(int j = 0; j < cols; j++)
51         {
52             double det_m = Ix2.at<double>(i,j) * Iy2.at<double>(i,j) - Ixy.at<double>(i,j) * Ixy.at<double>(i,j);
53             double trace_m = Ix2.at<double>(i,j) + Iy2.at<double>(i,j);
54             cornerStrength.at<double>(i,j) = det_m - alpha*trace_m*trace_m;
55         }
56     }
57 
58     /* 5.阈值化并进行非极大值抑制 */
59     double maxStrength, minStrength;
60     minMaxLoc(cornerStrength, &minStrength, &maxStrength);
61     Mat dilated;
62     Mat localMax;
63     dilate(cornerStrength, dilated, Mat());
64     compare(cornerStrength, dilated, localMax, CMP_EQ);
65 
66     double threshold = 0.01 * maxStrength;
67     Mat cornerMap;
68     cornerMap = cornerStrength > threshold;
69     bitwise_and(cornerMap, localMax, cornerMap);
70     namedWindow("cornerMap");
71     imshow("cornerMap", cornerMap);
72 
73     /* 6.在原图上绘制角点 */
74     image = imread("../church01.jpg", 0);
75     for(int x = 0;x < cornerMap.cols; x++)
76     {
77         for(int y = 0; y < cornerMap.rows; y++)
78         {
79             if(cornerMap.at<uchar>(y,x))
80             {
81                 circle(image, Point(x,y), 3, Scalar(255), 1);
82 
83             }
84         }
85     }
86 
87     namedWindow("Harris Corner");
88     imshow("Harris Corner", image);
89     waitKey();
90     return 0;
91 }
View Code

      代码执行效果如下,originalImage是读入的原图,cornerMap是计算得到的角点(白色显示),Harris Corner是在原图上绘制角点的效果。

5.参考资料

 [1]《图像局部不变性特征与描述》

 [2]http://www.cnblogs.com/polly333/p/5416172.htmlHarris角点算法

转载于:https://www.cnblogs.com/Wiley-hiking/p/6895402.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
import cv2 as cv import numpy as np """"" cv2.cornerHarris() 可以用来进行角点检测。参数如下: • img - 数据类型为 float32 的输入图像。 • blockSize - 角点检测中要考虑的领域大小。 • ksize - Sobel 求导中使用的窗口大小 • k - Harris 角点检测方程中的自由参数,取值参数为 [0,04,0.06] """"" src_inital = cv.imread("E:/opencv/picture/building.jpg") src = cv.cvtColor(src_inital,cv.COLOR_BGR2GRAY) src = np.float32(src) dst = cv.cornerHarris(src,3,3,0.04) #R值是由det(M)-K(trace(M))*(trace(M)),当该点是角点时,该点所对应的R值就会很大,通过设置对R的阈值,就可以筛选得到角点 #这里的dst就是R值构成的灰度图像,灰度图像坐标会与原图像对应,R值就是角点分数,当R值很大的时候 就可以认为这个点是一个角点 print(dst.shape) src_inital[dst>0.08*dst.max()]=[0,0,255] """"" src_inital[dst>0.08*dst.max()]=[0,0,255] 这句话来分析一下 dst>0.08*dst.max()这么多返回是满足条件的dst索引值,根据索引值来设置这个点的颜色 这里是设定一个阈值 当大于这个阈值分数的都可以判定为角点 dst其实就是一个个角度分数R组成的,当λ1和λ2都很大,R 也很大,(λ1和λ2中的最小值都大于阈值)说明这个区域是角点。 那么这里为什么要大于0.08×dst.max()呢 注意了这里R是一个很大的值,我们选取里面最大的R,然后只要dst里面的值大于百分之八的R的最大值  那么此时这个dst的R值也是很大的 可以判定他为角点,也不一定要0.08可以根据图像自己选取不过如果太小的话 可能会多圈出几个不同的角点 """"" cv.imshow("inital_window",src_inital) cv.waitKey(0) cv.destroyAllWindows() 目标: 理解Harris角点检测的概念 使用函数cv2.cornerHarris(),cv2.cornerSubPix() 原理: Harris 角点检测的方法大概原理就是建立一个窗口区域,然后以当前窗口为中心向各个方向进行偏移。 如上图所示,第一个窗口向各个方向偏移的时候,像素值没有变,因为窗口偏移的时候没有遇到任何边缘信息。 第二个图,窗口当中有一个直线(即block是在边缘上),如果当前窗口进行上下的移动,也没有像素值发生变(在其他方向上灰度值也会变)。 第三个图,窗口覆盖了一个“拐角”,如果窗口进行偏移,任何方向上都会有像素变。 所以,第三张图片判断为检测到角点。 判断特征点是否为角点的依据:R只与M值有关,R为大数值正数时特征点为角点,R为大数值负数时为边缘,R为小数值时为平坦区 寻找R位于一定阈值之上的局部最大值,去除伪角点。 方向导数IxIx和IyIy可以使用cv2.Sobel()函数得到 Harris角点检测的结果是灰度图,图中的值为角点检测的打分值。需要选取合适的阈值对结果进行二值来检测角点。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值