引言:
角点是图像很重要的特征,对图像图形的理解和分析有很重要的作用。角点在保留图像图形重要特征的同时,可以有效地减少信息的数据量,使其信息的含量很高,有效地提高了计算的速度,有利于图像的可靠匹配,使得实时处理成为可能。 对于同一场景,即使视角发生变化,通常具备稳定性质的特征。我们可以利用这一稳定的性质将角点应用三维场景重建运动估计,目标跟踪、目标识别、图像配准与匹配等计算机视觉领域。
图像特征类型可以被分为如下三种:
<1>边缘
<2>角点 (感兴趣关键点)
<3>斑点(Blobs)(感兴趣区域)
其中,角点是个很特殊的存在。如果某一点在任意方向的一个微小变动都会引起灰度很大的变化,那么我们就把它称之为角点。角点作为图像上的特征点,包含有重要的信息,在图像融合和目标跟踪及三维重建中有重要的应用价值。它们在图像中可以轻易地定位,同时,他们在人造物体场景,比如门、窗、桌等出随处可见。因为角点位于两条边缘的交点处,代表了两个边缘变化的方向上的点,,所以他们是可以精确定位的二维特征,甚至可以达到亚像素的精度。且其图像梯度有很高的变化,这种变化是可以用来帮助检测角点的。需要注意的是,角点与位于相同强度区域上的点不同,与物体轮廓上的点也不同,因为轮廓点难以在相同的其他物体上精确定位。
关于角点的具体描述可以有几种:
- 一阶导数(即灰度的梯度)的局部最大所对应的像素点;
- 两条及两条以上边缘的交点;
- 图像中梯度值和梯度方向的变化速率都很高的点;
- 角点处的一阶导数最大,二阶导数为零,指示物体边缘变化不连续的方向。
我们可以直观的概括下角点所具有的特征:
- 轮廓之间的交点;
- 对于同一场景,即使视角发生变化,通常具备稳定性质的特征;
- 该点附近区域的像素点无论在梯度方向上还是其梯度幅值上有着较大变化;
检测原理:
Harris角点检测算法 - 简书 https://www.jianshu.com/p/9323f64733ff
由于角点代表了图像像素梯度变化,我们将寻找这个”变化”。
-
考虑到一个灰度图像
. 划动窗口
(with displacements
在x方向和
方向)
计算像素灰度变化。
其中:
is the window at position
is the intensity at
is the intensity at the moved window
-
为了寻找带角点的窗口,我们搜索像素灰度变化较大的窗口。于是, 我们期望最大化以下式子:
-
使用 泰勒(Taylor)展开式:
-
式子可以展开为:
-
一个举证表达式可以写为:
-
表示为:
-
因此我们有等式:
-
每个窗口中计算得到一个值。这个值决定了这个窗口中是否包含了角点:
其中:
一个窗口,它的分数
大于一个特定值,这个窗口就可以被认为是”角点”。
- det(M) =
- trace(M) =
- det(M) =
API:
代码展示:
#include "pch.h"
#include <iostream>
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;
int thresholdval = 130;
int thresholdmax = 255;
Mat src;
Mat graysrc;
void CornerHarris_demo(int pos, void* data);
int main()
{
//待检测图像
src = imread("F:\\visual studio\\Image\\building1.jpg");
if (src.empty())
{
cout << "Can't load the image" << endl;
return -1;
}
//转化为灰度图
cvtColor(src, graysrc, COLOR_BGR2GRAY);
namedWindow("dst", WINDOW_AUTOSIZE);
createTrackbar("Threshold", "dst", &thresholdval, thresholdmax, CornerHarris_demo);
CornerHarris_demo(0, 0);
waitKey(0);
}
void CornerHarris_demo(int pos, void* data)
{
Mat corner = Mat::zeros(graysrc.size(), CV_32FC1);
//角点检测参数
int blocksize = 2;
int aperturesize = 3;
double k = 0.04;
//角点检测
cornerHarris(graysrc, corner, blocksize, aperturesize, k, BORDER_DEFAULT);
//标准化
Mat corner_norm;
normalize(corner, corner_norm, 0, 255, NORM_MINMAX);
//转化为CV_8U类型
Mat corner_uchar;
convertScaleAbs(corner_norm, corner_uchar, 1, 0);
Mat dst = src.clone();
// 将检测到的,且符合阈值条件的角点绘制出来
for (int j = 0; j < dst.rows; j++)
{
for (int i = 0; i < dst.cols; i++)
{
if ((int)corner_norm.at<float>(j, i) > thresholdval)
{
circle(dst, Point(i, j), 5, Scalar(255, 0, 0), 2, 8, 0);
circle(corner_uchar, Point(i, j), 5, Scalar(0), 2, 8, 0);
}
}
}
imshow("dst", dst);
imshow("corner", corner_uchar);
}
效果展示:
阈值为130时:
阈值为72时: