图像匹配是指通过一定的匹配算法在两幅或多幅图像之间识别同名点。
应用:遥感(制图更新),计算机视觉应用程序,医疗用图像注册。
图像匹配主要可分为以灰度为基础的匹配和以特征为基础的匹配。
1.模版匹配
2.特征匹配
3.深度学习去找目标
模板匹配是基于像素的匹配,用来在一副大图中搜寻查找模版图像位置的方法。和 2D 卷积一样,它也是用模板图像在输入图像(大图)上滑动,并在每一个位置对模板图像和与其对应的输入图像的子区域进行比较。OpenCV 提供了几种不同的比较方法。返回的结果是一个灰度图像,每一个像素值表示了此区域与模板的匹配程度。
当你得到这幅图之后,就可以使用函数 cv2.minMaxLoc() 来找到其中的最小值和最大值的位置了。
第一个值为矩形左上角的点(位置),(w,h)为模板矩形的宽和高。这个矩形就是找到的模板区域了。注意:如果你使用的比较方法是 cv2.TM_SQDIFF,最小值对应的位置才是匹配的区域。
CV_TM_SQDIFF 平方差匹配法:该方法采用平方差来进行匹配;最好的匹配值为 0;匹配越差,匹配值越大。
CV_TM_CCORR?相关匹配法:该方法采用乘法操作;数值越大表明匹配程度越好。
CV_TM_CCOEFF?相关系数匹配法:1 表示完美的匹配;-1 表示最差的匹配。
CV_TM_SQDIFF_NORMED?归一化平方差匹配法
CV_TM_CCORR_NORMED?归一化相关匹配法
CV_TM_CCOEFF_NORMED?归一化相关系数匹配法
假如你的模板图像在目标图像中出现了很多次怎么办呢?
如果你想匹配一次,就找最大匹配的点,如果你想匹配多个物体,就可以自己来设置一个匹配阈值,根据你的需求来
模板匹配具有自身的局限性,主要表现在它只能进行平行移动,若原图像中的匹配目标发生旋转或大小变化,该算法无效。
1.SIFT 特征提取
2.FLANN 匹配器
3.FLANN 的单应性匹配
图像特征
特征描述,计算机对特征周围的区域进行描述,这样它才能在其他图像中找到相同的特征
SIFT:是一种检测局部特征的算法,该算法通过求一幅图中的特征点(interest points, or corner points)及其有关 scale 和 orientation 的描述子得到特征并进行图像特征点匹配
SIFT 特征不只具有尺度不变性,即使改变旋转角度,图像亮度或拍摄视角,仍然能够得到好的检测效果。
SIFT 特征提取流程
1.尺度空间极值检测:这是一个初始化操作,尺度空间理论目的是模拟图像数据的多尺度特征。
2.关键点(极值点)定位
3.为关键点(极值点)指定方向参数
4.关键点描述符的生成
1.构建尺度空间
不同的尺度空间不能使用相同的窗口检测极值点。对小的角点要用小的窗口,对大的角点只能使用大的窗口。为了达到这个目的我们要使用尺度空间滤波器
这是一个初始化操作,尺度空间理论目的是模拟图像数据的多尺度特征。使用具有不同方差值 σ 的高斯拉普拉斯算子(LoG)对图像进行卷积。
LoG 的计算量非常大,为了有效的在尺度空间检测到稳定的关键点,所以 SIFT 算法使用高斯差分算子(DoG)来对 LoG 做近似。利用不同尺度的高斯差分核与图像卷积生成。具体到图像处理来讲,就是将两幅图像在不同参数下的高斯滤波结果相减,得到 DoG 图
图像金字塔:我们可以通过降采样(如只取奇数行或奇数列)来构成一组图像尺寸(1,0.5,0.25 等)不同的金字塔,然后对这一组图像中的每一张图像使用具有不同方差 σ 的高斯卷积核构建出具有不同分辨率的图像金字塔(不同的尺度空间)。DoG 就是这组具有不同分辨率的图像金字塔中相邻的两层之间的差值。如下图所示:
i 为塔数(第几个塔),s 为每塔层数由图片 size 决定建几个塔,每塔几层图像 (S 一般为 3-5 层)。0 塔的第 0 层是原始图像 (或你 double 后的图像),直观上看来越往上图片越模糊。
2.检测 DOG 尺度空间极值点
高斯尺度空间金字塔中每组有五层不同尺度图像,相邻两层相减得到四层 DoG 结果。关键点搜索就在这四层 DoG 图像上寻找局部极值点。寻找 DoG 极值点时,每一个像素点和它所有的相邻点比较,当其大于(或小于)它的图像域和尺度域的所有相邻点时,即为极值点。则在比较时牺牲了-1 组的第 0 层和第 N 组的最高层
除去不好的特征点
以上极值点的搜索是在离散空间进行搜索的,由下图可以看到,在离散空间找到的极值点不一定是真正意义上的极值点。使用尺度空间的泰勒级数展开来获得极值的准确位置,如果极值点的灰度值小于阈值(0.03)就会被忽略掉。DoG 算法对边界非常敏感,会产生较强的边缘响应,所以我们必须要把边界去除,使用近似 Harris Corner 检测器。
通过拟和三维二次函数以精确确定关键点的位置和尺度(达到亚像素精度),同时去除低对比度的关键点和不稳定的边缘响应点,以增强匹配稳定性、提高抗噪声能力。
3.为关键点(极值点)指定方向参数
上一步中确定了每幅图中的特征点,为每个特征点计算一个方向,这样它才会具有旋转不变性。获取关键点(所在尺度空间)的邻域,然后计算这个区域的梯度级和方向。根据计算得到的结果创建一个含有 36 个 bins(每 10 度一个 bin)的方向直方图。直方图中的峰值为主方向参数,如果其他的任何柱子的高度高于峰值的 80% 被认为是辅方向。这就会在相同的尺度空间相同的位置构建除具有不同方向的关键点。这对于匹配的稳定性会有所帮助。
每个关键点有三个信息:位置,所处尺度、方向,由此可以确定一个 SIFT 特征区域。
关键点描述子的生成步骤
通过对关键点周围图像区域分块,计算块内梯度直方图,生成具有独特性的向量,这个向量是该区域图像信息的一种抽象,具有唯一性。
为了保证特征矢量具有旋转不变性,要以特征点为中心,在附近邻域内旋转θ角,即旋转为特征点的方向。
选取与关键点周围一个 16x16 的邻域,把它分成 16 个 4x4 的小方块,为每个小方块创建一个具有 8 个 bin 的方向直方图。绘制每个梯度方向的累加值,即可形成一个种子点,这样就可以对每个特征形成一个 4*4*8=128 维的描述子,每一维都可以表示 4*4 个格子中一个的 scale/orientation.?将这个向量归一化之后,就进一步去除了光照的影响
生成了 A、B 两幅图的描述子(分别是 k1*128 维和 k2*128 维)。
将两图中各个 scale(所有 scale)的描述子进行匹配,匹配上 128 维即可表示两个特征点 match 上了。
可以采用关键点特征向量的欧式距离来作为两幅图像中关键点的相似性判定度量。取第一个图的某个关键点,通过遍历找到第二幅图像中的距离最近的那个关键点。但有些情况下,第二个距离最近的关键点与第一个距离最近的关键点靠的太近。这可能是由于噪声等引起的。此时要计算最近距离与第二近距离的比值。如果比值大于 0.8,就忽略掉。这会去除 90% 的错误匹配,同时只去除 5% 的正确匹配。
FLANN 是快速最近邻搜索包(Fast_Library_for_Approximate_Nearest_Neighbors)的简称。它是一个对大数据集和高维特征进行最近邻搜索的算法的集合,而且这些算法都已经被优化过了。
使用 FLANN 匹配,我们需要传入两个字典作为参数。这两个用来确定要使用的算法和其他相关参数等,第一个是 IndexParams,第二个字典是 SearchParams。用它来指定递归遍历的次数。值越高结果越准确,但是消耗的时间也越多。
indexparams = dict(algorithm =FLANN_INDEX_KDTREE, trees = 5)
searchparams = dict(checks = 100)
flann = cv2.FlannBasedMatcher(indexParams,searchParams)
matches = flann.knnMatch(des1,des2,k=2)
检测出的匹配点可能有一些是错误正例(false positives)。因为这里使用过的 kNN 匹配的 k 值为 2(在训练集中找两个点),第一个匹配的是最近邻,第二个匹配的是次近邻。直觉上,一个正确的匹配会更接近第一个邻居。换句话说,一个不正确的匹配,两个邻居的距离是相似的。因此,我们可以通过查看二者距离的不同来评判匹配程度的好坏。并且舍去那些不好的匹配点,保留好的匹配点。
我们在一张杂乱的图像中找到了一个对象(的某些部分)的位置。这些信息足以帮助我们在目标图像中准确的找到(模板图像)对象。
我们可以使用 cv2.findHomography() 函数如果将这两幅图像中的特征点集传给这个函数,他就会找到这个对象的透视图变换。
透视变换 (Perspective Transformation) 是将成像投影到一个新的视平面 (Viewing Plane),也称作投影映射 (Projective Mapping)。
然后我们就可以使用函数 cv2.perspectiveTransform() 找到模板图像的 4 个坐标点变换到目标图像中的新的坐标了。
一个平面到另一个平面的映射关系。两张图分别有四个相对位置相同的点,Homography 就是一个变换(3*3 矩阵),将一张图中的点映射到另一张图中对应的点
特征匹配结果展示
实践中的小问题
用网络去训练的模型,能够识别出目标,但是对训练数据的构造要求比较高。迁移性很难得到保证。
a.先将要训练的图像进行标记,可以把你要识别的每个模板标为一类
b.训练的图尽可能的丰富,这样可以增强模型的迁移性
c.用训练好的模型去测试,识别出目标图片上的类
特征匹配与模板匹配的区别:模板匹配是基于像素的,特征匹配则是基于区域的,特征匹配在考虑像素灰度的同时还应考虑诸如空间整体特征、空间关系等因素。
特征是图像内容最抽象的描述,与基于灰度的匹配方法相比,特征相对于几何图像和辐射度影响来说更不易变化,但特征提取方法的计算代价通常较大,并且需要一些自由参数和事先按照经验选取的阀值,因而不便于实时应用。同时,在纹理较少的图像区域提取的特征的密度通常比较稀少,使局部特征的提取比较困难。另外,基于特征的匹配方法的相似性度量也比较复杂,往往要以特征属性、启发式方法及阀方法的结合来确定度量方法。
深度学习的方法对数据的要求较高,需要考虑模型的迁移性,相对训练的时间也会耗费更多,但数据集够丰富的时候,深度学习是个很好的选择。
在应用过程中,选择优先使用模板匹配,再用特征匹配,最后用深度学习的方式
第一个是 indexParams。配置我们要使用的算法
1、随机 k-d 树算法(The Randomized k-d TreeAlgorithm)
a.Classick-d tree
找出数据集中方差最高的维度,利用这个维度的数值将数据划分为两个部分,对每个子集重复相同的过程。
b.Randomizedk-d tree
建立多棵随机 k-d 树,从具有最高方差的 N_d 维中随机选取若干维度,用来做划分。在对随机 k-d 森林进行搜索时候,所有的随机 k-d 树将共享一个优先队列。
增加树的数量能加快搜索速度,但由于内存负载的问题,树的数量只能控制在一定范围内,比如 20,如果超过一定范围,那么搜索速度不会增加甚至会减慢
2、优先搜索 k-means 树算法(The Priority Search K-MeansTree Algorithm)
随机 k-d 森林在许多情形下都很有效,但是对于需要高精度的情形,优先搜索 k-means 树更加有效。 K-means tree 利用了数据固有的结构信息,它根据数据的所有维度进行聚类,而随机 k-d tree 一次只利用了一个维度进行划分。
2.1 算法描述
步骤 1 建立优先搜索 k-means tree:
(1) 建立一个层次化的 k-means 树;
(2) 每个层次的聚类中心,作为树的节点;
(3) 当某个 cluster 内的点数量小于 K 时,那么这些数据节点将做为叶子节点。
步骤 2 在优先搜索 k-means tree 中进行搜索:
(1) 从根节点 N 开始检索;
(2) 如果是 N 叶子节点则将同层次的叶子节点都加入到搜索结果中,count += |N|;
(3) 如果 N 不是叶子节点,则将它的子节点与 query Q 比较,找出最近的那个节点 Cq,同层次的其他节点加入到优先队列中;
(4) 对 Cq 节点进行递归搜索;
(5) 如果优先队列不为空且 count
聚类的个数 K,也称为 branching factor 是个非常主要的参数。
建树的时间复杂度 = O( ndKI ( log(n)/log(K) ))? n 为数据点的总个数,I 为 K-means 的迭代次数。搜索的时间复杂度 = O( L/K * Kd * ( log(n)/(log(K) ) ) = O(Ld ( log(n)/(log(K) ) )。
3.层次聚类树(The Hierarchical ClusteringTree)
层次聚类树采用 k-medoids 的聚类方法,而不是 k-means。即它的聚类中心总是输入数据的某个点,但是在本算法中,并没有像 k-medoids 聚类算法那样去最小化方差求聚类中心,而是直接从输入数据中随机选取聚类中心点,这样的方法在建立树时更加简单有效,同时又保持多棵树之间的独立性。
同时建立多棵树,在搜索阶段并行地搜索它们能大大提高搜索性能(归功于随机地选择聚类中心,而不需要多次迭代去获得更好的聚类中心)。建立多棵随机树的方法对 k-d tree 也十分有效,但对于 k-means tree 却不适用。
比如我们使用 SIFT,我们可以传入参数:
index_params=dict(algorithm = FLANN_INDEX_KDTREE,trees=5)