OpenCV 特征点检测与匹配

一 OpenCV特征场景

①图像搜索,如以图搜图;
②拼图游戏;
③图像拼接,将两长有关联得图拼接到一起;

1 拼图方法

寻找特征
特征是唯一的
可追踪的
能比较的

二 角点

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

三 Harris角点

哈里斯角点检测
在这里插入图片描述
Harris点
① 光滑地区,无论向哪里移动,衡量系数不变;
②边缘地址,垂直边缘移动时,衡量系统变换剧烈;
③在交点处,往哪个方向移动,衡量系统都变化剧烈;

1 Harris角点检测API

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

blockSize=2

ksize=1

k=0.04

img=cv2.imread('chess.jpg')

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

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

#Harris角点的展示
img[dst>0.04*dst.max()]=[0,0,255]
cv2.imshow('img',img)
cv2.waitKey(0)


四 Shi_Tomasi交点检测

Shi-Tomasi是Harris角点检测的改进;
Harris角点检测的稳定性和K有关,而k是个经验值,不好设定最佳值。

1 Shi-Tomasi角点检测API

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

maxCorners=100
ql=0.01


img=cv2.imread('./chess.jpg')
cv2.imshow('img',img)
#灰度化
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

# Shi-Tomasi
corners=cv2.goodFeaturesToTrack(gray,maxCorners,ql,10)
print(corners)
corners=np.int32(corners)
# Shi-Tomasi绘制角点
for i in corners:
    x,y=i.ravel()
    cv2.circle(img,(x,y),3,(255,0,0),-1)

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

五 SIFT(Scale-Invariant Feature Transform)

SIFT出现的原因:
harris 角点具有旋转不变的特性;
但缩放后,原来的角点有可能就不是角点了;

图放大
在这里插入图片描述

使用SIFT的步骤

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

from email.mime import image

import cv2
import numpy as np

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

gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

sift=cv2.xfeatures2d.SIFT_create()

kp=sift.detect(gray,None)

cv2.drawKeypoints(gray,kp,img)

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

在这里插入图片描述

六 SIFT计算描述子

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

计算描述子

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

同时计算关键点和描述

kp,des=sift.detectAndCompute(img,...)
mask:指明对img中哪个区域进行计算
import cv2
import numpy as np

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

gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

sift=cv2.xfeatures2d.SIFT_create()

kp,des=sift.detectAndCompute(gray,None)
print(des)
cv2.drawKeypoints(gray,kp,img)

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

在这里插入图片描述

七 SURF特征检测

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

使用SURF的步骤

surf=cv2.xfeatures2d.SUFR_create()
kp,des=surf.detectAndCompute(img,mask)
import cv2
import numpy as np

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

gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

surf=cv2.xfeatures2d.SURF_create()

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

print(des[0])

cv2.drawKeypoints(gray,kp,img)

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

八 ORB(Oriented FAST and Rotated BRIEF)特征检测

1 ORB 优势

①ORB可以做到实时检测
②ORB=Oriented FAST+Rotated BRIEF

2 FAST

可以做到特征点的实时检测

3 BRIEF

BRIEF是对已检测到的特征点进行描述,它加快了特征描述符建立的速度。同时也极大的降低了特征匹配的时间。

3 ORB使用步骤

orb=cv2.ORB_create()
kp,des=orb.detectAndCompute(img,mask)
import cv2
import numpy as np

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

gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

orb=cv2.ORB_create()

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

cv2.drawKeypoints(gray,kp,img)

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


在这里插入图片描述

九 暴力特征匹配

1 特征匹配方法

①BF(Brute-Force),暴力特征匹配方法;
②FLANN最快邻近区特征匹配方法;
它使用第一组中的每个特征的描述子与第二组中的所有特征描述子进行匹配计算它们之间的差距,然后将最接近一个匹配返回。

2 OpenCV特征匹配步骤

创建匹配器,BFMatcher(normType,crossCheck)
进行特征匹配,bf.match(des1,des2)
绘制匹配点,cv2.drawMatches(img1,kp1,img2,k2,...)
BFMatcher
normType:NORM_L1,NORM_L2,HAMMING1....
crossCheck:是否进行交叉匹配,默认为false
Match方法
参数为SIFT,SURF,OBR等计算的描述子
对两幅图的描述子进行计算
drawMatches
搜索img,kp
匹配图img,kp
match()方法返回的匹配结果

import cv2
import numpy as np

img=cv2.imread('./opencv_search.png')
img1=cv2.imread('./opencv_orig.png')



gray=cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray1=cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)

sift=cv2.xfeatures2d.SIFT_create()

kp1,des1=sift.detectAndCompute(gray,None)
kp2,des2=sift.detectAndCompute(gray1,None)

bf=cv2.BFMatcher(cv2.NORM_L1)
match=bf.match(des1,des2)

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

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

在这里插入图片描述

十 FLANN特征匹配

1 FLANN优缺点

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

2 使用FLANN特征匹配的步骤

