特征检测与描述1

理解特征

有很多小图像,需要正确组装它们以形成大的真实图像。问题是,要怎么做?将相同的理论投影到计算机程序上,以便计算机可以玩拼图游戏呢?如果计算机可以将多个自然图像缝合在一起,那么如何给建筑物或任何结构提供大量图片并告诉计算机从中创建3D模型呢?
如何将许多被扰的图像片段排列成一个大的单张图像?
寻找独特的,易于跟踪和比较的特定模板或特定特征,如果对这种特征进行定义,可能会发现很难用语言来表达它,但是知道它们是什么;如果要指出一项可以在多张图像中进行比较的良好特征,则可以指出其中一项;在图像中搜索这些特征,找到它们,在其他图像中寻找相同的特征并将它们对齐。
因此,一个基本问题扩展到更多,但变得更加具体,这些特征是什么(答案对于计算机也应该是可以理解的)?
如果深入研究某些图片并搜索不同的模板,会发现一些有趣的东西;例如,看以下的图片:
在这里插入图片描述
A和B是散布在很多区域上平坦的表面,很难找到这些补丁的确切位置。C和D是建筑物的边缘,可以找到一个大概的位置,但是准确的位置仍然很困难,因为沿着边缘的每个地方的图案都是相同的(建筑边缘外部情况可能有所不同);因此与平坦区域相比,边缘是更好的特征,但不够好(在拼图游戏中比较边缘的连续性很好)。E和F是建筑物的某些角落,很容易找到它们;因为在拐角处,无论将此修补区域移动到何处,它的外观都将有所不同;因此它们可以被视为很好的特征。
在这里插入图片描述
蓝色补丁是平坦区域,很难找到和跟踪,无论将其移到何处,看起来都一样。黑色补丁有一个边缘,如果你沿垂直方向(即沿渐变)移动它,则它会发生变化;沿着边缘(平行于边缘)移动,看起来相同。对于红色补丁,这是一个角落,无论将补丁移动到何处,它看起来都不同,这意味着它是唯一的。
因此基本上,拐点被认为是图像中的良好特征(不仅是角落,在某些情况下,斑点也被认为是不错的特征)。
如何找到不错的特征?寻找图像中在其周围所有区域中移动(少量)变化最大的区域。计算机语言中找到这些图像特征称为特征检测。
在图像中找到了特征,找到它之后,应该能够在其他图像中找到相同的图像,怎么做?围绕该特征采取一个区域,解释它,例如“上部是蓝天,下部是建筑物的区域,在建筑物上有玻璃等”,而在另一个建筑物中搜索相同的区域图片。
同样,计算机应该描述特征周围的区域,以便可以在其他图像中找到它,所谓的描述称为特征描述;获得特征及其描述后,可以在所有图像中找到相同的对象并将它们对齐,缝合在一起或进行所需的操作。
因此在此章节中,寻找OpenCV中的不同算法来查找特征,对其进行描述、匹配等。

哈里斯角检测

理论

角是图像中各个方向上强度变化很大的区域,哈里斯拐角检测器,基本上找到了 ( u , v ) (u, v) (u,v)在所有方向上位移的强度差异,表示如下:
E ( u , v ) = ∑ x , y w ( x , y ) ⏟ window function   [ I ( x + u , y + v ) ⏟ shifted intensity − I ( x , y ) ⏟ intensity ] 2 E(u,v) = \sum_{x,y} \underbrace{w(x,y)}_\text{window function} \, [\underbrace{I(x+u,y+v)}_\text{shifted intensity}-\underbrace{I(x,y)}_\text{intensity}]^2 E(u,v)=x,ywindow function w(x,y)[shifted intensity I(x+u,y+v)intensity I(x,y)]2
窗口函数要么是一个矩形窗口,要么是高斯窗口,它在下面赋予了值。
必须最大化这个函数 E ( u , v ) E(u, v) E(u,v)用于角检测,这意味着,必须最大化第二个项,将泰勒扩展应用于上述方程,并使用一些数学步骤,得到最后的等式:
E ( u , v ) ≈ [ u v ] M [ u v ] E(u,v) \approx \begin{bmatrix} u & v \end{bmatrix} M \begin{bmatrix} u \\ v \end{bmatrix} E(u,v)[uv]M[uv]
其中 M = ∑ x , y w ( x , y ) [ I x I x I x I y I x I y I y I y ] M = \sum_{x,y} w(x,y) \begin{bmatrix}I_x I_x & I_x I_y \\ I_x I_y & I_y I_y \end{bmatrix} M=x,yw(x,y)[IxIxIxIyIxIyIyIy]
在此, I x 和 I y I_x和I_y IxIy分别是在x和y方向上的图像导数(可使用函数cv.Sobel()找到)。
之后,创建了一个分数,它将确定一个窗口是否可以包含一个角: R = d e t ( M ) − k ( t r a c e ( M ) ) 2 R = det(M) - k(trace(M))^2 R=det(M)k(trace(M))2
其中

  • d e t ( M ) = λ 1 λ 2 det(M)=\lambda_1\lambda_2 det(M)=λ1λ2
  • t r a c e ( M ) = λ 1 + λ 2 trace(M)=\lambda_1 + \lambda_2 trace(M)=λ1+λ2
  • λ 1 和 λ 2 是 M 的特征值 \lambda_1 和\lambda_2是M的特征值 λ1λ2M的特征值
    这些特征值的值决定了区域是拐角、边缘还是平坦。
  • 当 ∣ R ∣ 较小,这在 λ 1 和 λ 2 较小时发生,该区域平坦。 当|R|较小,这在\lambda_1 和\lambda_2较小时发生,该区域平坦。 R较小,这在λ1λ2较小时发生,该区域平坦。
  • 当 R < 0 时,当 λ > > λ 2 时发生,反之亦然,该区域为边。 当R<0时,当\lambda >> \lambda2时发生,反之亦然,该区域为边。 R<0时,当λ>>λ2时发生,反之亦然,该区域为边。
  • 当 R 很大时,这发生在 λ 1 和 λ 2 大、 λ 1   λ 2 时,该区域是角。 当R很大时,这发生在\lambda_1 和\lambda_2大、\lambda_1 ~\lambda_2时,该区域是角。 R很大时,这发生在λ1λ2大、λ1 λ2时,该区域是角。
    可以用下图来表示:
    在这里插入图片描述
    Harris Corner Detection的结果是具有这些分数的灰度图像,合适的阈值可提供图像的各个角落。

