OpenCV学习——角点检测、SIFT算法的学习
- 图像的特征提取和描述
- 角点特征
- Harris角点检测
- Shi-Tomasi角点检测
- SIFT/SURF算法
- SIFT算法(尺度不变特征转换)
- 实现
图像的特征提取和描述
图像特征:图像特征主要有图像的颜色特征、纹理特征、形状特征和空间关系特征。
角点特征
角点:两条边的交点,严格的讲,角点是两个不同区域的不同方向的边界
Harris角点检测
原理:通过图像的局部小窗口观察图像,角点的特诊是窗口沿任意方向移动都会导致灰度的明显变化。
将黑塞矩阵M 的行列式值与 M 的迹相减,再将差值同预先给定的阈值进行比较
(由于其原理实现的数学公式导致作者大脑宕机,故直接跳过,讲述如何利用OpenCV实现)
# Harris检测
dst = cv.cornerHarris(img, blockSize, ksize, k)
# img:数据类型为float32的输入图像
# blockSize:角点检测中要考虑的领域大小(窗口)
# ksize:sobel求导使用的核大小(奇数哦)
# k:角点检测方程中的自由参数,取值参数为[0.04, 0.06]
代码测试
import cv2 as cv
import numpy as np
# 读取图像,转换成灰度图
img = cv.imread('img/img.png')
gray_img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# 讲获得的灰度图像转成float32格式
gray_img = np.float32(gray_img)
# 角点检测
dst = cv.cornerHarris(gray_img, 2, 3, 0.05)
# 绘制窗口(dst大于dst中最大值的0.001倍的均绘制出来)
img[dst>0.001 * dst.max()] = [0,0,255]
cv.imshow("Harris_img", img)
cv.waitKey(0)
Shi-Tomasi角点检测
原理:若黑塞矩阵M中较小的一个大于阈值,则认为是角点。
是对Harris检测的改进,可以更好的检测角点
API
corners = cv2.goodFeaturesToTrack(img, maxcorners, qualityLevel, minDistance)
# img:灰度图像
# maxcorners:获取角点的数目
# qualityLevel:该参数指出最低可接收的角点质量水平,0-1之间
# minDistance:角点之间最小的欧式距离,避免得到相邻特征点
# corners:搜索到的角点
代码测试:
import cv2 as cv
import numpy as np
# 读取图像,转换成灰度图
img = cv.imread('img/25.png')
gray_img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# 角点检测(指定1000个角点)
corners = cv.goodFeaturesToTrack(gray_img, 1000, 0.01, 10)
# 绘制角点
for i in corners:
x, y = i.ravel() # 平铺成坐标
cv.circle(img, (x, y), 2, (0, 0, 255), -1)
# 绘制窗口(dst大于dst中最大值的0.001倍的均绘制出来)
cv.imshow("Shi-Tomasi", img)
cv.waitKey(0)
Harris算法和Shi-Tomasi算法具有旋转不变性,但是不具有尺度不变性!
SIFT/SURF算法
SIFT算法(尺度不变特征转换)
原理:在不同的尺度空间上查找关键点,并计算关键点的方向。也就是说在空间尺度中寻找极值点,并提取位置、尺度、旋转不变量。
SIFT查找的关键点:一些十分突出的点,不会因光照、仿射变化和噪音等因素而变化的点,如角点、边缘点、暗区中的亮点以及亮区中的暗点。
基本流程
第一步:尺度空间机制检测:搜索所有尺度的图像位置,通过高斯差分函数来识别潜在的对于尺度和旋转不变的关键点
第二步:关键点定位:在每个候选位置上,通过一个拟合精细的模型来确定位置和尺度。关键点的选择一句与它们得稳定程度
第三步:关键点方向确定:基于图像局部得梯度方向,分配给每个关键点位置一个或多个方向
第四步:关键点描述:在每个关键点周围邻域内,在选定得尺度上测量图像局部梯度。
SIFT | SURF | |
特征点检测 | 使用不同尺度的图片与高斯函数进行卷积 | 使用不同大小的盒滤波器与原始图像做卷积,易于并行 |
方向 | 关键点邻接矩形区域内,利用梯度直方图计算 | 关键点灵界圆域内,计算x、y方向的harris小波 |
描述符生成 | 关键点邻域内划分d*d个子区域,每个子区域计算8个方向的直方图 | 关键点邻域内划分的d*d个子区域,每个子区域计算采样点的harr小波响应,记录:Σdx,Σdy,Σ|dx|,Σ|dy| |
实现
# 实例化sift
sift = cv.SIFT_create()
# 检测关键点
kp, des = sift.detectAndCompute(gray, None)
# gray:灰度图像
# kp:关键点信息(位置、尺度、方向)
# des:关键点描述符,每个关键点对应28个梯度信息的特征向量
# 绘制关键点信息
cv.drawKeypoints(img, keypoints, outputimage, color, flags)
# img:原始图像
# keypoints:关键点信息
# outputimage:输出图片
# color:颜色设置
# flags:绘图功能的标识设置
# cv.DRAW_MATCHS_FLAGS_DEFAULT:创建输出图像矩阵,使用现存的输出图像绘制匹配对和特征点,每一个关键点只绘制中间点
# cv.DRAW_MATCHS_fLAGS_DRAW_OVER_OUTIMG:不创建图像矩阵,在输出图像上绘制匹配对
# cv.DRAW_MATCHS_FLAGS_DRAW_RICH_KEYPOINTS:对每一个特征点绘制带大小和方向的关键点图形
# CV.DRAW_MATCHS_FLAGS_NOT_DRAW_SINGLE_POINTS:单点的特征点不被绘制
代码测试
import cv2 as cv
import numpy as np
# 读取图像,转换成灰度图
img = cv.imread('img/25.png')
gray_img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# sift检测cv2.SIFT_create()
sift = cv.SIFT_create()
kp, des = sift.detectAndCompute(gray_img, None)
# 绘制检测结果
cv.drawKeypoints(img, kp, img, flags=cv.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
cv.imshow("Shi-Tomas", img)
cv.waitKey(0)
圆形越大表示尺度越大,圆形越小表示尺度越小,圆中的半径是方向