OpenCV(图像处理)-基于Python-特征检测-特征点匹配

在这里插入图片描述

1.图像特征

图像特征就是指有意义的图像区域,具有独特性,易于识别性,比如角点、斑点以及高密度区。而为什么角点具有重要的特征呢?
看下图:
在这里插入图片描述
观察ABD三张图片,我们不容易得知图像的位置,而CEF三张图我们特别容易找到它们在原图中对应的位置,这是因为ABD比较平滑,我们不易找出他们的特点,而CEF三张图有很明显的轮廓特征,有很多边缘特征即角点,因此一幅图像中的角点非常重要。
想让计算机具有识别图片的功能,首先要让他们学会提取图片的特征,提取图像的角点。

角点的特征

  • 在特征中最重要的是角点
  • 是灰度梯度最大值所对应的像素
  • 两条线的交点
  • 极值点(一阶导数最大值但是二阶导数为0)

2. 哈里斯检测

原理:

图1方块上下左右移动都没有变化,说明图1不是角点;图2上下没有变化,左右移动有变化,说明图2是边缘;图3上下左右移动都有变化,说明图3是角点。

在这里插入图片描述

cornerHarris()

dst = cv2.cornerHarris(img, blockSize, ksize, k)
img :需要检测的图像,最好为灰度图
blockSize:检测窗口的大小,一般取2
ksiez:Sobel卷积核,一般取3
k:权重系数,经验值,一般取0.02~0.04之间
返回值:dst不是图像,是点的集合
缺点:k是个经验值需要自己调节

import cv2
import numpy as np