OpenCV中的哈里斯角检测

为此,有函数cv.cornerHarris(),其参数为: img 输入图像,应为灰度和float32类型;blockSize 是拐角检测考虑的邻域大小 ;ksize 使用的Sobel导数的光圈参数;k 等式中的哈里斯检测器自由参数。示例中用青色标记出找到的哈里斯角

SubPixel精度的转角

有时可能需要找到最精确的角落,OpenCV有函数cv.cornerSubPix(),它进一步细化了以亚像素精度检测到的角落。下面是一个例子,需要先找到哈里斯角;然后通过这些角的质心(可能在一个角上有一堆像素,取它们的质心)来细化它们;哈里斯角用红色像素标记,精制角用绿色像素标记;在特定的迭代次数或达到一定的精度后停止它;定义它将搜索角落的邻居的大小。
harriscorner_detect.py

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt

img = cv.imread('./OpenCV/blox.png')
img1 = img.copy()
img2 = img.copy()
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
gray = np.float32(gray)
dst = cv.cornerHarris(gray, 2, 3, 0.04)
# dst用于标记角点,并不重要
dst = cv.dilate(dst, None)
# 最佳值的阈值,可能因图像而异
img1[dst > 0.01 * dst.max()] = [255, 255, 0]
ret, dst = cv.threshold(dst, 0.01 * dst.max(), 255, 0)
dst = np.uint8(dst)
# 寻找质心
ret, labels, stats, centroids = cv.connectedComponentsWithStats(dst)
# 定义停止和完善拐角的条件
criteria = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 100, 0.001)
corners = cv.cornerSubPix(gray, np.float32(centroids), (5, 5), (-1, -1), criteria)
# 绘制
res = np.hstack((centroids, corners))
res = np.int0(res)
img2[res[:, 1], res[:, 0]] = [0, 0, 255]
img2[res[:, 3], res[:, 2]] = [0, 255, 0]
images = [img, img1, img2]
titles = ['Original', 'CornerHarris', 'SubPixel']
for i in range(3):
    plt.subplot(1, 3, i + 1)
    plt.imshow(cv.cvtColor(images[i], cv.COLOR_BGR2RGB))
    plt.title(titles[i])
    plt.xticks([]), plt.yticks([])
plt.show()

在这里插入图片描述

Shi-tomas拐角检测器和益于跟踪的特征

理论

Shi和C. Tomasi在他们的论文《有益于跟踪的特征》中做了一个小修改,与Harris Harris Detector相比,显示了更好的结果。
哈里斯拐角检测器的计分功能由下式给出:
R = λ 1 λ 2 − k ( λ 1 + λ 2 ) 2 R = \lambda_1 \lambda_2 - k(\lambda_1+\lambda_2)^2 R=λ1λ2k(λ1+λ2)2
取而代之的是,Shi和C. Tomasi提出:
R = m i n ( λ 1 , λ 2 ) R = min(\lambda_1, \lambda_2) R=min(λ1,λ2)
如果大于阈值,则将其视为拐角,如下图:
在这里插入图片描述
从图中可以看到,只有当 λ 1 和 λ 2 都大于最小值 λ m i n \lambda_1和\lambda_2都大于最小值\lambda_{min} λ1λ2都大于最小值λmin时,才将其视为拐角(绿色区域)。

OpenCV实现

OpenCV有一个函数cv.goodFeaturesToTrack(),它通过Shi-Tomasi方法(或指定哈里斯角检测)找到图像中的N个最强角。
图像应是灰度图像,然后指定要查找的角数;然后,指定质量级别,该值是介于0-1之间的值,该值表示每个角落都被拒绝的最低拐角质量;然后,提供检测到的角之间的最小欧式距离; 利用所有这些信息,该功能可以找到图像中的拐角,低于平均质量的所有拐角点均被拒绝;然后,它会根据质量以降序对剩余的角进行排序,然后函数首先获取最佳拐角,丢弃最小距离范围内的所有附近拐角,然后返回N个最佳拐角。
在下面的示例中,我们将尝试找到25个最佳弯角:
good_features.py

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt

img = cv.imread('./OpenCV/blox.png')
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
corners = cv.goodFeaturesToTrack(gray, 25, 0.01, 10)
corners = np.int0(corners)
for i in corners:
    x, y = i.ravel()
    cv.circle(img, (x, y), 3, 255, -1)
plt.imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB))
plt.title('GoodFeature')
plt.xticks([]), plt.yticks([])
plt.show()

在这里插入图片描述
学习来源:OpenCV-Python中文文档

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值