Harris原理及OpenCV实现

概述

harvest算法 harris算法 原理_源码分析

Harris算法是一种角点检测算法。

基本思想

harvest算法 harris算法 原理_OpenCV_02

   

harvest算法 harris算法 原理_特征检测_03

harvest算法 harris算法 原理_OpenCV_04

harvest算法 harris算法 原理_特征检测_05

在角点处,绿色小框在图像中沿着任意方向移动,方框覆盖的像素值都会发生很大的改变;平坦区域沿着任意方向都不会有太大变化;边缘区域其实向任意方向移动也不会有什么变化,除非是在边缘的末端。(是不是角点动一动就知道了,是骡子是马拉出来溜溜)

数学描述

harvest算法 harris算法 原理_harvest算法_06

表示像素以移动

harvest算法 harris算法 原理_harvest算法_07

之后像素值变化的方差和:

        

    

harvest算法 harris算法 原理_角点_08

    

harvest算法 harris算法 原理_OpenCV_09

数学特性

harvest算法 harris算法 原理_源码分析_10

harvest算法 harris算法 原理_源码分析_11

一届泰勒展开:

    

harvest算法 harris算法 原理_特征检测_12

    向指定方向

harvest算法 harris算法 原理_源码分析_13

移动,窗口内的像素值的变化量:    

harvest算法 harris算法 原理_harvest算法_14

    

harvest算法 harris算法 原理_源码分析_15

为滤波后的梯度散布矩阵,简写为

harvest算法 harris算法 原理_特征检测_16

。关键的地方在于,沿方向(u,v)算出来的值都是由ix,iy这个不变的东西决定的!

下面用三张图片验证:

harvest算法 harris算法 原理_角点_17

上图是用PS加上5%的杂色,杂色不是很明显,下图第一栏转换成double型后的显示效果,

harvest算法 harris算法 原理_角点_18

第二栏是

harvest算法 harris算法 原理_OpenCV_19

的分布,可以看出,平面的梯度散布范围很小,而边缘则呈扁椭圆,角点呈三角,但可以看到右上角的点

harvest算法 harris算法 原理_OpenCV_20

均比较大即我们要找的角点。

对应的特征值如下:


eigenvalue

Plane

Edge

Corner

harvest算法 harris算法 原理_源码分析_21

68483668088

116292777117498

62741886125931

harvest算法 harris算法 原理_角点_22

3358193434

7446530637

60918946323957


harvest算法 harris算法 原理_特征检测_23

上述只是定性的分析的关系,定量判定如下:

    

harvest算法 harris算法 原理_角点_24

    其中经验值

harvest算法 harris算法 原理_角点_25


harvest算法 harris算法 原理_源码分析_26

越大说明越有可能是角点。

harvest算法 harris算法 原理_特征检测_27

harvest算法 harris算法 原理_特征检测_28

上图为对应的响应

harvest算法 harris算法 原理_角点_29


在SIFT算法中使用了另一种判定方法:

设最大的特征值/最小的特征值为,例如则

考虑下式:

    

harvest算法 harris算法 原理_OpenCV_30

    令上式为

harvest算法 harris算法 原理_OpenCV_31


harvest算法 harris算法 原理_OpenCV_32


harvest算法 harris算法 原理_源码分析_33

为单调递增函数,故

harvest算法 harris算法 原理_角点_34

时判断为角点。经验值

harvest算法 harris算法 原理_OpenCV_35

。为什么角点沿任意方向移动,窗口内的像素都会有很大变化,而平坦区域沿任意方向移动都不会有变化,而边缘沿特定方向移动不会有变化呢?

为什么会有如此特性了,这就取决于M。

从梯度的散布形状可以判断该点是否是角点。梯度的散布形状又可以由散布矩阵的特征值大小、比例关系反映。因此,对对

harvest算法 harris算法 原理_特征检测_36

进行特征值分解得到特征值

harvest算法 harris算法 原理_harvest算法_37



不变性分析


  • 旋转不变性  

harvest算法 harris算法 原理_OpenCV_38

  • 局部仿射不变性

harvest算法 harris算法 原理_角点_39

  • 尺度不变性-不具备

harvest算法 harris算法 原理_源码分析_40

Harris-Laplace算法具有尺度不变性

算法

  1. 计算梯度,(考虑干扰用Sobel算子滤波),得到三张图片
  2. 对得到的三张图片继续滤波,实现在窗口下的累积和.
  3. 计算行列式、迹

OpenCV源码分析

cornerEigenValsVecs(constMat&src,Mat&eigenv,intblock_size,
intaperture_size,intop_type,doublek=0.,
intborderType=BORDER_DEFAULT )
{ 
#ifdef HAVE_TEGRA_OPTIMIZATION
if (tegra::cornerEigenValsVecs(src, eigenv, block_size, aperture_size, op_type, k, borderType))
return;
#endif
 
intsrc.depth();
doubledouble)(1 << ((aperture_sizeaperture_sizeblock_size;//1 << 2 *2 =8
if(aperture_size < 0 )
scale *= 2.;
if( depth ==CV_8U )
scale *= 255.;
scale = 1./scale;
 
CV_Assert(src.type() ==CV_8UC1src.type() ==CV_32FC1 );
 
Mat Dx, Dy;
if(aperture_size > 0 )
{ 
//[-1 0 1]
//|-2 0 2|
//[-1 0 1]
Sobel(src, Dx,CV_32F, 1, 0,aperture_size, scale, 0,borderType//3
Sobel(src, Dy,CV_32F, 0, 1,aperture_size, scale, 0,borderType//为什么来个这么大的scale??
} 
else
{ 
Scharr(src, Dx,CV_32F, 1, 0, scale, 0,borderType );
Scharr(src, Dy,CV_32F, 0, 1, scale, 0,borderType );
} 
 
Sizesrc.size();
Mat//dx^2,dxdy,dy^2
int i, j;
 
for( i = 0; i < size.height; i++ )
{ 
float* cov_data = (float*)(cov.data + i*cov.step);
constfloat* dxdata = (constfloat*)(Dx.data + i*Dx.step); 
constfloat* dydata = (constfloat*)(Dy.data + i*Dy.step); 
 
for( j = 0; j < size.width; j++ )
{ 
float dx = dxdata[j];
float dy = dydata[j];
 
cov_data[j*3] = dx*dx;
cov_data[j*3+1] = dx*dy;
cov_data[j*3+2] = dy*dy;
} 
} 
 
boxFilter(cov, cov, cov.depth(),Size(block_size,block_size),Point(-1,-1),false,borderType ); 
default value Point(-1,-1) means that the anchor is at the kernel center.
//改成Gaussian滤波
//GaussianBlur(cov, cov, Size(5, 5), 0,0 );
if( op_type == MINEIGENVAL )
calcMinEigenVal( cov, eigenv );
elseif( op_type == HARRIS )
calcHarris( cov, eigenv, k );
elseif( op_type == EIGENVALSVECS )
calcEigenValsVecs( cov, eigenv );
} 
}
calcHarris(constMat&_cov,Mat&_dst,doublek )
{
        …………………… 
for( ; j < size.width; j++ )
{ 
float a = cov[j*3];
float b = cov[j*3+1];
float c = cov[j*3+2];
dst[j] = (float)(a*c - b*b -k*(a + c)*(a + c));//R =
}
……………… 
}