角点检测原理
角点检测原理使用一个固定窗口在图像上进行任意方向上的滑动,比较滑动前与滑动后两种情况,窗口中的像素灰度变化程度,如果存在任意方向上的滑动,都有着较大灰度变化,那么我们可以认为该窗口中存在角点。
图像特征类型分类
- 边缘
- 角点(感兴趣关键点)
- 斑点(Blos)(感兴趣区域)
关于角点的具体描述
- 一阶导数(即灰度的梯度)的局部最大所对应的像素点;
- 两条及两条以上边缘的交点;
- 图像中梯度值和梯度方向的变化速率都很高的点;
- 角点处的一阶导数最大,二阶导数为零,它指示了物体边缘变化不连续的方向。
Harris角点检测
Harris角点检测是一种直接基于灰度图像的角点提取算法,稳定性高,尤其对L型角点检测精度高。
当一个窗口在图像上移动,在平滑区域如图(a),窗口在各个方向上没有变化。在边缘上如图(b),窗口在边缘的方向上没有变化。在角点处如图(c),窗口在各个方向上具有变化。Harris角点检测正是利用了这个直观的物理现象,通过窗口在各个方向上的变化程度,决定是否为角点。
由于角点代表了图像像素梯度变化,我们将寻找这个”变化”。考虑到一个灰度图像 . 划动窗口 (with displacements 在x方向和 方向) 计算像素灰度变化。
其中:
is the window at position //是位于点处的窗口
is the intensity at //是位于点处的窗口的灰度值
is the intensity at the moved window //是位于点 处的移动窗口的灰度值
为了寻找带角点的窗口,我们搜索像素灰度变化较大的窗口。于是, 我们期望最大化以下式子:
使用 泰勒(Taylor)展开式:
式子可以展开为:
一个举证表达式可以写为:
表示为:
因此我们有等式:
每个窗口中计算得到一个值。这个值决定了这个窗口中是否包含了角点:
其中:
det(M) =
trace(M) =
一个窗口,它的分数大于一个特定值,这个窗口就可以被认为是”角点”。
代码
#include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc.hpp" #include <iostream> #include <stdio.h> #include <stdlib.h> using namespace cv; using namespace std; /// Global variables Mat src, src_gray; int thresh = 200; int max_thresh = 255; char* source_window = "Source image"; char* corners_window = "Corners detected"; /// Function header void cornerHarris_demo( int, void* ); /** @function main */ int main() { /// Load source image and convert it to gray src = imread("F:\\磊神图片\\上箭头.png", 1 ); cvtColor( src, src_gray, CV_BGR2GRAY ); /// Create a window and a trackbar namedWindow( source_window, CV_WINDOW_AUTOSIZE ); createTrackbar( "Threshold: ", source_window, &thresh, max_thresh, cornerHarris_demo ); imshow( source_window, src ); cornerHarris_demo( 0, 0 ); waitKey(0); return(0); } /** @function cornerHarris_demo */ void cornerHarris_demo( int, void* ) { Mat dst, dst_norm, dst_norm_scaled; dst = Mat::zeros( src.size(), CV_32FC1 ); /// Detector parameters int blockSize = 3; int apertureSize = 3; double k = 0.04; /// Detecting corners cornerHarris( src_gray, dst, blockSize, apertureSize, k, BORDER_DEFAULT ); /// Normalizing normalize( dst, dst_norm, 0, 255, NORM_MINMAX, CV_32FC1, Mat() ); convertScaleAbs( dst_norm, dst_norm_scaled ); /// Drawing a circle around corners for( int j = 0; j < dst_norm.rows ; j++ ) { for( int i = 0; i < dst_norm.cols; i++ ) { if( (int) dst_norm.at<float>(j,i) > thresh ) { circle( dst_norm_scaled, Point( i, j ), 5, Scalar(0), 2, 8, 0 ); } } } /// Showing the result namedWindow( corners_window, CV_WINDOW_AUTOSIZE ); imshow( corners_window, dst_norm_scaled ); }
分析
先将RGB图片进行灰度化处理
cvtColor( src, src_gray, CV_BGR2GRAY );
使用cornerHarris()函数检测角点
cornerHarris( src_gray, dst, blockSize, apertureSize, k, BORDER_DEFAULT );
函数原型:
void cornerHarris( InputArray src, OutputArray dst, int blockSize, int ksize, double k, int borderType=BORDER_DEFAULT );
其中:
- src:输入图像
- dst:输出图像
- blockSize:邻域的大小,比如:3x3
- ksize:Sobel()算子的孔径大小
- k:Harris参数,一般取值为0.04~0.06
- borderType:图像像素的边界模式,默认为BORDER_DEFAULT
将图片转化成为8位图形进行显示
convertScaleAbs( dst_norm, dst_norm_scaled );
函数原型:
void convertScaleAbs(InputArray src, OutputArray dst, double alpha=1, double beta=0);
效果图
原图
角点图
参考:
https://blog.csdn.net/lwzkiller/article/details/54633670
www.opencv.org.cn
https://blog.csdn.net/xiaowei_cqu/article/details/7805206