Bootstrap

OpenCV中的特征检测与描述 —— 理解特征 + 哈里斯角检测 + Shi-Tomas拐角检测器

💖OpenCV中的特征检测与描述 —— 理解特征 + 哈里斯角检测 + Shi-Tomas拐角检测器

🌎上一节我们介绍了OpenCV中霍夫线/圈变换的原理和应用、使用分水岭算法实现图像分割和使用GrabCut算法实现交互式前景提取,这一部分我们就正式进入了下一个专题——特征检测与描述,在这一小节我们将介绍特征和拐角等几个重要的概念、哈里斯角检测及应用和Shi-Tomas拐角检测器及应用的内容

🏠哈喽大家好,这里是ErrorError!,一枚某高校大二本科在读的♂同学,希望未来在机器视觉领域能够有所成就,很荣幸能够在CSDN结识众多志同道合和在各方面都有所造诣的小伙伴,我们一起加油吧~💖

🚀上节内容:OpenCV中的图像处理 —— 霍夫线 / 圈变换 + 图像分割(分水岭算法) + 交互式前景提取(GrabCut算法)


1. 理解特征

1.1 一切从拼图游戏说起

在拼图游戏中,我们会得到很多的小图像,然后正确组装它们以形成大的完整的图像,但是我们是怎么完成这个过程的呢?我们可不可以将相同的理论投影在计算机中让计算机也可以完成拼图游戏?如果计算机有这样的能力,我们就可以给计算机提供很多自然风光的真实图像,然后计算机会将这些图像拼接成一个大图像。再想想如果这个场景应用在建筑物或任何结构,为计算机提供大量图片,计算机又如何创建3模型呢?

我们要做的事情还有很多,敢想敢干是促进科技发展的灵魂。上面我们说的若干种情况其实其最本质的问题是:你如何玩拼图游戏?你如何将许多被扰的图像片段排列成一个大的单张图像?你如何将许多自然图像拼接到一张图像上?并将这种能力赋予计算机

在进行拼图游戏的时候,我们寻找独特的、易于跟踪和比较的特定模板或特定特征,如果让我们对这种特征进行定义,可能会发现很难用语言来表达它,但是我们知道它们是什么。如果有人要求你指出一项可以在多张图像中进行比较的良好特征,则可以指出其中一项。这就是为什么即使是小孩也可以玩这些游戏的原因。我们在图像中搜索这些特征,找到它们,在其他图像中寻找相同的特征并将它们对齐,这就是我们完成拼图游戏的思想,仅此而已

很难说人类如何发现这些特征,这已经在我们的大脑中进行了编码,但是,如果我们深入研究某些图片并搜索不同的模板,我们会发现一些有趣的东西

1.2 投影到现实,再抽象到计算机

在这里插入图片描述

上面我们给出了一张图片,在图像的顶部,给出了六个小图像块,我们要做的事情是在原始图像中找到这些补丁的确切位置。A和B是平坦的表面,它们散布在很多区域上,所以很难找到这些补丁的确切位置。C和D更简单,它们是建筑物的边缘。我们可以找到一个大概的位置,但是准确的位置仍然很困难。这是因为沿着边缘的每个地方的图案都是相同的。但是,在边缘,情况有所不同,因此与平坦区域相比,边缘是更好的特征,但不够好(在拼图游戏中比较边缘的连续性很好)

最后,E和F是建筑物的某些角落。而且很容易找到它们。因为在拐角处,无论将此修补程序移动到何处,它的外观都将有所不同,因此它们可以被视为很好的特征。因此,现在我们进入更简单(且被广泛使用的图像)以更好地理解

下面我们把上述的思想再抽象化,投影在一个简单的图像上

在这里插入图片描述

就像上面一样,蓝色补丁是平坦区域,很难找到和跟踪,无论我们将蓝色补丁移到何处,它看起来都一样。黑色补丁有一个边缘,如果你沿垂直方向(即沿渐变)移动它,则它会发生变化,但是如果沿着边缘(平行于边缘)移动,看起来相同。对于红色补丁,这是一个角落。无论你将补丁移动到何处,它看起来都不同,这意味着它是唯一的。因此,基本上,拐点被认为是图像中的良好特征(不仅是角落,在某些情况下,斑点也被认为是不错的功能),这些除了特定位置,移动到其他位置就是不行的**”补丁”(在上面的例子中我们找的是拐角),就是我们要提取的特征**

现在我们回答了我们的问题,“这些特征是什么?”,但是出现了下一个问题,我们如何找到它们?还是我们如何找到角落?我们以一种直观的方式回答了这一问题,即寻找图像中在其周围所有区域中移动(少量)变化最大的区域,找到这些区域(图像特征)被称为特征检测

2. 哈里斯角检测

2.1 Harris Corner Detection理论

上一节我们说拐角是图像中各个方向上强度变化很大的区域,Chris Harris和Mike Stephens在1988年的论文《组合式拐角和边缘检测器》中做了一次尝试找到这些拐角的尝试,所以现在将其称为哈里斯拐角检测器,他们把这个简单的想法变成了数学形式,它基本上找到了(u,v)在所有方向上位移的强度差异,它长这样:在这里插入图片描述

