角点是指在各个方向上灰度值变化都非常大的区域,灰度变化也就是灰度梯度。寻找角点也就是寻找灰度梯度最大的像素点。
我们使用一个窗口在图像上滑动来计算灰度的梯度
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,y∑w(x,y)[I(x+u,y+v)−I(x,y)]2
其中
w
(
x
,
y
)
w(x,y)
w(x,y)为窗口函数,
I
(
x
,
y
)
I(x,y)
I(x,y)为某个像素点的灰度值,
I
(
x
+
u
,
y
+
v
)
I(x+u,y+v)
I(x+u,y+v)为窗口移动后的灰度值。
进行泰勒展开:
E
(
u
,
v
)
=
∑
x
,
y
w
(
x
,
y
)
[
u
,
v
]
[
I
x
I
x
I
x
I
y
I
x
I
x
I
x
I
y
]
[
u
v
]
E(u,v)=\sum_{x,y}w(x,y) [u,v]\begin{bmatrix} I_xI_x & I_xI_y\\I_xI_x & I_xI_y\end{bmatrix}\begin{bmatrix} u\\v\end{bmatrix}
E(u,v)=x,y∑w(x,y)[u,v][IxIxIxIxIxIyIxIy][uv]
其中,
I
x
,
I
y
I_x,I_y
Ix,Iy为灰度值在两个方向的梯度。
令
M
=
∑
x
,
y
w
(
x
,
y
)
[
I
x
I
x
I
x
I
y
I
x
I
x
I
x
I
y
]
M=\sum_{x,y}w(x,y) \begin{bmatrix} I_xI_x & I_xI_y\\I_xI_x & I_xI_y\end{bmatrix}
M=x,y∑w(x,y)[IxIxIxIxIxIyIxIy]
即
E
(
u
,
v
)
=
[
u
,
v
]
M
[
u
v
]
E(u,v)=[u,v]M\begin{bmatrix} u\\v\end{bmatrix}
E(u,v)=[u,v]M[uv]
这里使用一个便于计算的数值来判断窗口在滑动过程中是否出现角点,即
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
- 当 ∣ R ∣ |R| ∣R∣很小时,表示平坦区域;
- 当 R < 0 R<0 R<0时,表示边缘区域;
- 当 R R R很大时,表示角点区域;
可以使用OpenCV的 cv.cornerHarris() 可直接获得图像中每个位置像素点的计算结果R,同时指定一个合适的阈值就可以筛选出所需要的角点信息。
Parameters:
- img - Input image, it should be grayscale and float32 type.
- blockSize - It is the size of neighbourhood considered for corner detection
- ksize - Aperture parameter of Sobel derivative used.
- k - Harris detector free parameter in the equation.
实例代码:
img = cv.imread('lena.jpg')
img_gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
# Input image should be grayscale and float32 type.
img_gray = np.float32(img_gray)
# the result of Harris Corner Detection is a grayscale image with these scores.
dst = cv.cornerHarris(img_gray,2,3,0.04)
#result is dilated for marking the corners, not important
dst = cv.dilate(dst,None)
# Threshold for an optimal value, it may vary depending on the image.
img[dst>0.01*dst.max()]=[0,0,255]
img_plt = cv.cvtColor(img,cv.COLOR_BGR2RGB)
plt.figure(figsize=(10,10))
plt.imshow(img_plt)