Python语言实现SIFT算法
作者:米开朗琪罗儿 发布时间:2022-12-30 17:58:14
本文侧重于如何使用Python语言实现SIFT算法
所有程序已打包:基于OpenCV-Python的SIFT算法的实现
一、什么是SIFT算法
SIFT,即尺度不变特征变换(Scale-invariant feature transform,SIFT),是用于图像处理领域的一种描述。这种描述具有尺度不变性,可在图像中检测出关键点,是一种局部特征描述子。
二、准备工作
2.1 实验设备
本文在Windows10系统上,使用pycharm软件完成所有实验。
2.2 OpenCV安装
我们可以使用OpenCV库中的cv2.xfeatures2d.SIFT_create()
函数实现SIFT,但由于专利保护,很多版本的OpenCV库已无法提供该函数,目前仅3.4.2.16
版本的OpenCV库可使用此函数。
安装教程:
(1)查看当前版本opencv:进入cmd(组合键win+R,输入cmd),输入conda list
,查看当前pycharm所有库并找到opencv-python,若找不到库,说明没有安装。
(2)卸载原版本(在cmd中输入:pip uninstall opencv
)
(3)安装新版本(在cmd中输入:pip install opencv-python==3.4.2.16 -i "https://pypi.doubanio.com/simple/"
(4)安装附属库(在cmd中输入:pip install opencv-contrib-python==3.4.2.16 -i "https://pypi.doubanio.com/simple/"
)
三、实验工作
3.1 图像选择
这里选择经典的lena图像作为实验对象,为了选择一个待匹配图像,本文使用如下代码对lena图像进行逆时针45°旋转。
from PIL import Image
img = Image.open('lena.png')
img2 = img.rotate(45) # 逆时针旋转45°
img2.save("lena_rot45.png")
img2.show()
参考图像与待匹配图像(即旋转图像)如下图所示:
3.2 程序实现
"""
图像匹配——SIFT点特征匹配实现步骤:
(1)读取图像;
(2)定义sift算子;
(3)通过sift算子对需要匹配的图像进行特征点获取;
a.可获取各匹配图像经过sift算子的特征点数目
(4)可视化特征点(在原图中标记为圆圈);
a.为方便观察,可将匹配图像横向拼接
(5)图像匹配(特征点匹配);
a.通过调整ratio获取需要进行图像匹配的特征点数量(ratio值越大,匹配的线条越密集,但错误匹配点也会增多)
b.通过索引ratio选择固定的特征点进行图像匹配
(6)将待匹配图像通过旋转、变换等方式将其与目标图像对齐
"""
import cv2 # opencv版本需为3.4.2.16
import numpy as np # 矩阵运算库
import time # 时间库
original_lena = cv2.imread('lena.png') # 读取lena原图
lena_rot45 = cv2.imread('lena_rot45.png') # 读取lena旋转45°图
sift = cv2.xfeatures2d.SIFT_create()
# 获取各个图像的特征点及sift特征向量
# 返回值kp包含sift特征的方向、位置、大小等信息;des的shape为(sift_num, 128), sift_num表示图像检测到的sift特征数量
(kp1, des1) = sift.detectAndCompute(original_lena, None)
(kp2, des2) = sift.detectAndCompute(lena_rot45, None)
# 特征点数目显示
print("=========================================")
print("=========================================")
print('lena 原图 特征点数目:', des1.shape[0])
print('lena 旋转图 特征点数目:', des2.shape[0])
print("=========================================")
print("=========================================")
# 举例说明kp中的参数信息
for i in range(2):
print("关键点", i)
print("数据类型:", type(kp1[i]))
print("关键点坐标:", kp1[i].pt)
print("邻域直径:", kp1[i].size)
print("方向:", kp1[i].angle)
print("所在的图像金字塔的组:", kp1[i].octave)
print("=========================================")
print("=========================================")
"""
首先对原图和旋转图进行特征匹配,即图original_lena和图lena_rot45
"""
# 绘制特征点,并显示为红色圆圈
sift_original_lena = cv2.drawKeypoints(original_lena, kp1, original_lena, color=(255, 0, 255))
sift_lena_rot45 = cv2.drawKeypoints(lena_rot45, kp2, lena_rot45, color=(255, 0, 255))
sift_cat1 = np.hstack((sift_original_lena, sift_lena_rot45)) # 对提取特征点后的图像进行横向拼接
cv2.imwrite("sift_cat1.png", sift_cat1)
print('原图与旋转图 特征点绘制图像已保存')
cv2.imshow("sift_point1", sift_cat1)
cv2.waitKey()
# 特征点匹配
# K近邻算法求取在空间中距离最近的K个数据点,并将这些数据点归为一类
start = time.time() # 计算匹配点匹配时间
bf = cv2.BFMatcher()
matches1 = bf.knnMatch(des1, des2, k=2)
print('用于 原图和旋转图 图像匹配的所有特征点数目:', len(matches1))
# 调整ratio
# ratio=0.4:对于准确度要求高的匹配;
# ratio=0.6:对于匹配点数目要求比较多的匹配;
# ratio=0.5:一般情况下。
ratio1 = 0.5
good1 = []
for m1, n1 in matches1:
# 如果最接近和次接近的比值大于一个既定的值,那么我们保留这个最接近的值,认为它和其匹配的点为good_match
if m1.distance < ratio1 * n1.distance:
good1.append([m1])
end = time.time()
print("匹配点匹配运行时间:%.4f秒" % (end-start))
# 通过对good值进行索引,可以指定固定数目的特征点进行匹配,如good[:20]表示对前20个特征点进行匹配
match_result1 = cv2.drawMatchesKnn(original_lena, kp1, lena_rot45, kp2, good1, None, flags=2)
cv2.imwrite("match_result1.png", match_result1)
print('原图与旋转图 特征点匹配图像已保存')
print("=========================================")
print("=========================================")
print("原图与旋转图匹配对的数目:", len(good1))
for i in range(2):
print("匹配", i)
print("数据类型:", type(good1[i][0]))
print("描述符之间的距离:", good1[i][0].distance)
print("查询图像中描述符的索引:", good1[i][0].queryIdx)
print("目标图像中描述符的索引:", good1[i][0].trainIdx)
print("=========================================")
print("=========================================")
cv2.imshow("original_lena and lena_rot45 feature matching result", match_result1)
cv2.waitKey()
# 将待匹配图像通过旋转、变换等方式将其与目标图像对齐,这里使用单应性矩阵。
# 单应性矩阵有八个参数,如果要解这八个参数的话,需要八个方程,由于每一个对应的像素点可以产生2个方程(x一个,y一个),那么总共只需要四个像素点就能解出这个单应性矩阵。
if len(good1) > 4:
ptsA = np.float32([kp1[m[0].queryIdx].pt for m in good1]).reshape(-1, 1, 2)
ptsB = np.float32([kp2[m[0].trainIdx].pt for m in good1]).reshape(-1, 1, 2)
ransacReprojThreshold = 4
# RANSAC算法选择其中最优的四个点
H, status =cv2.findHomography(ptsA, ptsB, cv2.RANSAC, ransacReprojThreshold)
imgout = cv2.warpPerspective(lena_rot45, H, (original_lena.shape[1], original_lena.shape[0]),
flags=cv2.INTER_LINEAR + cv2.WARP_INVERSE_MAP)
cv2.imwrite("imgout.png", imgout)
cv2.imshow("lena_rot45's result after transformation", imgout)
cv2.waitKey()
3.3 程序结果
来源:https://blog.csdn.net/qq_42856191/article/details/121306915
猜你喜欢
- selenium 安装与 chromedriver安装我们前文提到,Python脚本中使用了selenium库,而selenium又通过ch
- ckptfrom tensorflow.python import pywrap_tensorflow checkpoint_path =
- javascript 常见汉字转换成拼音,上下行排列,方便对比,速度快,你可以把代码复制到本地,作为一个不错的汉字转换拼音的工具!转换效果图
- 常用的 random 模块方法import random# random.random()用于生成一个 0 到 1 的随机浮点数: 0 &l
- 本篇介绍Python字典的常见操作。修改字典元素,如图。添加字典元素,如图。删除字典元素del方法,如图。删除字典元素clear方法,如图。
- 方法一.Image { max-width:600px;height:
- 引言在这篇文章中,我将介绍如何使用YOLOv5构建一个佩戴安全帽检测和识别系统。这个系统可以实时检测图像上人物是否有未佩戴安全帽,并及时进行
- 在document.form1.submit();后加document.body.innerHtml = "W
- eval()函数可以将字符串型的list、tuple、dict等等转换为原有的数据类型即使用eval可以实现从元组,列表,字典型的字符串到元
- 换脸!这段时间,deepfakes搞得火热,比方说把《射雕英雄传》里的朱茵换成了杨幂,看下面的图!毫无违和感!其实早在之前,基于AI换脸的技
- 技术背景GPU的加速技术在深度学习、量子计算领域都已经被广泛的应用。其适用的计算模型是小内存的密集型计算场景,如果计算的模型内存较大,则需要
- 如下所示:<code class="language-python">import numpy as np
- 前言最新需要做一个小工具,让协作部门能够获取到服务器上的一些资源讯息,因为工具是pyqt写的所以牵扯到用python链接linux的问题,这
- Python中类似于PHP的数组的结构有list,tuple,dict和set, 其中list, tuple和set的类似于PHP的索引数组
- 在一些情况下,MySQL可以直接使用索引来满足一个 ORDER BY 或 GROUP BY 子句而无需做额外的排序。尽管 ORDER BY
- 执行效果如下:from tkinter import *import urllib.requestimport gzipimport jso
- 前言本文使用 cpu 版本的 TensorFlow 2.4 ,分别搭建单层 Bi-LSTM 模型和多层 Bi-LSTM 模型完成文本分类任务
- 按照CSS规范,浮动元素(floats)会被移出文档流,不会影响到块状盒子的布局而只会影响内联盒子(通常是文本)的排列。因此当其高度超出包含
- 对于某一类网站, 管理界面 是基础设施中非常重要的一部分。 这是以网页和有限的可信任管理者为基础的界面,它可以让你添加,编辑和删除网站内容。
- 写在前面的话关于《交互设计实用指南》,我们最近收到很多朋友的反馈,有支持的也有批评的,在此一并感谢了,有你们的关注,我们才能走得更远。《交互