一、Harris角点检测理论
首先需要明确什么是角点 角点的特点 平坦区域:窗口移动在所有方向没有明显的梯度变化 边缘区域:窗口移动在某个方向有明显梯度变化 角点区域:窗口移动在各个方向梯度值都有明显变化公式推导 窗口平移
[
U
,
V
]
[U, V]
[U,V]方向产生灰度变化
E
(
u
,
v
)
E(u, v)
E(u,v),可以将公式写为
E
(
u
,
v
)
=
∑
x
,
y
w
(
x
,
y
)
[
I
(
x
+
u
,
y
+
v
)
]
−
I
(
x
,
y
)
]
2
E(u,v)=\sum_{x,y}w(x,y){[I(x+u,y+v)]-I(x,y)]}^2
E(u,v)=∑x,yw(x,y)[I(x+u,y+v)]−I(x,y)]2
w
(
x
,
y
)
w(x,y)
w(x,y):窗口函数,内含权重信息,常用的权重为1或者高斯正态分布。函数
I
I
I:像素密度函数,类比于像素值。
x
,
y
x,y
x,y:窗口像素坐标
u
,
v
u,v
u,v:窗口偏移量
根据上述公式可知,当窗口在平坦区域上滑动时,
E
(
u
,
v
)
=
0
E(u, v)=0
E(u,v)=0;如果窗口处于变化剧烈的区域,灰度变化会很大,
E
(
u
,
v
)
E(u, v)
E(u,v)值也会很大。 下面要做的就是找到
E
(
u
,
v
)
E(u, v)
E(u,v)的最大值,对于给定的窗口函数
w
(
x
,
y
)
w(x,y)
w(x,y),我们就要找到
[
I
(
x
+
u
,
y
+
v
)
]
−
I
(
x
,
y
)
]
2
[I(x+u,y+v)]-I(x,y)]^2
[I(x+u,y+v)]−I(x,y)]2的最大值。 根据泰勒公式
f
(
x
+
u
,
y
+
v
)
≈
f(x+u,y+v)\approx
f(x+u,y+v)≈
f
(
x
,
y
)
+
u
f
x
(
x
,
y
)
+
v
f
y
(
x
,
y
)
f(x,y)+uf_x(x,y)+vf_y(x,y)
f(x,y)+ufx(x,y)+vfy(x,y) 可以得到:
∑
\sum
∑
[
I
(
x
+
u
,
y
+
v
)
]
−
I
(
x
,
y
)
]
2
≈
[I(x+u,y+v)]-I(x,y)]^2\approx
[I(x+u,y+v)]−I(x,y)]2≈
∑
\sum
∑
u
2
I
x
2
+
2
u
v
I
x
I
y
+
v
2
I
y
2
u^2I_x^2+2uvI_xI_y+v^2I_y^2
u2Ix2+2uvIxIy+v2Iy2
=
∑
\sum
∑
[
u
v
]
\begin{bmatrix} u&v\\ \end{bmatrix}
[uv]
[
I
x
2
I
x
I
y
I
x
I
y
I
y
2
]
\begin{bmatrix} I_x^2&I_xI_y\\ I_xI_y&I_y^2 \end{bmatrix}
[Ix2IxIyIxIyIy2]
[
u
v
]
\begin{bmatrix} u\\ v\\ \end{bmatrix}
[uv]
=
[
u
v
]
\begin{bmatrix} u&v\\ \end{bmatrix}
[uv] (
∑
\sum
∑
[
I
x
2
I
x
I
y
I
x
I
y
I
y
2
]
\begin{bmatrix} I_x^2&I_xI_y\\ I_xI_y&I_y^2 \end{bmatrix}
[Ix2IxIyIxIyIy2])
[
u
v
]
\begin{bmatrix} u\\ v\\ \end{bmatrix}
[uv]
这里令Harris矩阵
M
=
M=
M=
∑
x
,
y
\sum_{x,y}
∑x,y
w
(
x
,
y
)
w(x,y)
w(x,y)
[
I
x
2
I
x
I
y
I
x
I
y
I
y
2
]
\begin{bmatrix} I_x^2&I_xI_y\\ I_xI_y&I_y^2 \end{bmatrix}
[Ix2IxIyIxIyIy2]
则,
E
(
u
,
v
)
=
E(u, v)=
E(u,v)=
[
u
v
]
\begin{bmatrix} u&v\\ \end{bmatrix}
[uv]
M
M
M
[
u
v
]
\begin{bmatrix} u\\ v\\ \end{bmatrix}
[uv]
I
x
I_x
Ix、
I
y
I_y
Iy代表图像在x和y方向的导数 ,
λ
1
\lambda_1
λ1代表x方向偏导的特征值,
λ
2
\lambda_2
λ2代表y方向偏导的特征值。
特征值都比较大时,说明窗口中含有角点。特征值一个较大,一个较小时,说明窗口中含有边缘。特征值都比较小时,说明是平坦区域。
用图片表示如下: 4、角度响应
R
=
d
e
t
(
M
)
−
k
(
t
r
a
c
e
(
M
)
)
2
R=det(M)-k(trace(M))^2
R=det(M)−k(trace(M))2
k
k
k一般取经验值0.04~0.06
d
e
t
(
M
)
=
λ
1
λ
2
det(M)=\lambda_1\lambda_2
det(M)=λ1λ2
t
r
a
c
e
(
M
)
=
λ
1
+
λ
2
trace(M)=\lambda_1+\lambda_2
trace(M)=λ1+λ2
二、参数说明
cornerHarris(
InputArray src
,
OutputArray dst
,
int blockSize
,
int ksize
,
double k
,
int borderType
=Border_DEFAULT
)
三、代码演示
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv
;
using namespace std
;
Mat src
, gray_src
;
thresh
= 130;
max_count
= 255;
const char* output_title
= "HarrisCornerDetection Result";
void Harris_Demo(int, void*);
int main() {
src
= imread("image path");
if (src
.data
) {
cout
<< "cout not load image..." << endl
;
return -1;
}
namedWindow("input image", WINDOW_AUTOSIZE
);
imshow("output", src
);
namedWindow(output_title
, WINDOW_AUTOSIZE
);
cvtColor(src
, gray_src
, COLOR_BGR2GRAY
);
createTrackbar("Threshold", output_title
, &thresh
, max_count
, Harris_Demo
);
Harris_Demo(0, 0);
waitKey(0);
return 0;
}
void Harris_Demo(int, void*) {
Mat dst
, norm_dst
, normScaleDst
;
dst
= Mat
::zeros(gray_src().size(), CV_32FC1
);
int blockSize
= 2;
int ksize
= 3;
double k
= 0.04;
cornerHarris(gray_src
, dst
, blockSize
, ksize
, k
, BORDER_DEFAULT
);
normalize(dst
, norm_dst
, 0, 255, NORM_MINMAX
, CV_32FC1
, Mat());
convertScaleAbs(norm_dst
, normScaleDst
);
Mat resultImg
= src
.clone();
for (int row
= 0; row
< resultImg
.rows
; row
++) {
uchar
* currentRow
= normScaleDst
.ptr(row
);
for (int col
= 0; col
< resultImg
.cols
; col
++) {
int value
= (int)*currentRow
;
if (value
> thresh
) {
circle(resultImg
, Point(col
, row
), 2, Scalar(0, 0, 255), 2, 8, 0);
}
currentRow
++;
}
}
imshow(output_title
, resultImg
);
}
输出结果: