Harris 角点检测 ~~
Why is a corner so special
Because, since it is the intersection of two edges, it represents a point in which the directions of these two edges change.
角点是两条边界的交点,体现了两个梯度方向上的变化
Hence, the gradient of the image (in both directions) have a high variation, which can be used to detect it.
- Consider a grayscale image 灰度图像. We are going to sweep a window (with displacements in the x direction and in the right direction) and will calculate the variation of intensity.
where:
- is the window at position
- is the intensity at
- is the intensity at the moved window
- Since we are looking for windows with corners, we are looking for windows with a large variation in intensity. Hence, we have to maximize the equation above, specifically the term: 角点 ~~ 梯度值
- Using Taylor expansion: 使用泰勒展开
- Expanding the equation and cancelling properly:
- Which can be expressed in a matrix form as:
- Let’s denote:
- So, our equation now is:
- A score is calculated for each window, to determine if it can possibly contain a corner:
where:
- det(M) =
- trace(M) =
a window with a score greater than a certain value is considered a “corner”
通过阈值判断是否属于角点 ~~
程序流程
1,检测角点:
cornerHarris( src_gray, dst, blockSize, apertureSize, k, BORDER_DEFAULT );
2,归一化:
normalize( dst, dst_norm, 0, 255, NORM_MINMAX, CV_32FC1, Mat() );3,计算绝对值
convertScaleAbs( dst_norm, dst_norm_scaled );
4,阈值判断
void cornerHarris(InputArray src, OutputArray dst, int blockSize, int ksize, double k, intborderType=BORDER_DEFAULT )
Parameters:
- src – Input single-channel 8-bit or floating-point image.
- dst – Image to store the Harris detector responses. It has the type CV_32FC1 and the same size assrc .
- blockSize – Neighborhood size (see the details on cornerEigenValsAndVecs() ).
- ksize – Aperture parameter for the Sobel() operator.
- k – Harris detector free parameter. See the formula below.
- borderType – Pixel extrapolation method. See borderInterpolate() .
C++: void convertScaleAbs(InputArray src, OutputArray dst, double alpha=1, double beta=0)
On each element of the input array, the function convertScaleAbs performs three operations sequentially: scaling, taking an absolute value, conversion to an unsigned 8-bit type:
In case of multi-channel arrays, the function processes each channel independently.
Code
#include "stdafx.h" #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( int argc, char** argv ) { /// Load source image and convert it to gray src = imread( "test1.jpg", 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 = 2; 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 ); }
注意:
apertureSize 和 参数k 的取值 ~~