opencv-特征检测
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角点具有旋转不变性,但缩放后,原来的角点可能就无法检测,如下图
使用步骤:
- 创建SIFT对象
- 进行检测,kp = sift.detect(img, ....)
- 绘制关键点,drawKeypoints(gray,kp,img)。关键点有信息位置,大小和方向
- 计算描述子。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的优点。
- 创建surf对象。surf = cv2.xfeatures2d.SURF_create()
- 检测关键点,计算描述子。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是对已检测到的特征点进行描述,它加快了特征描述建立的速度,同时也极大降低了特征匹配的时间
使用步骤:
- 创建ORB对象。orb = cv2.ORB_create()
- 检测关键点,计算描述子。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(暴力)特征匹配
通过枚举方式进行特征匹配
原理:特征匹配要有两张图,首先计算第一张图的关键点和描述子。然后使用第一张图的每个特征的描述子与第二组中的所有特征描述子进行匹配。计算两者之间的差距,然后将匹配度最接近的一个匹配返回
特征匹配步骤:
- 创建匹配器。bf = BFMatcher(normType, crossCheck)。第一个参数指匹配类型,也就是我们要用哪种方法进行相似度的计算,包括NORM_L1,NORM_L2,NORM_HAMMING1,NORM_HAMMING2,其中NORM_L1,NORM_L2用于对SIFT和SURF描述子进行计算,NORM_HAMMING1是对ORB得到的描述子进行计算,默认为NORM_L2。第二个参数是是否进行交叉匹配(用第一张图描述子去匹配第二张图,得到相似度较高的再用第二张图描述子去匹配第一张图,起检查的作用),默认为false,开启此功能计算时间会变长
- 进行特征匹配。bf.match(des1, des2)。des1是获取到的第一张图的描述子,des2是获取到的第二张图的描述子
- 绘制匹配点(将匹配点通过线连接到一起)。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速度更快。但是由于它使用的是邻近近似值,所以精度较差
使用步骤:
- 创建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)
- 进行特征匹配。flann.match(...)或者是knnMatch(...)。knnMatch():第一二个参数为两张图象计算的描述子,第三个参数为k,表示取欧式距离最近的前k个关键点,即第一张图像中的任何一个描述子与第二张图像中的所有描述子匹配之后最接近的前k个。返回的是DMatch对象,DMatch中包括distance(描述子之间的距离,值越小说明近似度越高),queryIdx(第一个图像的描述子索引值),trainIdx(第二个图像的描述子索引值),imgIdx(第二幅图索引值)
- 绘制匹配点。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()
相关文章:

opencv-特征检测
1,Harris角点检测 如果粉色窗口向四周移动,窗口内的像素没有变化则认定为平坦区域,如果窗口向上移动无明显变化,而左右移动有变化则认定为边缘,如果窗口向任意方向移动均有明显变化则为角点,如下图 dst不是…...

单片机在线升级架构(bootloader+app)
1、架构(bootloaderapp) 在一定的时间内如果没有程序需要更新则自动跳转到app地址执行用户程序 内部flash 512K bootloader 跑裸机 48k 主要实现USB升级和eeprom标志位升级 app 跑freeRtos 464K 程序的基本功能,升级时软件复位开始执行bootloader升级…...

leetcode169. 多数元素,摩尔投票法附证明
leetcode169. 多数元素 给定一个大小为 n 的数组 nums ,返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。 你可以假设数组是非空的,并且给定的数组总是存在多数元素。 示例 1: 输入:nums [3,2,3] 输…...

