精华内容
下载资源
问答
  • 图像特征
    千次阅读
    2018-08-15 22:07:24

    1.表示图像的特征有哪些?

    图像特征主要有图像的颜色特征、纹理特征、形状特征和空间关系特征。

    • 颜色特征是一种全局特征,描述了图像或图像区域所对应的景物的表面性质。

      由于颜色对图像或图像区域的方向、大小等变化不敏感,所以颜色特征不能很好地捕捉图像中对象的局部特征。颜色直方图是最常用的表达颜色特征的方法, 其优点是不受图像旋转和平移变化的影响,进一步借助归一化还可不受图像尺度变化的影响,特别适用于描述那些难以自动分割的图像和不需要考虑物体空间位置的图像。其缺点在于:它无法描述图像中颜色的局部分布及每种色彩所处的空间位置,即无法描述图像中的某一具体的对象或物体,即无法表达出颜色空间分布的信息。 


       

    • 纹理特征也是一种全局特征,它也描述了图像或图像区域所对应景物的表面性质。但由于纹理只是一种物体表面的特性,并不能完全反映出物体的本质属性,所以仅仅利用纹理特征是无法获得高层次图像内容的。与颜色特征不同,纹理特征不是基于像素点的特征,它需要在包含多个像素点的区域中进行统计计算。

      作为一种统计特征,纹理特征常具有旋转不变性,并且对于噪声有较强的抵抗能力。但是,纹理特征也有其缺点,一个很明显的缺点是当图像的分辨率变化的时候,所计算出来的纹理可能会有较大偏差。另外,由于有可能受到光照、反射情况的影响,从2-D图像中反映出来的纹理不一定是3-D物体表面真实的纹理。


       

    • 形状特征有两类表示方法,一类是轮廓特征,另一类是区域特征。图像的轮廓特征主要针对物体的外边界,而图像的区域特征则关系到整个形状区域。
    • 所谓空间关系,是指图像中分割出来的多个目标之间的相互的空间位置或相对方向关系,这些关系也可分为连接/邻接关系、交叠/重叠关系和包含/包容关系等。通常空间位置信息可以分为两类:相对空间位置信息和绝对空间位置信息。前一种关系强调的是目标之间的相对情况,如上下左右关系等,后一种关系强调的是目标之间的距离大小以及方位。

    特征是描述模式的最佳方式,我们通常认为特征的各个维度能够从不同的角度描述模式,在理想情况下,维度之间是互补完备的。特征提取的主要目的是降维。特征抽取的主要思想是将原始样本投影到一个低维特征空间,得到最能反应样本本质或进行样本区分的低维样本特征

     

     

     

    更多相关内容
  • 图像特征总结(一)

    千次阅读 2022-03-25 20:17:16
    图像特征总结1.Histogram(直方图)特征1.1 直方图均衡化1.2 直方图规定化1.3 例子2. GLCM参考资料链接 1.Histogram(直方图)特征 灰度直方图是最简单、有用的工具之一。从对图像的分析与观察,直到形成一个有效的...

    1.图像特征

    图像特征是指可以对图像的特点或内容进行表征的一系列属性的集合,主要包括图像自然特征(如亮度、色彩、纹理等)和图像人为特征(如图像频谱、图像直方图等)。
    图像特征主要有图像的颜色特征、纹理特征、形状特征和空间关系特征。
    图像特征提取根据其相对尺度可分为全局特征提取和局部特征提取两类。全局特征提取关注图像的整体表征。常见的全局特征包括颜色特征、纹理特征、形状特征、空间位置关系特征等。局部特征提取关注图像的某个局部区域的特殊性质。一幅图像中往往包含若干兴趣区域,从这些区域中可以提取数量不等的若干个局部特征。
    特征特点有:代表性、稳定性和独立性。

    1.1 颜色特征

    颜色特征是一种全局特征,描述了图像或图像区域所对应的景物的表面性质。

    一般情况下,颜色特征是基于像素点的特征(即所有属于图像或图像区域的像素都有各自的贡献)。

    由于,颜色对图像或图像区域的方向、大小等变化不敏感,所以颜色特征不能很好地捕捉图像中对象的局部特征。此外,仅使用颜色特征进行查询时,如果数据库很大,常会将许多不需要的图像也检索出来。

    颜色特征描述方法有:颜色直方图、颜色集、颜色矩(颜色分布)、颜色聚合向量、颜色相关图。

    1.1.1 颜色直方图

    颜色直方图是最常用的表达颜色特征的方法。其优点在于:它能简单描述一幅图像中颜色的全局分布,即不同色彩在整幅图像中所占的比例,特别适用于描述那些难以自动分割的图像和不需要考虑物体空间位置的图像,同时不受图像旋转和平移变化的影响,进一步借助归一化还可不受图像尺度变化的影响;其缺点是:它无法描述图像中颜色的局部分布及每种色彩所处的空间位置,即无法描述图像中的某一具体的对象或物体。
    最常用的颜色空间:RGB颜色空间、HSV颜色空间。
    颜色直方图特征匹配方法:直方图相交法、距离法、中心距法、参考颜色表法、累加颜色直方图法。

    1.1.2 颜色集

    颜色直方图法是一种全局颜色特征提取与匹配方法,无法区分局部颜色信息。颜色集是对颜色直方图的一种近似首先将图像从 RGB颜色空间转化成视觉均衡的颜色空间(如HSV 空间),并将颜色空间量化成若干个柄。然后,用色彩自动分割技术将图像分为若干区域,每个区域用量化颜色空间的某个颜色分量来索引,从而将图像表达为一个二进制的颜色索引集。在图像匹配中,比较不同图像颜色集之间的距离和色彩区域的空间关系。

    1.1.3 颜色矩 (颜色分布)

    图像中任何的颜色分布均可以用它的矩来表示。此外,由于颜色分布信息主要集中在低阶矩中,因此,仅采用颜色的一阶矩(mean)、二阶矩(variance)和三阶矩(skewness)就足以表达图像的颜色分布。

    1.1.4 颜色聚合向量

    其核心思想是:将属于直方图每一个柄的像素分成两部分,如果该柄内的某些像素所占据的连续区域的面积大于给定的阈值,则该区域内的像素作为聚合像素,否则作为非聚合像素。

    1.1.5 颜色相关图

    颜色相关图(color correlogram)是图像颜色分布的另一种表达方式。这种特征不但刻画了某一种颜色的像素数量占整个图像的比例,还反映了不同颜色对之间的空间相关性。实验表明,颜色相关图比颜色直方图和颜色聚合向量具有更高的检索效率,特别是查询空间关系一致的图像。
    如果考虑到任何颜色之间的相关性,颜色相关图会变得非常复杂和庞大(空间复杂度为O(N2d))。一种简化的变种是颜色自动相关图(color auto-correlogram),它仅仅考察具有相同颜色的像素间的空间关系,因此空间复杂度降到O(Nd)

    1.2 纹理特征

    纹理特征也是一种全局特征,它也描述了图像或图像区域所对应景物的表面性质。但由于纹理只是一种物体表面的特性,并不能完全反映出物体的本质属性,所以仅仅利用纹理特征是无法获得高层次图像内容的。

    与颜色特征不同,纹理特征不是基于像素点的特征,它需要在包含多个像素点的区域中进行统计计算。在模式匹配中,这种区域性的特征具有较大的优越性,不会由于局部的偏差而无法匹配成功。

    作为一种统计特征,纹理特征常具有旋转不变性,并且对于噪声有较强的抵抗能力。但是,纹理特征也有其缺点,一个很明显的缺点是当图像的分辨率变化的时候,所计算出来的纹理可能会有较大偏差。另外,由于有可能受到光照、反射情况的影响,从2-D图像中反映出来的纹理不一定是3-D物体表面真实的纹理。

    例如,水中的倒影,光滑的金属面互相反射造成的影响等都会导致纹理的变化。由于这些不是物体本身的特性,因而将纹理信息应用于检索时,有时这些虚假的纹理会对检索造成“误导”。

    引入纹理语义分层分析。在检索具有粗细、疏密等方面较大差别的纹理图像时,利用纹理特征是一种有效的方法。但当纹理之间的粗细、疏密等易于分辨的信息之间相差不大的时候,通常的纹理特征很难准确地反映出人的视觉感觉不同的纹理之间的差别。

    纹理特征描述方法有:统计方法、几何方法、模型法、信号处理法。

    1.2.1 统计方法

    统计方法的典型代表是一种称为灰度共生矩阵(GLCM)的纹理特征分析方。灰度共生矩阵有四个关键特征:能量、惯量、熵和相关性。
    统计方法中另一种典型方法,则是从图像的自相关函数(即图像的能量谱函数)提取纹理特征,即通过对图像的能量谱函数的计算,提取纹理的粗细度及方向性等特征参数。

    1.2.2 几何方法

    所谓几何法,是建立在纹理基元(基本的纹理元素)理论基础上的一种纹理特征分析方法。纹理基元理论认为,复杂的纹理可以由若干简单的纹理基元以一定的有规律的形式重复排列构成。
    在几何法中,比较有影响的算法有两种:Voronio 棋盘格特征法和结构法。

    1.2.3 模型法

    模型法以图像的构造模型为基础,采用模型的参数作为纹理特征。典型的方法是随机场CRF模型法,如马尔可夫(Markov)随机场(MRF)模型法和 Gibbs 随机场模型法。

    1.2.4 信号处理法

    如:小波变换。

    灰度共生矩阵特征提取与匹配主要依赖于能量、惯量、熵和相关性四个参数。Tamura 纹理特征基于人类对纹理的视觉感知心理学研究,提出6种属性,即:粗糙度、对比度、方向度、线像度、规整度和粗略度。自回归纹理模型(simultaneous auto-regressive, SAR)是马尔可夫随机场(MRF)模型的一种应用实例。

    1.3 形状特征

    许多形状特征仅描述了目标局部的性质,要全面描述目标常对计算时间和存储量有较高的要求;许多形状特征所反映的目标形状信息与人的直观感觉不完全一致,或者说,特征空间的相似性与人视觉系统感受到的相似性有差别。另外,从 2-D 图像中表现的 3-D 物体实际上只是物体在空间某一平面的投影,从 2-D 图像中反映出来的形状常不是 3-D 物体真实的形状,由于视点的变化,可能会产生各种失真。同时,如果目标有变形时检索结果往往不太可靠;

    通常情况下,形状特征有两类表示方法,一类是轮廓特征,另一类是区域特征。图像的轮廓特征主要针对物体的外边界,而图像的区域特征则关系到整个形状区域。典型的形状特征描述方法有:边界特征法、傅里叶形状描述符法、几何参数法、形状不变矩法等待

    1.3.1 边界特征法

    该方法通过对边界特征的描述来获取图像的形状参数。其中Hough 变换检测平行直线方法和边界方向直方图方法是经典方法。Hough 变换是利用图像全局特性而将边缘像素连接起来组成区域封闭边界的一种方法,其基本思想是点—线的对偶性;边界方向直方图法首先微分图像求得图像边缘,然后,做出关于边缘大小和方向的直方图,通常的方法是构造图像灰度梯度方向矩阵。

    1.3.2 傅里叶形状描述符法

    傅里叶形状描述符(Fourier shape deors)基本思想是用物体边界的傅里叶变换作为形状描述,利用区域边界的封闭性和周期性,将二维问题转化为一维问题。
    由边界点导出三种形状表达,分别是曲率函数、质心距离、复坐标函数。

    1.3.3 几何参数法

    形状的表达和匹配采用更为简单的区域特征描述方法,例如采用有关形状定量测度(如矩、面积、周长等)的形状参数法(shape factor)。在 QBIC 系统中,便是利用圆度、偏心率、主轴方向和代数不变矩等几何参数,进行基于形状特征的图像检索。
    需要说明的是,形状参数的提取,必须以图像处理及图像分割为前提,参数的准确性必然受到分割效果的影响,对分割效果很差的图像,形状参数甚至无法提取。

    1.3.4 形状不变矩法

    利用目标所占区域的矩作为形状描述参数。

    1.4 空间关系特征

    所谓空间关系,是指图像中分割出来的多个目标之间的相互的空间位置或相对方向关系,这些关系也可分为连接/邻接关系、交叠/重叠关系和包含/包容关系等。通常空间位置信息可以分为两类:相对空间位置信息和绝对空间位置信息。前一种关系强调的是目标之间的相对情况,如上下左右关系等,后一种关系强调的是目标之间的距离大小以及方位。显而易见,由绝对空间位置可推出相对空间位置,但表达相对空间位置信息常比较简单。

    空间关系特征的使用可加强对图像内容的描述区分能力,但空间关系特征常对图像或目标的旋转、反转、尺度变化等比较敏感。另外,实际应用中,仅仅利用空间信息往往是不够的,不能有效准确地表达场景信息。为了检索,除使用空间关系特征外,还需要其它特征来配合。

    提取图像空间关系特征可以有两种方法:一种方法是首先对图像进行自动分割,划分出图像中所包含的对象或颜色区域,然后根据这些区域提取图像特征,并建立索引;另一种方法则简单地将图像均匀地划分为若干规则子块,然后对每个图像子块提取特征,并建立索引。

    姿态估计问题:确定某一三维目标物体的方位指向问题。姿态估计在机器人视觉、动作跟踪和单照相机定标等很多领域都有应用。

    基于视觉的姿态估计根据使用的摄像机数目又可分为单目视觉姿态估计和多目视觉姿态估计。根据算法的不同又可分为基于模型的姿态估计和基于学习的姿态估计。

    1.4.1 基于模型的姿态估计方法

    基于模型的方法通常利用物体的几何关系或者物体的特征点来估计。其基本思想是利用某种几何模型或结构来表示物体的结构和形状,并通过提取某些物体特征,在模型和图像之间建立起对应关系,然后通过几何或者其它方法实现物体空间姿态的估计。这里所使用的模型既可能是简单的几何形体,如平面、圆柱,也可能是某种几何结构,也可能是通过激光扫描或其它方法获得的三维模型。
    基于模型的姿态估计方法是通过比对真实图像和合成图像,进行相似度计算更新物体姿态。目前基于模型的方法为了避免在全局状态空间中进行优化搜索,一般都将优化问题先降解成多个局部特征的匹配问题,非常依赖于局部特征的准确检测。当噪声较大无法提取准确的局部特征的时候,该方法的鲁棒性受到很大影响。

    1.4.2 基于学习的姿态估计方法

    基于学习的方法借助于机器学习(machine learning)方法,从事先获取的不同姿态下的训练样本中学习二维观测与三维姿态之间的对应关系,并将学习得到的决策规则或回归函数应用于样本,所得结果作为对样本的姿态估计。基于学习的方法一般采用全局观测特征,不需检测或识别物体的局部特征,具有较好的鲁棒性。其缺点是由于无法获取在高维空间中进行连续估计所需要的密集采样,因此无法保证姿态估计的精度与连续性。

    基于学习的方法一般采用全局观测特征,可以保证算法具有较好的鲁棒性。然而这一类方法的姿态估计精度很大程度依赖于训练的充分程度。要想比较精确地得到二维观测与三维姿态之间的对应关系,就必须获取足够密集的样本来学习决策规则和回归函数。而一般来说所需要样本的数量是随状态空间的维度指数级增加的,对于高维状态空间,事实上不可能获取进行精确估计所需要的密集采样。因此,无法得到密集采样而难以保证估计的精度与连续性,是基于学习的姿态估计方法无法克服的根本困难。

    2.图像特征提取方法

    2.1 颜色特征提取

    2.1.1 颜色直方图

    1. 一般颜色直方图 cv2.calcHist
      颜色直方图是最基本的颜色特征,它反映的是图像中像素颜色值的组成分布,即出现了哪些颜色以及各种颜色出现的概率。
      假设 s ( x i ) s(x_i) s(xi)图像F中某一特定颜色 x i x_i xi的像素个数,则 x i x_i xi像素出现的频率为:
      h ( x i ) = s ( x i ) N = s ( x i ) ∑ j s ( x j ) h(x_i) = \frac{s(x_i)}{N}=\frac{s(x_i)}{\sum_js(x_j)} h(xi)=Ns(xi)=js(xj)s(xi)
      那么,整个图像的一般直方图可以表示为: H ( F ) = [ h ( x 1 ) , h ( x 2 ) , … , h ( x n ) ] H(F) = [h(x_1),h(x_2),\dots,h(x_n)] H(F)=[h(x1),h(x2),,h(xn)]
      opencv中方法:cv2.calcHist(image,channels,mask,histSize,ranges)
      参数:
      • image:原始图像,需要[]括起来
      • channel:通道编号,需要[]括起来
      • mask:掩膜图像,当统计全局图像,值设为None,统计局部图像的直方图,需要使用到它
      • histSize:表示直方图的灰度级数,例如[0,255]一共256级
      • range:表示像素值范围[a,b],表示a到b
      • accumulate:表示累计标识,默认False,如果设为True,则直方图在开始计算时不会被清零,计算的是多个直方图的累积结果,用于对一组图像计算直方图。参数可选
    import matplotlib.pyplot as plt
    import cv2 as cv
    from skimage import data
    img = data.coffee()
    hist0 = cv.calcHist([img],[0],None,[256],[0,255])
    hist1 = cv.calcHist([img],[1],None,[256],[0,255])
    hist2 = cv.calcHist([img],[2],None,[256],[0,255])
    

    2.1.2 全局累加直方图

    当图像中的颜色值不能取遍所有可能的颜色值时,一般颜色直方图中就会出现一些零值。这些零值的出现会影响相似性的度量,进而会使计算出的相似度不能准确反映图像之间的颜色分布差异。
    为了弥合一般颜色直方图法的上述缺陷,在一般直方图方法的基础之上,通过对直方图元素进行累加,消除零值影响,形成全局累加直方图,即:
    λ ( x i ) = ∑ j ≤ i h ( x j ) \lambda(x_i) = \sum_{j \leq i}h(x_j) λ(xi)=jih(xj)

    img = data.coffee()
    hist0 = np.cumsum(cv.calcHist([img],[0],None,[256],[0,255]))
    hist1 = np.cumsum(cv.calcHist([img],[1],None,[256],[0,255]))
    hist2 = np.cumsum(cv.calcHist([img],[2],None,[256],[0,255]))
    plt.figure(figsize=(6,6))
    plt.plot(range(256),hist0,label = 'R')
    plt.plot(range(256),hist1,label = 'G')
    plt.plot(range(256),hist2,label = 'B')
    plt.legend()                 
    plt.title("累积直方图")
    

    在这里插入图片描述

    2.1.3 主色调直方图

    在一幅图像中,不同颜色值出现的概率不尽相同,且通常情况下少数几种颜色就能涵盖整幅图像的主色调。基于该思想,主色调直方图法会计算出图像中每种颜色出现的频率,选择出现频率最高的几种颜色并将其作为主色调。

    2.1.4 颜色矩

    矩是非常重要的统计量,用于表征数据分布的特点。在统计中,一阶矩表示数据分布的均值,二阶矩表示数据分布的方差,三阶矩表示数据分布的偏移度。
    图像的颜色矩用于对图像内的颜色分布进行表征,是比较重要的一种全局图像特征表示。图像的颜色矩特征提取时主要瞄准图像颜色矩中的一阶矩、二阶矩和三阶矩,对于图像而言,这3种统计特征已经足以表达数字图像的颜色分布。相对于颜色直方图特征提取,颜色矩特征提取的优点是无须对颜色特征进行提前量化。

    对于数字图像P,其一阶颜色矩的定义为:
    μ i = 1 N ∑ j = 1 N P i j \mu_i = \frac{1}{N} \sum_{j=1}^N P_{ij} μi=N1j=1NPij
    其中 P i j P_{ij} Pij表示数字图像P的第i个图像通道的第j个像素的像素值,N表示图像中像素的个数。

    二阶颜色矩的定义为:
    σ i = [ 1 N ∑ j = 1 N ( P i j − μ i ) 2 ] 1 2 \sigma_i =[\frac{1}{N} \sum_{j=1}^N(P_{ij} - \mu_i)^2]^{\frac{1}{2}} σi=[N1j=1N(Pijμi)2]21

    三阶颜色矩的定义为:

    s i = [ 1 N ∑ j = 1 N ( P i j − μ i ) 3 ] 1 3 s_i =[\frac{1}{N} \sum_{j=1}^N(P_{ij} - \mu_i)^3]^{\frac{1}{3}} si=[N1j=1N(Pijμi)3]31
    其中一阶矩可以表征该颜色通道的平均响应强度,二阶矩可以表示该颜色通道的响应方差,三阶矩可以表征该颜色通道数据分布的偏移度。针对彩色图像,图像的颜色矩一共有9个分量,每个颜色通道均有3个低阶矩。

    def color_comment(img):
        r,g,b = cv.split(img)
        color_featrue = []
        # 一阶矩
        r_mean = np.mean(r)
        g_mean = np.mean(g)
        b_mean = np.mean(b)
        # 二阶矩
        r_std = np.std(r)
        g_std = np.std(g)
        b_std = np.std(b)
        #三阶矩
        r_offset = (np.mean(np.abs((r - r_mean)**3)))**(1./3)
        g_offset = (np.mean(np.abs((g - g_mean)**3)))**(1./3)
        b_offset = (np.mean(np.abs((b - b_mean)**3)))**(1./3)
        color_featrue.extend([r_mean,g_mean,b_mean,r_std,g_std,b_std,r_offset,g_offset,b_offset])
        return color_featrue
    print(color_comment(img))
    

    2.1.5 颜色相关图

    颜色相关图是图像颜色分布的另外一种表达方式。颜色相关图不仅可以显示像素在图像中的占比,也可以反映不同颜色对间的空间位置的相关性。颜色相关图利用颜色对间的相对距离分布来描述空间位置信息。

    颜色相关图是一张用颜色对<i,j>索引的表,其中<i,j>的第k个分量表示颜色为c(i)的像素和颜色为c(j)的像素之间的距离等于k的概率。设I表示整张图像的全部像素,Ic(i)表示颜色为c(i)的所有像素,则图像的颜色相关图可以表达为:
    在这里插入图片描述
    |p1-p2|表示像素p1和p2之间的距离

    def is_vaild(X,Y,point): #判断像素分布点是否超出图像范围,超出返回False
        if point[0] < 0 or point[0] >= X:
            return False
        if point[1] < 0 or point[1] >= Y:
            return False
        return True
        
    def getNeighbors(X,Y,x,y,dist):  # 输入图片的一个像素点的位置,返回它的8邻域
        cn1 = (x+dist,y+dist)
        cn2 = (x+dist,y)
        cn3 = (x+dist,y-dist)
        cn4 = (x,y-dist)
        cn5 = (x-dist,y-dist)
        cn6 = (x-dist,y)
        cn7 = (x-dist,y+dist)
        cn8 = (x,y+dist)
        point = (cn1,cn2,cn3,cn4,cn5,cn6,cn7,cn8)
        Cn = []
        for i in point:
            if is_vaild(X,Y,i):
                Cn.append(i)
        return Cn
            
    def corrlogram(img,dist):
        xx,yy,tt = img.shape
        cgram = np.zeros((256,256),np.uint8)
        for x in range(xx):
            for y in range(yy):
                for t in range(tt):
                    color_i = img[x,y,t]   # X的某一个通道的像素值
                    neighbors_i = getNeighbors(xx,yy,x,y,dist)
                for j in neighbors_i:
                    j0 = j[0]
                    j1 = j[1]
                    color_j = img[j0,j1,t]   #X的某一个邻域像素点的某一个通道的像素值
                    cgram[color_i,color_j] +=  1  #统计像素值i核像素值j的个数
        return cgram
    crgam = corrlogram(img,4)  # 4 
    plt.imshow(crgam)
    plt.show()
    

    2.2 纹理特征提取

    2.2.1 LBP特征

    对LBP特征向量进行提取的步骤如下:

    首先将检测窗口划分为16×16的小区域(cell),对于每个cell中的一个像素,将其环形邻域内的8个点(也可以是环形邻域多个点,如图 3‑4. 应用LBP算法的三个邻域示例所示)进行顺时针或逆时针的比较,如果中心像素值比该邻点大,则将邻点赋值为1,否则赋值为0,这样每个点都会获得一个8位二进制数(通常转换为十进制数)。然后计算每个cell的直方图,即每个数字(假定是十进制数)出现的频率(也就是一个关于每一个像素点是否比邻域内点大的一个二进制序列进行统计),然后对该直方图进行归一化处理。最后将得到的每个cell的统计直方图进行连接,就得到了整幅图的LBP纹理特征,然后便可利用SVM或者其他机器学习算法进行分类了。
    

    2.2.2 灰度共生矩阵

    灰度共生矩阵(GLCM)是另一种纹理特征提取方法,首先对于一幅图像定义一个方向(orientation)和一个以pixel为单位的步长(step),灰度共生矩阵T(N×N),则定义M(i,j)为灰度级为i和j的像素同时出现在一个点和沿所定义的方向跨度步长的点上的频率。其中N是灰度级划分数目。由于共生矩阵有方向和步长的组合定义,而决定频率的一个因素是对矩阵有贡献的像素数目,而这个数目要比总共数目少,且随着步长的增加而减少。因此所得到的共生矩阵是一个稀疏矩阵,所以灰度级划分N常常减少到8级。如在水平方向上计算左右方向上像素的共生矩阵,则为对称共生矩阵。类似的,如果仅考虑当前像素单方向(左或右)上的像素,则称为非对称共生矩阵。

    2.3 形状特征提取

    形状特征的表达必须以对图像中物体或区域的分割为基础。
    两种经典的算法是SIFT和HOG。Sift是先找特征点,而hog是对图片进行分割。

    2.4 边缘特征提取

    边缘检测通常用于特征提取和特征检测,旨在检测一张数字图像中有明显变化的边缘或者不连续的区域。在一维空间中,类似的操作被称作步长检测(step detection)。边缘是一幅图像中不同屈原之间的边界线,通常一个边缘图像是一个二值图像。边缘检测的目的是捕捉亮度急剧变化的区域。

    在一幅图像中两度不连续的区域通常是以下几项之一:

    1. 图像深度不连续处
    2. 图像(梯度)朝向不连续处
    3. 图像光照(强度)不连续处
    4. 纹理变化处

    检测方法:

    1. Canny算子边缘检测
    2. Sobel算子边缘检测

    参考资料链接

    特征提取之颜色特征提取
    图像特征提取
    常用的图像特征描述

    展开全文
  • OpenCV中图像特征提取与描述

    千次阅读 2022-03-08 20:12:13
    目录图像特征提取与描述图像的特征Harris和Shi-Tomas算法Harris角点检测Shi-Tomasi角点检测小结SIFT/SURF算法SIFT原理基本流程尺度空间极值检测关键点定位关键点方向确定关键点描述SURF原理小结Fast和ORB算法Fast...

    图像特征提取与描述

    主要内容是:

    • 图像的特征
    • Harris和Shi-Tomasi算法的原理及角点检测的实现
    • SIFT/SURF算法的原理及使用SIFT/SURF进行关键点的检测方法
    • Fast算法角点检测的原理角及其应用
    • ORB算法的原理,及特征点检测的实现

    图像的特征

    大多数人都玩过拼图游戏。首先拿到完整图像的碎片,然后把这些碎片以正确的方式排列起来从而重建这幅图像。如果把拼图游戏的原理写成计算机程序,那计算机就也会玩拼图游戏了。

    在拼图时,我们要寻找一些唯一的特征,这些特征要适于被跟踪,容易被比较。我们在一副图像中搜索这样的特征,找到它们,而且也能在其他图像中找到这些特征,然后再把它们拼接到一起。我们的这些能力都是天生的。

    那这些特征是什么呢?我们希望这些特征也能被计算机理解。

    如果我们深入的观察一些图像并搜索不同的区域,以下图为例:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CLCQPeEj-1646741526289)(F:\Python学习\129黑马人工智能2.0课程\学习随笔\阶段4计算机视觉与图像处理\图像处理与OpenCV随笔\第十章图像特征提取与描述随笔\笔记图片\image-20191008141826875.png)]

    在图像的上方给出了六个小图。找到这些小图在原始图像中的位置。你能找到多少正确结果呢?

    A 和 B 是平面,而且它们的图像中很多地方都存在。很难找到这些小图的准确位置。

    C 和 D 也很简单。它们是建筑的边缘。可以找到它们的近似位置,但是准确位置还是很难找到。这是因为:沿着边缘,所有的地方都一样。所以边缘是比平面更好的特征,但是还不够好。

    最后 E 和 F 是建筑的一些角点。它们能很容易的被找到。因为在角点的地方,无论你向哪个方向移动小图,结果都会有很大的不同。所以可以把它们当 成一个好的特征。为了更好的理解这个概念我们再举个更简单的例子。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qdUDffVD-1646741526290)(笔记图片/image-20191008141945745.png)]

    如上图所示,蓝色框中的区域是一个平面很难被找到和跟踪。无论向哪个方向移动蓝色框,都是一样的。对于黑色框中的区域,它是一个边缘。如果沿垂直方向移动,它会改变。但是如果沿水平方向移动就不会改变。而红色框中的角点,无论你向那个方向移动,得到的结果都不同,这说明它是唯一的。 所以,我们说角点是一个好的图像特征,也就回答了前面的问题。

    角点是图像很重要的特征,对图像图形的理解和分析有很重要的作用。角点在三维场景重建运动估计,目标跟踪、目标识别、图像配准与匹配等计算机视觉领域起着非常重要的作用。在现实世界中,角点对应于物体的拐角,道路的十字路口、丁字路口等

    那我们怎样找到这些角点呢?接下来我们使用 OpenCV 中的各种算法来查找图像的特征,并对它们进行描述。

    小结:

    图像特征:图像特征要有区分性,容易被比较。一般认为角点,斑点等是较好的图像特征

    特征检测:找到图像中的特征

    特征描述:对特征及其周围的区域进行描述

    Harris和Shi-Tomas算法

    学习目标

    • 理解Harris和Shi-Tomasi算法的原理
    • 能够利用Harris和Shi-Tomasi进行角点检测

    Harris角点检测

    Harris角点检测的思想是通过图像的局部的小窗口观察图像,角点的特征是窗口沿任意方向移动都会导致图像灰度的明显变化,如下图所示:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yOXnbuXc-1646741526291)(笔记图片/image-20191008144647540.png)]

    将上述思想转换为数学形式,即将局部窗口向各个方向移动(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

    其中I(x,y)是局部窗口的图像灰度,I(x+u,y+v)是平移后的图像灰度,w(x,y)是窗口函数,该可以是矩形窗口,也可以是对每一个像素赋予不同权重的高斯窗口,如下所示:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M5t4GaIT-1646741526291)(笔记图片/image-20191008153014984.png)]在这里插入图片描述

    角点检测中使E(u,v)的值最大。利用一阶泰勒展开有:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9BCm4U3s-1646741526292)(笔记图片/image-20220308154736341.png)]

    其中Ix和 Iy是沿x和y方向的导数,可用sobel算子计算。

    推导如下:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TxnKqc3x-1646741526293)(笔记图片/image-20191015180016665.png)]

    M矩阵决定了E(u,v)的取值,下面我们利用M来求角点,M是Ix和Iy的二次项函数,可以表示成椭圆的形状,椭圆的长短半轴由M的特征值λ1和λ2决定,方向由特征矢量决定,如下图所示:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-57t0gy3p-1646741526293)(笔记图片/image-20191008160908338.png)]

    椭圆函数特征值与图像中的角点、直线(边缘)和平面之间的关系如下图所示。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fYSghOel-1646741526294)(笔记图片/image-20191008161040473.png)]

    共可分为三种情况:

    • 图像中的直线。一个特征值大,另一个特征值小,λ1>>λ2或 λ2>>λ1。椭圆函数值在某一方向上大,在其他方向上小。
    • 图像中的平面。两个特征值都小,且近似相等;椭圆函数数值在各个方向上都小。
    • 图像中的角点。两个特征值都大,且近似相等,椭圆函数在所有方向都增大

    Harris给出的角点计算方法并不需要计算具体的特征值,而是计算一个角点响应值R来判断角点。R的计算公式为:

    R = det ⁡ M − α (  trace  M ) 2 R=\operatorname{det} M-\alpha(\text { trace } M)^{2} R=detMα( trace M)2

    式中,detM为矩阵M的行列式;traceM为矩阵M的迹;α为常数,取值范围为0.04~0.06。事实上,特征是隐含在detM和traceM中,因为:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EPP9DF8O-1646741526295)(笔记图片/image-20191015181643847.png)]

    那我们怎么判断角点呢?如下图所示:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fnymxFOo-1646741526296)(笔记图片/image-20191008161904372.png)]

    • 当R为大数值的正数时是角点
    • 当R为大数值的负数时是边界
    • 当R为小数是认为是平坦区域

    在OpenCV中实现Hariis检测使用的API是:

    dst=cv.cornerHarris(src, blockSize, ksize, k)
    

    参数:

    • img:数据类型为 float32 的输入图像。
    • blockSize:角点检测中要考虑的邻域大小。
    • ksize:sobel求导使用的核大小
    • k :角点检测方程中的自由参数,取值参数为 [0.04,0.06].
    import cv2 as cv
    import numpy as np 
    import matplotlib.pyplot as plt
    # 1 读取图像,并转换成灰度图像
    img = cv.imread('./image/chessboard.jpg')
    gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
    # 2 角点检测
    # 2.1 输入图像必须是 float32
    gray = np.float32(gray)
    
    # 2.2 最后一个参数在 0.04 到 0.05 之间
    dst = cv.cornerHarris(gray,2,3,0.04)
    # 3 设置阈值,将角点绘制出来,阈值根据图像进行选择
    img[dst>0.001*dst.max()] = [0,0,255]
    # 4 图像显示
    plt.figure(figsize=(10,8),dpi=100)
    plt.imshow(img[:,:,::-1]),plt.title('Harris角点检测')
    plt.xticks([]), plt.yticks([])
    plt.show()
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aejrQNvt-1646741526297)(笔记图片/image-20191008164344988.png)]

    Harris角点检测的优缺点:

    优点:

    • 旋转不变性,椭圆转过一定角度但是其形状保持不变(特征值保持不变)
    • 对于图像灰度的仿射变化具有部分的不变性,由于仅仅使用了图像的一介导数,对于图像灰度平移变化不变;对于图像灰度尺度变化不变

    缺点:

    • 对尺度很敏感,不具备几何尺度不变性。
    • 提取的角点是像素级的

    Shi-Tomasi角点检测

    Shi-Tomasi算法是对Harris角点检测算法的改进,一般会比Harris算法得到更好的角点。Harris 算法的角点响应函数是将矩阵 M 的行列式值与 M 的迹相减,利用差值判断是否为角点。后来Shi 和Tomasi 提出改进的方法是,若矩阵M的两个特征值中较小的一个大于阈值,则认为他是角点,即:

    R = min ⁡ ( λ 1 , λ 2 ) R=\min \left(\lambda_{1}, \lambda_{2}\right) R=min(λ1,λ2)

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DFUZEQdN-1646741526298)(笔记图片/image-20191008171309192.png)]

    从这幅图中,可以看出来只有当 λ1 和 λ 2 都大于最小值时,才被认为是角点。

    在OpenCV中实现Shi-Tomasi角点检测使用API:

    corners = cv2.goodFeaturesToTrack ( image, maxcorners, qualityLevel, minDistance )
    

    参数:

    • Image: 输入灰度图像
    • maxCorners : 获取角点数的数目。
    • qualityLevel:该参数指出最低可接受的角点质量水平,在0-1之间。
    • minDistance:角点之间最小的欧式距离,避免得到相邻特征点。

    返回:

    • Corners: 搜索到的角点,在这里所有低于质量水平的角点被排除掉,然后把合格的角点按质量排序,然后将质量较好的角点附近(小于最小欧式距离)的角点删掉,最后找到maxCorners个角点返回。
    import numpy as np 
    import cv2 as cv
    import matplotlib.pyplot as plt
    # 1 读取图像
    img = cv.imread('./image/tv.jpg') 
    gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
    # 2 角点检测
    corners = cv.goodFeaturesToTrack(gray,1000,0.01,10)  
    # 3 绘制角点
    for i in corners:
        x,y = i.ravel()
        cv.circle(img,(x,y),2,(0,0,255),-1)
    # 4 图像展示
    plt.figure(figsize=(10,8),dpi=100)
    plt.imshow(img[:,:,::-1]),plt.title('shi-tomasi角点检测')
    plt.xticks([]), plt.yticks([])
    plt.show()
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-62FemMhq-1646741526299)(笔记图片/image-20191008174257711.png)]

    小结

    1. Harris算法

      思想:通过图像的局部的小窗口观察图像,角点的特征是窗口沿任意方向移动都会导致图像灰度的明显变化。

      API: cv.cornerHarris()

    2. Shi-Tomasi算法

      对Harris算法的改进,能够更好地检测角点

      API: cv2.goodFeatureToTrack()

    SIFT/SURF算法

    学习目标

    • 理解SIFT/SURF算法的原理,
    • 能够使用SIFT/SURF进行关键点的检测

    SIFT原理

    前面两节我们介绍了Harris和Shi-Tomasi角点检测算法,这两种算法具有旋转不变性,但不具有尺度不变性,以下图为例,在左侧小图中可以检测到角点,但是图像被放大后,在使用同样的窗口,就检测不到角点了。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C7BkR9K6-1646741526300)(笔记图片/image-20191008181535222.png)]

    所以,下面我们来介绍一种计算机视觉的算法,尺度不变特征转换即SIFT (Scale-invariant feature transform)。它用来侦测与描述影像中的局部性特征,它在空间尺度中寻找极值点,并提取出其位置、尺度、旋转不变量,此算法由 David Lowe在1999年所发表,2004年完善总结。应用范围包含物体辨识、机器人地图感知与导航、影像缝合、3D模型建立、手势辨识、影像追踪和动作比对等领域。

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

    基本流程

    Lowe将SIFT算法分解为如下四步

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

    我们就沿着Lowe的步骤,对SIFT算法的实现过程进行介绍:

    尺度空间极值检测

    在不同的尺度空间是不能使用相同的窗口检测极值点,对小的关键点使用小的窗口,对大的关键点使用大的窗口,为了达到上述目的,我们使用尺度空间滤波器。

    高斯核是唯一可以产生多尺度空间的核函数。-《Scale-space theory: A basic tool for analysing structures at different scales》。

    一个图像的尺度空间L(x,y,σ),定义为原始图像I(x,y)与一个可变尺度的2维高斯函数G(x,y,σ)卷积运算 ,即:

    L ( x , y , σ ) = G ( x , y , σ ) ∗ I ( x , y ) L(x, y, \sigma)=G(x, y, \sigma) * I(x, y) L(x,y,σ)=G(x,y,σ)I(x,y)

    其中:

    G ( x , y , σ ) = 1 2 π σ 2 e − x 2 + y 2 2 σ 2 G(x, y, \sigma)=\frac{1}{2 \pi \sigma^{2}} e^{-\frac{x^{2}+y^{2}}{2 \sigma^{2}}} G(x,y,σ)=2πσ21e2σ2x2+y2

    σ是尺度空间因子,它决定了图像的模糊的程度。在大尺度下(σ值大)表现的是图像的概貌信息,在小尺度下(σ值小)表现的是图像的细节信息。

    在计算高斯函数的离散近似时,在大概3σ距离之外的像素都可以看作不起作用,这些像素的计算也就可以忽略。所以,在实际应用中,只计算**(6σ+1)*(6σ+1)**的高斯卷积核就可以保证相关像素影响。

    下面我们构建图像的高斯金字塔,它采用高斯函数对图像进行模糊以及降采样处理得到的,高斯金字塔构建过程中,首先将图像扩大一倍,在扩大的图像的基础之上构建高斯金字塔,然后对该尺寸下图像进行高斯模糊,几幅模糊之后的图像集合构成了一个Octave,然后对该Octave下选择一幅图像进行下采样,长和宽分别缩短一倍,图像面积变为原来四分之一。这幅图像就是下一个Octave的初始图像,在初始图像的基础上完成属于这个Octave的高斯模糊处理,以此类推完成整个算法所需要的所有八度构建,这样这个高斯金字塔就构建出来了,整个流程如下图所示:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c06QPKDP-1646741526300)(笔记图片/image-20191009110944907.png)]

    利用LoG(高斯拉普拉斯方法),即图像的二阶导数,可以在不同的尺度下检测图像的关键点信息,从而确定图像的特征点。但LoG的计算量大,效率低。所以我们通过两个相邻高斯尺度空间的图像的相减,得到DoG(高斯差分)来近似LoG。

    为了计算DoG我们构建高斯差分金字塔,该金字塔是在上述的高斯金字塔的基础上构建而成的,建立过程是:在高斯金字塔中每个Octave中相邻两层相减就构成了高斯差分金字塔。如下图所示:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xuIzxCn4-1646741526300)(笔记图片/image-20191009113953721.png)]

    高斯差分金字塔的第1组第1层是由高斯金字塔的第1组第2层减第1组第1层得到的。以此类推,逐组逐层生成每一个差分图像,所有差分图像构成差分金字塔。概括为DOG金字塔的第o组第l层图像是有高斯金字塔的第o组第l+1层减第o组第l层得到的。后续Sift特征点的提取都是在DOG金字塔上进行的

    在 DoG 搞定之后,就可以在不同的尺度空间中搜索局部最大值了。对于图像中的一个像素点而言,它需要与自己周围的 8 邻域,以及尺度空间中上下两层中的相邻的 18(2x9)个点相比。如果是局部最大值,它就可能是一个关键点。基本上来说关键点是图像在相应尺度空间中的最好代表。如下图所示:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YUry630u-1646741526301)(笔记图片/image-20191009115023016.png)]

    搜索过程从每组的第二层开始,以第二层为当前层,对第二层的DoG图像中的每个点取一个3×3的立方体,立方体上下层为第一层与第三层。这样,搜索得到的极值点既有位置坐标(DoG的图像坐标),又有空间尺度坐标(层坐标)。当第二层搜索完成后,再以第三层作为当前层,其过程与第二层的搜索类似。当S=3时,每组里面要搜索3层,所以在DOG中就有S+2层,在初使构建的金字塔中每组有S+3层。

    关键点定位

    由于DoG对噪声和边缘比较敏感,因此在上面高斯差分金字塔中检测到的局部极值点需经过进一步的检验才能精确定位为特征点。

    使用尺度空间的泰勒级数展开来获得极值的准确位置, 如果极值点的 灰度值小于阈值(一般为0.03或0.04)就会被忽略掉。 在 OpenCV 中这种阈值被称为 contrastThreshold。

    DoG 算法对边界非常敏感, 所以我们必须要把边界去除。 Harris 算法除了可以用于角点检测之外还可以用于检测边界。从 Harris 角点检测的算法中,当一个特征值远远大于另外一个特征值时检测到的是边界。那在DoG算法中欠佳的关键点在平行边缘的方向有较大的主曲率,而在垂直于边缘的方向有较小的曲率,两者的比值如果高于某个阈值(在OpenCV中叫做边界阈值),就认为该关键点为边界,将被忽略,一般将该阈值设置为10。

    将低对比度和边界的关键点去除,得到的就是我们感兴趣的关键点。

    关键点方向确定

    经过上述两个步骤,图像的关键点就完全找到了,这些关键点具有尺度不变性。为了实现旋转不变性,还需要为每个关键点分配一个方向角度,也就是根据检测到的关键点所在高斯尺度图像的邻域结构中求得一个方向基准。

    对于任一关键点,我们采集其所在高斯金字塔图像以r为半径的区域内所有像素的梯度特征(幅值和幅角),半径r为: r = 3 × 1.5 σ r = 3\times1.5\sigma r=3×1.5σ

    其中σ是关键点所在octave的图像的尺度,可以得到对应的尺度图像。

    梯度的幅值和方向的计算公式为:

    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{array}{c} m(x, y)=\sqrt{\left(L(x+1, y)-L(x-1, y)^{2}+(L(x, y+1)-L(x, y-1))^{2}\right.} \\ \theta(x, y)=\arctan \left(\frac{L(x, y+1)-L(x, y-1)}{L(x+1, y)-L(x-1), y}\right) \end{array} m(x,y)=(L(x+1,y)L(x1,y)2+(L(x,y+1)L(x,y1))2 θ(x,y)=arctan(L(x+1,y)L(x1),yL(x,y+1)L(x,y1))

    邻域像素梯度的计算结果如下图所示:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YXDeXyta-1646741526302)(笔记图片/image-20191009143818527.png)]

    完成关键点梯度计算后,使用直方图统计关键点邻域内像素的梯度幅值和方向。具体做法是,将360°分为36柱,每10°为一柱,然后在以r为半径的区域内,将梯度方向在某一个柱内的像素找出来,然后将他们的幅值相加在一起作为柱的高度。因为在r为半径的区域内像素的梯度幅值对中心像素的贡献是不同的,因此还需要对幅值进行加权处理,采用高斯加权,方差为1.5σ。如下图所示,为简化图中只画了8个方向的直方图。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aOMVF0Lf-1646741526303)(笔记图片/image-20191009144726492.png)]

    每个特征点必须分配一个主方向,还需要一个或多个辅方向,增加辅方向的目的是为了增强图像匹配的鲁棒性。辅方向的定义是,当一个柱体的高度大于主方向柱体高度的80%时,则该柱体所代表的的方向就是给特征点的辅方向。

    直方图的峰值,即最高的柱代表的方向是特征点邻域范围内图像梯度的主方向,但该柱体代表的角度是一个范围,所以我们还要对离散的直方图进行插值拟合,以得到更精确的方向角度值。利用抛物线对离散的直方图进行拟合,如下图所示:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tvI16CIU-1646741526304)(笔记图片/image-20191009150008701.png)]

    获得图像关键点主方向后,每个关键点有三个信息(x,y,σ,θ):位置、尺度、方向。由此我们可以确定一个SIFT特征区域。通常使用一个带箭头的圆或直接使用箭头表示SIFT区域的三个值:中心表示特征点位置,半径表示关键点尺度,箭头表示方向。如下图所示:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SSSjCByR-1646741526304)(笔记图片/image-20191025112522974.png)]

    关键点描述

    通过以上步骤,每个关键点就被分配了位置,尺度和方向信息。接下来我们为每个关键点建立一个描述符,该描述符既具有可区分性,又具有对某些变量的不变性,如光照,视角等。而且描述符不仅仅包含关键点,也包括关键点周围对其有贡献的的像素点。主要思路就是通过将关键点周围图像区域分块,计算块内的梯度直方图,生成具有特征向量,对图像信息进行抽象。

    描述符与特征点所在的尺度有关,所以我们在关键点所在的高斯尺度图像上生成对应的描述符。以特征点为中心,将其附近邻域划分为d∗d个子区域(一般取d=4),每个子区域都是一个正方形,边长为3σ,考虑到实际计算时,需进行三次线性插值,所以特征点邻域的为 3 σ ( d + 1 ) ∗ 3 σ ( d + 1 ) 3\sigma(d+1)*3\sigma(d+1) 3σ(d+1)3σ(d+1)的范围,如下图所示:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UeUD2iKa-1646741526305)(笔记图片/image-20191009161647267.png)]

    为了保证特征点的旋转不变性,以特征点为中心,将坐标轴旋转为关键点的主方向,如下图所示:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6UiLjK3u-1646741526305)(笔记图片/image-20191009161756423.png)]

    计算子区域内的像素的梯度,并按照σ=0.5d进行高斯加权,然后插值计算得到每个种子点的八个方向的梯度,插值方法如下图所示:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-41V1IvNb-1646741526305)(笔记图片/image-20191009162914982.png)]

    每个种子点的梯度都是由覆盖其的4个子区域插值而得的。如图中的红色点,落在第0行和第1行之间,对这两行都有贡献。对第0行第3列种子点的贡献因子为dr,对第1行第3列的贡献因子为1-dr,同理,对邻近两列的贡献因子为dc和1-dc,对邻近两个方向的贡献因子为do和1-do。则最终累加在每个方向上的梯度大小为:  weight  = w ∗ d r k ( 1 − d r ) ( 1 − k ) d c m ( 1 − d c ) 1 − m d o n ( 1 − d o ) 1 − n \text { weight }=w * d r^{k}(1-d r)^{(1-k)} d c^{m}(1-d c)^{1-m} d o^{n}(1-d o)^{1-n}  weight =wdrk(1dr)(1k)dcm(1dc)1mdon(1do)1n

    其中k,m,n为0或为1。 如上统计4∗4∗8=128个梯度信息即为该关键点的特征向量,按照特征点的对每个关键点的特征向量进行排序,就得到了SIFT特征描述向量。

    小结:SIFT在图像的不变特征提取方面拥有无与伦比的优势,但并不完美,仍然存在实时性不高,有时特征点较少,对边缘光滑的目标无法准确提取特征点等缺陷,自SIFT算法问世以来,人们就一直对其进行优化和改进,其中最著名的就是SURF算法。

    SURF原理

    使用 SIFT 算法进行关键点检测和描述的执行速度比较慢, 需要速度更快的算法。 2006 年 Bay提出了 SURF 算法,是SIFT算法的增强版,它的计算量小,运算速度快,提取的特征与SIFT几乎相同,将其与SIFT算法对比如下:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RRi3cHRM-1646741526306)(笔记图片/image-20191016163330835.png)]

    在OpenCV中利用SIFT检测关键点的流程如下所示:

    实例化sift

    sift = cv.xfeatures2d.SIFT_create()
    

    利用sift.detectAndCompute()检测关键点并计算

    kp,des = sift.detectAndCompute(gray,None)
    

    参数:

    • gray: 进行关键点检测的图像,注意是灰度图像

    返回:

    • kp: 关键点信息,包括位置,尺度,方向信息
    • des: 关键点描述符,每个关键点对应128个梯度信息的特征向量

    将关键点检测结果绘制在图像上

    cv.drawKeypoints(image, keypoints, outputimage, color, flags)
    

    参数:

    • image: 原始图像
    • keypoints:关键点信息,将其绘制在图像上
    • outputimage:输出图片,可以是原始图像
    • color:颜色设置,通过修改(b,g,r)的值,更改画笔的颜色,b=蓝色,g=绿色,r=红色。
    • flags:绘图功能的标识设置
      1. cv2.DRAW_MATCHES_FLAGS_DEFAULT:创建输出图像矩阵,使用现存的输出图像绘制匹配对和特征点,对每一个关键点只绘制中间点
      2. cv2.DRAW_MATCHES_FLAGS_DRAW_OVER_OUTIMG:不创建输出图像矩阵,而是在输出图像上绘制匹配对
      3. cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS:对每一个特征点绘制带大小和方向的关键点图形
      4. cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS:单点的特征点不被绘制

    SURF算法的应用与上述流程是一致,这里就不在赘述。

    利用SIFT算法在中央电视台的图片上检测关键点,并将其绘制出来:

    import cv2 as cv 
    import numpy as np
    import matplotlib.pyplot as plt
    # 1 读取图像
    img = cv.imread('./image/tv.jpg')
    gray= cv.cvtColor(img,cv.COLOR_BGR2GRAY)
    # 2 sift关键点检测
    # 2.1 实例化sift对象
    sift = cv.xfeatures2d.SIFT_create()
    
    # 2.2 关键点检测:kp关键点信息包括方向,尺度,位置信息,des是关键点的描述符
    kp,des=sift.detectAndCompute(gray,None)
    # 2.3 在图像上绘制关键点的检测结果
    cv.drawKeypoints(img,kp,img,flags=cv.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
    # 3 图像显示
    plt.figure(figsize=(8,6),dpi=100)
    plt.imshow(img[:,:,::-1]),plt.title('sift检测')
    plt.xticks([]), plt.yticks([])
    plt.show()
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yJhRF91M-1646741526306)(笔记图片/image-20191009181525538.png)]

    小结

    SIFT原理:

    • 尺度空间极值检测:构建高斯金字塔,高斯差分金字塔,检测极值点。
    • 关键点定位:去除对比度较小和边缘对极值点的影响。
    • 关键点方向确定:利用梯度直方图确定关键点的方向。
    • 关键点描述:对关键点周围图像区域分块,计算块内的梯度直方图,生成具有特征向量,对关键点信息进行描述。

    API:cv.xfeatures2d.SIFT_create()

    SURF算法:

    对SIFT算法的改进,在尺度空间极值检测,关键点方向确定,关键点描述方面都有改进,提高效率

    Fast和ORB算法

    学习目标

    • 理解Fast算法角点检测的原理,能够完成角点检测
    • 理解ORB算法的原理,能够完成特征点检测

    Fast算法

    我们前面已经介绍过几个特征检测器,它们的效果都很好,特别是SIFT和SURF算法,但是从实时处理的角度来看,效率还是太低了。为了解决这个问题,Edward Rosten和Tom Drummond在2006年提出了FAST算法,并在2010年对其进行了修正。

    FAST (全称Features from accelerated segment test)是一种用于角点检测的算法,该算法的原理是取图像中检测点,以该点为圆心的周围邻域内像素点判断检测点是否为角点,通俗的讲就是若一个像素周围有一定数量的像素与该点像素值不同,则认为其为角点

    FAST算法的基本流程

    1. 在图像中选取一个像素点 p,来判断它是不是关键点。Ip等于像素点 p的灰度值。
    2. 以r为半径画圆,覆盖p点周围的M个像素,通常情狂下,设置 r=3,则 M=16,如下图所示:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TYSKKj1R-1646741526307)(笔记图片/image17.jpg)]

    1. 设置一个阈值t,如果在这 16 个像素点中存在 n 个连续像素点的灰度值都高于Ip + t,或者低于Ip - t,那么像素点 p 就被认为是一个角点。如上图中的虚线所示,n 一般取值为 12。

    2. 由于在检测特征点时是需要对图像中所有的像素点进行检测,然而图像中的绝大多数点都不是特征点,如果对每个像素点都进行上述的检测过程,那显然会浪费许多时间,因此采用一种进行非特征点判别的方法:首先对候选点的周围每个 90 度的点:1,9,5,13 进行测试(先测试 1 和 19, 如果它们符合阈值要求再测试 5 和 13)。如果 p 是角点,那么这四个点中至少有 3 个要符合阈值要求,否则直接剔除。对保留下来的点再继续进行测试(是否有 12 的点符合阈值要求)。

    虽然这个检测器的效率很高,但它有以下几条缺点:

    • 获得的候选点比较多
    • 特征点的选取不是最优的,因为它的效果取决与要解决的问题和角点的分布情况。
    • 进行非特征点判别时大量的点被丢弃
    • 检测到的很多特征点都是相邻的

    前 3 个问题可以通过机器学习的方法解决,最后一个问题可以使用非最大值抑制的方法解决。

    机器学习的角点检测器

    1. 选择一组训练图片(最好是跟最后应用相关的图片)
    2. 使用 FAST 算法找出每幅图像的特征点,对图像中的每一个特征点,将其周围的 16 个像素存储构成一个向量P。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2wDQSEL8-1646741526308)(笔记图片/image-20191010114459269.png)]

    1. 每一个特征点的 16 像素点都属于下列三类中的一种

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yTXjYytT-1646741526308)(笔记图片/image18.jpg)]

    1. 根据这些像素点的分类,特征向量 P 也被分为 3 个子集:Pd ,Ps ,Pb,

    2. 定义一个新的布尔变量Kp,如果 p 是角点就设置为 Ture,如果不是就设置为 False。

    3. 利用特征值向量p,目标值是 K p K_p Kp,训练ID3 树(决策树分类器)。

    4. 将构建好的决策树运用于其他图像的快速的检测。

    非极大值抑制

    在筛选出来的候选角点中有很多是紧挨在一起的,需要通过非极大值抑制来消除这种影响。

    为所有的候选角点都确定一个打分函数V , V的值可这样计算:先分别计算Ip与圆上16个点的像素值差值,取绝对值,再将这16个绝对值相加,就得到了V的值 V = ∑ i 16 ∣ I p − I i ∣ V=\sum_{i}^{16}\left|I_{p}-I_{i}\right| V=i16IpIi

    最后比较毗邻候选角点的 V 值,把V值较小的候选角点pass掉。

    FAST算法的思想与我们对角点的直观认识非常接近,化繁为简。FAST算法比其它角点的检测算法快,但是在噪声较高时不够稳定,这需要设置合适的阈值。

    OpenCV中的FAST检测算法是用传统方法实现的,

    实例化fast

    fast = =cv.FastFeatureDetector_create( threshold, nonmaxSuppression)
    

    参数:

    • threshold:阈值t,有默认值10
    • nonmaxSuppression:是否进行非极大值抑制,默认值True

    返回:

    • Fast:创建的FastFeatureDetector对象

    利用fast.detect检测关键点,没有对应的关键点描述

    kp = fast.detect(grayImg, None)
    

    参数:

    • gray: 进行关键点检测的图像,注意是灰度图像

    返回:

    • kp: 关键点信息,包括位置,尺度,方向信息

    将关键点检测结果绘制在图像上,与在sift中是一样的

    cv.drawKeypoints(image, keypoints, outputimage, color, flags)
    

    示例:

    import numpy as np
    import cv2 as cv
    from matplotlib import pyplot as plt
    # 1 读取图像
    img = cv.imread('./image/tv.jpg')
    # 2 Fast角点检测
    # 2.1 创建一个Fast对象,传入阈值,注意:可以处理彩色空间图像
    fast = cv.FastFeatureDetector_create(threshold=30)
    
    # 2.2 检测图像上的关键点
    kp = fast.detect(img,None)
    # 2.3 在图像上绘制关键点
    img2 = cv.drawKeypoints(img, kp, None, color=(0,0,255))
    
    # 2.4 输出默认参数
    print( "Threshold: {}".format(fast.getThreshold()) )
    print( "nonmaxSuppression:{}".format(fast.getNonmaxSuppression()) )
    print( "neighborhood: {}".format(fast.getType()) )
    print( "Total Keypoints with nonmaxSuppression: {}".format(len(kp)) )
    
    
    # 2.5 关闭非极大值抑制
    fast.setNonmaxSuppression(0)
    kp = fast.detect(img,None)
    
    print( "Total Keypoints without nonmaxSuppression: {}".format(len(kp)) )
    # 2.6 绘制为进行非极大值抑制的结果
    img3 = cv.drawKeypoints(img, kp, None, color=(0,0,255))
    
    # 3 绘制图像
    fig,axes=plt.subplots(nrows=1,ncols=2,figsize=(10,8),dpi=100)
    axes[0].imshow(img2[:,:,::-1])
    axes[0].set_title("加入非极大值抑制")
    axes[1].imshow(img3[:,:,::-1])
    axes[1].set_title("未加入非极大值抑制")
    plt.show()
    

    结果:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VI81ALuY-1646741526309)(笔记图片/image-20191010120822413.png)]

    ORB 算法

    SIFT和SURF算法是受专利保护的,在使用他们时我们是要付费的,但是ORB(Oriented Fast and Rotated Brief)不需要,它可以用来对图像中的关键点快速创建特征向量,并用这些特征向量来识别图像中的对象。

    ORB算法流程

    ORB算法结合了Fast和Brief算法,提出了构造金字塔,为Fast特征点添加了方向,从而使得关键点具有了尺度不变性和旋转不变性。具体流程描述如下:

    • 构造尺度金字塔,金字塔共有n层,与SIFT不同的是,每一层仅有一幅图像。第s层的尺度为: σ s = σ 0 s \sigma_{s}=\sigma_{0}^{s} σs=σ0s

    σ0是初始尺度,默认为1.2,原图在第0层。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WESFnY8x-1646741526309)(笔记图片/image-20191010145652681.png)]

    第s层图像的大小: S I Z E = ( H ∗ 1 σ s ) × ( W ∗ 1 σ s ) S I Z E=\left(H * \frac{1}{\sigma_{s}}\right) \times\left(W * \frac{1}{\sigma_{s}}\right) SIZE=(Hσs1)×(Wσs1)

    • 在不同的尺度上利用Fast算法检测特征点,采用Harris角点响应函数,根据角点的响应值排序,选取前N个特征点,作为本尺度的特征点。
    • 计算特征点的主方向,计算以特征点为圆心半径为r的圆形邻域内的灰度质心位置,将从特征点位置到质心位置的方向做特征点的主方向。

    计算方法如下:

    m p q = ∑ x , y x p y q I ( x , y ) m_{p q}=\sum_{x, y} x^{p} y^{q} I(x, y) mpq=x,yxpyqI(x,y)

    质心位置:

    C = ( m 10 m 00 , m 01 m 10 ) C=\left(\frac{m_{10}}{m_{00}}, \frac{m_{01}}{m_{10}}\right) C=(m00m10,m10m01)

    主方向:

    θ = arctan ⁡ ( m 01 , m 10 ) \theta=\arctan \left(m_{01}, m_{10}\right) θ=arctan(m01,m10)

    • 为了解决旋转不变性,将特征点的邻域旋转到主方向上利用Brief算法构建特征描述符,至此就得到了ORB的特征描述向量。

    BRIEF算法

    BRIEF是一种特征描述子提取算法,并非特征点的提取算法,一种生成二值化描述子的算法,不提取代价低,匹配只需要使用简单的汉明距离(Hamming Distance)利用比特之间的异或操作就可以完成。因此,时间代价低,空间代价低,效果还挺好是最大的优点。

    算法的步骤介绍如下

    1. 图像滤波:原始图像中存在噪声时,会对结果产生影响,所以需要对图像进行滤波,去除部分噪声。
    2. 选取点对:以特征点为中心,取S*S的邻域窗口,在窗口内随机选取N组点对,一般N=128,256,512,默认是256,关于如何选取随机点对,提供了五种形式,结果如下图所示:
      • x,y方向平均分布采样
      • x,y均服从Gauss(0,S^2/25)各向同性采样
      • x服从Gauss(0,S2/25),y服从Gauss(0,S2/100)采样
      • x,y从网格中随机获取
      • x一直在(0,0),y从网格中随机选取

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FLtmsLBb-1646741526309)(笔记图片/image-20191010153907973.png)]

    图中一条线段的两个端点就是一组点对,其中第二种方法的结果比较好。

    1. 构建描述符:假设x,y是某个点对的两个端点,p(x),p(y)是两点对应的像素值,则有:

    t ( x , y ) = { 1  ifp  ( x ) > p ( y ) 0  else  t(x, y)=\left\{\begin{array}{ll} 1 & \text { ifp }(x)>p(y) \\ 0 & \text { else } \end{array}\right. t(x,y)={10 ifp (x)>p(y) else 

    对每一个点对都进行上述的二进制赋值,形成BRIEF的关键点的描述特征向量,该向量一般为 128-512 位的字符串,其中仅包含 1 和 0,如下图所示:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JzWKr10y-1646741526310)(笔记图片/image-20191010161944491.png)]

    在OPenCV中实现ORB算法,使用的是:

    实例化ORB

    orb = cv.xfeatures2d.orb_create(nfeatures)
    

    参数:

    • nfeatures: 特征点的最大数量

    利用orb.detectAndCompute()检测关键点并计算

    kp,des = orb.detectAndCompute(gray,None)
    

    参数:

    • gray: 进行关键点检测的图像,注意是灰度图像

    返回:

    • kp: 关键点信息,包括位置,尺度,方向信息
    • des: 关键点描述符,每个关键点BRIEF特征向量,二进制字符串,

    将关键点检测结果绘制在图像上

    cv.drawKeypoints(image, keypoints, outputimage, color, flags)
    

    示例:

    import numpy as np
    import cv2 as cv
    from matplotlib import pyplot as plt
    # 1 图像读取
    img = cv.imread('./image/tv.jpg')
    
    # 2 ORB角点检测
    # 2.1 实例化ORB对象
    orb = cv.ORB_create(nfeatures=500)
    # 2.2 检测关键点,并计算特征描述符
    kp,des = orb.detectAndCompute(img,None)
    
    print(des.shape)
    
    # 3 将关键点绘制在图像上
    img2 = cv.drawKeypoints(img, kp, None, color=(0,0,255), flags=0)
    
    # 4. 绘制图像
    plt.figure(figsize=(10,8),dpi=100)
    plt.imshow(img2[:,:,::-1])
    plt.xticks([]), plt.yticks([])
    plt.show()
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qMz0QrHm-1646741526310)(笔记图片/image-20191010162532196.png)]

    小结

    1. Fast算法

      原理:若一个像素周围有一定数量的像素与该点像素值不同,则认为其为角点

      API: cv.FastFeatureDetector_create()

    2. ORB算法

      原理:是FAST算法和BRIEF算法的结合

      API:cv.ORB_create()

    LBP和HOG特征算子

    学习目标

    1. 了解LBP特征的原理
    2. 了解LBP的改进算法:圆形LBP,旋转LBP和等价模式
    3. 了解HOG算法的原理
    4. 熟悉灰度图像的γ变换
    5. 了解HOG特征的提取流程
    6. 了解LBP特征的提取方法
    7. 了解HOG特征的提取方法

    LBP算法

    LBP(Local Binary Pattern)指局部二值模式,是一种用来描述图像局部特征的算子,LBP特征具有灰度不变性和旋转不变性等显著优点。它是由T. Ojala, M.Pietikäinen, 和 D. Harwood在1994年提出,由于LBP特征计算简单、效果较好,因此LBP特征在计算机视觉的许多领域都得到了广泛的应用。

    LBP特征描述

    原始的LBP算子定义为在 3 ∗ 3 3*3 33的窗口内,以窗口中心像素为阈值,将相邻的8个像素的灰度值与其进行比较,若周围像素值大于中心像素值,则该像素点的位置被标记为1,否则为0。这样, 3 ∗ 3 3*3 33邻域内的8个点经比较可产生8位二进制数(通常转换为十进制数即LBP码,共256种),即得到该窗口中心像素点的LBP值,并用这个值来反映该区域的纹理信息。如下图所示:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JmPkmNhY-1646741526310)(笔记图片/image-20191107142559806.png)]

    LBP值是从左上角像素,顺时针旋转得到的结果,如下图所示:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tAmfA7Wq-1646741526311)(笔记图片/image-20191107142804781.png)]

    用公式来进行定义如下所示: L B P ( x c , y c ) = ∑ p = 0 p − 1 2 p s ( i p − i c ) L B P\left(x_{c}, y_{c}\right)=\sum_{p=0}^{p-1} 2^{p} s\left(i_{p}-i_{c}\right) LBP(xc,yc)=p=0p12ps(ipic)

    其中,(xc,yc)表示 3 ∗ 3 3*3 33邻域内的中心元素,它的像素值为ic,ip代表邻域内其他像素的值。s(x)是符号函数,定义如下:

    对于一幅大小为W∗H 的图像,因为边缘的像素无法计算8位的LBP值,所以将LBP值转换为灰度图像时,它的大小是(W-2)*(H-2)。

    LBP算子利用了周围点与该点的关系对该点进行量化。量化后可以更有效地消除光照对图像的影响。只要光照的变化不足以改变两个点像素值之间的大小关系,那么LBP算子的值不会发生变化,**所以一定程度上,基于LBP的识别算法解决了光照变化的问题,**但是当图像光照变化不均匀时,各像素间的大小关系被破坏,对应的LBP模式也就发生了变化。

    原始的LBP提出后,研究人员不断对其提出了各种改进和优化。

    圆形LBP算子

    原始LBP特征使用的是固定邻域内的灰度值,当图像的尺度发生变化时,LBP特征的编码将会发生变换,LBP特征将不能正确的反映像素点周围的纹理信息,因此研究人员对其进行了改进。基本的 LBP 算子的最大缺陷在于它只覆盖了一个固定半径范围内的小区域,只局限在3*3的邻域内,对于较大图像大尺度的结构不能很好的提取需要的纹理特征,因此研究者们对LBP算子进行了扩展。

    新的LBP算子 L B P p R LBP_{p}^{R} LBPpR计算不同半径邻域大小和不同像素点数的特征值,其中P表示周围像素点个数,R表示邻域半径,同时把原来的方形邻域扩展到了圆形,下图给出了三种扩展后的LBP例子,其中,R可以是小数:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WUNVwjNP-1646741526312)(笔记图片/image-20191107144658710.png)]

    对于没有落到整数位置的点,根据轨道内离其最近的两个整数位置像素灰度值,利用双线性插值的方法可以计算它的灰度值。

    该算子的计算公式与原始的LBP描述算子计算方法相同,区别在邻域的选择上。

    旋转不变LBP特征

    从 LBP 的定义可以看出,LBP算子不是旋转不变的。图像的旋转就会得到不同的 LBP值。所以 Maenpaa等人又将 LBP算子进行了扩展,提出了具有旋转不变性的 LBP 算子,即不断旋转圆形邻域得到一系列初始定义的 LBP值,取其最小值作为该邻域的 LBP 值。即:

    L B P p , R r i = min ⁡ { R O R ( L B P p R , i ) ∣ i = 0 , 1 , … p − 1 } L B P_{p, R}^{r i}=\min \left\{R O R\left(L B P_{p}^{R}, i\right) \mid i=0,1, \ldots p-1\right\} LBPp,Rri=min{ROR(LBPpR,i)i=0,1,p1}

    其中,ROR(x,i)指沿顺时针方向旋转LBP算子i次。如下图所示:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bAh4LlzH-1646741526312)(笔记图片/image-20191107150512440.png)]

    上图给出了求取旋转不变的 LBP 的过程示意图,算子下方的数字表示该算子对应的 LBP值,图中所示的 8 种 LBP模式,经过旋转不变的处理,最终得到的具有旋转不变性的 LBP值为 15。也就是说,图中的 8种 LBP 模式对应的旋转不变的 LBP模式都是 00001111。

    Uniform Pattern LBP特征

    Uniform Pattern,也被称为等价模式或均匀模式,由于一个LBP特征有多种不同的二进制形式,对于半径为R的圆形区域内含有P个采样点的LBP算子将会产生 2 P 2^P 2P种模式。很显然,随着邻域集内采样点数的增加,二进制模式的种类是以指数形式增加的。例如:5×5邻域内20个采样点,有2^20=1,048,576种二进制模式。这么多的二进制模式不利于纹理的提取、分类、识别及存取。例如,将LBP算子用于纹理分类或人脸识别时,常采用LBP模式的统计直方图来表达图像的信息,而较多的模式种类将使得数据量过大,且直方图过于稀疏。因此,需要对原始的LBP模式进行降维,使得数据量减少的情况下能最好的表示图像的信息。

    为了解决二进制模式过多的问题,提高统计性,Ojala提出了采用一种“等价模式”(Uniform Pattern)来对LBP算子的模式种类进行降维。Ojala等认为,在实际图像中,绝大多数LBP模式最多只包含两次从1到0或从0到1的跳变。因此,Ojala将“等价模式”定义为:当某个LBP所对应的循环二进制数从0到1或从1到0最多有两次跳变时,该LBP所对应的二进制就称为一个等价模式类。如00000000(0次跳变),00000111(只含一次从0到1的跳变),10001111(先由1跳到0,再由0跳到1,共两次跳变)都是等价模式类。除等价模式类以外的模式都归为另一类,称为混合模式类,例如10010111(共四次跳变)。

    下图所示的LBP值属于等价模式类:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SFhAh8He-1646741526313)(笔记图片/image-20191107151414795.png)]

    下图中包含四次跳变,属于非等价模式。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q5FAO3tJ-1646741526313)(笔记图片/image-20191107151519089.png)]

    通过这样的改进,二进制模式的种类大大减少,而不会丢失任何信息。模式数量由原来的 2 P 2^P 2P种减少为 P ( P-1)+2种,其中P表示邻域集内的采样点数。对于3×3邻域内8个采样点来说,二进制模式由原始的256种减少为58种,即:它把值分为59类,58个uniform pattern为一类,其它的所有值为第59类。这样直方图从原来的256维变成59维。这使得特征向量的维数更少,并且可以减少高频噪声带来的影响。

    等价特征的具体实现:采样点数目为8个,即LBP特征值有2^8种,共256个值,正好对应灰度图像的0-255,因此原始的LBP特征图像是一幅正常的灰度图像,而等价模式LBP特征,根据0-1跳变次数,将这256个LBP特征值分为了59类,从跳变次数上划分:跳变0次—2个,跳变1次—0个,跳变2次—56个,跳变3次—0个,跳变4次—140个,跳变5次—0个,跳变6次—56个,跳变7次—0个,跳变8次—2个。共9种跳变情况,将这256个值进行分配,跳变小于2次的为等价模式类,共58个,他们对应的值按照从小到大分别编码为1—58,即它们在LBP特征图像中的灰度值为1—58,而除了等价模式类之外的混合模式类被编码为0,即它们在LBP特征中的灰度值为0,因此等价模式LBP特征图像整体偏暗。

    实现

    在OpenCV中实现了LBP特征的计算,但没有提供一个单独的计算LBP特征的接口。所以我们使用skimage给大家演示该算法。

    skimage即是Scikit-Image。基于python脚本语言开发的数字图片处理包,scikit-image是基于scipy的一款图像处理包,它将图片作为numpy数组进行处理。安装方法:

    pip install scikit-image
    

    skimage包的全称是scikit-image SciKit (toolkit for SciPy) ,它对scipy.ndimage进行了扩展,提供了更多的图片处理功能。它是由python语言编写的,由scipy 社区开发和维护。skimage包由许多的子模块组成,各个子模块提供不同的功能。其中feature模块进行特征检测与提取。

    使用的API是:

    skimage.feature.local_binary_pattern(image, P, R, method=‘default’)
    

    参数:

    • image: 输入的灰度图像
    • P,R: 进行LBP算子计算时的半径和像素点数
    • method: 算法类型:{‘default’, ‘ror’, ‘nri-uniform’, ‘var’}

    default: “默认”,原始的LBP特征;ror: 圆形LBP算子;nri-uniform: 等价LBP算子;var:旋转不变LBP算子

    示例:

    我们在下图中提取LBP特征:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QniurKUH-1646741526314)(笔记图片/face.jpeg)]

    import cv2 as cv
    from skimage.feature import local_binary_pattern
    import matplotlib.pyplot as plt
    # 1.读取图像
    img = cv.imread("face.jpeg")
    face = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
    # 2.特征提取
    # 2.0 需要的参数
    # LBP算法中范围半径的取值
    radius = 1  
    # 领域像素点数
    n_points = 8 * radius 
    
    # 2.1 原始LBP特征
    lbp = local_binary_pattern(face, 8, 1)
    
    # 2.2 圆形LBP特征
    clbp = local_binary_pattern(face,n_points,radius,method="ror")
    
    # 2.3 旋转不变LBP特征
    varlbp = local_binary_pattern(face,n_points,radius,method="var")
    
    # 2.4 等价特征
    uniformlbp = local_binary_pattern(face,n_points,radius,method="nri-uniform")
    
    fig,axes=plt.subplots(nrows=2,ncols=2,figsize=(10,8))
    axes[0,0].imshow(lbp,'gray')
    axes[0,0].set_title("原始的LBP特征")
    axes[0,0].set_xticks([])
    axes[0,0].set_yticks([])
    axes[0,1].imshow(clbp,'gray')
    axes[0,1].set_title("圆形LBP特征")
    axes[0,1].set_xticks([])
    axes[0,1].set_yticks([])
    axes[1,0].imshow(varlbp,'gray')
    axes[1,0].set_title("旋转不变LBP特征")
    axes[1,0].set_xticks([])
    axes[1,0].set_yticks([])
    axes[1,1].imshow(uniformlbp,"gray")
    axes[1,1].set_title("等价特征")
    axes[1,1].set_xticks([])
    axes[1,1].set_yticks([])
    plt.show()
    

    检测结果如下所示:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BFP8g40F-1646741526314)(笔记图片/image-20191107161947626.png)]

    HOG算法

    HOG(Histogram of Oriented Gridients的简写)特征检测算法,最早是由法国研究员Dalal等在CVPR-2005上提出来的,一种解决人体目标检测的图像描述子,是一种用于表征图像局部梯度方向和梯度强度分布特性的描述符。其主要思想是:在边缘具体位置未知的情况下,边缘方向的分布也可以很好的表示行人目标的外形轮廓。

    特征提取流程

    HOG的主要思想是:在一副图像中,局部目标的表象和形状(appearance and shape)能够被梯度或边缘的方向密度分布(即梯度的统计信息,而梯度主要位于边缘的地方)很好地描述。

    HOG特征检测算法的几个步骤:颜色空间归一化—>梯度计算—>梯度方向直方图—>重叠块直方图归一化—>HOG特征。如下图所示:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jLMxny2I-1646741526314)(笔记图片/image-20191107164141468.png)]

    整体流程简单描述如下:

    1. 将输入图像(你要检测的目标或者扫描窗口)灰度化,即将彩色图转换为灰度图
    2. 颜色空间归一化:采用Gamma校正法对输入图像进行颜色空间的标准化(归一化),目的是调节图像的对比度,降低图像局部的阴影和光照变化所造成的影响,同时可以抑制噪音的干扰
    3. 梯度计算:计算图像每个像素的梯度(包括大小和方向);主要是为了捕获轮廓信息,同时进一步弱化光照的干扰
    4. 梯度方向直方图:将图像划分成小cells(例如8*8像素/cell), 统计每个cell的梯度直方图(不同梯度的个数),即可形成每个cell的描述符
    5. 重叠直方图归一化:将每几个cell组成一个block(例如3*3个cell/block),一个block内所有cell的特征descriptor串联起来便得到该block的HOG特征描述符。
    6. HOG特征:将图像image内的所有block的HOG特征描述符串联起来就可以得到该image(你要检测的目标)的HOG特征描述符,就得到最终的可供分类使用的特征向量了

    下面我们详细介绍每一步骤的内容:

    颜色空间归一化

    为了减少光照因素的影响,首先需要将整个图像进行规范化(归一化)。在图像的纹理强度中,局部的表层曝光贡献的比重较大,所以,这种压缩处理能够有效地降低图像局部的阴影和光照变化。因为颜色信息作用不大,通常先转化为灰度图,然后在进行伽马校正。

    伽马校正能够有效的降低图像的局部阴影和光照所带来的的影响,从而降低算法对光照的敏感度,增强算法的鲁棒性。

    伽马校正使用下式所得: Y ( x , y ) = I ( x , y ) γ Y(x, y)=I(x, y)^{\gamma} Y(x,y)=I(x,y)γ

    其中,I(x,y)是图像在伽马校正前像素点(x,y)处的灰度值,Y(x,y)为标准化的像素点(x,y)处的灰度值。伽马校正如图所示:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hMxUAan6-1646741526315)(笔记图片/image-20191107171015588.png)]

    从上图中可以看出:

    1. 当γ<1时,如上图中虚线所示,在低灰度值区域内,动态范围变大(当x在[0,0.2]时,y的范围是[0,0.5]),进而图像的对比度增强;在高灰度值区域内,动态范围变小(当x在[0.8,1]时,y的范围是[0.9,1]),图像的对比度降低;同时,图像整体的灰度值变大。
    2. 当γ>1时,如上图中实线所示,在低灰度值区域内,动态范围变小(当x在[0,0.5]时,y的范围是[0,0.2]),进而图像的对比度降低;在高灰度值区域内,动态范围变大,图像的对比度增强;同时,图像整体的灰度值变小。

    下图中左图是原图,中图是γ=1/2.2的校正结果,右图是γ=2.2的校正结果。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vR5ir9be-1646741526316)(笔记图片/image-20191107171040083.png)]

    在HOG特征提取中,γ一般取0.5,此时,图像的灰度值被拉伸,且灰度越低,拉伸的幅度越大,也就是说,对于光照较暗的图像处理较好,能较大程度提升他们的亮度。

    图像梯度计算

    边缘是由图像局部特征包括灰度、颜色和纹理的突变导致的。一幅图像中相邻的像素点之间变化比较少,区域变化比较平坦,则梯度幅值就会比较小,反之,则梯度幅值就会比较大。梯度在图像中对应的就是其一阶导数,所以图像梯度计算利用一阶微分求导处理,不仅能够捕获轮廓、人影以及一些纹理信息,还能进一步弱化光照的影响。Dalal研究了很多算子,如下表所示:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ep0iEs92-1646741526316)(笔记图片/image-20191115084424182.png)]

    最终表明[-1,0,1]和$[1,0,-1]^T $的效果最好,所以有梯度:

    G x ( x , y ) = I ( x + 1 , y ) − I ( x − 1 , y ) G y ( x , y ) = I ( x , y + 1 ) − I ( x , y − 1 ) \begin{aligned} G_{x}(x, y) &=I(x+1, y)-I(x-1, y) \\ G_{y}(x, y) &=I(x, y+1)-I(x, y-1) \end{aligned} Gx(x,y)Gy(x,y)=I(x+1,y)I(x1,y)=I(x,y+1)I(x,y1)

    式中,Gx,Gy,I(x,y)分别表示的是像素点(x,y)在水平方向上及垂直方向上的梯度以及像素的灰度值,其梯度的幅值及方向计算公式如下:

    G ( x , y ) = G x 2 + G y 2 α ( x , y ) = tan ⁡ − 1 ( G y G x ) \begin{array}{c} G(x, y)=\sqrt{G_{x}^{2}+G_{y}^{2}} \\ \alpha(x, y)=\tan ^{-1}\left(\frac{G_{y}}{G_{x}}\right) \end{array} G(x,y)=Gx2+Gy2 α(x,y)=tan1(GxGy)

    利用该算子计算梯度不仅效果好,而且运算量低。

    梯度直方图计算

    Dalal的研究结果表明,梯度方向为无符号且通道数为9时得到最好的检测效果,此时一个梯度方向的一个通道为180/9=20°,代表的是角度0,20,40,60…160。梯度方向矩阵中可以看到角度是0-180度,不是0-360度,这种被称之为"无符号"梯度(“unsigned” gradients)因为一个梯度和它的负数是用同一个数字表示的,也就是说一个梯度的方向以及它旋转180度之后的方向被认为是一样的,如下图所示:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TgJEFDNX-1646741526316)(笔记图片/image-20191107174042837.png)]

    假设图像被分为多个cell单元,如下所示:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uvunXIi2-1646741526316)(笔记图片/image-20191107175236497.png)]

    每个cell单元中包含8*8个像素,如下所示:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e36t0yjt-1646741526317)(笔记图片/image-20191107175558831.png)]

    我们将上一步得到的梯度方向投影到9个通道中,并将梯度幅值作为投影时的权值。

    在进行梯度方向投影处理时采用加权的方式,确定某个通道的权值,如下所示:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CImAEI2Z-1646741526317)(笔记图片/image-20191107180300619.png)]

    还有一个细节是,如果角度大于在(160,180)之间时,角度0和180是相等的,所以,角度为165时将其按照幅值比例投影到0和160两个通道中:(180-165)/(165-160)

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oAu73wkW-1646741526318)(笔记图片/image-20191107180534928.png)]

    遍历整个cell中的所有像素点,便可以得到该cell单元的梯度方向直方图:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1Qh53FGu-1646741526318)(笔记图片/image-20191107180617264.png)]

    重叠块直方图归一化

    由于图像的局部曝光度以及前景与背景之间的对比度存在多样化的情况,所以梯度值的变化范围非常广,引进归一化的直方图对于检测结果的提高有着非常重要的作用。

    在上一步中我们在每一个cell单元中创建了梯度方向直方图,在这一步中我们将在block块中进行梯度直方图的归一化,每一个block是由2*2=4个cell单元构成,如下图所示:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4bVGpYBP-1646741526318)(笔记图片/hog-3180128.gif)]

    在每个块中梯度直方图应该是4*9=36维的。

    在解释直方图是如何进行归一化之前,让我们看看长度为3的向量是如何进行归一化的:假设一个像素向量[128,64,32],向量的长度则为:sqrt{128^2 + 64^2 + 32^2} = 146.64 这也被称为向量的L2范数。将向量的每一个元素除以146.64得到归一化向量[0.87,0.43,0.22]。

    我们将一个block块中的梯度直方图串联成一个36*1维向量,并进行归一化,就得到了该block块内的特征,因为block块之间是有重叠的,也就是说每个cell单元中的特征会多次出现在不同的block块中。

    收集HOG特征

    上一步中我们得到一个block块的归一化后的梯度方向直方图,现在我们只需遍历检测图像中所有的块便可以得到整个图像的梯度方向直方图,这就是我们要求解的HOG特征向量。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HZsCz0UD-1646741526318)(笔记图片/image-20191108110820778.png)]

    如上图所示,block块与block块之间是可以重叠的,假设我们的检测图像大小为(64×128),其x方向的有(64−8×2)/8=7个block块,其中64为检测图像的宽度,第一个8为cell宽度,2为一个block块中的cell单元宽度,第二个8为block块的滑动增量,同理,y方向有(128−8×2)/8+1=15个block块,其中128为检测图像的高度,第一个8为cell高度,2为一个block块中的cell单元高度,第二个8为block块的滑动增量,因此一共有7×15=105 个block,每一个block中梯度直方图的维数为36,那么检测图像为(64×128)的HOG特征向量的维数为105×36=3780。将其显示在图像上如下图所示:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hJKq5iYN-1646741526319)(笔记图片/image-20191108111824266.png)]

    从上图中,我们可以发现直方图的主要方向捕捉了人的外形,尤其是躯干和腿的部位。我们得到归一化的HOG特征之后,就可以使用分类器对行人进行检测,比如使用支持向量机SVM进行人与背景的分类,如下图所示:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oLcae4uO-1646741526319)(笔记图片/image-20191115090149728.png)]

    HOG特征的优缺点

    HOG特征具有以下优点:

    • HOG表示的是边缘的结构特征,因此可以描述局部的形状信息
    • 位置和方向的量化在一定程度上可以一直平移和旋转带来的影响
    • 采取局部区域归一化直方图,可以部分抵消光照变换带来的影响

    它也有不少缺点:

    • 描述子生成冗长,维数较高,导致速度慢,实时性差
    • 很难处理遮挡问题
    • 由于梯度的性质,对噪声非常敏感

    实现

    OpenCV提供了计算HOG特征的API,实现HOG特征提取的流程是:

    1. 实例化HOG特征提取算子,使用的API是:
    hog = cv2.HOGDescriptor(winSize,blockSize,blockStride,cellSize,nbins)
    

    参数:

    • winSize: 检测窗口的大小
    • blockSize: block块的大小
    • blockStride: block块的滑动步长
    • cellSize: cell单元的大小
    • Nbins:统计梯度的方向的数目,一般取为9,即在一个cell单元中计算9个方向的梯度直方图

    返回:

    • hog: 实例化后的Hog特征检测对象
    • 搜索整个图像,计算图像的HOG特征,调用:
    hogDes = hog.compute(img, winStride, padding)
    

    参数:

    • img: 输入图像
    • winStrise:检测窗口的滑动步长
    • padding:填充,在图像的周围填充点对边界进行处理。

    返回:

    • hogDes: 整幅图像的HOG特征描述符,当padding为默认的(0,0)时,特征向量的维数:[(img_size - window_size) / window_stride +1 )]*(每个检测窗口中的特征维数)。

    示例:

    import cv2 as cv 
    import numpy as np
    import matplotlib.pyplot as plt
    
    # 1.读取图像
    img = cv.imread('xingren.jpeg')
    gray= cv.cvtColor(img,cv.COLOR_BGR2GRAY)
    
    # 2.Hog特征提取
    # 2.1 参数设置
    winSize = (64,128)
    blockSize = (16,16)
    blockStride = (8,8)
    cellSize = (8,8)
    nbins = 9
    
    # 2.2 实例化hog对象
    hog = cv.HOGDescriptor(winSize,blockSize,blockStride,cellSize,nbins)
    
    # 2.3 计算Hog特征描述符
    hogDes = hog.compute(img,winStride=(8,8))
    
    # 2.4 输出描述符的大小
    print(hogDes.size)
    

    输出结果为:578340,该图的大小为 ( 128 ∗ 256 ) (128*256) (128256),窗口大小为(64∗128) ,block块大小为(16,16),块的移动步长为 (8,8),cell单元大小为(8,8)时,每一个窗口的特征维度为3780,窗口移动步长为(8,8)时,则图像的特征的维度:

    ( 128 − 64 8 + 1 ) ∗ ( 256 − 128 8 + 1 ) ∗ 3780 = 578340 \left(\frac{128-64}{8}+1\right) *\left(\frac{256-128}{8}+1\right) * 3780=578340 (812864+1)(8256128+1)3780=578340

    小结

    1. LBP算法:

      原始LBP特征:在3∗3的窗口内,以窗口中心像素为阈值,将相邻的8个像素的灰度值与其进行比较,若周围像素值大于中心像素值,则该像素点的位置被标记为1,否则为0。这样,3∗3邻域内的8个点经比较可产生8位二进制数,即LBP值。

      圆形LBP算子:计算不同半径邻域大小和不同像素点数的特征值

      旋转不变LBP算子:不断旋转圆形邻域得到一系列初始定义的 LBP值,取其最小值作为该邻域的 LBP 值

      Uniform Pattern LBP特征:当某个LBP所对应的循环二进制数从0到1或从1到0最多有两次跳变时,该LBP所对应的二进制就称为一个等价模式类。除等价模式类以外的模式都归为另一类,称为混合模式类。

      API:

      Skiimage.feature.Local_binary_pattern()

    2. HOG算法

      思想:在一副图像中,局部目标的表象和形状(appearance and shape)能够利用梯度或边缘的方向密度分布来描述。

      HOG特征检测算法的步骤:

      颜色空间归一化—>梯度计算—>梯度方向直方图—>重叠块直方图归一化—>HOG特征

      简单描述如下:

      1)将输入图像灰度化,即将彩色图转换为灰度图

      2)颜色空间归一化:采用Gamma校正法对输入图像进行颜色空间的标准化(归一化),目的是调节图像的对比度,降低图像局部的阴影和光照变化所造成的影响,同时可以抑制噪音的干扰

      3)梯度计算:计算图像每个像素的梯度(包括大小和方向);主要是为了捕获轮廓信息,同时进一步弱化光照的干扰

      4)梯度方向直方图:将图像划分成小cells(例如6*6像素/cell), 统计每个cell的梯度直方图(不同梯度的个数),即可形成每个cell的描述符

      5)重叠直方图归一化:将每几个cell组成一个block(例如3*3个cell/block),一个block内所有cell的特征descriptor串联起来便得到该block的HOG特征描述符。

      6)HOG特征:将图像image内的所有block的HOG特征描述符串联起来就可以得到该image的HOG特征描述符,就得到最终的可供分类使用的特征向量了。

    3. API:

      1)实例化HOG对象:

      hog = cv.HOGDescriptor()

      2)计算HOG特征描述符

      hogdes = hog.Compute()

    展开全文
  • OpenCV图像特征提取

    千次阅读 2021-04-18 07:27:57
    图像特征提取 本章中我们将讨论如何识别并可靠稳定的跟踪连续帧中的图像特征。主要内容包括: intensity gradients and image filtering basics and the properties required to describe suitable keypoints ...

    Camera系列文章

    传感器融合是将多个传感器采集的数据进行融合处理,以更好感知周围环境;这里首先介绍Camera的相关内容,包括摄像头及图像知识基本介绍,OpenCV图像识别(特征提取,目标分类等),融合激光点云和图像进行TTC估计。

    系列文章目录
    1. 摄像头基础及校准
    2. Lidar TTC估计
    3. Camera TTC估计
    4. OpenCV图像特征提取



    前言

    后续这几节中我们将讨论如何识别并可靠稳定的跟踪连续帧中的图像特征。主要内容包括:

    1. 强度梯度和图像过滤基础,以及合理描述特征的特性;
    2. 熟悉如何用强度描述有效点,以及Harris检测算法
    3. 定位特征点:了解常用的特征检测算法及其特性,如图片旋转等变换条件,以及实际应用中的其他变换下的鲁棒性。
    4. 使用描述符跟踪连续帧中的特征点,重建车辆运动模型。

    本节主要覆盖前两点。


    考虑到图像识别知识点很多,在这里只是简单的把关键内容放上。另外,由于图像识别知识储备相对薄弱,如有描述不合理的地方还请指正。OpenCV提供了很多算法库用于检测图像的主要特征(Keypoint Detection),然后提取这些特征(Feature extraction),使其称为图像描述符(descriptor)

    一、预备知识

    特征定义

    我们将图像中的某个特别的区域作为一个特征。特征是图像中有意义的图像区域,该区域具有独特特性或易于识别性。角点和高密度区域是很好的特征,而大量重复的区域或低密度区域则不是很好的特征。边缘可将图像分为两个区域,因此也可作为好的特征。斑点也是有意义的特征。
    特征提取
    将原始特征转换为一组具有明显物理意义、几何特征(角点,不变量)、纹理(LBP HOG)、统计意义或核的特征;
    特征选择
    从特征几何中挑选一组最具统计意义的特征,达到降维的目的。通过合适的特征选择可以减少数据存储和输入数据带宽,减少冗余,发现更有意义的潜在变量。由于某些算法在识别和提取某种类型特征的时候有较好的效果,所以输入图像是何种类型特征很重要,有利于选择最合适的特征检测算法。

    二、强度梯度和图像过滤- 寻找Keypoints特征点

    如前一章所述,摄像头无法直接测距,计算TTS是基于目标物在图像中投影的尺寸比。因此我们需要定位特征点keypoints,比如以下从之前图片提取的图块,存在类似的特征点。
    在这里插入图片描述

    强度梯度介绍

    下图展示的是红线内图像的强度Intensity,强度梯度intensity gradient,可以看到,在特征点(边,角等)处存在明显的梯度变化。

    Intensity profile of image pixels along the red line
    下面我们看一下梯度的计算公式。
    Intensity profile of image pixels along the red line

    Intensity gradient for three patches and partial derivatives
    Equations for gradient direction and magnitude

    Equations for gradient direction and magnitude.

    通常直接通过相邻像素点的强度差计算强度梯度(Intensity Gradient)会受到图像噪点(如白噪声等)的影响,尤其是低照度环境下,因此我们需要对图像进行滤波,比如高斯滤波,对图像进行去噪,再进行梯度计算。

    图像去噪和高斯滤波

    为了消除噪声的影响,需要使用平滑算子对图像进行滤波。通常用的是高斯滤波器,使用高斯内核对图像进行处理(核是一组权重,通过相邻像素点来计算当前像素点的像素值;偏差 σ \sigma σ 代表权重分布,偏差越大,周围像素点的权重越大;核大小表示使用多少周围像素点来进行平滑过滤)。

    下图是不同偏差的高斯滤波器内核。
    在这里插入图片描述
    下图是滤波计算公式,通过周围像素点的像素值及权重重新计算像素值。 k ( i , j ) k(i,j) k(i,j)为该像素点的权重, a i a_i ai a j a_j aj为计算点在像素中的坐标。
    在这里插入图片描述
    下图是7×7内核的示例。A sample Gaussian matrix
    以下代码展示高斯滤波如何操作。加载图片后首先生成自定义的高斯内核,再使用Filter2D进行过滤。

    void gaussianSmoothing1()
    {
        // load image from file
        cv::Mat img;
        img = cv::imread("../images/img1gray.png");
    
        // create filter kernel
        float gauss_data[25] = {1, 4, 7, 4, 1,
                                4, 16, 26, 16, 4,
                                7, 26, 41, 26, 7,
                                4, 16, 26, 16, 4,
                                1, 4, 7, 4, 1};
        cv::Mat kernel = cv::Mat(5, 5, CV_32F, gauss_data);
    
        // STUDENTS NEET TO ENTER THIS CODE
        for (int i = 0; i < 25; i++)
        {
            gauss_data[i] /= 273;
        }
        // EOF STUDENT CODE
    
        // apply filter
        cv::Mat result;
        cv::filter2D(img, result, -1, kernel, cv::Point(-1, -1), 0, cv::BORDER_DEFAULT);
    
        // show result
        string windowName = "Gaussian Blurring";
        cv::namedWindow(windowName, 1); // create window
        cv::imshow(windowName, result);
        cv::waitKey(0); // wait for keyboard input before continuing
    }
    

    强度梯度计算

    对图像进行滤波降噪后,下面我们可以计算图像 x x x y y y方向的强度梯度。比较有名的是Sobel算子和Scharr算子。
    以下是Sobel算子 x x x y y y方向的3×3内核。
    Sobel operator
    以下是对图像进行 x x x方向梯度计算的代码。

        // load image from file to avoid computing the operator on each color channel.
        cv::Mat img;
        img = cv::imread("./img1.png");
    
        // convert image to grayscale
        cv::Mat imgGray;
        cv::cvtColor(img, imgGray, cv::COLOR_BGR2GRAY);
    
        // create filter kernel
        float sobel_x[9] = {-1, 0, +1,
                            -2, 0, +2, 
                            -1, 0, +1};
        cv::Mat kernel_x = cv::Mat(3, 3, CV_32F, sobel_x);
    
        // apply filter
        cv::Mat result_x;
        cv::filter2D(imgGray, result_x, -1, kernel_x, cv::Point(-1, -1), 0, cv::BORDER_DEFAULT);
    
        // show result
        string windowName = "Sobel operator (x-direction)";
        cv::namedWindow( windowName, 1 ); // create window 
        cv::imshow(windowName, result_x);
        cv::waitKey(0); // wait for keyboard input before continuing
    

    得到的梯度图如下,分别为① x x x方向梯度图;② x x x y y y方向梯度图。
    Gradient image with S_x filter.
    Gradient image with S_x and S_y filter.

    二、Harris角点检测

    由上一节可知,图像边角点等位置具有较大强度梯度,下面我们将使用这些梯度等信息来定义这些特征点,并介绍最常用的Harris角点检测算法。
    Harris角点检测算法的基本原理是通过对比与周围像素点的差异来寻找图像中明显变化的区域,以图像梯度作为输入,输出在x、y方向梯度都比较大的位置点。

    1.特征点唯一性的度量

    关键点检测的想法是检出图像中可以定位特征点x、y位置的独特结构,如角点。下图是角点的示意图,红色代表在该方向没有独特的特征(梯度为0),绿色代表有独特特征。
    在这里插入图片描述
    为定位角点,我们需要移动红框W并逐个计算梯度。常用的方法是计算红框内相邻点的平方差,公式如下。
    在这里插入图片描述
    首先使用泰勒公式展开:
    在这里插入图片描述
    再代入方差公式。其中H为协方差矩阵。
    在这里插入图片描述
    以下对协方差矩阵H进行可视化,由此可知,垂直于直线方向梯度变化率最大,对应长边的特征向量。沿着直线方向梯度变化率最小,对应短边特征向量。因此,为检出检点,需要找出H的特征向量极大值。
    在这里插入图片描述
    协方差矩阵H的特征向量计算公式如下:
    在这里插入图片描述
    Harris角点检测算法中,也使用了高斯窗 w ( x , y ) w(x,y) w(x,y)设置权重计算强度梯度。
    在这里插入图片描述

    2.Harris角点检测实例

    Harris角点检测主要基于以下公式计算每个像素点位置的角点响应值。k因子通常取值为0.04 - 0.06。
    在这里插入图片描述

    以下例子使用cornerHarrisl来识别角点。cornerHarris函数中最重要的参数是apertureSize,限定Sobel算子的核大小,取值范围为3~31间的奇数。

        // load image from file
        cv::Mat img;
        img = cv::imread("./img1.png");
    
        // convert image to grayscale
        cv::Mat imgGray; 
        cv::cvtColor(img, imgGray, cv::COLOR_BGR2GRAY);
    
        // Detector parameters
        int blockSize = 2; // for every pixel, a blockSize × blockSize neighborhood is considered
        int apertureSize = 3; // aperture parameter for Sobel operator (must be odd)
        int minResponse = 100; // minimum value for a corner in the 8bit scaled response matrix
        double k = 0.04; // Harris parameter (see equation for details)
    
        // Detect Harris corners and normalize output
        cv::Mat dst, dst_norm, dst_norm_scaled;
        dst = cv::Mat::zeros(imgGray.size(), CV_32FC1 );
        cv::cornerHarris( imgGray, dst, blockSize, apertureSize, k, cv::BORDER_DEFAULT ); 
        cv::normalize( dst, dst_norm, 0, 255, cv::NORM_MINMAX, CV_32FC1, cv::Mat() );
        cv::convertScaleAbs( dst_norm, dst_norm_scaled );
    
        // visualize results
        string windowName = "Harris Corner Detector Response Matrix";
        cv::namedWindow( windowName, 4 );
        cv::imshow( windowName, dst_norm_scaled );
        cv::waitKey(0);
    

    输出图像如下,像素点位置越亮,Harris角点响应越高。
    在这里插入图片描述

    3. NMS non-maxima suppression

    以上根据Harris角点检测我们获取了一系列的亮点。考虑到角点附近局部区域可能存在的亮点,要定位角点,还需要使用NMS非最大抑制提取角点,选出局部区域最亮的点作为角点。
    代码如下(示例):

    void cornernessHarris()
    {
        // load image from file
        cv::Mat img;
        img = cv::imread("../images/img1.png");
        cv::cvtColor(img, img, cv::COLOR_BGR2GRAY); // convert to grayscale
    
        // Detector parameters
        int blockSize = 2;     // for every pixel, a blockSize × blockSize neighborhood is considered
        int apertureSize = 3;  // aperture parameter for Sobel operator (must be odd)
        int minResponse = 100; // minimum value for a corner in the 8bit scaled response matrix
        double k = 0.04;       // Harris parameter (see equation for details)
    
        // Detect Harris corners and normalize output
        cv::Mat dst, dst_norm, dst_norm_scaled;
        dst = cv::Mat::zeros(img.size(), CV_32FC1);
        cv::cornerHarris(img, dst, blockSize, apertureSize, k, cv::BORDER_DEFAULT);
        cv::normalize(dst, dst_norm, 0, 255, cv::NORM_MINMAX, CV_32FC1, cv::Mat());
        cv::convertScaleAbs(dst_norm, dst_norm_scaled);
    
        // visualize results
        string windowName = "Harris Corner Detector Response Matrix";
        cv::namedWindow(windowName, 4);
        cv::imshow(windowName, dst_norm_scaled);
        cv::waitKey(0);
    
        // STUDENTS NEET TO ENTER THIS CODE (C3.2 Atom 4)
    
        // Look for prominent corners and instantiate keypoints
        vector<cv::KeyPoint> keypoints;
        double maxOverlap = 0.0; // max. permissible overlap between two features in %, used during non-maxima suppression
        for (size_t j = 0; j < dst_norm.rows; j++)
        {
            for (size_t i = 0; i < dst_norm.cols; i++)
            {
                int response = (int)dst_norm.at<float>(j, i);
                if (response > minResponse)
                { // only store points above a threshold
    
                    cv::KeyPoint newKeyPoint;
                    newKeyPoint.pt = cv::Point2f(i, j);
                    newKeyPoint.size = 2 * apertureSize;
                    newKeyPoint.response = response;
    
                    // perform non-maximum suppression (NMS) in local neighbourhood around new key point
                    bool bOverlap = false;
                    for (auto it = keypoints.begin(); it != keypoints.end(); ++it)
                    {
                        double kptOverlap = cv::KeyPoint::overlap(newKeyPoint, *it);
                        if (kptOverlap > maxOverlap)
                        {
                            bOverlap = true;
                            if (newKeyPoint.response > (*it).response)
                            {                      // if overlap is >t AND response is higher for new kpt
                                *it = newKeyPoint; // replace old key point with new one
                                break;             // quit loop over keypoints
                            }
                        }
                    }
                    if (!bOverlap)
                    {                                     // only add new key point if no overlap has been found in previous NMS
                        keypoints.push_back(newKeyPoint); // store new keypoint in dynamic list
                    }
                }
            } // eof loop over cols
        }     // eof loop over rows
    
        // visualize keypoints
        windowName = "Harris Corner Detection Results";
        cv::namedWindow(windowName, 5);
        cv::Mat visImage = dst_norm_scaled.clone();
        cv::drawKeypoints(dst_norm_scaled, keypoints, visImage, cv::Scalar::all(-1), cv::DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
        cv::imshow(windowName, visImage);
        cv::waitKey(0);
        // EOF STUDENT CODE
    }
    
    // this function illustrates a very simple non-maximum suppression to extract the strongest corners
    // in a local neighborhood around each pixel
    cv::Mat PerformNMS(cv::Mat corner_img)
    {
        // define size of sliding window
        int sw_size = 7;                  // should be odd so we can center it on a pixel and have symmetry in all directions
        int sw_dist = floor(sw_size / 2); // number of pixels to left/right and top/down to investigate
    
        // create output image
        cv::Mat result_img = cv::Mat::zeros(corner_img.rows, corner_img.cols, CV_8U);
    
        // loop over all pixels in the corner image
        for (int r = sw_dist; r < corner_img.rows - sw_dist - 1; r++) // rows
        {
            for (int c = sw_dist; c < corner_img.cols - sw_dist - 1; c++) // cols
            {
                // loop over all pixels within sliding window around the current pixel
                unsigned int max_val{0}; // keeps track of strongest response
                for (int rs = r - sw_dist; rs <= r + sw_dist; rs++)
                {
                    for (int cs = c - sw_dist; cs <= c + sw_dist; cs++)
                    {
                        // check wether max_val needs to be updated
                        unsigned int new_val = corner_img.at<unsigned int>(rs, cs);
                        max_val = max_val < new_val ? new_val : max_val;
                    }
                }
    
                // check wether current pixel is local maximum
                if (corner_img.at<unsigned int>(r, c) == max_val)
                    result_img.at<unsigned int>(r, c) = max_val;
            }
        }
      	  
        // visualize results
        std::string windowName = "NMS Result Image";
        cv::namedWindow(windowName, 5);
        cv::imshow(windowName, result_img);
        cv::waitKey(0);
      
        return result_img;
    }
    
    展开全文
  • 图像特征提取(VGG和Resnet特征提取卷积过程详解)

    万次阅读 多人点赞 2021-12-25 16:14:26
    图像特征提取(VGG和Resnet卷积过程详解) 第一章 图像特征提取认知 1.1常见算法原理和性能 众所周知,计算机不认识图像,只认识数字。为了使计算机能够“理解”图像,从而具有真正意义上的“视觉”,本章我们将研究...
  • 数字图像处理与Python实现笔记之图像特征提取

    万次阅读 多人点赞 2020-07-30 16:23:00
    数字图像处理与Python实现笔记摘要绪论1 数字图像处理基础知识2 彩色图像处理初步3 空间滤波4 频域滤波5 图像特征提取5.1 图像颜色特征提取5.2 图像纹理特征提取5.3 图像形状特征提取5.4 图像边缘特征提取6 图像压缩...
  • 视觉和声音是人类固有的感觉输入。我们的大脑是可以迅速进化我们的能力来处理视觉和听觉信号的,一些系统甚至在出生前就对刺激做出...我们已经在文本分析应用方面取得了比图像或音频更多的进展。以搜索问题为例。人们.
  • 图像特征提取总结

    万次阅读 多人点赞 2018-10-06 17:36:09
    它指的是使用计算机提取图像信息,决定每个图像的点是否属于一个图像特征。特征提取的结果是把图像上的点分为不同的子集,这些子集往往属于孤立的点、连续的曲线或者连续的区域。  特征的定义   至今为止特征没有...
  • 图像特征提取

    万次阅读 2018-07-14 00:49:04
    一、图像常用属性本节指的是一般来说,图像处理的一些角度,也是根据一些美图软件最为关注的一些图像属性:基本属性:图像亮度,对比度,色彩饱和度,清晰度(锐度)色阶:曝光、高光、阴影颜色:色温、色调 .1、...
  • 这种描述具有尺度不变性,可在图像中检测出关键点,是一种局部特征描述子。 SIFT特征是基于物体上的一些局部外观的兴趣点而与影像的大小和旋转无关。对于光线、噪声、微视角改变的容忍度也相当高...
  • 图像特征点检测算法汇总

    千次阅读 2022-01-17 20:53:10
    FAST Harris 概述:寻找图像中灰度沿任意方向变化都非常大的点,并将其转换为根据梯度矩阵M特征值进行判断。 参考:4.harris corner detection(角点检测)_哔哩哔哩_bilibili
  • 傅里叶与图像特征简介

    千次阅读 2021-12-08 13:21:58
    傅里叶变换在图像处理中有着广泛的应用,主要应用方向有:图像增强与去噪、边缘检测、特征提取、图像压缩等。其核心思想是使用傅里叶变换将图像由空间域转换至频率域,通过对频率域进行不同的运算操作,实现预期的...
  • 图像特征提取算法—HOG

    千次阅读 2020-11-29 12:01:09
    图像特征提取算法—HOG 一 图像基本概念 1.1特征 边缘,角,区域。但不同的目的对应着的不同的特征,边缘特征,颜色特征,梯度方向分布等。 每个物体,我们总可以用一些词语或部件来描述它,比如人脸的特征:两个...
  • 图像特征点匹配算法汇总

    千次阅读 2022-01-15 22:53:26
    SIFT 概述:算法大致流程为: 建立不同分辨率的图像金字塔以及不同尺度的高斯差分金字塔,经DoG算法得到每一族内大致特征点; 将特征点进行泰勒展开求得精确特征点,该步骤可以求得精确的图像尺度,该尺度下特征点...
  • 常见的图像特征

    万次阅读 多人点赞 2019-07-05 19:45:25
    颜色特征图像检索中应用最为广泛的视觉特征。颜色特征无需进行大量计算。只需将数字图像中的像素值进行相应转换,表现为数值即可。因此颜色特征以其低复杂度成为了一个较好的特征。 在图像处理中,我们可以将一...
  • Python人脸图像特征提取(HOG、Dlib、CNN方法)一、HOG人脸图像特征提取1、HOG特征:1) 主要思想:2) 实现方法:3) 性能提高:4) 优点2、HOG特征提取算法的实现过程:二、Dlib人脸图像特征提取1.Dlib介绍2.主要特点三...
  • 图像处理之图像特征及提取

    千次阅读 2021-05-05 10:57:12
    图像处理之图像特征提取 图像特征: 几何特征(位置与方向、周长、面积、长轴与短轴、距离(欧式距离、街区距离、棋盘距离)); 形状特征(几何形态分析(Blob分析):矩形度、圆形度、不变矩、偏心率、多边形描述...
  • 深度学习-CNN提取图像特征

    万次阅读 多人点赞 2019-01-30 15:14:37
    一、卷积层 1.卷积操作 2.特征提取—"X" or "O"? 二、池化(Pooling) 三、Relu 层 ...四、全连接层(Fully connected layers) ... 作为机器学习的一个分支...答案当然是图像特征了。将一张图像看做是一个个像素值组成的...
  • 图像特征融合

    千次阅读 2020-04-10 17:28:36
    图像特征融合 根据图像表征层次的不同,图像融合可分为三个层次的融合:像素级融合、特征级融合和决策级融合。 图像融合的优点:1.图像增强,提高图像分辨率和清晰度;2.增强图像的相关特征;3.相互补充相关信息,...
  • 图像特征可以分为视觉特征和统计特征,视觉特征主要是指人的视觉直观感受到的自然特征,比如图像的颜色、纹理、形状等,统计特征是指需要通过变换测量才能得到的特征,比如频谱、直方图等。 根据视觉特征的分类,本...
  • 图像特征匹配:选取一些图像,检测它们的主要特征,并通过单应性(homography)来检测这些图像是否存在于另一个图像中。 常用的opencv特征检测和提取方法 Harris: 该算法用于检测角点 SIFT: 该算法用于检测...
  • SAR图像特征

    千次阅读 2020-11-06 10:09:02
    更重要的是,必须牢记SAR图像实际上是一些数据样点的集合——不同极化模式下功率(或振幅和相位)的量化值,而不是利用微波进行的摄影。 SAR影响的基本维度是时延(距离向)和航向距离(方位向)。每个像素代表了某个特定...
  • 图像特征概念、什么是图像特征

    万次阅读 2016-07-26 16:01:48
    常用的图像特征有颜色特征、纹理特征、形状特征、空间关系特征。  一 :颜色特征  (一)特点:颜色特征是一种全局特征,描述了图像或图像区域所对应的景物的表面性质。一般颜色特征是基于像素点的特征,此时...
  • 图像特征提取之Haar特征

    千次阅读 2017-12-15 12:33:16
    原文站点:https://senitco.github.io/2017/06/15/image-feature-haar/  Haar特征是一种用于目标检测或识别的图像特征描述子,Haar特征通常和AdaBoost分类器组合使用,而且由于Haar特征提取的实时性以及AdaBoost...
  • Python人脸图像特征提取方法

    千次阅读 2020-07-11 10:45:22
    Python人脸图像特征提取方法 一、HOG人脸图像特征提取 1、HOG特征: 1) 主要思想: 2) 实现方法: 3) 性能提高: 4) 优点 2、HOG特征提取算法的实现过程: 二、Dlib人脸图像特征提取 1.Dlib介绍 2.主要特点 三、卷积...
  • 图像特征提取(纹理特征)

    万次阅读 2018-07-26 20:32:08
    图像纹理特征总体简述 ...不同于灰度、颜色等图像特征,纹理通过像素及其周围空间邻域的灰度分布来表现,即局部纹理信息。另外,局部纹理信息不同程度上的重复性,就是全局纹理信息。 纹理特征体现全局特征的...
  • 基于opencv的图像特征点提取

    千次阅读 2022-03-17 13:03:04
    图片特征提取
  • 图像特征匹配方法——SIFT算法原理及实现

    万次阅读 多人点赞 2019-03-16 21:31:25
    传统图像处理中图像特征匹配有三个基本步骤:特征提取、特征描述和特征匹配。特征提取就是从图像中提取出关键点(或特征点、角点)等。特征描述就是用一组数学向量对特征点进行描述,其主要保证不同的向量和不同的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 381,345
精华内容 152,538
关键字:

图像特征