SIFT算法详细原理与应用

SIFT算法详细原理与应用

1 SIFT算法由来

1.1 什么是 SIFT?

SIFT,全称为 Scale-Invariant Feature Transform(尺度不变特征变换),是一种用于图像特征检测和描述的经典算法。它通过提取图像中的局部关键点,并为每个关键点生成具有尺度和旋转不变性的描述子,使其能够在不同的图像中进行特征匹配。SIFT 算法尤其适合处理视角变化、尺度变换、部分遮挡和光照变化的问题,因此被广泛应用于计算机视觉领域。通过sift算法可生成图像的特征向量(128维),对图像特征向量可以理解为图像的细节纹理特征,它具有光照,角度,尺寸大小不变性,一个特征向量可能为某个人脸图像的局部一个特征纹理,比如为人脸图像中鼻子的特征,不同人脸图像的鼻子特征是不同的,故,通过收集人脸图像的所有特征向量,可以进行人脸识别,图像匹配等场景。

1.2 SIFT 的发展历程

SIFT 由计算机科学家 David G. Lowe 于 1999 年首次提出,并在 2004 年发表的论文《Distinctive Image Features from Scale-Invariant Keypoints》中进一步完善。其革命性的设计使得 SIFT 成为了特征提取领域的重要里程碑。
虽然 SIFT 曾因专利保护限制了开源使用,但随着专利过期(美国专利于 2020 年到期),SIFT 再次成为开源社区的重要工具,并在许多实际项目中被广泛应用。

此外,SIFT 的思想也启发了许多后续算法的诞生,例如 SURF(Speeded-Up Robust Features)和 ORB(Oriented FAST and Rotated BRIEF),进一步推动了特征提取技术的发展。

2 SIFT算法详细原理

  • 根据高斯函数生成高斯金字塔
    生成高斯金字塔的作用可以理解为 通过相机调整距离物体的距离拍摄的物理,实际上对于物体本身,不管相机距离物体的距离远近,总有一些特征是不变的,比如物体的边缘及轮廓等。
    高斯金字塔底层的图像可以理解为相机近距离拍摄物体的图像,顶层可以理解为相机远距离拍摄物体的图像。故sift具有图像尺寸不变性及旋转不变性(再生成种子时会进行角度旋转变换及归一化处理),而角点检测算法Harris只具有旋转不变性
    在这里插入图片描述
    通过模拟不同距离的图像,尽可能的找到图像的所有特征点

  • 根据高斯金字塔生成差分金字塔(DOG)
    在这里插入图片描述
    通过对高斯金字塔同一组中相邻的图像进行相减,得到DOG差分图像

  • 根据DOG差分图像找到关键点(极值点)
    在这里插入图片描述
    为了寻找尺度空间的极值点,每一个采样点要和它所有的相邻点比较,看其是否比它的图像域和尺度域的相邻点大或者小。如图所示,中间的检测点和它同尺度的8个相邻点和上下相邻尺度对应的9×2个点共26个点比较,以确保在尺度空间和二维图像空间都检测到极值点。 一个点如果在DOG尺度空间本层以及上下两层的26个领域中是最大或最小值时,就认为该点是图像在该尺度下的一个特征点,如图所示。

  • 关键点过滤
    真正的关键点都是灰度值在,x,y方向都有明显变化的,即:一个定义不好的高斯差分算子的极值在横跨边缘的地方有较大的主曲率,而在垂直边缘的方向有较小的主曲率。

  • 根据找到的关键点计算出对应的描述子

    • 计算关键点周围领域的直方图(包括变化尺度,角度(角度可以分为8个方向)),得出当前关键点的主方向(变换尺度最大的为主方向)
      在这里插入图片描述
      通过对每个关键点领域做直方图计算,可以得到该关键点的主方向及大小,由此每个关键点有三个基本的属性:(关键点位置,主方向(与x轴的角度),主方向的大小)
    • 对关键点周围领域进行旋转,将主方向旋转成与x方向一致的方向,以确保旋转不变性
      在这里插入图片描述
    • 将关键点领域分为4x4的 16个子区域,每个子区域分别计算他们的直方图,然后生成由右图组成的16个种子,每个种子包含八个方向的变化尺度。
      在这里插入图片描述
    • 生成描述子
      根据关键点生成的16个种子的八维向量,组成一个4x4x8-128维的向量。再将特征向量进行归一化(就是使的特征向量的值1,成为单位向量)。即每一个关键点就能得到一个128维的向量,也成为一个关键点的描述子。
  • 两个图像描述子的匹配
    通过sift算法分别生成两个图像的各自的多个描述子,分别计算两个图像描述子向量之间的距离,计算两个向量的距离有多种
    计算两个向量的距离有多种方式

    • 曼哈顿距离欧氏距离
    • 欧氏距离
    • 切比雪夫距离
    • 闵可夫斯基距离
    • 标准化欧式距离
    • 余弦距离
    • 汉明距离
    • 杰卡德距离
    • 马氏距离
      具体详见:9个机器学习算法常见距离计算公式

详见:
经典算法研究(1):SIFT算法1
SIFT算法详解
SIFT 全面解析:原理、实现与应用
经典的图像匹配算法----SIFT

3 SIFT算法应用

详见:OpenCV入门学习笔记之Harris角点检测与SIFT特征匹配算法

3.1 cv2中sift算法的使用

""" SIFT,全称为 Scale-Invariant Feature Transform(尺度不变特征变换)"""
src_img = cv2.imread('resources/sift_2.jpg')img = copy.deepcopy(src_img)
gray1 = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)gray = copy.deepcopy(gray1)# SIFT检测器
sift = cv2.SIFT_create()# 找出图像中的关键点
kp = sift.detect(gray, None)# 在图中画出关键点
sift_src_img = cv2.drawKeypoints(img, kp, img, color=(255, 0, 0), flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)sift_gray_img = cv2.drawKeypoints(gray, kp, gray, color=(255, 0, 0),flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)# 计算关键点对应的SIFT特征向量
# kp, des = sift.compute(gray, kp)# 调整子图间距
plt.subplot(1, 2, 1), plt.imshow(src_img), plt.title('Origin')
plt.subplot(1, 2, 2), plt.imshow(sift_src_img), plt.title('Sift_Origin')
# plt.subplot(2, 2, 3), plt.imshow(gray, cmap='gray'), plt.title('Gray')
# plt.subplot(2, 2, 4), plt.imshow(sift_gray_img, cmap='gray'), plt.title('Sift_Gray')
plt.show()

在这里插入图片描述
其中右图中的每个关键点是由位置,方向,方向大小组成,通过断点调试可以看到这些信息均包含在kp数组里
在这里插入图片描述

3.2 cv2中sift算法进行图像拼接

如下图有不同角度拍摄的书面,两个图片有共同部分,也有不同部分,现在要对这两个图片进行拼接,共同组成一个完整的图片。

请添加图片描述

左图
请添加图片描述

右图

拼接的过程:
1, 通过sift求出两个图片的特征向量
2,通过knn匹配算法找到两个图片的多对(四队以上)相互匹配的关键点坐标
3,通过四对关键点坐标对B图像进行投射变换
4,A图像与变换后的B图像进行拼接得到原图
下面是完整的

