不知不觉,漫谈计算机视觉也写了四篇了,我们从最基本的除噪引出计算机图形学的各种技术,然后又学会了发现图像的轮廓,发现图像的边缘,等等,但是始终没有接触一个核心的问题——特征。我们肯定经常在数据科学或者人工智能领域不断的听到这个词汇,我们之前做的内容比如轮廓发现,计算轮廓面积周长,发现图像边缘等等其实也都或多或少能够在很多牵扯到图像的领域中用来发现或者创造特征,但是却始终没有直接接触计算机视觉中的特征这一概念。而角点检测算得上是第一次真正的接触。
角点检测,一如其名,就是检测图像中的角点的。本质上角点是一种很容易在图像中定位的局部特征,并且广泛存在于人造物体中,如桌子椅子车子房子等等(自然界中多曲线,这个你可以在散步的时候观察一下)。另外角点可以被精确地检测(即使是亚像素级精度)这点对于实用也非常有价值。
至于角点的用处,本质上来说,角点是作为图像的一种特征来使用的。我们可以想象一下拼图,很明显角点信息对于图像的拼接,对齐都有极大的价值,而图像或者图像中的物体发生变化时,如图像检测,运动追踪等也同样具有不小的价值。
我们的主要工具还是OpenCV,所以还是要主讲OpenCV中的角点检测。比较简单的角点检测,OpenCV中的角点检测主要有Harris角点检测,Shi-Tomasi
角点检测。除了一般性的角点检测外,OpenCV中还有一些更正式的基于角点检测的特征点检测算法,如ORB,ASIFT等等。这些正式的特征点检测器更适合我们直接使用。不过由浅入深,我们还是需要从最基本的角点检测器讲起。
Harris角点检测的基本假设来自于人眼对角点的识别,对于整个图像我们选择一个小窗作为我们实际观察的部分,如果一个点上下左右移动后他周围的灰度变化比较大,那么他应该就是一个角点,如果延一个方向变化大一个方向变化小,那么他就很可能是一条线。这样我们通过设定一个固定窗口,对比其左右变化就可以得到区域中的角点了。
同样也因此,我们需要设定三个参数,观察窗口的大小,需要考虑领域(也就是角点范围,或者说这个角点可能有多大)的大小,以及阈值。对于Harris算法,我们可以直接调用OpenCV中的cornerHarris
算法,而这三个关键参数,则是
blockSize —— 角点检测中要考虑的领域大小。
ksize —— Sobel 求导中使用的窗口大小
k ——Harris 角点检测方程中的自由参数,取值参数为 [0.04,0.06].
下面是有关代码,这里我们使用了opencv的github项目中的一张图片,你可以到opencv的github下载原图片或者fongtian的github项目–漫谈计算机视觉下载所有代码和图片:
img = cv2.imread('/home/fonttian/Data/image/OpenCV/blox.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# cornerHarris函数图像格式为 float32 ,因此需要将图像转换 float32 类型
gray = np.float32(gray)
blockSize = 2 # 领域尺寸
ksize = 3 # 口径尺寸
k = 0.04 # Harris
dst = cv2.cornerHarris(src=gray, blockSize=blockSize, ksize=ksize, k=k)
# 变量a的阈值为0.01 * dst.max(),如果dst的图像值大于阈值,那么该图像的像素点设为True,否则为False
# 将图片每个像素点根据变量a的True和False进行赋值处理,赋值处理是将图像角点勾画出来
a = dst > 0.01 * dst.max()
img[a] = [0, 0, 255]
# 显示图像
cv2.imshow('corners', img)
上面的代码中我们并没有直接使用获取的焦点数据,而是对数据进行了过滤,然后再绘制角点,这样避免了角点过多的问题,除此之外,我们也可以使用一个更合适的角点检测器来简化我们的代码,那就是——goodFeaturesToTrack
函数,具体使用请看接下来的代码。
Shi-Tomasi 角点检测是对Harris角点检测的改进。由于 Harris 角点检测算法的稳定性和与k 值这个经验数值有关,因此并不能太好的直接获得最佳数值。但是Shi-Tomasi 发现,角点的稳定性其实和矩阵 M 的较小特征值有关,于是直接用较小的那个特征值作为分数,于是便有了不需要调整k值的新算法。
下面的第一个公式是Harris的原始分数公式,第二个是《Good_Features_to_Track》论文中改进后的分数公式
R = λ 1 λ 2 − k ( λ 1 + λ 2 ) 2 R=\lambda_1\lambda_2-k(\lambda_1+\lambda_2)^2 R=λ1λ2−k(λ1+λ2)2
R = m i n ( λ 1 − λ 2 ) R=min(\lambda_1-\lambda_2) R=min(λ1−λ2)
至于Shi-Tomasi 角点检测的使用,我们可以直接在OpenCV中使用goodFeaturesToTrack
函数获取最好的几个点,并选定角点检测方法为Shi-Tomasi算法,该函数具体参数如下:
这个函数的特殊之处就在于,他帮助我们完成了点的筛选,之前我们通过自己设定的dst > 0.01 * dst.max()
进行参数筛选。而该函数首先获取所有右焦点,然后忽略低于质量系数的角点并排序。之后保留质量最高的一个焦点,然后删除最小距离内的角点,并依次进行该步骤并获得最终的N个最佳角点。代码和效果如下:
img = cv2.imread('/home/fonttian/Data/image/OpenCV/blox.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
corners = cv2.goodFeaturesToTrack(gray, maxCorners, qualityLevel, minDistance)
# print(len(corners))
# print(corners)
for i in corners:
x, y = i.ravel()
cv2.circle(img, (x, y), 2, (0, 0, 255), -1)
cv2.imshow('Shi-Tomasi', img)
我们之前所说的都是直接的角点检测,而角点本质是一种图像的特征点,而除了这些直接获取角点的算法外,我们还有需要很多其他的特征点检测算法可以直接使用,而这些特征点检测算法同样都离不开各种基础算子。比如ORB算法。
RB特征是将FAST特征点的检测方法与BRIEF特征描述子结合起来,并在它们原来的基础上做了改进与优化。
首先,它利用FAST特征点检测的方法来检测特征点,然后利用Harris角点的度量方法,从FAST特征点从挑选出Harris角点响应值最大的N个特征点。
除了上述的描述外,ORB算法本身还牵扯到很多内容,比如旋转不变性(FAST特征本身没有),多尺度不变性,非极大值抑制等等,需要想要详细的了解类似ORB算法的特征提取算法,是需要大量笔墨的所以我们放在下一章节再来讲。不过在OpenCV中使用起来却十分简单:
img = cv2.imread('/home/fonttian/Data/image/OpenCV/blox.jpg')
orb = cv2.ORB_create()
kp = orb.detect(img, None)
kp, des = orb.compute(img, kp)
img = cv2.drawKeypoints(img, kp, img, color=(0, 255, 0), flags=0)
cv2.imshow('p', img)
上面的第一行代码是读取图片,第二行代码就是ORB的创建,之后使用detect进行特征检测,并使用compute进行特征的计算,最终绘制。这里des实际上并没有用到,之后我们再讲解具体怎么使用。但是仅从代码分析,我们可以很清楚的看到创建,检测,绘制各只需要一行代码,而绘制这一步,我们甚至只需要调用OpenCV中封装好的类即可,可以说非常简单了。效果则如下所示,具体绘制效果我们也可以通过参数修改:
与orb类似的事,opecv中还有很多其他的有用的特征检测器,使用起来同样十分方便。我们将会在下一篇文章中讲解。
fongtian的github项目–漫谈计算机视觉