目标
在本教程中,您将学习:
-
特征时什么,为什么他们很重要
- 使用函数cv :: cornerHarris以及Harris-Stephens方法检测拐角。
理论
什么是特征?
- 在计算机视觉中,通常我们需要找到环境的不同帧之间的匹配点。为什么?如果我们知道两个图像如何相互关联,我们可以使用这两个图像来提取它们的信息。
- 当我们说匹配点时,一般指的是我们可以轻易识别的场景中的特征。我们称这些为特征。
-
那么,特征应具备哪些特性呢?
- 它必须是唯一可识别的
图像特征的类型
- 边缘
- 角落(也称为兴趣点)
- 斑点(也称为感兴趣的区域)
在本教程中,我们将专门研究角落特征。
为什么角落如此特别?
- 因为它是两条边的交点,所以它表示这两条边的方向改变的点。因此,图像的梯度(在两个方向上)具有很高的变化,可用于检测它。
它是如何工作的?
- 我们来找角落。由于角落代表图像中渐变的变化,我们将寻找这种“变化”。
- 考虑一个灰度图像I。我们要移动窗口,其中与在x方向位移为u和在y方向的位移为v,计算强度的变化。
E(u,v)=∑x,yw(x,y)[I(x+u,y+v)−I(x,y)]2
其中:w(x,y)是位置(x,y)的窗口,I(x,y)是位置(x,y)的强度,I(x+u,y+v)是位置(x+u,y+v)处的的强度
- 我们正在寻找有拐角的窗口,其强度变化很大。因此,我们必须最大化上面的等式:
∑x,y[I(x+u,y+v)−I(x,y)]2
-
使用泰勒展开:
E(u,v)≈∑x,yu2I2x+2uvIxIy+v2I2y
- 矩阵表示:
E(u,v)≈[uv](∑x,yw(x,y)[I2xIxIyIxIyI2y])[uv]
- 也就是:
M=∑x,yw(x,y)[I2xIxIyIxIyI2y]
- 也就是:
E(u,v)≈[uv]M[uv]
- 计算每个窗口的分数,以确定它是否可能包含角点:
R=det(M)−k(trace(M))2
其中:det(M) = λ1λ2 ,trace(M) = λ1+λ2
程序
#include "opencv2/highgui.hpp"#include "opencv2/imgproc.hpp"
#include <iostream>
using namespace cv;
using namespace std;
Mat src, src_gray;
int thresh = 200;
int max_thresh = 255;
const char* source_window = "Source image";
const char* corners_window = "Corners detected";
void cornerHarris_demo( int, void* );
int main( int argc, char** argv )
{
CommandLineParser parser( argc, argv, "{@input | building.jpg | input image}" );
src = imread( parser.get<String>( "@input" ) );
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 );
namedWindow( source_window );
createTrackbar( "Threshold: ", source_window, &thresh, max_thresh, cornerHarris_demo );
imshow( source_window, src );
cornerHarris_demo( 0, 0 );
waitKey();
return 0;
}
void cornerHarris_demo( int, void* )
{
int blockSize = 2;
int apertureSize = 3;
double k = 0.04;
Mat dst = Mat::zeros( src.size(), CV_32FC1 );
//输入,输出,邻域大小,sobel算子大小,k
cornerHarris( src_gray, dst, blockSize, apertureSize, k );
Mat dst_norm, dst_norm_scaled;
//输入,输出,最小值,最大值,归一化类型,类型,掩码
normalize( dst, dst_norm, 0, 255, NORM_MINMAX, CV_32FC1, Mat() );
//计算结果,并将结果转换为8位。输入,输出,alpha.
convertScaleAbs( dst_norm, dst_norm_scaled );
for( int i = 0; i < dst_norm.rows ; i++ )
{
for( int j = 0; j < dst_norm.cols; j++ )
{
if( (int) dst_norm.at<float>(i,j) > thresh )
{
circle( dst_norm_scaled, Point(j,i), 5, Scalar(0), 2, 8, 0 );
}
}
}
namedWindow( corners_window );
imshow( corners_window, dst_norm_scaled );
}