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)就能够导电,若是不给那么就是一个绝缘体不会导电。 读出二进制原理: 通常…...

前端实习手记(7):立秋快乐
这周相比上周感觉挺好的哈哈哈,可能只有自己感觉蛮好的,旁边师父忙的飞起了要,不仅赶工作还要回答我乱七八糟的问题(心疼一秒)。这周也是立秋&七夕咯,立秋快乐哇家人们(虽然还是很热嘛&…...

感恩放下,笑对人生,在人生的长河中,每一天都是独特的篇章,或顺心如意,或充满挑战
在人生的长河中,每一天都是独特的篇章,或顺心如意,或充满挑战。然而,无论今日的经历如何,我们都应怀着感恩与放下的心态,因为人生的旅程远不止这短暂的一天,明天依然充满希望,等待我们继续努力前行。 生活,犹如一场变幻莫测的舞台剧,顺心之时,我们仿佛置身于温暖的…...

URLSession之初窥门径
NSURLSession 于 2013 年随 iOS 7 的发布一起面世,苹果将其定位为 NSURLConnection 的替代者。我们使用最广泛的第三方框架如 AFNetworking 和 SDWebImage 的最新版也都已经全面切换至 NSURLSession。 NSURLSession 不仅仅指代同名类 NSURLSession,它还…...

ios创建控制器的3种方法实现页面跳转
ios遵守mvc设计模式,下面介绍创建控制器viewcontroller的几种方法,来实现页面的跳转 1.纯代码创建 // // AppDelegate.m // study2024 // // Created by zhifei zhu on 2024/8/7. //#import "AppDelegate.h" #import "MyViewContro…...

Android逆向题解-boomshakalaka-3-难度5
这个app 是一个cocos游戏,没有用脚本实现,纯c实现。 题目描述:play the game, get the highest score 题目要求是玩游戏得到最高分就可以得到flag,是写到配置文件的,初始flag值看着是base编码的。 核心代码在so里面的ControlLay…...

Linux(Ubuntu 22.04)系统中固定串口
Linux(Ubuntu 22.04)系统中固定串口 文章目录 前言正文查看linux串口信息修改udev固化串口校验是否修改完成 注意 前言 在Linux系统中固定串口(通常指的是串行通信接口,如/dev/ttyS0或/dev/ttyUSB0)的原因有几个方面&…...

LeetCode - 209 - 长度最小的子数组
力扣209题 题目描述:长度最小的子数组 给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其总和大于等于 target 的长度最小的 子数组 [numsl, numsl1, ..., numsr-1, numsr] ,并返回其长度**。**如果不存在符合条件的子数组&…...

探索空间计算与VR中的手势跟踪新纪元:XHand框架详解
在虚拟现实(VR)和扩展现实(XR)技术日新月异的今天,手势跟踪作为实现沉浸式体验的关键技术之一,正逐步从概念走向成熟。今天,我们将深入探索一个创新的框架——XHand,它以其卓越的性能和先进的技术亮点,为空间计算与VR领域的手势跟踪带来了全新的解决方案。 XHand框架…...

leetcode + 项目复习
上午 Leetcode算法 参考文章——代码随想录 1. KMP 概念 主要应用 字符串匹配 主要思想 根据之前匹配的信息,当发现字符串不匹配时,避免从头开始匹配。 什么是前缀表(next数组、prefix) 是用来回退的,当文本串和…...

树莓派4/5:设置apt、pip、conda首选清华镜像源
一、教程简介 在中国大陆地区,使用清华镜像源可以显著缩短资源下载时间。 本教程介绍如何将清华镜像源设置为树莓派的apt、pip、conda下载的首选项(默认项)。其中,apt和pip为树莓派系统自带,conda则需要安装miniforg…...