import copy
import time
from datetime import datetime
from typing import Anyimport cv2
import numpy as np
import matplotlib
import matplotlib.pyplot as plt#  modify backend to TkAgg
matplotlib.use('TkAgg')# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']  # 使用黑体
plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题#  modify backend to TkAgg
matplotlib.use('TkAgg')# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']  # 使用黑体
plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题class SIFT():def __init__(self):passdef sift_keypoints_draw(self):""" SIFT,全称为 Scale-Invariant Feature Transform(尺度不变特征变换)"""src_img = cv2.imread('resources/sift_2.jpg')img = copy.deepcopy(src_img)gray1 = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)gray = copy.deepcopy(gray1)# SIFT检测器sift = cv2.SIFT_create()# 找出图像中的关键点kp = sift.detect(gray, None)# 在图中画出关键点sift_src_img = cv2.drawKeypoints(img, kp, img, color=(255, 0, 0), flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)sift_gray_img = cv2.drawKeypoints(gray, kp, gray, color=(255, 0, 0),flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)# 计算关键点对应的SIFT特征向量# kp, des = sift.compute(gray, kp)# 调整子图间距plt.subplot(1, 2, 1), plt.imshow(src_img), plt.title('Origin')plt.subplot(1, 2, 2), plt.imshow(sift_src_img), plt.title('Sift_Origin')# plt.subplot(2, 2, 3), plt.imshow(gray, cmap='gray'), plt.title('Gray')# plt.subplot(2, 2, 4), plt.imshow(sift_gray_img, cmap='gray'), plt.title('Sift_Gray')plt.show()def image_sift(self, src_image_a, src_image_b):# 对两个图像通过sift 分别求出各自的特征向量,根据特征向量求出两个图像的所有相同的部分的点坐标信息,并返回""" SIFT,全称为 Scale-Invariant Feature Transform(尺度不变特征变换)"""gray_a = cv2.cvtColor(src_image_a, cv2.COLOR_BGR2GRAY)gray_b = cv2.cvtColor(src_image_b, cv2.COLOR_BGR2GRAY)# generate kps and feature vectorsift = cv2.SIFT_create()(kps_a, features_a) = sift.detectAndCompute(gray_a, None)(kps_b, features_b) = sift.detectAndCompute(gray_b, None)n_kps_a = np.float32([kp.pt for kp in kps_a])n_kps_b = np.float32([kp.pt for kp in kps_b])# feature vector matchratio = 0.95n = 2matcher = cv2.BFMatcher()# 获取两个图像之间所有的匹配点(通过knn算法 进行匹配 对于A图像的每个匹配点,都在B中找到两个最近的匹配点)raw_matches = matcher.knnMatch(features_a, features_b, n)good_matches = []# 通过第一匹配点与第二匹配点的距离差异大小,过滤掉可能为不真实的匹配点for match in raw_matches:if match[0].distance < ratio * match[1].distance:good_matches.append(match[0])if len(good_matches) < 4:print("numbers of match points is less than 4")# 求透视矩阵(用RANSAC方法)# 关于重投影阈值的取值,1:可以根据应用场景来取"""应用场景	                    推荐阈值范围	说明高精度匹配(如标定板、AR 标记)	1.0~3.0	    适用于特征点位置非常准确的场景图像拼接(SIFT/SURF/ORB 匹配)	3.0~5.0	    平衡噪声和精度动态场景或低质量图像	            5.0~10.0	容忍更大的匹配误差"""src_pts = np.float32([n_kps_b[match.trainIdx] for match in good_matches])dst_pts = np.float32([n_kps_a[match.queryIdx] for match in good_matches])return src_pts, dst_ptsdef image_perspective_transformation(self, src_image_a, src_image_b, src_pts, dst_pts):# 图像透视变换reproj_threshold = 4.0H, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, reproj_threshold)distance = 700# 对图像B进行透视变换,变换成与A图像相同角度的平面图像,以便于与图像A进行拼接pert_src_image_b = cv2.warpPerspective(src_image_b, H, (src_image_b.shape[1] + distance, src_image_b.shape[0]))# 图像变形和拼接h1, w1 = src_image_a.shape[:2]h2, w2 = src_image_b.shape[:2]# 计算拼接后图像的尺寸corners1 = np.float32([[0, 0], [0, h1], [w1, h1], [w1, 0]]).reshape(-1, 1, 2)corners2 = np.float32([[0, 0], [0, h2], [w2, h2], [w2, 0]]).reshape(-1, 1, 2)warped_corners2 = cv2.perspectiveTransform(corners2, H)all_corners = np.concatenate((corners1, warped_corners2), axis=0)[xmin, ymin] = np.int32(all_corners.min(axis=0).ravel() - 0.5)[xmax, ymax] = np.int32(all_corners.max(axis=0).ravel() + 0.5)# 计算平移变换translation_dist = [-xmin, -ymin]H_translation = np.array([[1, 0, translation_dist[0]],[0, 1, translation_dist[1]],[0, 0, 1]])# 应用变换,图像拼接result = cv2.warpPerspective(src_image_b, H_translation.dot(H), (xmax - xmin, ymax - ymin))result[translation_dist[1]:h1 + translation_dist[1],translation_dist[0]:w1 + translation_dist[0]] = src_image_areturn resultdef image_mosaicking(self):# 图像拼接src_image_a = cv2.imread('resources/sift_1.jpg')src_image_b = cv2.imread('resources/sift_2.jpg')src_pts, dst_pts = self.image_sift(src_image_a, src_image_b)dst_image_b = self.image_perspective_transformation(src_image_a, src_image_b, src_pts, dst_pts)plt.subplot(1, 3, 1), plt.imshow(src_image_a), plt.title('src_image_a')plt.subplot(1, 3, 2), plt.imshow(src_image_b), plt.title('src_image_b')plt.subplot(1, 3, 3), plt.imshow(dst_image_b), plt.title('Origin_perspective')plt.show()if __name__ == '__main__':sift = SIFT()sift.image_mosaicking()

