openCV 图像特征点检测与匹配

一、应用场景

        1.图像搜索,以图搜图。

        2.拼图游戏。

        3.图像拼接,将两张有关联的图拼接在一起。

二、基础概念

2.1 什么是图像特征?

        图像特征就是指有意义的图像区域,具有独特性、易于识别性,比如角点、斑点以及高密度区。

         从上图我们可以发现:

        A、B两图我们很难找到具体定位;

        C、D两图可以找到一些相似区域,但不太容易确定;

        E、F两图则很容易确定其定位,即特征信息丰富。

        由此,我们可以知道角点是非常重要的特征信息。

2.2 角点

        (1)在特征中最重要的是角点;

        (2)灰度梯度的最大值对应的像素点;

        (3)两条线的交点;

        (4)极值点(一阶导数最大值,但二阶导数为0)。

三、特征检测

3.1 角点检测

3.1.1 Harris角点检测

  • 光滑地区,无论向哪个移动,衡量系数不变
  • 边缘地区,垂直边缘移动时,衡量系统剧烈变化
  • 在交点处,往那个方向移动,衡量系统都发生剧烈变化

    Harris角点检测API

  • cornerHarrris(img,dst,blockSize,ksize,k)
  • blockSize: 检测窗口大小
  • ksize: Sobel的卷积核
  • k 权重系数,经验值,一般取0.02-0.04之间
import cv2
import numpy as np

# 读取图片
img = cv2.imread('./chess.png')

# 灰度化
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# Harris角点检测
dst = cv2.cornerHarris(gray, blockSize=2, ksize=3, k=0.04)

# Harris角点的展示
img[dst > 0.01*dst.max()] = (0, 0, 255)

cv2.imshow('Harris', img)
cv2.waitKey(0)

3.1.2 Shi-Tomasi角点检测

  • shi- tomasi是Harris角点检测的改进
  • Harris角点检测算的稳定性和k有关,而k是个经验值,不好设定最佳值

   Shi-Tomasi角点检测API

  • goodFeaturesToTrack(img,maxCorners,…)
  • maxCorners:角点的最大数,值为0表示无限制
  • qualityLevel:小于1.0的正数,一般在0.01-0.1之间
  • minDistance:角之间最小欧式距离,忽略小于此距离的点
  • mask: 感兴趣的区域
  • blockSize:检测窗口
  • useHarrisDectector:是否使用Harris算法
  • k :默认是0.04
import cv2
import numpy as np

img = cv2.imread('./chess.png')

# 灰度化
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 角点检测
corners = cv2.goodFeaturesToTrack(gray, maxCorners=1000, qualityLevel=0.01, minDistance=10,)
corners = np.int0(corners)

# Shi-Tomasi绘制角点
for i in corners:
    x,y = i.ravel()
    cv2.circle(img, (x,y), 3, (0,0,255),-1)


cv2.imshow('Shi-Tomasi', img)
cv2.waitKey(0)

3.1.3 检测效果展

   

                          图1 原图                                                   图2 Harris角点检测                                      图3  Shi-Tomasi角点检测

3.2关键点与描述子

  • 关键点:位置,大小和方向
  • 关键点描述子:记录了关键点周围对其有贡献的像素点的一组向量值,其不受仿射变换、光照变换等的影响

3.2.1 SIFT(Scale-Invariant Feature Transfrom)特征检测

   SIFT出现的原因

  • Harris 角点具有旋转不变的特性,但缩放后,原来的角点有可能就不是角点了,如下图所示:

   使用SIFT的步骤

  • 创建SIFT对象,sift = cv2.SIFT_create()
  • 进行检测,kp = sift.detect(img,…)
  • 绘制关键点,drawKeypoints(gray, kp, img)

  计算描述子

  • kp,des=sift.compute(img,kp)
  • 其作用就是进行特征匹配

   同时计算关键点和描述子的API

  • kp,des=sift.detectAndCompute(img,…)
  • mask:指明对img中哪个区域进行计算

3.2.2 SURF(Speeded-Up Robust Features)特征检测

  SURF的优点 

  • SIFT最大的问题就是速度慢,因此才有SURF

  使用SURF的步骤

  • surf = cv2.xfeatures2d.SURF_create()
  • kp, des = surf.detectAndCompute(img, mask)