# 读取图片,并转为灰度图
img = cv2.imread('./image/chess.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# Harris角点检测
dst = cv2.cornerHarris(gray, 2, 3, 0.02)

# 表示img中dst值大于0.01*dst.max()的像素点索引出来,然后将这些像素点的值赋为 [0,0,255]。
img[dst > 0.01*dst.max()] = [0, 0, 255]
cv2.imshow('img', img)

cv2.waitKey(0)

在这里插入图片描述

3.Shi-Tomasi角点检测

Shi-Tomasi是Harris角点检测的改进,因为Harris角点检测的稳定性与k有关,而k是个经验值,与人的主观因素有关。Shi-Tomasi避免了这个问题。

goodFeaturesToTrack()

dst = cv2.goodFeaturesToTrack(img, maxCorners, qualityLevel, minDistance)
img:需要检测的图像,最好为灰度图
maxCorners:角点的最大数量,值为0表示无限制
qualityLevel:小于1.0的正数,一般在0.01-1.0之间
minDistance:角之间最小欧式距离,忽略小于此距离的点
mask:感兴趣的区域,不填默认全部图像
blockSize:检测窗口大小
useHarrisDetector:是否使用Harris算法,True/False
k:默认是0.04

import cv2
import numpy as np

# 读取图片,并转为灰度图
img = cv2.imread('./image/chess.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# Harris角点检测
# dst = cv2.cornerHarris(gray, 2, 3, 0.02)

maxCorners = 100
ql = 0.01
minDistance = 10
# ShiTomasi角点检测
corners = cv2.goodFeaturesToTrack(gray, maxCorners, ql, minDistance)
# corners为float32类型,需要转化为整型
corners = np.int0(corners)
# 表示img中dst值大于0.01*dst.max()的像素点索引出来,然后将这些像素点的值赋为 [0,0,255]。
# img[dst > 0.01*dst.max()] = [0, 0, 255]

for i in corners:
    x, y = i.ravel() # 将迭代的数组,转化成一维的
    cv2.circle(img, (x, y), 3, (0, 0, 255), -1)

cv2.imshow('img', img)

cv2.waitKey(0)

在这里插入图片描述

4.Scale-Invariant Feature Transform(SIFT)

该算法是与缩放无关的特征检测,比如说,以前是角点,但是在图放大或缩小后,由于图片比例的变化,原来是角,放大之后,可能就不是角;原来是角,缩小之后可能就是角。而该算法正好解决了这个问题。
在这里插入图片描述


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

SIFT语法

  • 首先创建SIFT对象
  • 进行检测,kp =sift.detect(img,…)
  • 绘制关键点,drawKeypoints(gray, kp, img)
  • 从灰度图gray中检测的,关键点kp,在原图img中画

创建SIFT对象
sift = cv2.xfeatures2d.SIFT_create(什么也不写)
kp = sift.detect(img, mask)
img:是检测图片,尽量用灰度图
mask:掩码,指明对图中哪部分进行检测,一般填None(全图)

import cv2
import numpy as np

# 读取图片,并转为灰度图
img = cv2.imread('./image/chess.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 创建sift对象
sift = cv2.xfeatures2d.SIFT_create()
# 关键点检测
kp = sift.detect(gray, None)
# 使用关键点画图
cv2.drawKeypoints(gray, kp, img)
cv2.imshow('img', img)

cv2.waitKey(0)

在这里插入图片描述


此接口一下能算出关键点和描述子
kp, des = sift.detectAndCompute(img, mask)
img:是检测图片,尽量用灰度图
mask:掩码,指明对图中哪部分进行检测,一般填None(全图)

import cv2
import numpy as np

# 读取图片,并转为灰度图
img = cv2.imread('./image/chess.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 创建sift对象
sift = cv2.xfeatures2d.SIFT_create()
# kp = sift.detect(gray, None)

kp, des = sift.detectAndCompute(gray, None)

cv2.drawKeypoints(gray, kp, img)
cv2.imshow('img', img)

cv2.waitKey(0)

在这里插入图片描述


SIFT缺点:速度慢

5.SURF

由于SIFT速度较慢,因此又产生了SURF算法,该算法速度优于SIFT。

  • 首先创建SURF对象
  • 进行检测,kp, des =surf.detectAndCompute(img, mask)
  • 绘制关键点,drawKeypoints(gray, kp, img)
  • 从灰度图gray中检测的,关键点kp,在原图img中画

创建surf对象
surf = cv2. xfeatures2d.SURF_create()
kp, des = surf.detectAndCompute(img, mask)
img:是检测图片,尽量用灰度图
mask:掩码,指明对图中哪部分进行检测,一般填None(全图)
kp:检测出的关键字
des:是描述子,用来特征匹配使用的

import cv2
import numpy as np

# 读取图片,并转为灰度图
img = cv2.imread('./image/chess.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# # 创建sift对象
# sift = cv2.xfeatures2d.SIFT_create()

# 创建surf对象
surf = cv2.xfeatures2d.SURF_create()

# 计算关键点和描述子
kp, des = surf.detectAndCompute(gray, None)

cv2.drawKeypoints(gray, kp, img)
cv2.imshow('img', img)

cv2.waitKey(0)

注意:此算法由于付费的缘由,需要使用3.4.2.17版本的opencv库

6.ORB(Oriented FAST and Rotated BRIEF)

其中FAST用于特征检测,BRIEF是对已检测到的特征点进行描述,它加快了特征描述符的建立速度,同时也极大降低了特征匹配的时间。
ORB的优势在于:速度快,可用于实时监测;免费。

先建立ORB对象
orb = cv2.ORB_create()
计算特征点与描述子
kp, des = orb.detectAndCompute(img, mask)
使用kp画出特征点
cv2.drawKeypoints(gray, kp, img)

img:是检测图片,尽量用灰度图
mask:掩码,指明对图中哪部分进行检测,一般填None(全图)

import cv2
import numpy as np

# 读取图片,并转为灰度图
img = cv2.imread('./image/chess.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

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

cv2.drawKeypoints(gray, kp, img)
cv2.imshow('img', img)

cv2.waitKey(0)

在这里插入图片描述


检测出的特征点越来越少,因此在提升检测速度的同时,精度也在丢失。

7.特征匹配

根据特征点的描述子进行匹配,特征匹配方法有:

  • BF(Brute-Force),暴力特征匹配方法
  • FLANN 最快临近区特征匹配方法

7.1 暴力特征匹配

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

  • 创建匹配器,bf = cv2.BFMatcher(normType, crossCheck)
  • 进行特征匹配,match = bf. match(des1, des2)
  • 绘制匹配点, cv2.drawMatches(img1, kp1, img2, kp2,…)

创建匹配器
bf = cv2.BFMatcher(normType, crossCheck)
normType:NORM_L1(SIFT),NORM_L2(SURF), HAMMING1(ORB)
crossCheck:是否进行交叉匹配,默认为false
描述子进行匹配
match = bf.match(dst1, dst2)
dst1:要搜索的图的描述子
dst2:从库里能匹配的描述子
画相同的地方
img3 = cv2.drawMatchers(img1, kp1, img2, kp2, match, None)
img1, kp1:要搜索的图,和特征点
img2, kp2:从库里匹配的图和特征点
match:匹配好的描述子

import cv2
import numpy as np

# 读取图片,并转为灰度图
img1 = cv2.imread('./image/opencv_search.png')
img2 = cv2.imread('./image/opencv_orig.png')
gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)

# 创建orb对象
orb = cv2.ORB_create()
# 对ORB进行检测
kp1, dst1 = orb.detectAndCompute(gray1, None)
kp2, dst2 = orb.detectAndCompute(gray2, None)

# 创建匹配器
bf = cv2.BFMatcher(cv2.NORM_HAMMING)
# 描述子进行匹配
match = bf.match(dst1, dst2)

img3 = cv2.drawMatches(img1, kp1, img2, kp2, match, None)

cv2.imshow('img3', img3)

在这里插入图片描述

7.2 FLANN

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

创建匹配器
flann = cv2.FlannBasedMatcher()
进行特征匹配
match = flann.match()
绘制匹配点
img3 = cv2.drawMatches()

import cv2
import numpy as np

# 读取图片,并转为灰度图
img1 = cv2.imread('./image/opencv_search.png')
img2 = cv2.imread('./image/opencv_orig.png')
gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)

# 创建orb对象
orb = cv2.ORB_create()
# 对ORB进行检测
kp1, dst1 = orb.detectAndCompute(gray1, None)
kp2, dst2 = orb.detectAndCompute(gray2, None)
# 判断描述子的数据类型,若不符合,则进行数据替换
if dst1.dtype != 'float32':
    dst1 = dst1.astype('float32')
if dst2.dtype != 'float32':
    dst2 = dst2.astype('float32')

# 创建匹配器(FLANN)
flann = cv2.FlannBasedMatcher()
# 描述子进行匹配计算
matches = flann.match(dst1, dst2)
img3 = cv2.drawMatches(img1, kp1, img2, kp2, matches, None)

cv2.imshow('img3', img3)

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_45153969/article/details/131399378