我们必须最大化这个函数E(u,v)用于角检测,这意味着我们必须最大化第二个项,我们把它简化一下:在这里插入图片描述
其中的M就是我们研究的重点在这里插入图片描述
Ix和Iy分别是在x和y方向上的图像导数(看到这个是不是就会想到我们亲切的cv.Sobel),然后他们创建了一个分数,基本上是一个等式,它将确定一个窗口是否可以包含一个角:在这里插入图片描述
其中det(M)=λ1λ2;trace(M)=λ1+λ2;λ1 和 λ2 是 M 的特征值,这些特征值的值决定了区域是拐角,边缘还是平坦

  • 当|R|较小,这在λ1和λ2较小时发生,该区域平坦;

  • 当R<0时(当λ1>>λ2时发生,反之亦然),该区域为边;

  • 当R很大时,这发生在λ1和λ2大且λ1~λ2时,该区域是角。

在这里插入图片描述

因此,Harris Corner Detection的结果是具有这些分数的灰度图像,合适的阈值可为我们提供图像的各个角落

2.2 OpenCV中的哈里斯角检测

OpenCV为哈里斯拐角检测器提供了一个函数cv.cornerHarris()来实现其功能(现在知道OpenCV为什么强大了吧哈哈哈)其中包含4个参数:第一个参数**- img -是输入源图像,应为灰度图且是float32类型;第二个参数- blockSize -是拐角检测考虑的邻域大小;第三参数- ksize -是使用的Sobel导数的光圈参数;第四个参数- k -**是等式中的哈里斯检测器自由参数

import numpy as np
import cv2 as cv

filename = r'E:\image\test38.png'
img = cv.imread(filename)
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
gray = np.float32(gray)
dst = cv.cornerHarris(gray, 2, 3, 0.04)
# result用于标记角点,并不重要
dst = cv.dilate(dst, None)
# 最佳值的阈值,它可能因图像而异。
img[dst > 0.01 * dst.max()] = [0, 0, 255]
cv.imshow('dst', img)
if cv.waitKey(0) & 0xff == 27:
    cv.destroyAllWindows()

在这里插入图片描述

✏️代码解析:这段代码其他的都好理解,只有第12行看起来有点儿意思,这其实是设置了一个阈值,大于这个值的角点都会被标红

2.3 SubPixel精度的转角

有时,我们可能需要找到最精确的角落,因此OpenCV附带了一个函数cv.cornerSubPix(),它进一步细化了以亚像素精度检测到的角落,这个函数比上面的要稍显复杂一点,我们需要先找到哈里斯角,然后我们通过这些角的质心(可能在一个角上有一堆像素,我们取它们的质心)来细化它们,Harris角用红色像素标记,精制角用绿色像素标记

对于这个函数,我们必须定义何时停止迭代的条件,我们在特定的迭代次数或达到一定的精度后停止它,无论先发生什么,我们还需要定义它将搜索角落的邻居的大小

import numpy as np
import cv2 as cv

filename = r'E:\image\test39.png'
img = cv.imread(filename)
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# 寻找哈里斯角
gray = np.float32(gray)
dst = cv.cornerHarris(gray, 2, 3, 0.04)
dst = cv.dilate(dst, None)
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)
img[res[:, 1], res[:, 0]] = [0, 0, 255]
img[res[:, 3], res[:, 2]] = [0, 255, 0]
cv.imshow('cornerSubPix', img)
cv.waitKey(0)

在这里插入图片描述

3. Shi-Tomas拐角检测器

3.1 Shi-Tomas拐角检测理论

上一节内容我们看了哈里斯拐角检测器,现在我们来看看Shi-Tomas拐角检测,1994年下半年,J.Shi和C.Tomasi在他们的论文《有益于跟踪的特征》中做了一个小修改,与Harris Harris Detector相比,显示了更好的结果,他们研究了另一种计分功能:在这里插入图片描述
同样是设置了阈值,只有当λ1λ1和λ2λ2大于最小值λminλmin时,才将其视为拐角(绿色区域)角

在这里插入图片描述

3.2 OpenCV实现Shi-Tomas拐角检测

OpenCV提供了函数cv.goodFeaturesToTrack(),它通过Shi-Tomasi方法(或哈里斯角检测,如果指定)找到图像中的N个最强角吗,像往常一样图像应该是灰度图

然后我们需要指定要查找的角数,还需要您指定质量级别,该值是介于0-1之间的值,该值表示每个角落都被拒绝的最低拐角质量。我们还要提供检测到的角之间的最小欧式距离。利用所有这些信息,该功能可以找到图像中的拐角,低于平均质量的所有拐角点均被拒绝,函数会根据质量以降序对剩余的角进行排序,然后首先获取最佳拐角,丢弃最小距离范围内的所有附近拐角,最终返回N个最佳拐角

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread(r'E:\image\test40.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(img),plt.show()

在这里插入图片描述

按照我们给定的要求最终返回了25个最佳拐点,为了便于观察我后期手动添加了一些标记


(注:文章内容参考OpenCV4.1中文官方文档)
如果文章对您有所帮助,记得一键三连支持一下哦👍+⭐️+📝

;