3.2.3 ORB(Orirnted FAST and Rotated BRIEF)特征检测

  ORB的优点 

  • 可以实现实时检测
  • ORB = Orirnted FAST + Rotated BRIEF,即是两种技术的结合
  • FAST 可以做到特征点的实时检测
  • BRIEF 对已经检测到的特征点进行描述,加快了特征点描述符建立的速度,同时也极大的降低了特征匹配的时间

  使用ORB的步骤

  • orb = cv2.ORB_create()
  • kp,des =orb.detectAndCompute(img,mask)

3.2.4 代码及检测效果

import cv2
import numpy as np

# 读文件
img = cv2.imread('chess.png')
# 灰度化
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 创建sift对象,进行检测
sift = cv2.SIFT_create()
kp,des = sift.detectAndCompute(gray, None)

# 创建SURF对象,进行检测
# surf = cv2.xfeatures2d.SURF_create()
# kp,des = surf.detectAndCompute(gray, None)

# 创建ORB对象,进行检测
# orb = cv2.ORB_create()
# kp,des = orb.detectAndCompute(gray, None)


# print(des)

# 绘制keypoints
cv2.drawKeypoints(gray, kp, img)

cv2.imshow('img', img)
cv2.waitKey(0)

                             图1 原图                                                    图2 SIFT特征检测                                        图3  ORB特征检测

四、特征匹配

4.1 BF(Brute-Force)暴力特征匹配方法

  暴力特征匹配方法的原理(枚举)

  • 它使用第一组中的每个特征的描述子,与第二组中的所有特征描述子进行匹配
  • 计算他们之间的差距,然后将最接近一个匹配返回(也即计算他们之间的相似度)

  openCV特征匹配的步骤

  • 创建匹配器,BFMatcher(normType, crossCheck)
  • 进行特征匹配,bf.match(des1,des2)
  • 绘制匹配点,cv2.drawMatches(img1,kp1,img2,k2)
import cv2
import numpy as np

# 读取图片
img1 = cv2.imread('2.jpg')
img2 = cv2.imread('1.jpg')
# # 灰度化
gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)

# 检测特征点+描述子
sift = cv2.SIFT_create()  # 创建SIFT对象
kp1, des1 = sift.detectAndCompute(gray1, None)   # 对整个图像进行检测,掩码设为None
kp2, des2 = sift.detectAndCompute(gray2, None)   # 对整个图像进行检测,掩码设为None

# 创建匹配器
bf = cv2.BFMatcher(cv2.NORM_L1)
match = bf.match(des1, des2)    # 获得匹配点
res = cv2.drawMatches(img1, kp1, img2, kp2, match, None)   # 绘制匹配点

# cv.drawKeypoints(gray, kp, img)  # 绘制特征点

# # 显示图像

cv2.imshow('BF', res)
cv2.waitKey(0)

4.2 FLANN最快邻近区特征匹配方法

   FLANN优缺点

  • 在进行批量特征匹配时,FLANN速度更快
  • 由于它使用的是邻近近似值,所以精度较差

  使用FLANN特征匹配的步骤

  • 创建FLANN匹配器,FlannBasedMatcher(…)
  • 进行特征匹配,flann.match/knnMatch(…)
  • 绘制匹配点,cv.drawMatches/drawMatchesKnn(…)
import cv2
import numpy as np

# 读取图片
img1 = cv2.imread('2.jpg')
img2 = cv2.imread('1.jpg')

# 灰度化
gray1 = cv2.cvtColor(img1,cv2.COLOR_BGR2GRAY)
gray2 = cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)

# 创建sift特征匹配器
sift = cv2.SIFT_create()
# 计算描述子与特征点
kp1, des1 = sift.detectAndCompute(gray1, None)
kp2, des2 = sift.detectAndCompute(gray2, None)

# 创建匹配器
index_params = dict(algorithm=1, trees=5)
search_params = dict(checks=50)
flann = cv2.FlannBasedMatcher(index_params, search_params)

# 对描述子进行匹配
matches = flann.knnMatch(des1, des2, k=2)
good = []
for i, (m, n) in enumerate(matches):
    if m.distance < 0.7*n.distance:
        good.append(m)

# 绘制匹配点
ret = cv2.drawMatchesKnn(img1,kp1,img2,kp2,[good],None)
cv2.imshow('FLANN', ret)
cv2.waitKey(0)

 4.3 特征匹配效果图

 

                                             图1 BF暴力特征匹配                                                                 图2 FLANN特征匹配

注:内容来自慕课网李超老师的视频课程整理。

猜你喜欢

转载自blog.csdn.net/cxzgood/article/details/129563544