精华内容
下载资源
问答
  • 角点、特征的区别(检测子,描述子)
    千次阅读
    2020-06-02 15:25:54

    在机器视觉中,经常听到两个名字:角点、特征点。出现频率比较高的:角点检测、特征点匹配。
    那么问题来了,角点和特征点到底什么关系?
    **图像的特征点(feature point)**是指图像中具有鲜明特性并能够有效反映图像本质特征能够标识图像中目标物体的点。(反应图像特征的点)
    **图像的角点(corner point)**作为图像关键的局部结构特征,通常被描述成灰度强度变化不连续的点,被称为灰度图像上的奇异特征点。
    角点属于特征点,而特征点包括了角点以及其他点。因此可以把角点叫做特征点,但是不能认为特征点就是角点。

    角点在图像特征点中占比很大,大部分的研究均围绕着它展开的。
    角点的两种定义:1)二维灰度图像中各个不同方向灰度亮度信息剧烈变化的点;2)图像中所有边缘轮廓线上的曲率极大值点。

    那么角点如何应用呢?
    ①获取图像角点(定位角点)
    检测子(detector)提取:利用基于灰度强度、基于角点模型和基于边缘轮廓的角点检测算法获得图像中角点的位置。(SIFT算法、SURF算法、Harris算法、FAST算法等)

    ②描述图像角点(角点特征)
    描述子(descriptor)提取:利用数值方法定义每个角点的特征,便于第三步的特征匹配。(邻域模板匹配、SIFT特征描述子、SURF特征描述子、ORB特征描述子)。

    ③匹配
    通过描述子,匹配待匹配的两幅图像的角点。(暴力匹配、KD树等)

    这里说一下sift
    从上面的描述不难发现,sift即有自己的检测子,又包括了自己的描述子。因此有时候我们会看到,sift检测子,sift描述子之类的描述,你可能会问sift到底是啥?
    sift是一个特征,可以用sift检测子从图像中检测出该特征,用sift描述子描述该特征。

    这里再提一下sift描述子
    描述子生成:
    1)旋转图像至主方向
    在角点的邻域内,把所有点的梯度方向统计至直方图(隔10°设置一个直方图,36个直方图),找到直方图中的值最大的方向为主方向。然后把两个待匹配的特征点的其中一个点进行旋转,保持两个特征点的主方向相同。
    2)三线性插值
    图像旋转后,原来在整点的像素点可能不在整点了,例如:原点为(2,4),旋转后是(3.5,3)。这样没法进行后续操作,因此需要插值,用非整点像素插值出整点像素。
    3)生成128维特征向量
    在这里插入图片描述
    大家可以数一下4X4X8=128
    总共有16个区域,每个区域16个像素点,把16个像素点的梯度化为8个方向的向量,类似于力合成与分解。
    4)归一化向量
    为了去除光照变化的影响,需要对特征向量归一化,每个向量除以总向量的L2范数。之后把归一化的向量中大于0.2的设置为0.2,再进行以此归一化。

    更多相关内容
  • 这篇文章整理两个图像处理中非常重要的算法,一个是Harris角点检测算法,另一个是SIFT特征匹配算法,这两个算法本质上还是去找图像里面的关键特征,帮助我们后续更好的理解图像以及做各种各样的分析。 由于这两个...

    1. 写在前面

    这篇文章整理两个图像处理中非常重要的算法,一个是Harris角点检测算法,另一个是SIFT特征匹配算法,这两个算法本质上还是去找图像里面的关键特征点,帮助我们后续更好的理解图像以及做各种各样的分析。 由于这两个算法涉及到的数学原理会比较多,而我刚入门,所以只是从使用的角度,简单的描述到底在做什么事情,至于详细的数学细节或者推导,这里不过多整理,以掉包能完成任务为首要目的啦。

    首先,先介绍Harris角点检测算法,角点在图像中是很重要的特征,信息含量很高,那么如何找到一个图像里面的角点呢? 这个算法就能轻松解决。但是呢?这个算法只考虑了旋转不变性,即一个角点旋转之后还是角点,没有考虑到尺度不变,尺度变化可能会导致角点变成边缘,所以有没有一种方法同时考虑这两个特性去找特征点呢? 这就是SIFT算法,这个算法也是用来侦测和描述影像中的局部性特征,基于位置,尺度,旋转不变性在空间尺度中寻找特征点。 这两个算法的使用场景非常广泛,比如图像配准,目标识别跟踪,图像对齐,图像拼接(全景图), 相机标定,三维场景重建等。最后,通过一个全景图拼接的Demo感受下这两个算法的魅力 😉

    大纲如下:

    • Harris角点检测算法
    • SIFT特征匹配算法
    • 特征匹配
    • 案例Demo: 全景图拼接

    Ok, let’s go!

    2. Harris角点检测算法

    角点特征能在保留图像重要特征的同时,有效减少信息数据量,算是图像中较好的特征,比边缘特征更好的用于定位。 在图像处理中,检测角点特征的算法很多,最常用,最基础的就是Harris角点检测算法。

    在说这个算法之前,先感受下啥子是角点:

    在这里插入图片描述
    如果我们人眼看的话,非常好理解,就是图像里面的物体的角呗。那么计算机看,定位这些角点可就不那么容易了。 如果想让计算机看,那么必须得搞明白一个事情: 这样的角点,与边界点,以及普通屏幕点有啥区别,即上图的红框,蓝框,黑框内的点在数值上会有啥区别呢?

    Harris角点检测认为:特征点具有局部差异性。如何描述呢? 每一个点为中心,取一个窗口,比如窗口大小 5 × 5 5\times5 5×5或者 7 × 7 7\times7 7×7, 那么窗口描述了这个特征点周围的环境。

    • 如果这个特定的窗口在图像各个方向移动时, 窗口内图像的灰度没有发生变化,那么窗口内不存在角点,比如蓝框
    • 如果窗口在某一个方向移动,窗口内图像灰度发生了较大变化,而另一些方向没有发生变化,那么,窗口内图像可能是一条直线边界, 黑框这个, 垂直方向移动就剧烈变化,水平方向就不变
    • 如果在各个方向上移动这个特征的小窗口,窗口内区域灰度都发生较大的变化,就认为这个窗口内有角点。

      在这里插入图片描述

    说是这么说,但具体应该怎么找到角点呢? Harris角点检测算法主要是三步:

    1. 当窗口同时向 x x x y y y两个方向移动时,计算窗口内部像素值变化量 E ( u , v ) E(u,v) E(u,v)
    2. 对于每个窗口,计算对应的角点响应函数 R R R
    3. 对于该函数阈值处理,如果 R > t h r e s h o l d R>threshold R>threshold,表示该窗口对应一个角点特征

    下面详细展开。

    2.1 窗口移动,计算像素值变化量

    这里的核心问题: 如何确定哪些窗口引起较大灰度值变化?

    假设当前窗口中心的像素点位置 ( x , y ) (x,y) (x,y), 这个点像素值 I ( x , y ) I(x,y) I(x,y), 如果这个窗口分别向 x x x y y y方向分别移动了 u u u v v v步, 到了一个新的位置 ( x + u , y + v ) (x+u, y+v) (x+u,y+v), 像素值 I ( x + u , y + v ) I(x+u, y+v) I(x+u,y+v), 那么 I [ ( x + u , y + v ) − I ( x , y ) ] I[(x+u,y+v)-I(x,y)] I[(x+u,y+v)I(x,y)]就是中心点移动引起的灰度值的变化。

    那我们这是个窗口呀,比如 3 × 3 3\times3 3×3,那就有9个点,窗口一移动的话,这9个点都有引起的灰度值的变化,而把这个都加和,就得到了窗口在各个方向上移动 ( u , v ) (u,v) (u,v)造成的像素灰度值变化,这个应该很好理解,公式如下:
    E ( u , v ) = ∑ ( x , y ) ∈ W ( x , y ) w ( x , y ) × [ I ( x + u , y + v ) − I ( x , y ) ] 2 E(u, v)=\sum_{(x, y)\in W(x,y)} w(x, y) \times[I(x+u, y+v)-I(x, y)]^{2} E(u,v)=(x,y)W(x,y)w(x,y)×[I(x+u,y+v)I(x,y)]2
    这里多出了一个 w ( x , y ) w(x,y) w(x,y)函数,表示窗口内各个像素的权重,可以设定为窗口中心为原点的高斯分布,如果窗口中心点像素是角点,那么窗口移动前后,中心点灰度值变化非常强烈,那么这个权重就大一些,表示该点对灰度变化贡献大。 而离着窗口中心较远的点,灰度变化较小,于是权重小一些,对灰度变化的贡献小。

    这个公式就是我们的目标函数,如果是角点,这个函数值会比较大,所以我们就是最大化这个函数来得到图像中的角点。

    But, 上面这个函数计算 E ( u , v ) E(u,v) E(u,v)会非常慢,比较涉及到了窗口内所有像素点的计算,所以,我们用泰勒,先对像素值函数进行近似。
    I ( x + u , y + v ) = I ( x , y ) + I x ( x , y ) u + I y ( x , y ) v + O ( u 2 , v 2 ) ≈ I ( x , y ) + I x ( x , y ) u + I y ( x , y ) v I(x+u, y+v)=I(x, y)+I_{x}(x, y) u+I_{y}(x, y) v+O\left(u^{2}, v^{2}\right) \approx I(x, y)+I_{x}(x, y) u+I_{y}(x, y) v I(x+u,y+v)=I(x,y)+Ix(x,y)u+Iy(x,y)v+O(u2,v2)I(x,y)+Ix(x,y)u+Iy(x,y)v
    其中, I x I_x Ix I y I_y Iy I I I偏微分, 在图像中是 x x x y y y方向上的梯度图,可通过cv2.Sobel()得到
    I x = ∂ I ( x , y ) ∂ x , I y = ∂ I ( x , y ) ∂ y I_{x}=\frac{\partial I(x, y)}{\partial x}, \quad I_{y}=\frac{\partial I(x, y)}{\partial y} Ix=xI(x,y),Iy=yI(x,y)
    把上面的式子代入 E ( u , v ) E(u,v) E(u,v)化简得:
    E ( u , v ) = ∑ ( x , y ) ∈ W ( x , y ) w ( x , y ) × [ I ( x , y ) + u I x + v I y − I ( x , y ) ] 2 = ∑ ( x , y ) ∈ W ( x , y ) w ( x , y ) × ( u I x + v I y ) 2 = ∑ ( x , y ) ∈ W ( x , y ) w ( x , y ) × ( u 2 I x 2 + v 2 I y 2 + 2 u v I x I y ) \begin{aligned} E(u, v) &=\sum_{(x, y)\in W(x,y)} w(x, y) \times\left[I(x, y)+u I_{x}+v I_{y}-I(x, y)\right]^{2} \\ &=\sum_{(x, y)\in W(x,y)} w(x, y) \times\left(u I_{x}+v I_{y}\right)^{2} \\ &=\sum_{(x, y)\in W(x,y)} w(x, y) \times\left(u^{2} I_{x}^{2}+v^{2} I_{y}^{2}+2 u v I_{x} I_{y}\right) \end{aligned} E(u,v)=(x,y)W(x,y)w(x,y)×[I(x,y)+uIx+vIyI(x,y)]2=(x,y)W(x,y)w(x,y)×(uIx+vIy)2=(x,y)W(x,y)w(x,y)×(u2Ix2+v2Iy2+2uvIxIy)
    这个用矩阵来表示, 线代的二次型转换:
    E ( u , v ) ≈ [ u , v ] M ( x , y ) [ u v ] E(u, v) \approx[u, v] M(x,y)\left[\begin{array}{l} u \\ v \end{array}\right] E(u,v)[u,v]M(x,y)[uv]
    其中, 矩阵 M M M如下:
    M ( x , y ) = ∑ w [ I x ( x , y ) 2 I x ( x , y ) I y ( x , y ) I x ( x , y ) I y ( x , y ) I y ( x , y ) 2 ] = [ ∑ w I x ( x , y ) 2 ∑ w I x ( x , y ) I y ( x , y ) ∑ w I x ( x , y ) I y ( x , y ) ∑ w I y ( x , y ) 2 ] = [ A C C B ] M(x, y)=\sum_{w}\left[\begin{array}{cc} I_{x}(x, y)^{2} & I_{x}(x, y) I_{y}(x, y) \\ I_{x}(x, y) I_{y}(x, y) & I_{y}(x, y)^{2} \end{array}\right]=\left[\begin{array}{cc} \sum_{w} I_{x}(x, y)^{2} & \sum_{w} I_{x}(x, y) I_{y}(x, y) \\ \sum_{w} I_{x}(x, y) I_{y}(x, y) & \sum_{w} I_{y}(x, y)^{2} \end{array}\right]=\left[\begin{array}{ll} A & C \\ C & B \end{array}\right] M(x,y)=w[Ix(x,y)2Ix(x,y)Iy(x,y)Ix(x,y)Iy(x,y)Iy(x,y)2]=[wIx(x,y)2wIx(x,y)Iy(x,y)wIx(x,y)Iy(x,y)wIy(x,y)2]=[ACCB]
    所以最终目标函数化成了:
    E ( x , y ; u , v ) ≈ A u 2 + 2 C u v + B v 2 A = ∑ w I x 2 , B = ∑ w I y 2 , C = ∑ w I x I y \begin{aligned} &E(x, y ;u, v) \approx A u^{2}+2 C u v+B v^{2} \\ &A=\sum_{w} I_{x}^{2}, B=\sum_{w} I_{y}^{2}, C=\sum_{w} I_{x} I_{y} \end{aligned} E(x,y;u,v)Au2+2Cuv+Bv2A=wIx2,B=wIy2,C=wIxIy
    到这里,应该很好理解,无非就是泰勒近似,以及线代里面二次型化简的东西,注意 M M M这里是一个协方差矩阵,主对角线可以看成是自己方向上梯度的方差,而副对角线是与其他方向梯度的协方差,并且这是一个对称矩阵。

    下面说点不是很好理解的: 二次项函数本质上是椭圆函数,椭圆方程为:
    [ u , v ] M ( x , y ) [ u v ] = 1 [u, v] M(x,y)\left[\begin{array}{l} u \\ v \end{array}\right]=1 [u,v]M(x,y)[uv]=1
    可视化出来如下:
    在这里插入图片描述
    这里的 λ \lambda λ就是实对称矩阵 M M M的特征值。 这里可能并不是很好理解,我下面尝试从基变换的角度解释下。 首先, M M M是实对称矩阵,那么就一定满足:
    R M R ⊤ = Λ = ( λ 1 0 0 λ 2 ) R M R^{\top}=\Lambda=\left(\begin{array}{llll} \lambda_{1} & 0 \\ 0& \lambda_{2} \end{array}\right) RMR=Λ=(λ100λ2)

    R R R M M M的特征向量组合, λ 1 , λ 2 \lambda_1, \lambda_2 λ1,λ2 M M M的特征值。把这个式子代入上面的式子:
    [ u , v ] R M R ⊤ [ u v ] = [ u , v ] Λ [ u v ] = [ u , v ] ( λ 1 0 0 λ 2 ) [ u v ] = λ 1 u 2 + λ 2 v 2 = u 2 1 λ 1 + v 2 1 λ 2 = 1 [u, v] R M R^{\top}\left[\begin{array}{l} u \\ v \end{array}\right] = [u, v] \Lambda\left[\begin{array}{l} u \\ v \end{array}\right]=[u, v] \left(\begin{array}{llll} \lambda_{1} & 0 \\ 0& \lambda_{2} \end{array}\right)\left[\begin{array}{l} u \\ v \end{array}\right]=\lambda_1u^2+\lambda_2v^2=\frac{u^2}{\frac{1}{\lambda_1}}+\frac{v^2}{\frac{1}{\lambda_2}}=1 [u,v]RMR[uv]=[u,v]Λ[uv]=[u,v](λ100λ2)[uv]=λ1u2+λ2v2=λ11u2+λ21v2=1
    这样就转成了标准的椭圆方程了,而 M M M的特征值平方根正好是表示着椭圆长短轴。那么特征值是啥? 其实就是将原始像素点映射到新的空间中(映射规则就是 [ u , v ] R [u,v]R [u,v]R), 在每组基方向上的梯度方差或者叫变化程度。所以我们可以用这个特征值去衡量某个方向上像素点的波动程度。这里如果再不明白,可以看下我这篇文章,补一下向量表示与基变换的相关知识。

    于是乎, 通过上面的一番操作,就把某个方向是灰度变化程度大小转成了看 M M M矩阵的特征值上。

    2.2 窗口的角点响应函数

    这里定义每个窗口的角点响应函数
    R = det ⁡ ( M ) − k ( trace ⁡ ( M ) ) 2 = λ 1 λ 2 − k ( λ 1 + λ 2 ) 2 R=\operatorname{det}(M)-k(\operatorname{trace}(\mathrm{M}))^{2}=\lambda_1\lambda_2-k(\lambda_1+\lambda_2)^2 R=det(M)k(trace(M))2=λ1λ2k(λ1+λ2)2
    这里的 k k k是一个经验常数,范围在 ( 0.04 , 0.06 ) (0.04,0.06) (0.04,0.06)之间。

    2.3 非极大值抑制

    根据 R 的值,将这个窗口所在的区域划分为平面、边缘或角点。为了得到最优的角点,我们还可以使用非极大值抑制

    当然,因为特征值 λ 1 \lambda_1 λ1 λ 2 \lambda_2 λ2决定了 R R R的值,所以我们可以用特征值来决定一个窗口是平面、边缘还是角点:

    • 平面:窗口在平坦区域上滑动,窗口内的灰度值基本不会发生变化,所以 ∣ R ∣ |R| R非常小,在水平和竖直方向变化量都比较小,即 I x I_x Ix I y I_y Iy小, λ 1 \lambda_1 λ1 λ 2 \lambda_2 λ2小。
    • 边缘: R < 0 R<0 R<0, 仅在水平或竖直方向有较大变化量, I x I_x Ix I y I_y Iy有一个较大,即 λ 1 > > λ 2 \lambda_1>>\lambda_2 λ1>>λ2或者 λ 2 > > λ 1 \lambda_2>>\lambda_1 λ2>>λ1
    • 角点: R R R值很大,水平和竖直方向变化都较大的点,即 I x I_x Ix I y I_y Iy大, λ 1 \lambda_1 λ1 λ 2 \lambda_2 λ2大。

    一图胜千言:
    在这里插入图片描述
    Harris 角点检测的结果是带有这些分数 R R R的灰度图像,设定一个阈值,分数大于这个阈值的像素就对应角点。

    注意:Harris 检测器具有旋转不变性,但不具有尺度不变性,也就是说尺度变化可能会导致角点变为边缘,如下图所示:
    在这里插入图片描述

    So, 如何找到旋转以及尺度不变的特征点呢?这就是SIFT算法干的事情了,但是介绍之前,先看看OpenCV中角点检测算法咋用。 理论一大推,但是用起来一个函数搞定。

    2.4 OpenCV中的角点检测

    这里的函数是cv2.cornerHarris():

    • img: 数据类型为float32的输入图像
    • blockSize: 角点检测中指定区域的大小, 即 w w w窗口大小
    • ksize: Sobel求导中使用的窗口大小, 需要用sobel算子求梯度,这里是设置sobel算子求导的窗口
    • k:取值参数为[0.04, 0.06]

    看个例子:

    img = cv2.imread('img/test_img.jpg')
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
    # 角点检测
    dst = cv2.cornerHarris(gray, 2, 3, 0.04)  # 这个是每个像素点的E值,即平移后灰度级变换程度值
    
    img[dst>0.01*dst.max()] = [0, 0, 255]
    

    下面是角点检测结果:

    在这里插入图片描述

    3. SIFT算法

    Scale Invariant Feature Transform(SIFT): 尺度不变特征转换用来侦测与描述影像中的局部性特征, 基于位置,尺度和旋转不变性在空间尺度中寻找极值点。

    特点:

    • SIFT特征是图像的局部特征,其对旋转、尺度缩放、亮度变化保持不变性,对视角变化、仿射变换、噪声也保持一定程度的稳定性
    • 独特性好,信息量丰富,适用于海量特征在数据库中快速,准确匹配
    • 多量性,即使少数几个物体也可以产生大量的SIFT特征向量
    • 高速性和可扩展性, 特征可以方便与其他向量联合

    解决问题:目标自身状态,场景所处环境和成像器材的成像特性等因素影响图像配准/目标识别跟踪的性能。SIFT算法一定程度可解决:

    1. 目标旋转,缩放,平移
    2. 图像仿射/投影变换
    3. 光照影响
    4. 目标遮挡
    5. 杂物场景
    6. 噪声

    SIFT算法的实质是在不同的尺度空间上查找关键点(特征点),并计算出关键点的方向。SIFT所查找到的关键点是一些十分突出,不会因光照,仿射变换和噪音等因素而变化的点,如角点、边缘点、暗区的亮点及亮区的暗点等。

    SIFT算法主要下面四步:

    1. 尺度空间极值检测: 搜索所有尺度上的图像位置,通过高斯微分函数来识别潜在的对于尺度和旋转不变的特征点
    2. 关键点定位:在每个候选的位置上,通过一个拟合精细的模型来确定位置和尺度。关键点的选择依据于它们的稳定程度。
    3. 方向确定:基于图像局部的梯度方向,分配给每个关键点位置一个或多个方向。所有后面的对图像数据的操作都相对于关键点的方向、尺度和位置进行变换,从而提供对于这些变换的不变性。
    4. 关键点描述:在每个关键点周围的邻域内,在选定的尺度上测量图像局部的梯度。这些梯度被变换成一种表示,这种表示允许比较大的局部形状的变形和光照变化。

    由于这个算法理论上稍微复杂些,下面就简单整理了,首先,要先明白这个算法到底做的是什么事情?

    我理解: 寻找图像中具有旋转,平移,以及尺度不变性的那些特征点,并且最终用一个向量表示出来。

    究竟是怎么做到的呢? 大致上细节如下。

    3.1 图像的尺度空间

    在一定范围内,无论物体时大还是小,人眼都可以分辨出来,然而计算机要有相同能力却很难,所有要让机器能够对物体在不同尺度下有一个统一的认知,就需要考虑图像在不同的尺度下都存在的特点。

    尺度空间的获取通常使用高斯模糊来实现。

    在这里插入图片描述
    高斯模糊是一种图像滤波器,它使用正态分布(高斯函数)计算模糊模板,并使用该模板与原图像做卷积运算,达到模糊图像的目的。公式如下:
    G ( r ) = 1 2 π σ 2 N e − r 2 / ( 2 σ 2 ) G(r)=\frac{1}{\sqrt{2 \pi \sigma^{2}} N} e^{-r^{2} /\left(2 \sigma^{2}\right)} G(r)=2πσ2 N1er2/(2σ2)
    σ \sigma σ参数是标准差,指定的越大,说明像素的变化幅度会越大,越偏离原始图像,即图像就会越模糊。 r r r模糊半径,指模板元素到模板中心的距离,假如二维模板大小维 m ∗ n m*n mn, 模板上元素 ( x , y ) (x,y) (x,y)对应的高斯计算公式:
    G ( x , y ) = 1 2 π σ 2 e − ( x − m / 2 ) 2 + ( y − n / 2 ) 2 2 σ 2 G(x, y)=\frac{1}{2 \pi \sigma^{2}} e^{-\frac{(x-m / 2)^{2}+(y-n / 2)^{2}}{2 \sigma^{2}}} G(x,y)=2πσ21e2σ2(xm/2)2+(yn/2)2
    分布不为零的像素组成的卷积矩阵与原始图像做变换。每个像素的值都是周围相邻像素值的加权平均。原始像素的值有最大的高斯分布值,所以有最大的权重,相邻像素随着距离原始像素越来越远,其权重也越来越小。这样进行模糊处理比其它的均衡模糊滤波器更高地保留了边缘效果。

    不同 σ \sigma σ的模糊效果如下:
    在这里插入图片描述

    3.2 多分辨率金字塔

    尺度空间使用高斯金字塔表示, 尺度规范化LoG(Laplacion of Gaussian)算子具有真正尺度不变性,Lowe使用高斯差分金字塔近似LoG算子,在尺度空间检测稳定关键点。

    尺度空间在实现时,使用高斯金字塔表示,高斯金字塔构建主要分为两部分:

    1. 对图像做不同尺度的高斯模糊
    2. 对图像做降采样点构建金字塔

    高斯金字塔应该不陌生了:

    在这里插入图片描述

    图像的金字塔模型是指,将原始图像不断降阶采样,得到一系列大小不一的图像,由大到小,从下到上构成的塔状模型。原图像为金子塔的第一层,每次降采样所得到的新图像为金字塔的一层(每层一张图像),每个金字塔共 n n n层。金字塔的层数根据图像的原始大小和塔顶图像的大小共同决定,其计算公式如下:
    n = log ⁡ 2 { min ⁡ ( M , N ) } − t , t ∈ [ 0 , log ⁡ 2 { min ⁡ ( M , N ) } ) n=\log _{2}\{\min (M, N)\}-t, t \in\left[0, \log _{2}\{\min (M, N)\}\right) n=log2{min(M,N)}t,t[0,log2{min(M,N)})
    其中 M , N M,N MN为原图像的大小, t t t为塔顶图像的最小维数的对数值。

    3.3 DoG空间极值点检测

    在实际计算时,使用高斯金字塔每组中相邻上下两层图像相减,得到高斯差分图像。

    在这里插入图片描述
    这个就是高斯金字塔中的每一层的图片,进行差分,这样得到的结果中,像素点相差较大的位置,就是不同尺度的图片之间的不同。DoG公式定义如下:
    D ( x , y , σ ) = [ G ( x , y , k σ ) − G ( x , y , σ ) ] ∗ I ( x , y ) = L ( x , y , k σ ) − L ( x , y , σ ) D(x, y, \sigma)=[G(x, y, k \sigma)-G(x, y, \sigma)] * I(x, y)=L(x, y, k \sigma)-L(x, y, \sigma) D(x,y,σ)=[G(x,y,kσ)G(x,y,σ)]I(x,y)=L(x,y,kσ)L(x,y,σ)
    这个公式也非常好理解, 差分结果就等于第一次高斯滤波的结果,与第二次高斯滤波结果之差。

    为了寻找尺度空间的极值点, 每个像素点要和其图像域(同一尺度空间)和尺度域(相邻的尺度空间)的所有相邻点进行比较, 当其大于(或者小于)所有相邻点时,该点就是极值点。 如下图所示, 中间的检测点要和其所在图像的 3 × 3 3\times 3 3×3邻域的8个像素点,以及其相邻的上下两层的 3 × 3 3\times 3 3×3领域的18个像素点,共26个像素点进行比较。
    在这里插入图片描述
    由于要在相邻尺度进行比较,如上上面那个图,每组含4层高斯差分金字塔,只能中间两层中进行两个尺度的极值点检测,为了在每组中检测 S S S个尺度的极值点,则DOG金字塔每组需要 S + 2 S+2 S+2层图像, 而DOG金字塔由高斯金字塔相邻两层相减得到, 则高斯金字塔每组需 S + 3 S+3 S+3层图像, 实际计算时 S S S在3-5之间。

    当然这样产生的极值点并不全都是稳定的特征点,因为某些极值点响应较弱,而且DoG算子会产生较强的边缘响应。

    值得一提的是,选出的高斯差分金字塔极值点只是候选的特征点。虽然高斯差分金字塔极值点已经能够较好地代表图像的特征并且具有尺度不变性,但在选取过程中没有考虑图像特征点对于图像噪声的鲁棒性,这样确定出的图像特征点在实际应用时易出现图像匹配不当等问题。

    3.4 关键点的精确定位

    以上方法检测到的极值点是离散空间的极值点,以下通过拟合三维二次函数来精确确定关键点的位置和尺度,同时去除低对比度的关键点和不稳定的边缘响应点(因为DoG算子会产生较强的边缘响应),以增强匹配稳定性、提高抗噪声能力。

    为了稍微好理解一点,先看看一维情况下,如何通过离散值拟合曲线:

    在这里插入图片描述
    放到三维情况下:
    D ( Δ x , Δ y , Δ σ ) = D ( x , y , σ ) + [ ∂ D x ∂ D y ∂ D σ ] [ Δ x Δ y Δ σ ] + 1 2 [ Δ x Δ y Δ σ ] [ ∂ 2 D ∂ x 2 ∂ 2 D ∂ x ∂ y ∂ 2 D ∂ x ∂ σ ∂ 2 D ∂ y ∂ x ∂ 2 D ∂ y 2 ∂ 2 D ∂ y ∂ σ ∂ 2 D ∂ σ ∂ x ∂ 2 D ∂ σ ∂ y ∂ 2 D ∂ σ 2 ] [ Δ x Δ y Δ σ ] D(\Delta x, \Delta y, \Delta \sigma)=D(x, y, \sigma)+\left[\begin{array}{lll} \frac{\partial D}{x} & \frac{\partial D}{y} & \frac{\partial D}{\sigma} \end{array}\right]\left[\begin{array}{c} \Delta x \\ \Delta y \\ \Delta \sigma \end{array}\right]+\frac{1}{2}\left[\begin{array}{lll} \Delta x & \Delta y & \Delta \sigma \end{array}\right]\left[\begin{array}{ccc} \frac{\partial^{2} D}{\partial x^{2}} & \frac{\partial^{2} D}{\partial x \partial y} & \frac{\partial^{2} D}{\partial x \partial \sigma} \\ \frac{\partial^{2} D}{\partial y \partial x} & \frac{\partial^{2} D}{\partial y^{2}} & \frac{\partial^{2} D}{\partial y \partial \sigma} \\ \frac{\partial^{2} D}{\partial \sigma \partial x} & \frac{\partial^{2} D}{\partial \sigma \partial y} & \frac{\partial^{2} D}{\partial \sigma^{2}} \end{array}\right]\left[\begin{array}{c} \Delta x \\ \Delta y \\ \Delta \sigma \end{array}\right] D(Δx,Δy,Δσ)=D(x,y,σ)+[xDyDσD]ΔxΔyΔσ+21[ΔxΔyΔσ]x22Dyx2Dσx2Dxy2Dy22Dσy2Dxσ2Dyσ2Dσ22DΔxΔyΔσ
    这里的 Δ x \Delta x Δx表示相对窗口中心的偏移量,等价于上一节中的 u u u。 如果对上面进行求导,并令导数等于0,就可以得到较为准确的极值点和极值。

    D ( x ) = D + ∂ D T ∂ x Δ x + 1 2 Δ x T ∂ 2 D T ∂ x 2 Δ x Δ x = − ∂ 2 D − 1 ∂ x 2 ∂ D ( x ) ∂ x D(x)=D+\frac{\partial D^{T}}{\partial x} \Delta x+\frac{1}{2} \Delta x^{T} \frac{\partial^{2} D^{T}}{\partial x^{2}} \Delta x \quad \Delta x=-\frac{\partial^{2} D^{-1}}{\partial x^{2}} \frac{\partial D(x)}{\partial x} D(x)=D+xDTΔx+21ΔxTx22DTΔxΔx=x22D1xD(x)
    这里将每个候选极值点求出相应的导数,然后代入,得到 D ( x ) D(x) D(x), 把结果值非常小的(比如小于0.03)的先进行首轮剔除。

    3.5. 消除边界响应

    DoG算子会产生较强的边缘响应,即容易保留边界点,所以下面需要剔除不稳定的边缘响应点。具体做法如下:

    首先,获取每个特征点出的Hessian矩阵, 这里其实和角点检测那里是一样的:
    H ( x , y ) = [ D x x ( x , y ) D x y ( x , y ) D x y ( x , y ) D y y ( x , y ) ] H(x, y)=\left[\begin{array}{ll} D_{x x}(x, y) & D_{x y}(x, y) \\ D_{x y}(x, y) & D_{y y}(x, y) \end{array}\right] H(x,y)=[Dxx(x,y)Dxy(x,y)Dxy(x,y)Dyy(x,y)]
    α \alpha α是最大的特征值, β \beta β是最小的特征值,下面找一个边界值:
    Tr ⁡ ( H ) = D x x + D y y = α + β Tr ⁡ ( H ) 2 Det ⁡ ( H ) = ( α + β ) 2 α β = ( γ + 1 ) 2 γ Det ⁡ ( H ) = D x x D y y − ( D x y ) 2 = α β \begin{array}{cl} \operatorname{Tr}(H)=D_{x x}+D_{y y}=\alpha+\beta & \frac{\operatorname{Tr}(H)^{2}}{\operatorname{Det}(H)}=\frac{(\alpha+\beta)^{2}}{\alpha \beta}=\frac{(\gamma+1)^{2}}{\gamma} \\ \operatorname{Det}(H)=D_{x x} D_{y y}-\left(D_{x y}\right)^{2}=\alpha \beta & \end{array} Tr(H)=Dxx+Dyy=α+βDet(H)=DxxDyy(Dxy)2=αβDet(H)Tr(H)2=αβ(α+β)2=γ(γ+1)2
    导数由采样点相邻差估计得到. 这个比值越大,说明两个特征值的比值越大,即在某一个方向的梯度值越大,而在另一个方向的梯度值越小,而边缘恰恰就是这种情况。所以为了剔除边缘响应点,需要让该比值小于一定的阈值。所以,对于每个特征点,再通过下面公式:
    Tr ⁡ ( H ) 2 Det ⁡ ( H ) < ( r + 1 ) 2 r \frac{\operatorname{Tr}(H)^{2}}{\operatorname{Det}(H)}<\frac{(r+1)^{2}}{r} Det(H)Tr(H)2<r(r+1)2
    这个不等式成立的关键点保留下来,反之剔除掉。论文中 γ = 10 \gamma=10 γ=10

    3.6 特征点的主方向

    根据上面的一顿操作,就能找到比较好的一些候选关键点,但是在建立高斯差分金字塔以选取图像特征点时,算法考虑了关键点的尺度不变性。而对于图像特征而言,与尺度不变性同等重要的还有旋转不变性。

    为了使描述具有旋转不变性,需要利用图像的局部特征为给每一个关键点分配一个主方向,该“主方向”以生成特征点周围的局部区域的梯度方向基准,使图像在旋转后仍能与旋转前保持相同的特征描述。

    算法将关键点指定大小领域中的所有点计算梯度方向与赋值,并统计所有梯度方向对应的赋值和,作关键点周围 i i i邻域梯度方向直方图。梯度的模值 m ( x , y ) m(x,y) m(x,y)和方向 ( θ ( x , y ) (\theta(x,y) (θ(x,y)计算公式如下:
    m ( x , y ) = [ L ( x + 1 , y ) − L ( x − 1 , y ) ] 2 + [ L ( x , y + 1 ) − L ( x , y − 1 ) ] 2 θ ( x , y ) = arctan ⁡ L ( x , y + 1 ) − L ( x , y − 1 ) L ( x + 1 , y ) − L ( x − 1 , y ) \begin{aligned} &m(x, y)=\sqrt{[L(x+1, y)-L(x-1, y)]^{2}+[L(x, y+1)-L(x, y-1)]^{2}} \\ &\theta(x, y)=\arctan \frac{L(x, y+1)-L(x, y-1)}{L(x+1, y)-L(x-1, y)} \end{aligned} m(x,y)=[L(x+1,y)L(x1,y)]2+[L(x,y+1)L(x,y1)]2 θ(x,y)=arctanL(x+1,y)L(x1,y)L(x,y+1)L(x,y1)
    这样,对于每个关键点, 就有了三个信息 ( x , y , σ , θ ) (x,y,\sigma, \theta) (x,y,σ,θ), 即位置,尺度和方向。但关键点的主方向到底是啥呢?

    对于一个关键点, 要统计它邻域内各个点的梯度直方图,

    下图直方图为简化版本(只有8个bin,实际操作时算法会统计从0到360°步长为10°的共计36个梯度方向的幅值和,共有36个bin)。梯度方向直方图中最高的bin对应的方向即定义为该关键点的主方向,若存在任一方向的幅值大于主方向幅值的80%,则将其作为辅方向。所以,对于同一个关键点,可能有多个方向,这种情况在相同位置和尺度将会有多个关键点被创建但方向不同。实际编程实现中,就是把该关键点复制成多份关键点,并将方向值分别赋给这些复制后的关键点。

    在这里插入图片描述
    直方图的横轴是方向,纵轴是邻域内各个点对应方向梯度的累加和。

    3.7 生成特征描述

    得到特征点二维位置、尺度位置、主方向的具体信息后,算法需要解决的最后一个问题就是生成关键点信息的描述子,即用一个向量描述图像中的特征点信息。使其不随各种变化而改变,比如光照变化、视角变化等等。这个描述子不但包括关键点,也包含关键点周围对其有贡献的像素点,并且描述符应该有较高的独特性,以便于提高特征点正确匹配的概率。

    为了保证特征矢量的旋转不变性, 要以特征点为中心, 在附近领域内将坐标轴旋转 θ \theta θ角度,即将坐标轴旋转为特征点的主方向。

    在这里插入图片描述
    各个像素点的坐标变换是用下面的公式:
    [ x ′ y ′ ] = [ cos ⁡ θ − sin ⁡ θ sin ⁡ θ cos ⁡ θ ] [ x y ] \left[\begin{array}{l} x^{\prime} \\ y^{\prime} \end{array}\right]=\left[\begin{array}{cc} \cos \theta & -\sin \theta \\ \sin \theta & \cos \theta \end{array}\right]\left[\begin{array}{l} x \\ y \end{array}\right] [xy]=[cosθsinθsinθcosθ][xy]
    旋转完之后,算法将特征点周围的 16 × 16 16\times16 16×16邻域分为4个 8 × 8 8\times8 8×8的区域,再将 8 × 8 8\times8 8×8的区域划为 2 × 2 2\times2 2×2区域,即每个小区域为 4 × 4 4\times4 4×4的范围。统计每个 4 × 4 4\times4 4×4区域的梯度方向直方图(直方图为8个bin,8个方向),故共计 4 ∗ 4 ∗ 8 = 128 4*4*8=128 448=128个bin。对应生成128维向量(值为梯度方向的幅值)。该128维向量即该点的特征描述子。

    在这里插入图片描述

    每个像素的梯度幅值和方向(箭头方向代表梯度方向,长度代表梯度幅值), 然后利用高斯窗口对其加权运算(离中心点距离不一样), 最后在每个 4 × 4 4\times4 4×4的小块上绘制8个方向的梯度直方图, 计算每个梯度方向的累加值, 即可形成一个种子点, 即每个特征点的由 4 × 4 4\times4 4×4个种子点组成, 每个种子点由8个方向的向量信息。

    论文中建议对每个关键点使用 4 × 4 4\times4 4×4共16个种子点来描述,每个种子点由 8 8 8个方向的梯度直方图描述,即8维向量, 这样一个关键点就会产生128维的SIFT特征向量

    在这里插入图片描述

    OK, 到这里,就把SIFT算法的大致流程整理了下,不过上面有些乱,下面集中总结下:

    1. 原始图片,先用高斯滤波做模糊操作的尺度变换,通过改变高斯核的标准差,得到 S S S图片

    2. 为了让后序的特征表达更加丰富,把这 S S S张图片,做成高斯金字塔

    3. 接下来,对于高斯金字塔的每一个level的 S S S张图片, 相邻图片进行差分运算,得到高斯差分图像, S − 1 S-1 S1

    4. 基于高斯差分图像,去寻找候选的极值点,所谓极值点,就是对差分图像中,不是首尾层的图像中的每个像素点,去对比不同尺度空间(上下相邻两层邻域)和同一尺度空间周围像素点的值与当前这个像素点值大小,拿到极大值点,作为候选的关键点。

    5. 定位精确的关键点,对尺度空间中DOG函数进行曲线拟合,计算其极值点,从而实现关键点的精确定位。这里用到了泰勒近似,拟合出函数来之后,把当前关键点代入,得到的函数值过小的(比如小于0.03)的关键点去掉。

    6. 消除边缘效应,对剩下的关键点,获取特征点处的梯度矩阵,使用的有限差分法求导,得到这个矩阵之后,根据特征值的比例再进行筛选,水平方向梯度与垂直方向梯度差不多的保留下来,相差很大,说明是边缘, 这种关键点要去掉,即消除边缘效应

    7. 通过上面步骤,就把关键点给选择了出来,但是仅仅从尺度不变性角度进行的考虑,接下来考虑平移不变性, 为每个关键点选择一个主方向

    8. 这个就是考虑关键点邻域内的所有像素点,用一个直方图去统计这个邻域内所有像素点的梯度方向以及梯度累加值,梯度方向由于是360度,这里进行了分桶操作,划分成了8个bins。拿到直方图之后,把梯度累加值最大的那个方向作为关键点的主方向, 当然次大的还可以作为辅方向,这样每个关键点就同时有了位置,尺度,方向三个特征描述(如果关键点还有辅方向的,就需要把这个观测点复制一份,保持位置,尺度不变,该变方向即可)。

    9. 每个观测点有了三种属性描述,接下来,需要转成特征,即想用一个向量来描述

      1. 首先,对于每个观测点值,先把邻域内的所有像素点的坐标值修改,修改原则是坐标轴要保持和当前观测点的主方向一致
      2. 修改完毕之后, 统计这个邻域内的像素点的梯度直方图,依然是8个bins,每个bins中是像素点梯度的累加值,这样对于一个关键点,锁定一个邻域就能得到8个值。 这算是一个种子区间内的特征描述
      3. 真正做的时候,是先对于一个关键点给定一个大的邻域,然后把这个大的邻域进行划分成小的邻域,作为一个个的种子区间,然后得到种子区间的特征
      4. 关键点最后的特征描述,就是所有种子矩阵特征的Concat值,上面是一个128维的向量表示,这样就得到了关键点尺度和平移不变的特征描述
    10. 金字塔中所有关键点,都得到特征描述,返回结果

    下面就可以看代码了。

    3.8 OpenCV下的SIFT算法

    对于SIFT算法, OpenCV中直接也是一个函数搞定。

    img = cv2.imread('img/test_1.jpg')
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
    # opencv版本高于3.4.3, 这个sift算法使用变成cv2.SIFT_create(), 在这之前的版本是cv2.xfeatures2d.SIFT_create()
    
    # SIFT检测器
    sift = cv2.SIFT_create()
    
    # 找出图像中的关键点
    kp = sift.detect(gray, None)
    
    # 在图中画出关键点
    img = cv2.drawKeypoints(gray, kp, img)  
    
    # 计算关键点对应的SIFT特征向量
    kp, des = sift.compute(gray, kp)   
    
    # 上面的两步,也可以用下面的一步
    sift = cv2.SIFT_create()
    kp1, des1 = sift.detectAndCompute(gray, None)   # 这里还能一步到位,直接算出关键点以及关键向量
    

    看下效果:
    在这里插入图片描述

    4. 特征匹配

    拿到图像中的关键点,以及也能用向量来描述这个关键点的特征了,那么给定两张图像之后,怎么看出这两张图片中哪些关键点比较相似呢?这就是看关键点向量之间的差异了,也是特征匹配在做的事情。

    4.1 Brute-Force蛮力匹配

    暴力匹配,两个图像中的关键点的特征向量,一个个的计算差异, 即两层for循环了。 这里直接看怎么用:

    首先, 读入两张图片,然后拿到各自的关键点以及关键点向量。

    img1 = cv2.imread('img/box.png', 0)
    img2 = cv2.imread('img/box_in_scene.png', 0)
    
    # sift算法,得到每张图的关键点以及关键向量
    sift = cv2.SIFT_create()
    kp1, des1 = sift.detectAndCompute(img1, None)   # 这里还能一步到位,直接算出关键点以及关键向量
    kp2, des2 = sift.detectAndCompute(img2, None)
    

    下面进行特征匹配:

    1. 1对1的匹配: 即图片A中的一个向量匹配图片B中的一个向量

      # crossCheck表示两个特征点要互相匹配,例如A中的第i个特征点与B中的第j个特征点最近的,并且B中的第j个特征点到A中的第i个特征点也是最近的
      # NORM_L2: 归一化数组的欧几里得距离, 如果其他特征计算方法需要考虑不同的匹配计算方式
      bf = cv2.BFMatcher(crossCheck=True)
      
      # 1对1的匹配
      matches = bf.match(des1, des2)
      matches = sorted(matches, key=lambda x: x.distance)
      

      如果这里指定属性crossCheck为False, 得到的结果是604,如果为True,得到的结果是206,所以我基于这个,盲猜下暴力匹配以及这个属性的意义。

      暴力匹配的话,就是对于A图像中的每个观测点的向量, 我遍历一遍B图像中每个观测点的向量,然后求欧几里得距离,拿到最小的。这样对于A图像中每个观测点,就得到了B图像里面的最佳匹配。

      然后再对于B图像中的每个观测点,也同样用上面的方式走一遍,这样对于B图像中的每个观测点,也得到了A图像中的最佳匹配。

      此时,如果是:

      • bf.match(des1, des2): 返回的就是A图像中的每个观测点的最佳匹配,个数是A中关键点的个数
      • bf.match(des2, des1): 返回的是B图像中每个观测点的最佳匹配, 个数是B中关键点的个数
      • 如果设置crossCheck为True的话:
        • bf.match(des1, des2)bf.match(des2, des1)都是260, 表示的其实是A和B中,关键点互相匹配的那些,比如A中的第j个观测点,最近点是B中的i,那么B中的i,也要对应A中的j,即<i,j> VS <j, i>
      img3 = cv2.drawMatches(img1, kp1, img2, kp2, matches[:10], None, flags=2)
      

      画10个最近的匹配看看:
      在这里插入图片描述

    2. K对最佳匹配: 对于一个关键点, 找K个最相似的向量。

      bf = cv2.BFMatcher()
      matches = bf.knnMatch(des1, des2, k=2)  # 相当于对于A中的每个关键点,不是找某一个最相似,而是K相似
      

      这里可以根据近邻之间的相似比例对关键点筛选

      good = []
      for m, n in matches:
          if m.distance < 0.75 * n.distance:
              good.append([m])
      

      也可以可视化一下:

      img3 = cv2.drawMatchesKnn(img1, kp1, img2, kp2, good, None, flags=2)
      

      结果如下:

      在这里插入图片描述

    这里会发现一个问题,对于上面的匹配结果,大部分结果还可以,但有某些匹配错误的点,这种情况怎么弥补呢? 可以使用RANSAC(Random sample consensus)随机抽样一致算法。 这个东西可以简单看下原理。

    4.2 RANSAC(Random sample consensus)算法

    这个算法也是一个拟合算法, 和最小二乘对比如下:
    在这里插入图片描述
    思路是这样: 先选择初始样本点进行拟合, 给定一个容忍的范围,不断进行迭代。
    在这里插入图片描述
    每一次拟合之后, 容差范围内都有对应的数据点数, 找出数据点个数最多的情况,就是最终的拟合结果。所以这种算法在拟合的时候,先随机抽样初始点,然后进行拟合的时候,会考虑容忍范围(能拟合的数据点个数)

    那么,这东西干啥用呢? 下面全景拼接的Demo会用到。

    5. 全景拼接Demo

    全景拼接大家肯定都玩过,相机里就有这个功能, 这个的原理大概是这样, 假设有两张图片要进行拼接,大概流程如下:

    1. 通过SIFT算法拿到两张图片的关键点以及关键向量

    2. 根据关键向量做特征匹配

    3. 根据特征匹配点,对图片进行一些仿射变换,比如平移,选择,缩放等,这里是保证能无缝衔接上,如果不做处理,那肯定拼接不是。

      1. 既然是仿射变换,本质是乘变换矩阵,所以核心就是这个变换矩阵求解
        在这里插入图片描述
      2. 如果需要做变换,目的就是求变换矩阵, 至少有4对匹配好的特征点才行。
      3. 那么思路就是,先用随机采样算法采出四对匹配点,然后解8个方程得到上面的变换矩阵, 然后基于这个变换矩阵算其他的匹配点是否能匹配上,定义一个loss函数为匹配上的点的对数,这样就能基于当前的四对匹配点算出一个loss值。 然后再随机采样四对, 再求变换矩阵,再看看其他匹配点能匹配上的个数,得到损失。依次迭代多次, 取loss函数最小的那个变换矩阵。
    4. 找到变换矩阵,对某张图片先进行变换,然后进行拼接即可。

    这么说比较抽象,下面通过一个Demo把这个过程带起来。

    5.1 读入图像,拿到SIFT特征

    代码如下:

    image_left = cv2.imread('img/left_01.png')
    image_right = cv2.imread('img/right_01.png')
    

    这两张图片如下:

    在这里插入图片描述
    显然,这样拼接是无法拼接上的。

    下面拿到关键点和特征向量

    def detectAndDescribe(image):
        # 将彩色图片转成灰度图
        gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
        
        # SIFT生成器
        destriptor = cv2.SIFT_create()
        (kps, features) = destriptor.detectAndCompute(image, None)
        
        # 结果转成numpy数组
        kps = np.float32([kp.pt for kp in kps])
        return (kps, features)
     
    # 检测A, B图片的SIFT特征关键点,得到关键点的表示向量
    (kps_left, features_left) = detectAndDescribe(image_left)   # kpsA (关键点个数, 坐标)  features(关键点个数,向量)
    (kps_right, features_right) = detectAndDescribe(image_right)
    

    5.2 特征匹配

    这里依然是写个函数:

    def matchKeyPoints(kpsA, kpsB, featuresA, featuresB, ratio=0.75, reprojThresh=4.0):
        # 建立暴力匹配器
        matcher = cv2.BFMatcher()
        
        # KNN检测来自两张图片的SIFT特征匹配对
        rawMatches = matcher.knnMatch(featuresA, featuresB, 2)
        
        matches = []
        for m in rawMatches:
            # 当最近距离跟次近距离的比值小于ratio时,保留此配对
            # (<DMatch 000001B1D6B605F0>, <DMatch 000001B1D6B60950>) 表示对于featuresA中每个观测点,得到的最近的来自B中的两个关键点向量
            if len(m) == 2 and m[0].distance < m[1].distance * ratio:   
                # 存储两个点在featuresA, featuresB中的索引值
                matches.append([m[0].trainIdx, m[0].queryIdx])    # 这里怎么感觉只用了m[0]也就是最近的那个向量啊,应该没用到次向量
                # 这个m[0].trainIdx表示的时该向量在B中的索引位置, m[0].queryIdx表示的时A中的当前关键点的向量索引
        
        # 当筛选后的匹配对大于4时,可以拿来计算视角变换矩阵
        if len(matches) > 4:
            # 获取匹配对的点坐标
            ptsA = np.float32([kpsA[i] for (_, i) in matches])
            ptsB = np.float32([kpsB[i] for (i, _) in matches])
            
            # 计算视角变换矩阵  这里就是采样,然后解方程得到变换矩阵的过程
            (H, status) = cv2.findHomography(ptsA, ptsB, cv2.RANSAC, reprojThresh)
            
            return (matches, H, status)
        
        # 匹配结果小于4时,返回None
        return None   
    

    主要逻辑是从图片B中给图片A中的关键点拿最近的K个匹配向量,然后基于规则筛选, 保存好匹配好的关键点的两个索引值,通过索引值取到匹配点的坐标值,有了多于4对的坐标值,就能得到透视变换矩阵。 这里返回的主要就是那个变换矩阵。

    # 匹配两张图片的所有特征点,返回匹配结果 注意,这里是变换right这张图像,所以应该是从left找与right中匹配的点,然后去计算right的变换矩阵
    M = matchKeyPoints(kps_right, kps_left, features_right, features_left)
    if not M:
        # 提取匹配结果
        (matches, H, status) = M
    

    这里要一定要注意好,到底是对哪张图片做变换,比如给图片B做变换,那么就从A中找与B中特征点匹配的特征向量,求的是让图片B变换的透视矩阵。 这里是对right做变换,所以从left中给right的关键点找匹配点,给right计算透视矩阵,接下来,变换right

    # 图片right进行视角变换, result是变换后的图片
    result = cv2.warpPerspective(image_right, H, (image_left.shape[1] + image_right.shape[1], image_right.shape[0]))
    
    cv_imshow('result', result)
    

    这里看下变换之后的结果:
    在这里插入图片描述
    接下来,进行拼接即可:

    # 将图片A传入result图片最左端
    result[0:image_right.shape[0], 0:image_right.shape[1]] = image_left
    

    结果如下:

    在这里插入图片描述
    这样就拼接起来了,除了亮度不太一样外,效果还是不错的。

    5.3 画出匹配图像

    这里还可以在图像上画出匹配的向量:

    def drawMatches(imageA, imageB, kpsA, kpsB, matches, status):
        # 初始化可视化图片,将A、B图左右连接到一起
        (hA, wA) = imageA.shape[:2]
        (hB, wB) = imageB.shape[:2]
        vis = np.zeros((max(hA, hB), wA + wB, 3), dtype="uint8")
        vis[0:hA, 0:wA] = imageA
        vis[0:hB, wA:] = imageB
    
        # 联合遍历,画出匹配对
        for ((trainIdx, queryIdx), s) in zip(matches, status):
            # 当点对匹配成功时,画到可视化图上
            if s == 1:
                # 画出匹配对
                ptA = (int(kpsA[queryIdx][0]), int(kpsA[queryIdx][1]))
                ptB = (int(kpsB[trainIdx][0]) + wA, int(kpsB[trainIdx][1]))
                cv2.line(vis, ptA, ptB, (0, 255, 0), 1)
    
        # 返回可视化结果
        return vis
    
    vis = drawMatches(image_left, image_right, kps_left, kps_right, matches, status)
    

    结果如下:
    在这里插入图片描述

    6. 小总

    这篇文章主要是整理了在图像处理中重要且常用的找特征点的两个算法Harris和SIFT算法,包括算法的数学原理以及如何使用,然后是整理了下特征匹配与一致性采样算法,这俩东西其实为了后面的透视变换矩阵服务。 最后通过一个全景图拼接的Demo感受了下算法的魅力。

    当然这只是冰山下面的一小角哈,因为后面要做一个停车场车位识别的一个项目, 会用到这里面的这些知识。另外就是这些方法依然是普适性的算法,所以也想沉淀下,方便后面回看。

    参考

    展开全文
  • Harris角点检测 及 Matlab实验

    万次阅读 多人点赞 2019-04-25 16:53:45
    目录 1 基础知识 1.1 图像变化的类型 1.2 提取特征的作用 1.3 什么是好的角点检测算法? ...2Harris 角点检测 ...2.1 Harris角点检测基本思想 ...角点在保留图像图重要特征的同时,可以有效地减少信息的数据量,...

    目录

    1 基础知识

    1.1 图像变化的类型

    1.2 提取点特征的作用

    1.3 什么是好的角点检测算法?

    2 Harris 角点检测

    2.1 Harris角点检测基本思想

    2.2 Harris角点检测:数学描述

    3 总结

    4 Matlab 实验

    参考资料


    角点是图像重要的特征,对图像图形的理解和分析有很重要的作用。角点在保留图像图重要特征的同时,可以有效地减少信息的数据量,使其信息的含量很高,有效地提高了计算的速度,有利于图像的可靠匹配和实时处理。下面将介绍Harris角点检测 及 Matlab实验。

     

    1 基础知识

    1.1 图像变化的类型

     

    1.2 提取点特征的作用

    图像的点特征是许多计算机视觉算法的基础:使用特征点来代表图像的内容,在运动目标跟踪、物体识别、图像配准、全景图像拼接 和 三维重建 等方向有较多的用处。

    有一类重要的点特征:角点(corner points)

    角点(corner points):局部窗口沿各方向移动,均产生明显变化的点,图像局部曲率突变的点

    典型的角点检测算法:Harris角点检测 , CSS角点检测等。下图展示的是不同学者提出的角点检测算法。

     

    下图为不同类型的角点,那么,怎么才算的好的角点检测算法呢?下面将慢慢介绍。

     

    1.3 什么是好的角点检测算法?

    (1)检测出图像中“真实的”角点;

    (2)准确的定位性能;

    (3)很高的重复检测率(稳定性好);

    (4)具有对噪声的鲁棒性;

    (5)具有较高的计算效率。


     

    Harris 角点检测

    1988年,Harris提出角点检测的方法效果较好。从谷歌学术来看,引用已达到1万6千多次,佩服佩服。

     

    2.1 Harris角点检测基本思想

    基本思想:从图像局部的小窗口观察图像特征。

    角点定义:窗口向任意方向的移动都导致图像灰度的明显变化。

     

     

    2.2 Harris角点检测:数学描述

    将图像窗口平移 [u,v] 产生灰度变化 E(u,v)

                                                                E(u,v) = \sum\limits_{x,y} {w(x,y){​{\left[ {I(x + u,y + v) - I(x,y)} \right]}^2}}

    由:I(x + u,y + v) = I(x,y) + {I_x}u + {I_y}v + O({u^2},{v^2})

    得到:

                                                                E(u,v) = \sum\limits_{x,y} {w(x,y){​{\left[ {​{I_x}u + {I_y}v + O({u^2},{v^2})} \right]}^2}}

                                                                  {\left[ {​{I_x}u + {I_y}v} \right]^2} = [u,v]\left[ {\begin{array}{*{20}{c}} {I_x^2}&{​{I_x}{I_y}}\\ {​{I_x}{I_y}}&{I_y^2} \end{array}} \right]\left[ {\begin{array}{*{20}{c}} u\\ v \end{array}} \right]

    于是对于局部微小的移动量 [u,v] ,可以近似得到下面的表达:

                                                                                  E(u,v) \cong \left[ {u,} \right.\left. v \right]\begin{array}{*{20}{c}} {} \end{array}M\begin{array}{*{20}{c}} {} \end{array}\left[ {\begin{array}{*{20}{c}} u\\ v \end{array}} \right]

    其中,M2 \times 2 矩阵,可由图像的导数求得:

                                                                             M = \sum\limits_{x,y} {w(x,y)\left[ {\begin{array}{*{20}{c}} {I_x^2}&{​{I_x}{I_y}}\\ {​{I_x}{I_y}}&{I_y^2} \end{array}} \right]}

    窗口移动导致的图像变化:实对称矩阵M的特征值分析

                                                                                  E(u,v) \cong \left[ {u,} \right.\left. v \right]\begin{array}{*{20}{c}} {} \end{array}M\begin{array}{*{20}{c}} {} \end{array}\left[ {\begin{array}{*{20}{c}} u\\ v \end{array}} \right]

    其中,M的特征值{\lambda _{\max }},{\rm{ }}{\lambda _{\min }} 。

     

     

     

    定义角点响应函数R

                                                                                 R = \det M - k{\left[ {​{\mathop{\rm trace}\nolimits} (M)} \right]^2}

    其中,\det M = {\lambda _1}{\lambda _2}{\text{ , trace (}}M) = {\lambda _1} + {\lambda _2} 。

     

     

    Harris角点检测结果如下图所示:


     

    3 总结

    上面是Harris角点检测的数学推导,通过查阅相关文献,对Harris角点检测的推导过程进行整理,其简要步骤如下:

    Harris角点检测器分为三步:梯度计算矩阵形成 特征值计算。首先,计算 x 和 y 方向上的平滑 (使用高斯函数) 梯度来检测给定灰度图像 I(x,y) 中的角点,由下面的式子给出:

                                                                               {g_x}(x,y) = \frac{​{ - x}}{​{2\pi \tau _g^4}}\exp \left( { - \frac{​{​{x^2} + {y^2}}}{​{2\tau _g^2}}} \right)

                                                                               {g_y}(x,y) = \frac{​{ - y}}{​{2\pi \tau _g^4}}\exp \left( { - \frac{​{​{x^2} + {y^2}}}{​{2\tau _g^2}}} \right)

    其中,{\tau _g} 是平滑参数。

    计算图像I(x,y) 的平滑梯度为:

                                                                                   {I_x} = {g_x}(x,y) \otimes I(x,y)

                                                                                  {I_y} = {g_y}(x,y) \otimes I(x,y)

    其中,“ \otimes ” 表示二维卷积运算。

    Harris角点检测器依赖于计算一个矩阵(与自相关函数有关),由下面的式子给出:

                                                                                  A(x,y) = \left( {\begin{array}{*{20}{c}} {​{a_{xx}}}&{​{a_{xy}}}\\ {​{a_{xy}}}&{​{a_{yy}}} \end{array}} \right)

    其中,

                                                                                  {a_{xx}} = {\sum\limits_{​{x_i} \in W} {\sum\limits_{​{​{\text{y}}_i} \in W} {[{I_x}({x_i},{y_i})]} } ^2}

                                                                                  {a_{yy}} = {\sum\limits_{​{x_i} \in W} {\sum\limits_{​{​{\text{y}}_i} \in W} {[{I_y}({x_i},{y_i})]} } ^2}

                                                                            {a_{xy}} = \sum\limits_{​{x_i} \in W} {\sum\limits_{​{​{\text{y}}_i} \in W} {​{I_x}({x_i},{y_i})} } {I_y}({x_i},{y_i})

    从上面的式子可以看出,{a_{xx}},{a_{yy}} 和 {a_{xy}} 表示平均梯度幅值,矩阵A 的特征值提供关于给定位置的边缘的信息。如果给定位置的矩阵的特征值都很大,那么大部分区域均为角点。Harris通过计算响应函数可以避免精确的特征值计算,由下面的式子给出:

                                                                                   R = \det A - k{\left[ {​{\mathop{\rm trace}\nolimits} (A)} \right]^2}

    其中,\det A = {\lambda _1}{\lambda _2}{\text{ , trace (}}A) = {\lambda _1} + {\lambda _2} , k是可调参数,一般设置在区间 [0.04, 0.06] 内。通过判定 R 大小来判断像素点是否为角点,对于角点\left| R \right| 的值很;而平坦的区域\left| R \right| 的值很

     


     

    4 Matlab 实验

     

    Harris角点检测 Matlab 代码如下:

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %%%% Harris角点检测算法 Matlab code
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    clear all; clc ;tic;
    
    ori_im = imread('lena.tiff');     % 读取图像
    
    if(size(ori_im,3)==3)
        ori_im = rgb2gray(uint8(ori_im));  %转为灰度图像
    end
    
    % fx = [5 0 -5;8 0 -8;5 0 -5];          % 高斯函数一阶微分,x方向(用于改进的Harris角点提取算法)
    fx = [-2 -1 0 1 2];                 % x方向梯度算子(用于Harris角点提取算法)
    Ix = filter2(fx,ori_im);              % x方向滤波
    % fy = [5 8 5;0 0 0;-5 -8 -5];          % 高斯函数一阶微分,y方向(用于改进的Harris角点提取算法)
    fy = [-2;-1;0;1;2];                 % y方向梯度算子(用于Harris角点提取算法)
    Iy = filter2(fy,ori_im);              % y方向滤波
    Ix2 = Ix.^2;
    Iy2 = Iy.^2;
    Ixy = Ix.*Iy;
    clear Ix;
    clear Iy;
    
    h= fspecial('gaussian',[7 7],2);      % 产生7*7的高斯窗函数,sigma=2
    
    Ix2 = filter2(h,Ix2);
    Iy2 = filter2(h,Iy2);
    Ixy = filter2(h,Ixy);
    
    height = size(ori_im,1);
    width = size(ori_im,2);
    result = zeros(height,width);         % 纪录角点位置,角点处值为1
    
    R = zeros(height,width);
    for i = 1:height
        for j = 1:width
            M = [Ix2(i,j) Ixy(i,j);Ixy(i,j) Iy2(i,j)];             % auto correlation matrix
            R(i,j) = det(M)-0.06*(trace(M))^2;   
        end
    end
    cnt = 0;
    for i = 2:height-1
        for j = 2:width-1
            % 进行非极大抑制,窗口大小3*3
            if  R(i,j) > R(i-1,j-1) && R(i,j) > R(i-1,j) && R(i,j) > R(i-1,j+1) && R(i,j) > R(i,j-1) && R(i,j) > R(i,j+1) && R(i,j) > R(i+1,j-1) && R(i,j) > R(i+1,j) && R(i,j) > R(i+1,j+1)
                result(i,j) = 1;
                cnt = cnt+1;
            end
        end
    end
    Rsort=zeros(cnt,1);
    [posr, posc] = find(result == 1);
    for i=1:cnt
        Rsort(i)=R(posr(i),posc(i));
    end
    [Rsort,ix]=sort(Rsort,1);
    Rsort=flipud(Rsort);
    ix=flipud(ix);
    ps=100;
    posr2=zeros(ps,1);
    posc2=zeros(ps,1);
    for i=1:ps
        posr2(i)=posr(ix(i));
        posc2(i)=posc(ix(i));
    end
       
    imshow(ori_im);
    hold on;
    plot(posc2,posr2,'g+');
    
    toc;
    

     

    运行结果如下图所示:

     

    C++实验代码可参见:https://blog.csdn.net/linqianbi/article/details/78930239


     

    参考资料

    [1] C.Harris, M.Stephens. “A Combined Corner and Edge Detector”. Proc. of 4th Alvey Vision Conference, 1988.

    [2] Harris角点检测 PPT

    [3] https://blog.csdn.net/u010703122/article/details/49308153

    [4] https://blog.csdn.net/woxincd/article/details/60754658

    [5] https://blog.csdn.net/linqianbi/article/details/78930239

     

    展开全文
  • CS131专题-5:图像特征——Harris角点

    千次阅读 2021-11-21 23:07:19
    2 特征——Harris角点 2.1 角点 2.2 数学描述 2.3 公式推导 2.4 公式的物理意义 2.5 算法流程 2.6检测效果 2.7 Harris角点性质 1 图像特征 试想,从不同的距离,不同的方向、角度,不同的光照条件下观察...

    目录

    1 图像特征

    2 点特征——Harris角点

    2.1 角点

    2.2 数学描述

    2.3 公式推导

    2.4 公式的物理意义

    2.5 算法流程

    2.6 检测效果

    2.7 Harris角点性质


    1 图像特征

    试想,从不同的距离,不同的方向、角度,不同的光照条件下观察一个物体时,物体的大小、形状、明暗都会有所不同。但我们依然可以判断它是同一个物体。 这是因为什么呢?因为特征!

    计算机视觉中常用的图像特征包括:点、边缘、以及特有的组件等等。

    而其中点特征(不是指像素点,而是指图像中一个小局部)在视觉的各种任务中非常有用,如全景拼接、运动跟踪、物体识别等等。

    为什么选择图像的点特征?

    答:点特征作为图像特征之一的优势如下:

    • 提取具有可重复性准确性
      • 不受图像平移、旋转、缩放变化的影响
      • 对仿射变换也较为鲁棒
      • 抗光照变化,噪声,模糊,量化
    • 局部性:点特征属于局部特征,所以对图像遮挡有一定鲁棒性;
    • 数量:通常图像中可以检测到成百上千的点特征,以量取胜;
    • 辨识性:点特征有较好的辨识性,不同物体上的点容易区分;
    • 效率:点特征提取通常速度很快;

     

    一个基于特征点来实现图像匹配的神奇例子:

    2 点特征——Harris角点

    Harris算子是一种点特征提取算子,哈里斯+史蒂芬斯于1988年提出(是对Moravec角点检测算子的改进)。

    2.1 角点

    角点就是图像的“角落”位置,也是灰度值会发生突变的位置。“角点”特征相比“边缘”特征而言,在辨识性和信息量方面都具备很多优势,看下面这张图,你就知道为什么“角点”是一种好的特征。

    如上图,当我们用一个窗口去和图像局部区域像素进行例如累加求和操作时,仅在“角点”位置其计算结果会与其临近的其他位置计算结果差异都比较大。

    2.2 数学描述

    为了得到角点的精确位置,以及量化是否是角点的概率值,需要对角点进行明确的数学描述。关于角点的上述性质的数学建模如下:

    • I(x, y):窗口移动前所覆盖的原图区的x,y位置的灰度值。注意:这个x,y坐标是相对此处这个窗口的坐标系而言,而元素值是图像的灰度值而不是窗口函数内元素值。
    • I(x+u, y+v):窗口在图像上移动[u, v]个单位后所覆盖的原图区的位置的灰度值,这个x,y同样是相对窗口的坐标系。
    • W(x, y)是:窗口函数,也就是权重系数,比如一个元素值全1的矩阵窗口,或者高斯核窗口。
    • 遍历x,y累加求和中的x,y是什么:这里的x,y指的是窗口尺度的大小,假如窗口大小是10x10像素,那么公式里就要累加100个像素点位置的差值和。
    • E(u, v):简单说,E是一个二维矩阵,它存储的是窗口在图像上平移前后内部元素灰度值变化的差值。具体说,窗口在图像上平移[u, v]后,新窗口区域内像素值和平移之前窗口内像素值的对应位置的差的平方再乘以权重系数再累加之和。描述的有点拗口,语言不好整理,看下面这个可视化例子解释:

    假设左边这个大图是某图像的一个局部区域,红色框是我们用于判定图像此处是否有角点的窗口,它是个初始位置。E(3, 2)意思是,这个红色窗口,移动[3,2]个单位,到达图像中绿色框位置,然后把两个框内像素的灰度值一个个的代入到上述公式中去计算加权累加和。

    有个点注意:

    • E(0, 0)必定为0,即窗口没移动,所以对应位置像素值差全为0。
    • E(u, v)中元素值越大,代表两个位置窗口内情况差异越大。
    • Moravec角点检测用的全1权重窗口,而Harris角点检测用的高斯核窗口(中心点附近的差值权重大,边缘点附近的差值给的权重少)。

    接下来不要忘记一个很重要的点(不然后面公式推导看不懂目的)角点处是滑窗往任意方向移动变化量都大。所以,如果一个窗口内有角点,那么这个窗口往四周滑动计算出的 E(u, v) 矩阵,其除了E(0, 0)位置之外,E(u, v)矩阵中其他位置的元素值,必须都要足够大才行,有任何一个位置点值不大,都表示很可能不是角点了。

    2.3 公式推导

    为了能够直接观察到E(u,v)[u,v]之间的联系,根据泰勒展开式,对公式推导优化如下:(https://zhuanlan.zhihu.com/p/90393907)

    上述公式汇总,Ix, Iy是某个像素位置的图像偏导值。对它们的一些直观印象可如下:

    如何通过矩阵判断角点的?

    其实上面,我们已经推导出E(u,v)的表达式,大家看看这个表达式有什么特征,其中矩阵H是实对称矩阵,那么E表达式其实就是二次型,对于二次型想必大家会有印象,U,V代表窗口滑动方向以及滑动量,E代表灰度变化,通过矩阵M进行特征值求解,而特征值所对应的特征向量即为灰度变化方向。如果两个特征值较大,则表示有两个方向灰度变化较快。所以可以直接通过求解H的特征值进行角点判断。

    如果线性代数知识忘了,可以看下面这种可视化解释:

    2.4 公式的物理意义

    考虑下面这种角点情况:

    哈里斯矩阵可以简化为一个对角矩阵(主对角线之外的元素皆为0的矩阵):

    原因:上图那种情况,每个像素点位置,其x、y方向的偏导,必定至少有一个方向的偏导为0,所以x方向偏导乘以y方向偏导其值一定为0,所以累加结果也一样为0。

     这意味着:如果任何一个λ接近0,那么这就不是一个角,所以我们应该寻找两个λ都很大的图像窗口。

    当然实际上,角点方向是随意的,哈里斯矩阵一般是这样:

    但是,根据线性代数知识,一个实对称矩阵,有下面这种性质:

    R是正交矩阵(旋转矩阵),而旋转矩阵的逆和旋转矩阵自身的转置相等,进一步化简E(u,v)有:

    上公式中,u'和v'相当于对u,v坐标系旋转了一定角度。而实际上,一个角点旋转后,还是个角点,与旋转无关,所以,我们判定是否是角点可以只要关注λ1和λ2。

    上述公式表面,E(u, v),u, v三者在立体空间中是一个椭圆关系,如下:

    (3D绘图软件:https://www.geogebra.org/calculator)

    如上图,要使E(u,v)中u,v取任何值,都要相对E(0, 0)位置差异越大越好,则λ1和λ2要同时足够大。因为根据最终推导出的公式,只有它们同时足够大,这个空间中形成的椭球,相对u,v平面就会越陡峭,无论u,v往那个方向移动,E值都变化很大。

    具体来说,λ1和λ2两者取不同范围值时,窗口内分别是“平坦区”或“角点”或“边缘”的情况:

    为了进一步用公式表示上述现象,也为了方便计算,Harris角点检测中采用如下角点响应函数(不是仅有这样才行)来直接判定一个位置是否为角点:

    其中,α是个常量取值在[0.04, 0.06]。

    即现在变成:(当然R也可以设定大于一个其他固定阈值)

    为什么会使用这样的角点响应函数

    https://blog.csdn.net/lwzkiller/article/details/54633670)

    答:Harris也许对很多函数模型非常了解,对于创造出这样的一个函数表达式,易如反掌。这个角点响应函数画出来如下:

    刚好符合对λ1和λ2的要求:

    2.5 算法流程

    1. 滤波、平滑,避免出现阶跃函数。
    2. 计算图像梯度。
    3. 计算每个像素位置的Harris矩阵M。
    4. 计算每个像素位置的角点响应函数R。
    5. 设置门限R,寻找响应函数的局部最大值(非最大抑制)。

    2.6 检测效果

    原图

    响应函数R:(颜色越暖,代表该像素点位置R结果越大)

    对R设置阈值:

    仅保留局部最大的点(非极大值抑制):

    最终效果图:

    其他场景的检测效果图:

    2.7 Harris角点性质

    • 当光线强度,明暗改变时,只是改变了部分角点的值,还有大部分的点可以用于检测,可以进行检测。
    • 平移和旋转位角度时,可以检测。
    • 当改变窗口大小时,大窗口下是角点,而小窗口下是线或者边缘,无法检测。

    展开全文
  • LabVIEW角点检测(基础篇—10)

    万次阅读 2021-07-18 17:49:25
    角点是图像中一种特殊的特征,基于角点进行图像检测和匹配,能在较难找到图像特征的情况下,创建图像拼接或图像匹配应用。
  • 阿菊的OpenCv——一分钟了解特征检测中的角点以及斑点1.角点2. 斑点参考文献: 1.角点 通常意义上来说,角点就是极值,即在某方面属性特别突出的,是在某些属性上强度最大或者最小的孤立、线段的终点。 对于...
  • 角点检测一、SIFT(Scale-Invariant Feature Trans-form)1.1 尺度空间极值检测1.2关键(极值)定位1.3 为关键(极值)指定方向参数1.4 关键描述符1.5 关键匹配二、 SURF(Speeded-Up Robust Features) ...
  • 一、harris角点检测 此次实验的运行环境是pycharm,下面先简单介绍一下pycharm的下载安装以及简单的测试,先通过相关网站下载pycharm安装包,通过一步步的提示完成安装,安装完成后pycharm的相关破解参考网站...
  • 角点检测

    千次阅读 2018-06-01 09:14:40
     角点家族的族长是Moravec在1977年提出的Moravec角点检测算子,它是一种基于灰度方差的角点检测方法,该算子计算图像中某个像素沿水平、垂直方向上的灰度差异,以确定角点位置,Moravec是第一个角点检测算法,也...
  • Python计算机视觉——Harris角点检测

    千次阅读 2021-06-07 22:14:11
    文章目录Python计算机视觉——Harris角点检测写在前面1 Harris角点检测基本思想2 Harris角点检测公式推导3 实验分析 写在前面 在传统目标识别中,特征提取是最终目标识别效果好坏的一个重要决定因素,因此,在这项...
  • 首先感谢以下两位的博文帮助我的理解。 (1)lwzkiller http://blog.csdn.net/lwzkiller/article/details/54633670 (2)青雲-吾道乐途 ...1. 何为角点? 下
  • 特征检测是一种局部特征子,而局部特征子非常适合于图像匹配及识别(尤其是目标出现阻挡的情况),但问题是如何才能找到具有不变的特征子(针对于旋转、仿射、光照、尺度等不变特征)。
  • opencv——角点检测

    千次阅读 2019-04-28 22:31:22
    一:角点检测 什么是角点,难道是角落里面的?我们知道,比如说墙角,他有往左延申的边缘,又有往右延申的边缘,那么这样的概念同样可以帮助我们理解图像的角点检测。 其实我们人眼对于角点的识别是通过一个小...
  • 角点具有的特征: <1>轮廓之间的交点; <2>局部窗口沿任意方向移动,均产生明显变化的; <3>图像局部曲率突变的; <4>对于同一场景,即使视角发生变化,通常具备稳定性质的特征; ...
  • Harris角点检测原理详解

    万次阅读 多人点赞 2017-01-20 23:34:03
    关于角点的应用在图像处理上的应用也比较广泛,比如图像匹配(FPM特征匹配)、相机标定等。网上也有很多博客对Harris角点检测原理进行描述,但基本上只是描述了算法流程,而其中有关细节并未作出解释,这里我想对...
  • Sober算子边缘检测与Harris角点检测1

    千次阅读 多人点赞 2022-03-02 16:38:38
    此篇文章主要介绍了Sobel算子的底层运算规律,和cv Harris的相关介绍 Harris opencv 的对应代码 cv2.cornerHarris(src, block...blockSize - 用于角点检测的邻域大小,就是上面提到的窗口的尺寸 ksize - 用于计算梯
  • 为把握好地球系统模拟、遥感地物反演的太阳辐射数据精度,需要探讨尺度效应引起的太阳高度的区域代表性问题以及确定太阳高度数据密度的方法。设计区域太阳高度平均偏差计算方法,建立分布合理的样本数据,根据...
  • 可区别:不同的有不同的表达 高效:特征数量应远小于像素数量 本地:特征仅与一小片区域相关 1.FAST特征 FAST是一种角点,主要检测局部像素灰度变化明显的地方,以速度快著称。它的思想是:如果一个...
  • 角点是邻域内具有两个主方向的特征; 有以下特点: 局部窗口沿各方向移动,均产生明显变化; 图像局部曲率突变; 不同类型的角点: 1.2 典型的角点检测算法 一种需要对图像边缘进行...
  • 我们可以直观的概括下角点具有的特征: 轮廓之间的交点; 对于同一场景,即使视角发生变化,通常具备稳定性质的特征; 该附近区域的像素无论在梯度方向上还是其梯度幅值上有着较大变化; 2. 角点检测算法...
  • 前面两节我们介绍了Harris和Shi-Tomasi角点检测算法,这两种算法具有旋转不变,但不具有尺度不变,以下图为例,在左侧小图中可以检测到角点,但是图像被放大后,在使用同样的窗口,就检测不到角点了。...
  • 2 Harris角点检测过程与非严谨数学推导 2.1 角点以及角点检测过程 之前讲过图像梯度,而通过梯度可以进行边缘检测,除此之外,还可以检测角点。系统地来说,一个图像根据图像灰度值变化大小地不同可以分为三个...
  • sift 角点检测

    千次阅读 2016-09-17 03:47:05
    SIFT(Scale-invariant feature transform)是一种检测局部特征的算法,该算法通过求一幅图中的特征(interest points,or corner points)及其有关scale 和 orientation 的描述子得到特征并进行图像
  • 形态学及边缘角点检测

    千次阅读 2018-07-10 20:36:38
    再看下图所示,放大图像的两处角点区域: 我们可以直观的概括下角点具有的特征: >轮廓之间的交点; >对于同一场景,即使视角发生变化,通常具备稳定性质的特征; >该附近区域的像素无论在梯度方向上还是其...
  • 一、角点定义 ...角点通常被定义为两条边的交点,更严格的说,角点的局部邻域应该具有两个不同区域的不同方向的边界。而实际应用中,大多数所谓的角点检测方法检测的是拥有特定特征的图像,而不仅
  •  通过对关键周围图像区域分块,计算块内梯度直方图,生成具有独特的向量,这个向量是该区域图像信息的一种抽象,具有唯一。 5. 关键描述子的生成 首先将坐标轴旋转为关键的方向,以确保...
  • opencv角点检测学习总结

    千次阅读 2016-03-16 09:41:10
    如果一个在两个正交方向上都有明显的导数,则我们认为此更倾向于是独一无二的,所以许多可跟踪的特征都是角点。 一下为角点检测中用到的一些函数 cvGoodFeaturesToTrack采用Shi和Tomasi提出的方法,先计算...
  • 目录: 一、 LOG算子 二、Harris算子 三、SUSAN算子 一、LOG算子 ...LOG算子:是高斯和拉普拉斯的双...这两个模型来源最初都是因为求导导致模板对噪声干扰敏感比较强! 1、拉普拉斯算子的出发 在图像中,...
  • 本篇博客主要介绍一下基于shi-tomasi角点检测的追踪算法。应用场景是摄像头固定物体移动的情况下。首先我们来介绍一下角点:特征检测与匹配是Computer Vision 应用总重要的一部分,这需要寻找图像之间的特征建立对应...
  • 多尺度Harris角点的学习

    千次阅读 2017-04-18 10:12:42
    Harris角点检测原理分析 我进入原文 ============================【Harris角点】======================= 1. 不同类型的角点 在现实世界中,角点对应于物体的拐角,道路的十

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 106,810
精华内容 42,724
关键字:

角点具有代表性