Pixel Adventure Unity2D开发完整指南
本文参考:2-2. Get and Setup Assets_哔哩哔哩_bilibili 1、下载资源 在Asset Store中下载Pix Adventure1 2的资源: 在import的时候,不用到Scene import进来,如下图所示,Scenes目录反勾选一下。 两个资源都下载完成后…...
signed main()与int main()的区别
刷算法题时为了防止爆int ,通常会开long long #define int long long 但这样int main()会出现问题,main函数的返回值必须是signed或int,由于定义int 为long long 我们只能让返回值变为signed main() #include<bits/stdc.h> using namespace std; #define int long lo…...
【面试宝典】Java基础 这个面试题整理的不全 后期会进行补充
一、equals 和 hashcode 1、简述 hashCode() 和 equals(Object obj) 的作用及其关系 hashCode() 方法用于获取对象的哈希码,即一个整数。这个哈希码在基于哈希的集合(如HashSet、HashMap等)中用于确定对象的存储位置。 equals(Object obj)…...
获取语音文件时长
获取语音文件时长一会儿有一会儿没的,百思不得其解。 错误代码: const getAudioDuration async src > {const audio new Audio(src);const duration await new Promise(resolve > {if (audio.duration) {return resolve(parseInt(audio.duratio…...
应急响应计划:网络安全事件后的快速恢复策略
在数字化时代,网络安全威胁日益严峻,任何企业都无法完全避免遭受网络攻击或数据泄露的风险。因此,制定一套完善的应急响应计划,以便在网络安全事件发生后能够迅速、有效地进行应对和恢复,成为企业保障业务连续性、保护…...

【网络】IP和MAC地址的映射——ARP协议和ARP欺骗概述
目录 引言 ARP的工作机制 ARP欺骗 ARP欺骗的断网行为 ARP欺骗成为中间人 工具介绍 个人主页:东洛的克莱斯韦克-CSDN博客 引言 同一子网内不同主机用数据链路层的MAC地址来寻址,而不是子网内的私有IP(网络层)。数据包中的IP…...

鸿蒙(API 12 Beta3版)【音视频解封装】 文件解析封装
开发者可以调用本模块的Native API接口,完成音视频解封装,即从比特流数据中取出音频、视频等媒体帧数据。 当前支持的数据输入类型有:远程连接(http协议、HLS协议)和文件描述符(fd)。 支持的解封装格式如下: 媒体格式封装格式码…...
智能马桶盖和普通马桶盖有什么不同?
智能马桶盖与普通马桶盖之间存在显著的差异,主要体现在以下几个方面: 一、功能差异 1.清洗功能: 智能马桶盖:配备了清洗功能,包括臀洗、妇洗等,特别针对女性设计了贴心功能,如移动喷水、水流按…...

C# OnnxRuntime部署LivePortrait实现快速、高质量的人像驱动视频生成
目录 效果 说明 项目 模型信息 代码 下载 效果 LivePortrait实现快速、高质量的人像驱动视频生成 说明 官网地址:https://github.com/KwaiVGI/LivePortrait 代码实现参考:https://github.com/hpc203/liveportrait-onnxrun 模型下载:…...

Spring boot框架指南
1. Spring Boot 概述 1.1 定义与起源 Spring Boot是一种基于Spring框架的开源框架,旨在简化Spring应用程序的创建和开发过程。它通过提供一系列默认配置和自动配置功能,减少了开发者在配置上的工作量,使得快速搭建生产级别的Spring应用程序…...

数据结构--树与二叉树
数据结构分类 集合 线性结构(一对一) 树形结构(一对多) 图结构(多对多) 数据结构三要素 1、逻辑结构 2、数据的运算 3、存储结构(物理结构) 树的概念 树的分类 满二叉树和完全二叉树 二叉排序树 平衡二叉树 二叉树分类总结 二叉树的存储结构 …...
C#项目实战经验——计时方法总结
前言 我们在开发C#程序的过程中经常需要计算某段程序执行的时间,比如调用的某个算法的时间,这时候我们就需要利用计时工具,本文就是详细介绍在C#中我们常用哪些计时工具。 1、计时方法—StopWatch 在C#中我们可以利用Stopwatch这个类来实现…...
电子盖章软件哪个好|盖章软件
在选择电子盖章软件时,需要考虑多个因素,包括软件的功能、安全性、易用性、兼容性以及成本等。以下是根据当前市场情况推荐的一些优秀的电子盖章软件: e章宝: 功能丰富:e章宝是国内领先的电子盖章系统,功能…...

ThreejsWebGPU运动残影demo
功能点 实例化SkinnedMesh 修改NodeMaterial着色器 节点材质系统 shader 语言 使用uniform和attribute 中合其他几篇博客中的内容 代码仓库 克隆后需要放到three源码同级别目录下 运行 three源码部分不在git仓库中(太大了) 使用vscode的live-server启动后访问 http://127.0.0.…...

HttpSession常用方法
1.HttpSession常用方法 是在Java Servlet中用来管理会话状态的重要接口,它提供了一种在多个请求或页面之间存储用户特定信息的方式。以下是一些 HttpSession 常用的方法和用法: 获取会话对象: HttpSession session request.getSession();…...

【JavaEE初阶】文件操作和IO
目录 🌴认识文件 🚩树型结构组织和目录 🚩文件路径(Path) 🚩 文件分类 🎍Java 中操作文件 🚩 File 概述: 📌属性 📌构造方法 Ὄ…...

存储器芯片的基本原理
目录 1.存储元 1.1栅极电容 1.2双稳态触发器 2.存储单元 3.存储体 4.存储器 5.容量计算 6.寻址 1.存储元 1.1栅极电容 给MOS管一个阈值电压(5v)就能够导电,若是不给那么就是一个绝缘体不会导电。 读出二进制原理: 通常…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...

【Python】 -- 趣味代码 - 小恐龙游戏
文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...

8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...
【解密LSTM、GRU如何解决传统RNN梯度消失问题】
解密LSTM与GRU:如何让RNN变得更聪明? 在深度学习的世界里,循环神经网络(RNN)以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而,传统RNN存在的一个严重问题——梯度消失&#…...

HTML 列表、表格、表单
1 列表标签 作用:布局内容排列整齐的区域 列表分类:无序列表、有序列表、定义列表。 例如: 1.1 无序列表 标签:ul 嵌套 li,ul是无序列表,li是列表条目。 注意事项: ul 标签里面只能包裹 li…...

华为OD机试-食堂供餐-二分法
import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...
【AI学习】三、AI算法中的向量
在人工智能(AI)算法中,向量(Vector)是一种将现实世界中的数据(如图像、文本、音频等)转化为计算机可处理的数值型特征表示的工具。它是连接人类认知(如语义、视觉特征)与…...
MySQL中【正则表达式】用法
MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现(两者等价),用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例: 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...

dify打造数据可视化图表
一、概述 在日常工作和学习中,我们经常需要和数据打交道。无论是分析报告、项目展示,还是简单的数据洞察,一个清晰直观的图表,往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server,由蚂蚁集团 AntV 团队…...
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...