下面是拼接后的效果图:

在这里插入图片描述

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

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

相关文章

NPOI操作EXCEL文件 ——CAD C# 二次开发

缺点:dll.版本容易加载错误。CAD加载插件时&#xff0c;没有加载所有类库。插件运行过程中用到某个类库&#xff0c;会从CAD的安装目录找&#xff0c;找不到就报错了。 【方案2】让CAD在加载过程中把类库加载到内存 【方案3】是发现缺少了哪个库&#xff0c;就用插件程序加载进…

Go字符串切片操作详解:str1[:index]

在Go语言中&#xff0c;return str1[:index] 是一个​​字符串切片操作​​&#xff0c;它截取字符串的一部分。让我们深入解析这个操作的含义和原理&#xff1a; 基本语法和含义 str1&#xff1a;原始字符串[:index]&#xff1a;切片操作符str1[:index]&#xff1a; ​​起始…

NVIDIA Dynamo:数据中心规模的分布式推理服务框架深度解析

NVIDIA Dynamo&#xff1a;数据中心规模的分布式推理服务框架深度解析 摘要 NVIDIA Dynamo是一个革命性的高吞吐量、低延迟推理框架&#xff0c;专为在多节点分布式环境中服务生成式AI和推理模型而设计。本文将深入分析Dynamo的架构设计、核心特性、代码实现以及实际应用示例&…

408第一季 - 数据结构 - 栈与队列的应用

括号匹配 用瞪眼法就可以知道的东西 栈在表达式求值运用 先简单看看就行&#xff0c;题目做了就理解了 AB是操作符,也是被狠狠加入后缀表达式了&#xff0c;然后后面就是*&#xff0c;只要优先级比栈顶运算符牛逼就放里面&#xff0c;很显然&#xff0c;*比牛逼 继续前进&#…

Ubuntu 下开机自动执行命令的方法

Ubuntu 下开机自动执行命令的方法&#xff08;使用 crontab&#xff09; 在日常使用 Ubuntu 或其他 Linux 系统时&#xff0c;我们常常需要让某些程序或脚本在系统启动后自动运行。例如&#xff1a;启动 Clash 代理、初始化服务、定时同步数据等。 本文将介绍一种简单且常用的…

jpackage 打包 jar包 为exe可执行程序

jpackage --input target/ --main-jar note.jar --runtime-image H:/Dpanbeifeng/apps/finalshell/jre --type app-image --dest output/ --main-class com.textmanager.Main --icon logo2.png --name 猫咪快笔记 jpackage 打包指令详细介绍 jpackage 概述 jpackage 是…

H5移动端性能优化策略(渲染优化+弱网优化+WebView优化)

一、渲染优化&#xff1a;首屏速度提升的核心​​ ​​1. 关键页面采用SSR或Native渲染​​ ​​适用场景​​&#xff1a;首页、列表页、详情页等强内容展示页面 ​​优化原理​​&#xff1a; ​​SSR&#xff08;服务端渲染&#xff09;​​&#xff1a;在服务端生成完整…

Matlab | matlab中的图像处理详解

MATLAB 图像处理详解 这里写目录标题图像处理 MATLAB 图像处理详解一、图像基础操作1. 图像读写与显示2. 图像信息获取3. 图像类型转换二、图像增强技术1. 对比度调整2. 去噪处理3. 锐化处理三、图像变换1. 几何变换2. 频域变换四、图像分割1. 阈值分割2. 边缘检测3. 区域分割五…

keysight是德科技N9923A网络分析仪

