图像特征提取与描述
我们怎么判断两幅图像是否描述的是同一个事物呢?很多时候我们需要给出这样的判断,那我们判断的依据是什么呢?比如说判断一个人,你怎么知道你眼前的人就是你知道的那个人?是因为他的长相和之前存储在我们大脑里的那个名字所对应的长相相匹配,或者你一直记着他鼻子下面长着一颗痣,我们才确定他就是我们认识的人。
那么对于图像来说是否也存在某种可以检测出来的特征,可以用于匹配呢?
答案当然是有的。
我们可以基于图像元素来进行特征的提取与匹配,如点与块、边缘和线条。
我们将特征点检测与匹配的过程分为四个阶段:
- 特征检测阶段:从每一幅图像中寻找那些能在其他图像中较好匹配的位置。
- 特征描述阶段:把检测到的特征点周围的每一个区域转化成一个更紧凑和稳定的描述子(descriptor),描述子可以和其他描述子进行匹配。
- 特征匹配阶段:在其他图像中搜索可能的匹配候选。
- 特征跟踪阶段:是第三阶段的另一种替代方式,它只在检测到特征点周围一个小的领域匹配,因此更适合视频处理。
特征检测器
- Harris检测器:GoodFeaturesToTrackDetector with Harris detector enabled
- SIFT : SIFT (nonfree module)
- FAST : FastFeatureDetector
其中SIFT是最常用的。
Harris角点检测
角点的一个特性:向任何方向移动变化都很大。Chris_Harris 和 Mike_Stephens 早在 1988 年的文章《A Combined Corner and Edge Detector》中就已经提出了焦点检测的方法,被称为Harris 角点检测。他把这个简单的想法转换成了数学形式。将窗口向各个方向移动(u,v)然后计算所有差异的总和。表达式如下:
窗口函数可以是正常的矩形窗口也可以是对每一个像素给予不同权重的高
斯窗口角点检测中要使 E (μ, ν) 的值最大。这就是说必须使方程右侧的第二项的取值最大。对上面的等式进行泰勒级数展开然后再通过几步数学换算(可以参
考其他标准教材),我们得到下面的等式:
其中:
这里 I x 和 I y 是图像在 x 和 y 方向的导数。(可以使用函数 cv2.Sobel()计算得到)。
然后就是主要部分了。他们根据一个用来判定窗口内是否包含角点的等式进行打分。
其中:
- det (M ) = λ 1 λ 2
- trace (M ) = λ 1 + λ 2
- λ 1 和 λ 2 是矩阵 M 的特征值
所以根据这些特征中我们可以判断一个区域是否是角点,边界或者是平面。
代码实现
import cv2
import numpy as np
filename = 'chessboard.jpg'
img = cv2.imread(filename)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
gray = np.float32(gray)
# 输入图像必须是 float32 ,最后一个参数在 0.04 到 0.05 之间
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[dst>0.01*dst.max()]=[0,0,255]
cv2.imshow('dst',img)
if cv2.waitKey(0) & 0xff == 27:
cv2.destroyAllWindows()
结果如下:
SIFT特征检测
Harris角点检测具有旋转不变性,即使图片发生了旋转,我们也能找到同样的角点.很明显即使图像发生旋转后角点还是角点.
如果我们对图像进行缩放呢?角点可能就不是角点了.
2004年,D.lowe提出了一个新的算法:尺度不变特征变换(SIFT).
SIFT算法的实现分为四部,我们在下一篇blog里再讲解.