①创建FLANN匹配器,FlannBasedMatcher(...)
②进行特征匹配,flann.match/knnMatch(...)
③绘制匹配点,cv2.drawMathes/drawMatchesKnn(...)
FlannBasedMathcer
index_params字典:匹配算法KDTREE、LSH
search_params字典:指定KETREE算法中遍历树的次数
KDTREE
index_params=dict(algorithmFLANN_INDEX_KETREE,trees=5)
search_params
search_params=dict(checks=50)
knnMatch方法
参数为SIFT、SURF、ORB等计算的描述子;
k,表示取欧式距离最近的前k个关键点;
返回的是匹配的结果DMatch对象;
DMatch的内容
distance,描述子之间的距离,值越低越好;
queryIdx,第一个图像的描述子索引值;
trainIdx,第二个图的描述子索引值;
imgIdx,第二个图的索引值;

drawMatchesKnn
搜索img,kp
匹配图img,kp
match()方法返回的匹配结果

十一 实战FLANN特征匹配

import cv2
import numpy as np

img1=cv2.imread('opencv_search.png')
img2=cv2.imread('opencv_orig.png')

gray1=cv2.cvtColor(img1,cv2.COLOR_BGR2GRAY)
gray2=cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)

#创建SIFT特征
sift=cv2.xfeatures2d.SIFT_create()

#计算描述子与特征
kp1,des1=sift.detectAndCompute(img1,None)
kp2,des2=sift.detectAndCompute(img2,None)

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

#对描述子进行匹配计算
matchs=flann.knnMatch(des1,des2,k=2)

good=[]
for i,(m,n)in enumerate(matchs):
    if m.distance<0.7*n.distance:
        good.append(m)

ret=cv2.drawMatchesKnn(img1,kp1,img2,kp2,[good],None)

cv2.imshow('result',ret)
cv2.waitKey(0)

在这里插入图片描述

十二 图像查找

1 图像查找

特征匹配+单应性矩阵

什么是单应性矩阵
在这里插入图片描述

import cv2
import numpy as np

img1=cv2.imread('opencv_search.png')
img2=cv2.imread('opencv_orig.png')

gray1=cv2.cvtColor(img1,cv2.COLOR_BGR2GRAY)
gray2=cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)

#创建SIFT特征
sift=cv2.xfeatures2d.SIFT_create()

#计算描述子与特征
kp1,des1=sift.detectAndCompute(img1,None)
kp2,des2=sift.detectAndCompute(img2,None)

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

#对描述子进行匹配计算
matchs=flann.knnMatch(des1,des2,k=2)


good=[]

for i,(m,n) in enumerate(matchs):
     if m.distance<0.7*n.distance:
         good.append(m)


if len(good)>=4:
    #print(len(good.trainIdx))
    srcPts = np.float32([kp1[m.queryIdx].pt for m in good]).reshape(-1, 1, 2)
    dstPts = np.float32([kp2[m.trainIdx].pt for m in good]).reshape(-1, 1, 2)

    H, _ = cv2.findHomography(srcPts, dstPts, cv2.RANSAC, 5.0)

    h, w = img1.shape[:2]

    pts = np.float32([[0, 0], [0, h - 1], [w - 1, h - 1], [w - 1, 0]]).reshape(-1, 1, 2)
    dst = cv2.perspectiveTransform(pts, H)

    cv2.polylines(img2, [np.int32(dst)], True, (0, 0, 255))
else:
    print('the number of god is less than 4')
    exit()

ret=cv2.drawMatchesKnn(img1,kp1,img2,kp2,[good],None)

cv2.imshow('resutl',ret)

cv2.waitKey(0)


十三 图像拼接

1 图像合并的步骤

读文件并重置尺寸;
根据特征点和计算描述子,得到单应性矩阵;
图像变换;
图像拼接并输出图像;

import cv2
import numpy as np

#第一步 读取文件,将图片设置成一样大小640x640
#第二步 找特征点,描述子,计算单应性矩阵
#第三步 根据单应性矩阵对图像进行变换,然后平移
#第四步 拼接并输出最终结果

#读取两张图片
img1=cv2.imread('map1.png')
img2=cv2.imread('map2.png')

#将两张同样图片设置成同样大小
img1=cv2.resize(img1,(640,480))
img2=cv2.resize(img2,(640,480))

inputs=np.hstack((img1,img2))
cv2.imshow('input img',inputs)
cv2.waitKey(0)
import cv2
import numpy as np

def stitch_image(img1,img2,H):
#获得每张图片的四个角点
#对图片进行变换(单应性矩阵使图进行旋转,平移)
#创建一张大图,将两张图拼接到一起
#将结果输出

#获得原始图的高/宽
       h1,w1=img1.shape[:2]
       h2,w2=img2.shape[:2]

       img1_dims=np.float32([[0,0],[0,h1],[w1,h1],[w1,0]]).reshape(-1,1,2)
       img2_dims=np.float32([[0,0],[0,h2],[w2,h2],[w2,0]]).reshape(-1,1,2)

       img1_transform=cv2.perspectiveTransform(img1_dims,H)

       result_dims=np.concatenate((img2_dims,img1_transform),axis=0)


       [x_min, y_min] = np.int32(result_dims.min(axis=0).ravel() - 0.5)
       [x_max, y_max] = np.int32(result_dims.max(axis=0).ravel() + 0.5)

#平移的距离
       transform_dist=[-x_min,-y_min]

       transform_array=np.array([[1,0,transform_dist[0]],
                                 [0,1,transform_dist[1]],
                                 [0,0,1]])

       result_img=cv2.warpPerspective(img1,transform_array.dot(H),(x_max-x_min,y_max-y_min))

       result_img[transform_dist[1]:transform_dist[1]+h2,
       transform_dist[0]:transform_dist[0]+w2]=img2

       return result_img

#第一步 读取文件,将图片设置成一样大小640x640
#第二步 找特征点,描述子,计算单应性矩阵
#第三步 根据单应性矩阵对图像进行变换,然后平移
#第四步 拼接并输出最终结果

def get_homo(img1,img2):
#创建特征转换对象
#通过特征转换对象获得特征点和描述子
#创建特征匹配器
#进行特征匹配
#过滤特征,找出有效的特征匹配点
     sift=cv2.xfeatures2d.SIFT_create()

     k1,d1=sift.detectAndCompute(img1,None)
     k2,d2=sift.detectAndCompute(img2,None)

#创建特征匹配
     bf=cv2.BFMatcher()
     matches=bf.knnMatch(d1,d2,k=2)
#过滤特征,找出有效的特征匹配点
     verify_ratio=0.8
     verify_matches=[]
     for m1,m2 in matches:
         if m1.distance<0.8*m2.distance:
             verify_matches.append(m1)

     min_matches=8
     if len(verify_matches)>min_matches:
         img1_pts=[]
         img2_pts=[]

         for m in verify_matches:
             img1_pts.append(k1[m.queryIdx].pt)
             img2_pts.append(k2[m.trainIdx].pt)

         img1_pts=np.float32(img1_pts).reshape(-1,1,2)
         img2_pts=np.float32(img2_pts).reshape(-1,1,2)
         H,mask=cv2.findHomography(img1_pts,img2_pts,cv2.RANSAC,5.0)
         return H
     else:
          print("err:Not enough matches!")
          exit()
#第一步 读取文件,将图片设置成一样大小640x480
#第二步 找特征点,描述子,计算单应性矩阵
#第三步 根据单应性矩阵对图像进行变换,然后平移
#第四步 拼接并输出最终结果

#读取两张图片
img1=cv2.imread('map1.png')
img2=cv2.imread('map2.png')

#将两张同样图片设置成同样大小
img1=cv2.resize(img1,(640,480))
img2=cv2.resize(img2,(640,480))

inputs=np.hstack((img1,img2))

#获得单应性矩阵
H=get_homo(img1,img2)

#进行图像拼接
result_image=stitch_image(img1,img2,H)

cv2.imshow('input img',inputs)
cv2.waitKey(0)
OpenCV提供了多种特征点检测算法,常用的有以下几种: 1. Shi-Tomasi角点检测 Shi-Tomasi角点检测是一种基于Harris角点检测的改进算法,它在计算角点响应函数时使用了更加准确的公式,因此在一些场景下比Harris角点检测更加准确。 在OpenCV中,可以使用`cv2.goodFeaturesToTrack()`函数进行Shi-Tomasi角点检测,该函数的参数包括: - 输入图像 - 要检测的角点数量 - 角点的最小质量(在计算响应函数时,低于该值的角点将被忽略) - 角点之间的最小距离 2. Harris角点检测 Harris角点检测是一种基于图像梯度的方法,它通过计算每个像素周围的像素点的梯度值,来判断该像素是否为角点。 在OpenCV中,可以使用`cv2.cornerHarris()`函数进行Harris角点检测,该函数的参数包括: - 输入图像 - 角点邻域的大小 - Sobel算子的参数k,一般取值为0.04-0.06 - 角点检测结果的精度参数,一般取值为0.01-0.03 3. SIFT特征点检测 SIFT是一种局部特征描述算法,它可以在图像中检测出一些具有鲁棒性的关键点,并对这些关键点进行描述,从而实现图像匹配等任务。 在OpenCV中,可以使用`cv2.xfeatures2d.SIFT_create()`函数创建SIFT检测器,该函数的参数包括: - SIFT特征点的数量 - SIFT特征点的尺度空间 - SIFT特征点的高斯差分空间 4. SURF特征点检测 SURF是一种基于SIFT算法的改进算法,它通过使用快速Hessian矩阵计算方法,加速了SIFT算法的计算过程,从而实现了更快的特征点检测速度。 在OpenCV中,可以使用`cv2.xfeatures2d.SURF_create()`函数创建SURF检测器,该函数的参数包括: - SURF特征点的数量 - SURF特征点的尺度空间 - SURF特征点的Hessian阈值
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值