keysight是德科技N9923A网络分析仪 简  述&#xff1a;N9923A 是一款使用电池供电的便携式射频矢量网络分析仪&#xff0c;其中包括全 2 端口网络分析仪、电缆和天线测试仪、故障点距离测试仪、功率计以及 1 通道和 2 通道矢量电压表。 主要特性与技术指标 网络分析仪 * 2…

idea不识别lombok---实体类报没有getter方法

介绍 本篇文章&#xff0c;主要讲idea引入lombok后&#xff0c;在实体类中加注解Data&#xff0c;在项目启动的时候&#xff0c;编译不通过&#xff0c;报错xxx.java没有getXxxx&#xff08;&#xff09;方法。 原因有以下几种 1. idea没有开启lombok插件 2. 使用idea-2023…

本地主机部署开源企业云盘Seafile并实现外部访问

Seafile是一个开源、专业、可靠的云存储平台&#xff1b;解决文件集中存储、共享和跨平台访问等问题。这款软件功能强大&#xff0c;界面简洁、操作方便。 本文将详细的介绍如何利用本地主机部署 Seafile&#xff0c;并结合nat123&#xff0c;实现外网访问本地部署的 Seafile …

【从0-1的CSS】第1篇:CSS简介,选择器以及常用样式

文章目录 CSS简介CSS的语法规则选择器id选择器元素选择器类选择器选择器优先级 CSS注释 CSS常用设置样式颜色颜色名称(常用)RGB(常用)RGBA(常用)HEX(常用)HSLHSLA 背景background-colorbackground-imagebackground-size 字体text-aligntext-decorationtext-indentline-height 边…

SpringBoot+MySQL家政服务平台 设计开发

概述 基于SpringBootMySQL开发的家政服务平台完整项目&#xff0c;该系统实现了用户预约、服务管理、订单统计等核心功能&#xff0c;采用主流技术栈开发&#xff0c;代码规范且易于二次开发。 主要内容 系统功能架构 本系统采用前后端分离架构&#xff0c;前端提供用户交互…

3.1 HarmonyOS NEXT分布式数据管理实战:跨设备同步、端云协同与安全保护

HarmonyOS NEXT分布式数据管理实战&#xff1a;跨设备同步、端云协同与安全保护 在万物互联的时代&#xff0c;数据的跨设备流转与安全共享是全场景应用的核心需求。HarmonyOS NEXT通过分布式数据管理技术&#xff0c;实现了设备间数据的实时同步与端云协同&#xff0c;为开发…

高保真组件库:数字输入框

拖入一个文本框。 拖入一个矩形,作为整个数字输入框的边框,边框颜色为灰色DCDEE2,圆角半径为4。 拖入一个向上的箭头图标作为增加按钮,再拖入一个矩形,将向上箭头图标放入矩形内。矩形:18x15,边框颜色DCDEE2,边框左下可见,箭头图标:8x5,矩形置底,组合在一起命名”增…

【力扣链表篇】19.删除链表的倒数第N个节点

题目&#xff1a; 给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], n 2 输出&#xff1a;[1,2,3,5]示例 2&#xff1a; 输入&#xff1a;head [1], n 1 输出&#xff1a;[]…

论文笔记——相干体技术在裂缝预测中的应用研究

目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术&#xff1a;基于互相关的相干体技术&#xff08;Correlation&#xff09;第二代相干体技术&#xff1a;基于相似的相干体技术&#xff08;Semblance&#xff09;基于多道相似的相干体…

wpf ListBox 去除item 单击样式

在WPF中去除ListBox项的单击样式&#xff0c;可以通过修改ItemContainerStyle来实现。以下是解决方案&#xff1a; <ListBox><ListBox.ItemContainerStyle><Style TargetType"ListBoxItem"><Setter Property"Background" Value"…

A Execllent Software Project Review and Solutions

The Phoenix Projec: how do we produce software? how many steps? how many people? how much money? you will get it. i am a pretty judge of people…a prank

Android 视图系统入门指南

1. View&#xff1a;界面的最小单位 本质&#xff1a;屏幕上的一个矩形区域&#xff0c;能显示内容或接收触摸。比喻&#xff1a;就像乐高积木&#xff0c;是组成界面的最小单位。常见子类&#xff1a; TextView&#xff08;文字积木&#xff09;、Button&#xff08;按钮积木…