Harris角点检测
作者:互联网
Harris角点提取算法:Harris 角点提取算法是Chris Harris 和Mike Stephens 在H.Moravec 算法的基础上发展出的通过自相关矩阵的角点提取算法,又称Plessey算法。Harris角点提取算法这种算子受信号处理中自相关面数的启发,给出与自相关函数相联系的矩阵M。M 阵的特征值是自相关函数的一阶曲率,如果两个曲率值都高,那么就认为该点是角点特征。
我的理解是角点作为一种图像特征,常常描述图像中的拐角,边界点等信息,使用滑动窗口的方式来进行识别,原理类似于边缘检测,检测窗口内的灰度突变。如果滑动窗口在各个方向滑动时都发生了灰度突变,则认为出现了角点,如果只有一个方向出现了突变,认为是遇到了直线线段。
窗口平移产生的灰度变化计算如下
其中窗口的权重可以采用边缘检测类似的01权重也可以采用高斯分布,越靠近中心像素点权重越高
将公式平移,做泰勒展开
因为Ο(u2,v2)近似为0,所以这个展开式可以进一步简化,uv是局部微小移动量,因此可以将余项忽略,得到一个二项式函数
M由图像求导计算得出
其中M=W*MI,而MI又等于
该卷积的目的是得到MI在周围像素上的局部平均。矩阵M又称为Harris矩阵。W 的宽度决定了在像素x 周围的感兴趣区域,即邻域大小。
像这样在区域附近对矩阵M取平均的原因是,特征值会依赖于局部图像特性而变化。如果图像的梯度在该区域变化,那么MI 的第二个特征值将不再为0。如果图像的梯度没有变化,M的特征值也不会变化。
忽略余项之后的表达式为一个二项式函数,然而二项式函数的本质上就是一个椭圆函数,椭圆的扁率和尺寸是由M(x,y)的特征值λ1、λ2决定的,椭圆的方向是由M(x,y)的特征矢量决定的,如下图所示,椭圆方程为:
椭圆函数特征值与图像中的角点、直线(边缘)和平面之间的关系如下图所示。共可分为三种情况:
a. 图像中的直线。一个特征值大,另一个特征值小,λ1>λ2或λ2>λ1。自相关函数值在某一方向上大,在其他方向上小。
b. 图像中的平面。两个特征值都小,且近似相等;自相关函数数值在各个方向上都小。
c. 图像中的角点。两个特征值都大,且近似相等,自相关函数在所有方向都增大。
通过M的两个特征值λ1和λ2的大小对图像点进行分类:
如果λ1和λ2都很小,图像窗口在所有方向上移动都无明显灰度变化。
由于我们是通过M的两个特征值的大小对图像进行分类,所以,定义角点相应函数R:
其中k为经验常数,一般取k=0.04~0.06。为了去除加权常数κ,我们通常使用商数detM/(traceM)2作为指示器。:所以,上图可以转化为:
其中:
• R 只与M的特征值有关
• 角点:R 为大数值正数
• 边缘:R 为大数值负数
• 平坦区:R 为小数值
在判断角点的时候,–对角点响应函数R进行阈值处理:R > threshold,提取R的局部极大值。
API
void cv::cornerHarris(
InputArray src,//灰度图像
OutputArray dst,
int BlockSize, // 计算λ1λ2时候的矩阵大小,常为2
int ksize, // 窗口大小,一般为3
double k, // 表示计算角度响应时候的参数大小,一般取0.04~0.06
int borderType=BORDERDEFAULT
)
demo
#include"pch.h" #include<iostream> #include<opencv2/opencv.hpp> #include<math.h> using namespace std; using namespace cv; const char* output_title = "HarrisCornerDetection Reslut"; int thresh = 130; int max_count = 255; Mat src, gray_src; void Harris_Demo(int, void*); int main(int argc, char** argv) { src = imread("1.jpg"); imshow("input img", src); namedWindow(output_title, CV_WINDOW_AUTOSIZE); cvtColor(src, gray_src, COLOR_BGR2GRAY); createTrackbar("Threshold:", output_title, &thresh, max_count, Harris_Demo); Harris_Demo(0, 0); waitKey(); return 0; } void Harris_Demo(int, void*) { Mat dst, norm_dst, normScaleDst; dst = Mat::zeros(gray_src.size(), CV_32FC1); int blocksize = 2; int ksize = 3; double k = 0.04; cornerHarris(gray_src, dst, blocksize, ksize, k, BORDER_DEFAULT); //按照最大最小值进行归一化 normalize(dst, norm_dst, 0, 255, NORM_MINMAX, CV_32FC1, Mat()); convertScaleAbs(norm_dst, normScaleDst); Mat resultImg = src.clone(); for (int row=0;row<resultImg.rows;++row) { uchar* currentRow = normScaleDst.ptr(row);//拿出一整行数据,另一种按像素操作图像的方法 for (int col = 0; col < resultImg.cols; ++col) { int value = (int)*currentRow; if (value > thresh) { circle(resultImg, Point(col, row), 2, Scalar(0, 0, 255), 2, 8, 0); } currentRow++; } } imshow(output_title, resultImg); }
标签:src,特征值,int,检测,角点,Harris,图像 来源: https://www.cnblogs.com/wangtianning1223/p/13499660.html