简介
- 角点检测是计算机视觉中获取图像特征的一种方法,在运动检测、图像匹配等任务中都有比较广泛的应用。
- 角点被定义为
两条边的交点
,由于视觉任务的特殊性,角点检测的鲁棒性一般都是从平移、灰度变换、旋转、尺度变换等角度去评价。 - 最早有
Moravec角点检测算法
,是通过计算自相关函数,找到局部方差和最大的点,作为角点,但是这种方法只能比较8个方向(8邻域)的特征变换,而且自相关函数的窗口是方形的,且是二元的,因此响应函数可能会有噪声。
harris角点检测讲解
像素点描述
- 窗口发生$[u,v]$移动时,滑动窗口的像素灰度变换描述如下(借鉴了自相关函数的概念)
$$E(u,v) = \sum\limits_{(x,y) \in W(u,v)} {w(x,y){[I(x + u,y + v) - I(x,y)]}^2}$$
$[u,v]$是窗口的偏移量,$(x,y)$是窗口内的像素位置,$w(x,y)$是窗口函数,一般有常数窗口(1 inside and 0 outside
)或者高斯窗口。
- 因此在灰度变换平缓的区域,一般$E(u,v)$都比较小,而在灰度变换比较剧烈的区域,$E(u,v)$很大。
$E(u,v)$泰勒展开
- 利用泰勒公式,将$I(x+u,y+v)$进行泰勒展开,得到下式
$$E(u,v) = \sum\limits_{(x,y) \in W(x,y)} { (u I_x + v I_y)^2} = \sum\limits_{(x,y) \in W(x,y)} {\left[ u \; v \right]
\left[ {\begin{array}{*20c}
{I_x^2}& I_x I_y\\
I_x I_y & {I_y^2}
\end{array}} \right]
\left[ u \; v \right]^T}$$
令$M = \sum w(x,y){\left[ \begin{array}{*20c}
{I_x^2}& I_x I_y\\
I_x I_y & {I_y^2}
\end{array} \right]} $,则有
$$E(u,v) = \left[ u \; v \right]
M
\left[ \begin{array}{*20c}
u\\
v
\end{array} \right]$$
M矩阵分析
- 图像中主要有3种区域:flat area,line和corner,对于flat area,灰度在x和y方向上变化都比较平缓;对于line,灰度在一个方向上变化很剧烈(不一定是水平或者竖直方向,可以使任意方向),在另一方向上变化平缓;对于corner,灰度在2个方向的变化都很剧烈。具体如下图所示
特征值对应特征向量的权重,特征向量可以使任意方向的。对于M矩阵的特征值,如果2个特征值都很大,则可以认为是corner,如果只有1个大,则可以认为是line,如果2个都小,则可以认为flat area。
因此定义变量$R$,度量角点响应,计算方法如下
$$R=det(M)-k(trace(M))^2$$
其中$det(M)=\lambda _1 \lambda _2$,$trace(M)=\lambda _1 + \lambda _2$。
其中$\lambda _i$是$M$的特征值,$k$一般取0.04~0.06左右,可以画出等高线如下,可以看出基本呈现出双曲线的形式,我们需要的是特征值都很大的点,因此这种度量方式符合要求。
- 绘图的matlab代码如下
clc,clear,close all
x = linspace(0.01, 10, 100);
[x, y] = meshgrid( x );
k = 0.06;
z = x.*y - k*(x+y).^2;
contour( x, y, z, 'ShowText','on' )
xlabel('$\lambda _ 1$', 'Interpreter', 'latex', 'FontSize', 16);
ylabel('$\lambda _ 2$', 'Interpreter', 'latex', 'FontSize', 16);
优缺点
- 由上述表述可知,harris对于灰度仿射是具有不变性的(
灰度值平移与尺度变换
),对于图像旋转也是具有不变性
的(计算只与特征值有关,与特征向量无关),但是对于图像尺度变换不具有不变性
(没有使用图像金字塔等结构)。
角点检测代码测试
- 基于harris的角点检测算法代码如下,使用
python+opencv
完成,代码参考了opencv官网。 -
import cv2 import numpy as np import matplotlib.pyplot as plt %matplotlib inline filename = 'image/chessboard.png' img = cv2.imread(filename) gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) img_after = img.copy() gray = np.float32(gray) dst = cv2.cornerHarris(gray, 2, 3, 0.04) #result is dilated for marking the corners, not important dst = cv2.dilate(dst, None) # Threshold for an optimal value, it may vary depending on the image. img_after[dst>0.01*dst.max()]=[255,0,0] plt.figure( figsize=(12,6) ) plt.subplot( 121 ) plt.imshow( img ) plt.title("origianl") plt.subplot( 122 ) plt.imshow( img_after ) plt.title("harris detection") plt.show()
- 检测效果如下所示