刚好看到datewhale关于opencv的学习部分,想着借机会熟悉一下opencv部分的内容,第一部分是harris特征点检测器部分的内容,之前学视觉SLAM的视觉就接触过一些特征点检测和计算描述子的方法,又跟着系统学习了一下关于harris特征点的计算方法,收获蛮大~
基础知识
角点:字面意思就是一些边角上的点,在之前的ORB的提取中就是看当前的点与周围一圈12个点,有多少个点是不同的,通常采用九点法,在harris中就采用了图像梯度的概念,即看当前点与周围点的变化幅度有多大,考虑图像的每个像素的某个邻域内的灰度变化
算法思想:核心即在局部窗口中在图像上进行移动,判断灰度是否发生了较大的变化,如果发生了较大变化,那么这个窗口所在区域就存在角点
算法分为以下三个步骤
- 窗口同时向x和y方向移动,计算窗口内部的像素值变化量
- 对于每个窗口,计算对应的一个角点响应函数
- 对函数进行一个阈值判断,如果大于阈值,则认为该窗口存在角点特征
数学模型
第一步 建立数学模型
第一步给当前的像素一个小的移动量,类似于给一个小扰动,得到新的位置的像素灰度值,对于窗口内的像素要给以响应的权重,最简单就是给所有像素权重为1,复杂一些可以认为符合高斯分布,认为窗口中心像素点贡献较大,离窗口中心较远的点,这些点的灰度变化影响比较小,可以把他们的权重设置的低一些,可以通过泰勒公式进行简化优化。
第二步 响应矩阵R
前面一步已经得到了 E ( u , v ) E(u,v) E(u,v)的最终形式,灰度值变化的大小取决于矩阵M,为了编程方便,定义了角点响应函数R,通过判断R大小,来判断像素是否为角点
第三步 角点判断
根据R的值,将这个窗口所在的区域划分为平面,边缘或角点,为了得到最优的角点,还可以使用非极大值抑制
harris检测器具有旋转不变性,但是不具有尺度不变性,即尺度变化可能会使得角点变成边缘,如果想要尺度不变,可以关注sift特征
具体实现部分
opencv提供了实现harris角点检测的函数cv2.cornerHarris,对于每一个像素(x,y), 计算梯度图的协方差矩阵
M
(
x
,
y
)
M(x,y)
M(x,y),然后通过上面第二步中的角点响应函数得到结果图。图像中的角点可以为该结果图的局部最大值。
函数原型:
cv2.cornerHarris(src, blockSize, ksize, k[, dst[, borderType]])
代码示例如下:
import cv2 as cv
from matplotlib import pyplot as plt
import numpy as np
# detector parameters
block_size = 3
sobel_size = 3
k = 0.06
image = cv.imread('Scenery.jpg')
print(image.shape)
height = image.shape[0]
width = image.shape[1]
channels = image.shape[2]
print("width: %s height: %s channels: %s"%(width, height, channels))
gray_img = cv.cvtColor(image, cv2.COLOR_BGR2GRAY)
# modify the data type setting to 32-bit floating point
gray_img = np.float32(gray_img)
# detect the corners with appropriate values as input parameters
corners_img = cv.cornerHarris(gray_img, block_size, sobel_size, k)
# result is dilated for marking the corners, not necessary
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(3, 3))
dst = cv.dilate(corners_img, kernel)
# Threshold for an optimal value, marking the corners in Green
#image[corners_img>0.01*corners_img.max()] = [0,0,255]
for r in range(height):
for c in range(width):
pix=dst[r,c]
if pix>0.05*dst.max():
cv2.circle(image,(c,r),5,(0,0,255),0)
image = cv.cvtColor(image, cv2.COLOR_BGR2RGB)
plt.imshow(image)
plt.show()
代码就直接搬运了datewhale的啦,还是比较通俗易懂的~
总结
- 阈值决定了角点的数量,阈值越高,则能被筛选出来的角点越少
- harris角点检测算子具有光照不变性
- harris具有旋转不变性
- harris角点检测算子不具有尺度不变性,所以需要考虑加上sift等方法