参考博客:https://blog.csdn.net/u011534057/article/details/77775974
学习笔记以及源码、图片下载:
提一下:
边缘角落(也称为兴趣点)Blob(也称为感兴趣的区域)在本教程中,我们将特别研究角落特征。
角点检测基本原理:
人们通常通过在一个小的窗口区域内观察点的灰度值大小来识别角点,如果往任何方向移动窗口都会引起比较大的灰度变换那么往往这就是我们要找的角点。
下面我们看一下Harris的数学公式,对于[x,y]平移[u,v]个单位后强度的变换有下式,I(x+u,y+v)是平移后的强度,I(x,y)是原图像像素。对于括号里面的值,如果是强度恒定的区域,那么它就接近于零,反之如果强度变化剧烈那么其值将非常大,所以我们期望E(u,v)很大。
其中w是窗函数,它可以是加权函数,也可以是高斯函数
利用二维泰勒展开式我们有
所以其中一阶可以近似为
于是我们可以给出Harris Corner的如下推导,其中Ix,Iy是x,y方向的Gradient模,乘以位移得到位移后的量
对于小的位移,我们可以用双线性插值方法近似:
其中M为2*2矩阵如下
在本质上我们可以把二次项看成一个椭圆函数,我们对M进行特征值分析有λ1,λ2
根据λ1,λ2的值我们可以把其分为三类:
1.λ1,λ2都很小且近似,E在所以方向接近于常数;
2.λ1>>λ2,或者λ2>>λ1, E将在某一方向上很大;
3.λ1,λ2都很大且近似,E将在所有方向上很大;
如图所示:
最后我们通过计算角点响应值R来判断其属于哪个区间
其中k一般为常数取在0.04-0.06间。
算法步骤:
1.计算图像x,y方向的梯度Ix,Iy
2.计算每个像素点的梯度平方
3.计算梯度在每个像素点的和
4.定义在每个像素点的矩阵H,也就是前面的M
5.计算每个像素的角点响应
6.设置阈值找出可能点并进行非极大值抑制
命令行参数: ./<可执行文件> 图片路径 example: 我上面压缩包里的文件的运行时使用
./cornerHarris_Demo building.jpg /** * @function cornerHarris_Demo.cpp * @brief Demo code for detecting corners using Harris-Stephens method * @author OpenCV team */ #include "opencv2/highgui.hpp" #include "opencv2/imgproc.hpp" #include <iostream> using namespace cv; using namespace std; /// Global variables Mat src, src_gray; int thresh = 200;//二值化图像时的阈值 int max_thresh = 255;//滑动条的最大阈值 const char* source_window = "Source image"; const char* corners_window = "Corners detected"; /// Function header void cornerHarris_demo( int, void* ); /** * @function main */ int main( int argc, char** argv ) { /// Load source image and convert it to gray CommandLineParser parser( argc, argv, "{@input | ../data/building.jpg | input image}" ); src = imread( parser.get<String>( "@input" ), IMREAD_COLOR ); if ( src.empty() ) { cout << "Could not open or find the image!\n" << endl; cout << "Usage: " << argv[0] << " <Input image>" << endl; return -1; } cvtColor( src, src_gray, COLOR_BGR2GRAY );//彩色变灰度 /// Create a window and a trackbar namedWindow( source_window, 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 * @brief Executes the corner detection and draw a circle around the possible corners */ void cornerHarris_demo( int, void* ) { Mat dst, dst_norm, dst_norm_scaled; dst = Mat::zeros( src.size(), CV_32FC1 ); /// Detector parameters 参数 int blockSize = 2; int apertureSize = 3; double k = 0.04; /// Detecting corners cornerHarris( src_gray, dst, blockSize, apertureSize, k, BORDER_DEFAULT );//Harris dectector /// 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 )//将得到的R与阈值比较,一般检测角点时阈值比较高,检测边时R<0,检测平滑区域时值比较小 { circle( dst_norm_scaled, Point( i, j ), 5, Scalar(0), 2, 8, 0 );//圈出角点 } } } /// Showing the result namedWindow( corners_window, WINDOW_AUTOSIZE ); imshow( corners_window, dst_norm_scaled ); }最终效果如下:
