opencv-特征检测

news2024/11/27 10:29:53

1,Harris角点检测

如果粉色窗口向四周移动,窗口内的像素没有变化则认定为平坦区域,如果窗口向上移动无明显变化,而左右移动有变化则认定为边缘,如果窗口向任意方向移动均有明显变化则为角点,如下图

dst不是输入参数,是输出参数,输出检测出来的角点 

 

2,Shi-Tomasi角点检测

 Shi-Tomasi是Harris角点检测

Harris角点检测算的稳定性和k有关,而k是个经验值,不是设定最佳值。而Shi-Tomasi好处(区别)在于不需要再对k值进行设定

第一个参数maxCorners是要检测的角点数量,无限制就是把能检测到的角点全部输出。qualityLevel是角点质量,实际上就是Harris检测时的代码img[dst>0.01*dst.max()],将很小的角点去掉,使用ShiTimasi方法就不用这一步了,直接在参数内填数值即可。第三个参数minDistance指两个交点间最小的距离,如果小于所设定的最小距离,则角点会舍弃只保留一个。第四个参数mask就是掩码,要检测哪个区域就创建一个mask,只保留要检测的区域,其他区域变为黑色。第五个参数blockSize与Harris相同。第六个参数useHarrisDetector,如果是true则使用Harris角点检测方法,如果是False则使用Shi-Tomasi检测方法,默认为false。第七个参数k是在第六个参数为true时启用的默认为0.04

import numpy as np
import cv2
img = cv2.imread('2.jpg')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
qualityLevel = 0.01#相当于之前的img[dst>0.01*dst.max()]
#Shi-Tomasi角点检测。获取的角点存在corners中,输出的corners是一个三维数组且有小数点
corners = cv2.goodFeaturesToTrack(gray,1000,qualityLevel,5)
#将corners数组中的浮点型数据转换为整型
corners = np.int64(corners)
#Shi-Tomasi绘制角点
for i in corners:
    x,y = i.ravel()#corners中的数组为多维数组,这里转换成一维数组
    cv2.circle(img,(x,y),3,255,-1)#-1画实心圆
cv2.imshow('img',img)
cv2.waitKey(0)

未进行整型转换的corners是一个三维数组且有小数点 

 

进行整型转换后的corners

 

corners[1]输出内容为一个二维数组

 

进行corners[1].ravel()操作后,corners[1]变为一维数组

 

3,SIFT特征检测

具体原理可以查看文章:SIFT算法原理-CSDN博客

Harris角点具有旋转不变性,但缩放后,原来的角点可能就无法检测,如下图

使用步骤:

  1. 创建SIFT对象
  2. 进行检测,kp = sift.detect(img, ....) 
  3. 绘制关键点,drawKeypoints(gray,kp,img)。关键点有信息位置,大小和方向
  4. 计算描述子。kp,des=sift.compute(img,kp),des为返回的描述子,为一个二维数组,每个数组内都有很多数据记录关键点信息。描述子记录了关键点周围对其有贡献的像素点的一组向量值,其不受仿射变换,光照变换等影响。描述子主要用于特征匹配
  • opencv为我们提供了一个可以同时计算关键字和描述子的函数
  • kp, des = sift.detectAndCompute(img, mask)。mask可以指明对哪个区域进行计算
import numpy as np
import cv2
img = cv2.imread('2.jpg')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
#创建SIFT对象
sift = cv2.xfeatures2d.SIFT_create()
#进行检测
kp = sift.detect(gray, None)#第二个参数可以设置一个掩码,对某区域进行检测,设为None表示对整 #张图进行检测
#绘制关键点
cv2.drawKeypoints(gray, kp, img)#在img图像上绘制
#计算描述子
kp, des = sift.compute(gray, kp)#返回两个结果,第一个结果kp还是关键点,第二个参数是每个关键 
 #点对应的特征向量,des.shape输出结果为(关键点数量,128)即每个关键点特征向量为128维
cv2.imshow('SIFT', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
import numpy as np
import cv2
img = cv2.imread('2.jpg')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
#创建SIFT对象
sift = cv2.xfeatures2d.SIFT_create()
#进行检测
kp, des = sift.detectAndCompute(gray, None)
#绘制关键点
cv2.drawKeypoints(gray, kp, img)#在img图像上绘制
cv2.imshow('SIFT', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

 4,SURF特征检测

SIFT最大的问题就是速度慢,而SURF速度更快,并且保留了SIFT的优点。

  1. 创建surf对象。surf = cv2.xfeatures2d.SURF_create()
  2. 检测关键点,计算描述子。kp, des = surf.detectAndCompute(img, mask)
import numpy as np
import cv2
img = cv2.imread('2.jpg')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
#创建SURF对象
surf = cv2.xfeatures2d.SURF_create()
#进行检测并计算描述子
kp, des = surf.detectAndCompute(gray, None)#第二个参数可以设置一个掩码,对某区域进行检测,设为None表示对整张图进行检测
#绘制关键点
cv2.drawKeypoints(gray, kp, img)#在img图像上绘制
cv2.imshow('SURF', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

5,ORB特征检测

ORB可以做到实时监测,也就是它的计算速度很快。ORB是FAST和BRIEF两种技术的结合,他的计算速度均高于两者,但准确度却不如两者。而且ORB是没有版权的,放在Opencv主库

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

使用步骤:

  1. 创建ORB对象。orb = cv2.ORB_create()
  2. 检测关键点,计算描述子。kp, des = orb.detectAndCompute(img, mask)
import numpy as np
import cv2
img = cv2.imread('2.jpg')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
#创建ORB对象
orb = cv2.ORB_create()
#进行检测并计算描述子
kp, des = orb.detectAndCompute(gray, None)#第二个参数可以设置一个掩码,对某区域进行检测,设为None表示对整张图进行检测
#绘制关键点
cv2.drawKeypoints(gray, kp, img)#在img图像上绘制
cv2.imshow('SURF', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

6,BF(暴力)特征匹配

通过枚举方式进行特征匹配

原理:特征匹配要有两张图,首先计算第一张图的关键点和描述子。然后使用第一张图的每个特征的描述子与第二组中的所有特征描述子进行匹配。计算两者之间的差距,然后将匹配度最接近的一个匹配返回

特征匹配步骤:

  1. 创建匹配器。bf = BFMatcher(normType, crossCheck)。第一个参数指匹配类型,也就是我们要用哪种方法进行相似度的计算,包括NORM_L1,NORM_L2,NORM_HAMMING1,NORM_HAMMING2,其中NORM_L1,NORM_L2用于对SIFT和SURF描述子进行计算,NORM_HAMMING1是对ORB得到的描述子进行计算,默认为NORM_L2。第二个参数是是否进行交叉匹配(用第一张图描述子去匹配第二张图,得到相似度较高的再用第二张图描述子去匹配第一张图,起检查的作用),默认为false,开启此功能计算时间会变长
  2. 进行特征匹配。bf.match(des1, des2)。des1是获取到的第一张图的描述子,des2是获取到的第二张图的描述子
  3. 绘制匹配点(将匹配点通过线连接到一起)。cv2.drawMatches(img1, kp1, img2, kp2.....),img1和kp1是指原图和关键点,img2和kp2是指匹配的图和其关键点。最后一个参数就是match()方法返回的匹配结果
import numpy as np
import cv2
img1 = cv2.imread('1.jpg')
img2 = cv2.imread('2.jpg')
g1 = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
g2 = cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)
#创建SIFT对象
sift = cv2.xfeatures2d.SIFT_create()
#进行检测,并计算描述子
kp1, des1 = sift.detectAndCompute(g1,None)
kp2, des2 = sift.detectAndCompute(g2,None)
bf = cv2.BFMatcher(cv2.NORM_L1)
match = bf.match(des1,des2)
img3 = cv2.drawMatches(img1,kp1,img2,kp2,match,None)
cv2.imshow('SIFT', img3)
cv2.waitKey(0)
cv2.destroyAllWindows()

7,FLANN特征匹配

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

使用步骤:

  1. 创建FLANN匹配器。FlannBasedMatcher(index_params)。第一个参数是index_params字典,主要填入的是匹配算法KDTREE或LSH.如果是SIFT和SURF计算的描述子则使用KDTREE算法,如果是ORB计算的描述子则使用LSH算法。如果使用了KDTREE算法则要设置第二个参数search_params字典,指定KDTREE算法中遍历树的次数。  由于要填入的参数是字典,所以KDTREE通常设置为index_params = dict(algorithm = FLANN_INDEX_KDTREE, tree = 5):FLANN_INDEX_KDTREE实际上代表1,填成1即可,填成0表示使用的是LSH算法,tree是经验值填5。serch_params = dict(checks = 50)
  2. 进行特征匹配。flann.match(...)或者是knnMatch(...)。knnMatch():第一二个参数为两张图象计算的描述子,第三个参数为k,表示取欧式距离最近的前k个关键点,即第一张图像中的任何一个描述子与第二张图像中的所有描述子匹配之后最接近的前k个。返回的是DMatch对象,DMatch中包括distance(描述子之间的距离,值越小说明近似度越高),queryIdx(第一个图像的描述子索引值),trainIdx(第二个图像的描述子索引值),imgIdx(第二幅图索引值)
  3. 绘制匹配点。cv2.drawMatches(...)或者是drawMatchesKnn(...)【如果特征匹配选择KnnMatch则用此方法】。drawMatchesKnn(...):参数与drawMatches(...)相同
import numpy as np
import cv2
img1 = cv2.imread('img1.jpg')
img2 = cv2.imread('img2.jpg')
g1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
g2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
sift = cv2.xfeatures2d.SIFT_create()
kp1, des1 = sift.detectAndCompute(g1, None)
kp2, des2 = sift.detectAndCompute(g2, 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('ret', ret)
cv2.waitKey(0)
cv2.destroyAllWindows()

8,实例练习:图像查找

图像查找用到了 特征匹配+单应性矩阵。特征匹配得到结果后可以把它当作输入来计算单应性矩阵,拿到单应性矩阵再经过透视变换就可以获取到最终的图像了。当我们需要通过一张图去找另一张图时,通过以上步骤就可以找到

单应性矩阵:通过单应性矩阵可以让图像由一个视角转换到另一个视角

在上述FLANN文件下,只需要利用获取的匹配点matches计算单应性矩阵,然后利用单应性矩阵通过透视变换最后找到想找的图像

import numpy as np
import cv2
img1 = cv2.imread('img1.jpg')
img2 = cv2.imread('img2.jpg')
g1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
g2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
sift = cv2.xfeatures2d.SIFT_create()
kp1, des1 = sift.detectAndCompute(g1, None)
kp2, des2 = sift.detectAndCompute(g2, 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)
#计算单应性矩阵H时,输入特征点必须大于等于4
if len(good) >= 4:
    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)
    #找到单应性矩阵,cv2.RANSAC是对匹配点的过滤,过滤到错误匹配的点。
    #该函数有两个返回值,第一个返回值H是需要的单应性矩阵,第二个参数是掩码,我们不需要所以用_代替即可
    H, _ =cv2.findHomography(srcPts, dstPts, cv2.RANSAC, 5.0)
    #透视变换
    #pts是原图的四个角点
    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, (255,0,0))
else:
    print('there are no matches')
    exit()
ret = cv2.drawMatchesKnn(img1, kp1, img2, kp2, [good], None)
cv2.imshow('ret', ret)
cv2.waitKey(0)
cv2.destroyAllWindows()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2044950.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MSSQL暴力破解

一、基本信息 靶机&#xff1a;IP&#xff1a;192.168.100.70 二、攻击过程 方法一&#xff1a;msfconsole 启动 msfconsole msfconsole 选用攻击模块&#xff0c;并设置参数 use auxiliary/scanner/mssql/mssql_login set rhosts 192.168.100.70 set USER_FILE /userna…

探舟数字与周村古商城景区携手签署AI导游导览合作协议

导语&#xff1a; 近日&#xff0c;国内领先的科技公司广州探舟数字科技有限公司&#xff08;以下简称探舟数字&#xff09;与国家5A级景区创建单位、国家级夜间文化和旅游消费集聚区山东周村古商城正式签署合作协议&#xff0c;共同推进AI导游导览系统的全面应用。此次合作标…

【Java数据结构】---List(ArrayList)

乐观学习&#xff0c;乐观生活&#xff0c;才能不断前进啊&#xff01;&#xff01;&#xff01; 我的主页&#xff1a;optimistic_chen 我的专栏&#xff1a;c语言 &#xff0c;Java 欢迎大家访问~ 创作不易&#xff0c;大佬们点赞鼓励下吧~ 文章目录 前言线性表顺序表&#x…

虚幻5|给武器添加碰撞检测与伤害

本章内容衔接上两章&#xff0c;需要完成上两章才能用本章内容 虚幻5|角色武器装备的数据库学习&#xff08;不只是用来装备武器&#xff0c;甚至是角色切换也很可能用到&#xff09;-CSDN博客虚幻5|普通攻击&#xff0c;使用接口更方便-CSDN博客 如有疑问&#xff0c;可访问…

TinyGPT-V:微型视觉语言模型【VLM】

AI技术正在不断融入我们的日常生活。人工智能的一个应用包括多模态化&#xff0c;例如将语言与视觉模型相结合。这些视觉语言模型可以应用于视频字幕、语义搜索等任务。 本周&#xff0c;我将重点介绍一种名为 TinyGPT-V&#xff08;Arxiv | GitHub&#xff09;的最新视觉语言…

QT:Telnet客户端与服务器的创建

客户端 telnetClient类 #ifndef TELNETCLIENT_H #define TELNETCLIENT_H#include <QObject> #include <QTcpSocket>class TelnetClient : public QObject {Q_OBJECTpublic:explicit TelnetClient(QObject *parent nullptr);~TelnetClient();// 连接到指定的主机…

智慧节能节水设备远程监控解决方案

智慧节能节水设备远程监控解决方案&#xff0c;作为现代物联网技术与环保理念深度融合的产物&#xff0c;旨在通过高度集成的传感器网络、大数据分析及云计算平台&#xff0c;实现对各类节能节水设施的精细化管理和实时监控&#xff0c;从而大幅度提升资源利用效率&#xff0c;…

eNSP 华为三层交换机实现VLAN间通信

华为三层交换机实现VLAN间通信 三层交换机&#xff1a; <Huawei>sys [Huawei]sys SW-3 [SW-3]vlan batch 10 20 [SW-3]int vlan 10 [SW-3-Vlanif10]ip address 192.168.10.254 24 [SW-3-Vlanif10]int vlan 20 [SW-3-Vlanif20]ip add 192.168.20.254 24 [SW-3-Vlanif20]in…

Qt登录窗口设计

widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QIcon> //图标类 #include <QPushButton> #include <QLineEdit> //行编辑 #include <QLabel> #include <QTextEdit> #include <QMovie>class Widge…

专业名词理解(一):鲁棒性和泛化能力

目录 前言 一、鲁棒性&#xff08;Robustness&#xff09; 二、泛化能力&#xff08;Generalization&#xff09; 总结 前言 鲁棒性&#xff08;Robustness&#xff09;和泛化能力&#xff08;Generalization&#xff09;是机器学习和人工智能模型的重要特性&#xff0c;它…

CDD数据库文件制作(四)——服务配置(0x11)

目录 1.子功能创建2.会话切换配置2.1.根据诊断调查表进行信息提取(0x1101)2.2.会话转换配置(0x1101)2.3.根据诊断调查表进行信息提取(0x1102)2.4.会话转换配置(0x1102)2.5.根据诊断调查表进行信息提取(0x1103)2.6.会话转换配置(0x1103)2.7.会话切换配置完成后效果图…

R9 9900X R9 9950X评测:看完觉得7800X3D更香了

原文转载修改自&#xff08;更多互联网新闻/搞机小知识&#xff09;&#xff1a; R9 9900X R9 9950X评测&#xff1a;能效提升&#xff0c;温度下降 R9 9900X R9 9950X基础规格 注&#xff1a;评测信息来自外媒Wccftech 老规矩&#xff0c;先介绍一下这两款锐龙9000旗舰CPU的…

【笔记1-7】Qt bug记录:error C2371: QStringList重定义;不同的基类型,Qt6无法使用QStringList

在Qt5工程升级到Qt6的过程中&#xff0c;出现了QStringList重定义的问题 一开始尝试在其他文件中使用QStringList&#xff0c;结果是Qt5.9.4版本怎么使用都没有问题&#xff0c;而Qt6.7.2在其他文件中写同样的代码也会有问题 通过调查Qt源码&#xff0c;发现是Qt6对qcontainer…

栈与计算—— 150、227、224※

150. 逆波兰表达式求值&#xff08;中等&#xff09; 给你一个字符串数组 tokens &#xff0c;表示一个根据 逆波兰表示法 表示的算术表达式。 请你计算该表达式。返回一个表示表达式值的整数。 注意&#xff1a; 有效的算符为 、-、* 和 / 。每个操作数&#xff08;运算对象&a…

web前端之实现一只可爱的小杰尼乌龟、伪元素、动画

MENU 前言效果图htmlstyle 前言 代码段使用HTML和CSS创建一个“杰尼龟”的动画。 效果图 html <div class"squirtle"><div class"tail"></div><div class"body"><div class"stomach"></div><d…

了解数据库中常用存储引擎数据结构(1)

目录 引言 存储引擎和存储结构 两者的关系 存储结构 分类 1. 按数据组织方式分类 2. 按索引结构分类 3. 按存储介质分类 4. 按数据分布方式分类 5. 按数据冗余和备份分类 存储结构需要的特性 BTree 补充知识&#xff1a;Lock和Latch的区别&#xff08;存储引擎并发…

干货分享|如何使用Stable Diffusion快速打造瞬息全宇宙?

Deforum也是一款文生视频插件&#xff0c;它把提示词跃迁和运镜结合到一起&#xff0c;生成的视频让人仿佛穿越不同时空&#xff0c;因此又被称作瞬息全宇宙。本节将介绍使用Deforum生成视频的方法。 在使用Deforum时&#xff0c;由于设置参数非常多&#xff0c;初次使用时很难…

【C语言篇】编译和链接以及预处理介绍(下篇)

文章目录 前言#和###运算符##运算符 命名约定#undef命令⾏定义条件编译#if和#endif多个分支的条件编译判断是否被定义嵌套指令 头文件被包含头文件被包含的方式本地文件包含库文件的包含 嵌套文件包含 其他预处理指令 写在最后 前言 本篇接前一篇【C语言篇】编译和链接以及预处…

fvm 管理多个 flutter 版本

前言&#xff1a; flutter SDK 版本更新还是比较快的&#xff0c;新的特性带来了新的体验&#xff0c;更新频繁也是好的事情。一方面说明 flutter 社区活跃&#xff0c;另一方面 说明 flutter 进化的脚本并没有停下。这样也会带来另一个问题&#xff0c;如果多个项目 使用了不…

详解Python 66 个内置函数!附代码

大家好&#xff0c;想掌握Python编程语言&#xff0c;从零基础的小白晋升为大神&#xff1f;没问题&#xff01;接下来我们将以轻松有趣的方式&#xff0c;逐一解锁Python的66个内置函数&#xff0c;每一步都将结合实际应用场景、函数功能解析及简洁代码演示&#xff0c;带你深…