Python计算机视觉 第2章-局部图像描述子

news2024/11/16 3:44:51

Python计算机视觉 第2章-局部图像描述子

2.1 Harris角点检测器

Harris角点检测算法(也称Harris & Stephens角点检测器)是一个极为简单的角点检测算法。该算法的主要思想是,如果像素周围显示存在多于一个方向的边,我们认为该点为兴趣点。该点就称为角点。

Harris角点检测算法

Harris角点检测算法基于图像灰度值的变化来识别角点。角点通常出现在图像中灰度值变化剧烈的区域,特别是梯度在两个方向上都有较大变化的地方。

具体来说,算法的步骤如下:

  1. 计算图像梯度:

    • 计算图像在x方向和y方向上的梯度,通常使用Sobel算子或其他类似的滤波器来计算。
  2. 构造矩阵 M M M

    • 对于图像中的每个像素,计算自相关矩阵 M M M

      M = [ I x 2 I x I y I x I y I y 2 ] M = \begin{bmatrix} I_x^2 & I_xI_y \\ I_xI_y & I_y^2 \end{bmatrix} M=[Ix2IxIyIxIyIy2]

      其中, I x I_x Ix I y I_y Iy 是图像在 x 方向和 y 方向的梯度,矩阵中的各项可以通过对梯度值进行加权求和得到。

  3. 响应函数 R R R

    • 通过矩阵 M M M 的特征值分析,计算响应函数 R R R

      R = det ( M ) − k ⋅ ( trace ( M ) ) 2 R = \text{det}(M) - k \cdot (\text{trace}(M))^2 R=det(M)k(trace(M))2

      其中, det ( M ) \text{det}(M) det(M) M M M 的行列式, trace ( M ) \text{trace}(M) trace(M) M M M 的迹, k k k 是一个经验常数,通常取值为 0.04 到 0.06 之间。

  4. 角点检测:

    • 对于每个像素,计算对应的 R R R 值。如果 R R R 值大于某个阈值并且是局部最大值,则该像素被认为是一个角点。

以下是算法的示例代码:

from matplotlib import pyplot as plt
from PIL import Image
import numpy as np
from scipy.ndimage import gaussian_filter


def compute_harris_response(img, sigma=3):
    # 计算图像的x和y方向的梯度
    imgx = np.zeros(img.shape)
    gaussian_filter(img, (sigma, sigma), (0, 1), imgx)
    imgy = np.zeros(img.shape)
    gaussian_filter(img, (sigma, sigma), (1, 0), imgy)

    # 计算Harris矩阵的分量
    Wxx = gaussian_filter(imgx * imgx, sigma)
    Wxy = gaussian_filter(imgx * imgy, sigma)
    Wyy = gaussian_filter(imgy * imgy, sigma)

    # 计算Harris响应,并处理可能的除零情况
    Wdet = Wxx * Wyy - Wxy * Wxy
    Wtran = Wxx + Wyy
    Wtran[Wtran == 0] = 1e-10  # 避免除零错误
    return Wdet / Wtran


def get_harris_points(harrisimg, min_dist=10, threshold=0.1):
    # 找到角点
    corners = harrisimg.max() * threshold
    harrisimg_t = (harrisimg > corners) * 1
    coords = np.array(harrisimg_t.nonzero()).T
    candidate_values = [harrisimg[c[0], c[1]] for c in coords]
    index = np.argsort(candidate_values)

    # 将坐标保存在允许的位置
    allow_locations = np.zeros(harrisimg.shape)
    allow_locations[min_dist:-min_dist, min_dist:-min_dist] = 1
    filtered_coords = []
    for idx in index:
        if allow_locations[coords[idx][0], coords[idx][1]] == 1:
            filtered_coords.append(coords[idx])
            allow_locations[coords[idx][0] - min_dist:coords[idx][0] + min_dist,
            coords[idx][1] - min_dist:coords[idx][1] + min_dist] = 0
    return filtered_coords


# 加载图像并进行Harris角点检测
img = Image.open(r'img.png').convert('L')
img = np.array(img)
harrisimg = compute_harris_response(img)
filtered_coords1 = get_harris_points(harrisimg, 6, threshold=0.1)
filtered_coords2 = get_harris_points(harrisimg, 6, threshold=0.05)

# 显示结果并保存图像
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.subplot(141), plt.imshow(img, cmap='gray'), plt.title('原始图像'), plt.axis('off')
plt.subplot(142), plt.imshow(harrisimg, cmap='gray'), plt.title('角点图像'), plt.axis('off')
plt.subplot(143), plt.imshow(img, cmap='gray'), plt.plot([p[1] for p in filtered_coords1],
                                                         [p[0] for p in filtered_coords1], '.'), plt.title(
    '阈值为0.1'), plt.axis('off')
plt.subplot(144), plt.imshow(img, cmap='gray'), plt.plot([p[1] for p in filtered_coords2],
                                                         [p[0] for p in filtered_coords2], '.'), plt.title(
    '阈值为0.05'), plt.axis('off')

# 保存图像为文件
plt.savefig('harris_corner_detection.png', dpi=300, bbox_inches='tight')

# 显示图像
plt.show()


在这里插入图片描述

实验图1 Harris角点检测算法处理结果

在图像间寻找对应点

Harris 角点检测器仅仅能够检测出图像中的兴趣点,但是没有给出通过比较图像间的兴趣点来寻找匹配角点的方法。我们需要在每个点上加入描述子信息,并给出一个比较这些描述子的方法。
兴趣点描述子是分配给兴趣点的一个向量,描述该点附近的图像的表观信息。描述子越好,寻找到的对应点越好。我们用对应点或者点的对应来描述相同物体和场景点在不同图像上形成的像素点。
Harris 角点的描述子通常是由周围图像像素块的灰度值,以及用于比较的归一化互相关矩阵构成的。图像的像素块由以该像素点为中心的周围矩形部分图像构成。

通常,两个(相同大小)像素块 I 1 ( x ) I_1(x) I1(x) I 2 ( x ) I_2(x) I2(x)的相关矩阵定义为:
c ( I 1 , I 2 ) = ∑ x f ( I 1 ( x ) , I 2 ( x ) ) c(\boldsymbol{I}_1,\boldsymbol{I}_2)=\sum_{x}f(\boldsymbol{I}_1(\mathbf{x}),\boldsymbol{I}_2(\mathbf{x})) c(I1,I2)=xf(I1(x),I2(x))

其中,函数 f f f随着相关方法的变化而变化。上式取像素块中所有像素位置 x x x的和。对于互相关矩阵,函数 f ( I 1 , I 2 ) = I 1 I 2 f(I_1 ,I_2 )=I_1 I_2 f(I1,I2)=I1I2, 因此, c ( I 1 , I 2 ) = I 1 ⋅ I 2 c(I_1,I_2 )=I_1 · I_2 c(I1,I2)=I1I2 , 其中· 表示向量乘法(按照行或者列堆积的像素)。 c ( I 1 , I 2 ) c(I_1,I_2) c(I1,I2)的值越大,像素块 I 1 I_1 I1 I 2 I_2 I2的相似度越高。

归一化的互相关矩阵是互相关矩阵的一种变形,可以定义为:
n c c ( I 1 , I 2 ) = 1 n − 1 ∑ x ( I 1 ( x ) − μ 1 ) σ 1 ⋅ ( I 2 ( x ) − μ 2 ) σ 2 ncc(I_1,I_2)=\frac{1}{n-1}\sum_{x}\frac{(I_1(\mathbf{x})-\mu_1)}{\sigma_1}\cdot\frac{(I_2(\mathbf{x})-\mu_2)}{\sigma_2} ncc(I1,I2)=n11xσ1(I1(x)μ1)σ2(I2(x)μ2)

其中, n n n为像素块中像素的数目, μ 1 μ_1 μ1 μ 2 μ_2 μ2表示每个像素块中的平均像素值强度, σ 1 σ_1 σ1 σ 2 σ_2 σ2分别表示每个像素块中的标准差。通过减去均值和除以标准差,该方法对图像亮度变化具有稳健性。

2.2 SIFT(尺度不变特征变换)

David Lowe 在文献[17]中提出的SIFT(Scale-Invariant Feature Transform,尺度不变特征变换)是过去十年中最成功的图像局部描述子之一。SIFT特征后来在文献中得到精炼并详述,经受住了时间的考验。SIFT特征包括兴趣点检测器和描述子。SIFT描述子具有非常强的稳健性,这在很大程度上也是SIFT特征能够成功和流行的主要原因。自从SIFT特征的出现,许多其他本质上使用相同描述子的方法也相继出现。现在,SIFT描述符经常和许多不同的兴趣点检测器相结合使用(有些情况下是区域检测器),有时甚至在整幅图像上密集地使用。SIFT特征对于尺度、旋转和亮度都具有不变性,因此,它可以用于三维视角和噪声的可靠匹配。

2.2.1 兴趣点

SIFT 特征使用高斯差分函数来定位兴趣点:
D ( x , σ ) = [ G κ σ ( x ) − G σ ( x ) ] ∗ I ( x ) = [ G κ σ − G σ ] ∗ I = I κ σ − I σ D(\mathbf{x},\sigma)=[G_{\kappa\sigma}(\mathbf{x})-G_{\sigma}(\mathbf{x})]*I(\mathbf{x})=[G_{\kappa\sigma}-G_{\sigma}]*I=I_{\kappa\sigma}-I_{\sigma} D(x,σ)=[Gκσ(x)Gσ(x)]I(x)=[GκσGσ]I=IκσIσ

其中, G σ G_σ Gσ是上一章中介绍的二维高斯核, I σ I_σ Iσ是使用 G σ G_σ Gσ模糊的灰度图像, κ κ κ是决定相差尺度的常数。兴趣点是在图像位置和尺度变化下 D ( x , σ ) D(x,σ) D(x,σ)的最大值和最小值点。这些候选位置点通过滤波去除不稳定点。基于一些准则,比如认为低对比度和位于边上的点不是兴趣点,我们可以去除一些候选兴趣点。

2.2.2 描述子

上面讨论的兴趣点(关键点)位置描述子给出了兴趣点的位置和尺度信息。为了实现旋转不变性,基于每个点周围图像梯度的方向和大小,SIFT描述子又引入了参考方向。SIFT描述子使用主方向描述参考方向。主方向使用方向直方图(以大小为权重)来度量。

2.2.3 检测兴趣点

以下是实验代码:

import cv2
import numpy as np
from matplotlib import pyplot as plt

# 加载图像
img = cv2.imread('img.png', cv2.IMREAD_GRAYSCALE)
img_color = cv2.cvtColor(img, cv2.COLOR_GRAY2RGB)  # 转换为 RGB 图像

# 计算 Harris 角点
dst = cv2.cornerHarris(img, 2, 3, 0.04)

# 结果膨胀以标记角点
dst = cv2.dilate(dst, None)

# 设置阈值以标记角点
img_color[dst > 0.01 * dst.max()] = [0, 0, 255]  # 使用红色标记角点

# 显示结果
plt.imshow(img_color)
plt.title('Harris Corners')
plt.axis('off')

# 保存结果图像
plt.savefig('harris_corners.png', dpi=300, bbox_inches='tight')

plt.show()

在这里插入图片描述

实验图2 处理结果

2.2.4 匹配描述子

对于将一幅图像中的特征匹配到另一幅图像的特征,一种稳健的准则(同样是由Lowe 提出的)是使用这两个特征距离和两个最匹配特征距离的比率。相比于图像中的其他特征,该准则保证能够找到足够相似的唯一特征。使用该方法可以使错误的匹配数降低。
以下为实验代码:

import cv2
import numpy as np
from matplotlib import pyplot as plt

# 加载图像
img1 = cv2.imread('img.png', cv2.IMREAD_GRAYSCALE)  # 查询图像
img2 = cv2.imread('img.png', cv2.IMREAD_GRAYSCALE)  # 训练图像

# 检查图像是否成功加载
if img1 is None:
    raise ValueError("无法读取图像文件 'img1.png'。请检查文件路径和文件名。")
if img2 is None:
    raise ValueError("无法读取图像文件 'img2.png'。请检查文件路径和文件名。")

# 创建 SIFT 检测器
sift = cv2.SIFT_create()

# 检测关键点和计算描述符
kp1, des1 = sift.detectAndCompute(img1, None)
kp2, des2 = sift.detectAndCompute(img2, None)

# 创建 BFMatcher 对象
bf = cv2.BFMatcher(cv2.NORM_L2, crossCheck=True)

# 进行描述符匹配
matches = bf.match(des1, des2)

# 按照距离排序
matches = sorted(matches, key=lambda x: x.distance)

# 绘制匹配结果
img_matches = cv2.drawMatches(img1, kp1, img2, kp2, matches[:50], None, flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)

# 显示匹配结果
plt.imshow(img_matches)
plt.title('Feature Matches')
plt.axis('off')

# 保存匹配结果图像
plt.savefig('feature_matches.png', dpi=300, bbox_inches='tight')

plt.show()

在这里插入图片描述

实验图3 处理结果

2.3 匹配地理标记图像

我们首先通过图像间是否具有匹配的局部描述子来定义图像间的连接,然后可视化这些连接情况。为了完成可视化,我们可以在图中显示这些图像,图的边代表连接。

2.3.1 使用局部描述子匹配

在这种情况下,我们将使用前面部分讲述的SIFT特征描述子。我们假设已经对这些图像使用SIFT特征提取代码进行了处理,并且将特征保存在和图像同名(但文件名后缀是.sift,而不是.jpg)的文件中。假设imlist和featlist列表中包含这些文件名。我们可以对所有组合图像对进行逐个匹配,以下为示例关键代码:

import sift
import numpy as np

# 图像列表和特征文件列表
imlist = [...]  # 替换为实际图像文件列表
featlist = [...]  # 替换为实际特征文件列表

# 初始化
nbr_images = len(imlist)
matchscores = np.zeros((nbr_images, nbr_images))

# 计算每对图像的匹配得分
for i in range(nbr_images):
    for j in range(i, nbr_images):  # 仅计算上三角
        print('Comparing', imlist[i], imlist[j])
        
        # 读取特征
        l1, d1 = sift.read_features_from_file(featlist[i])
        l2, d2 = sift.read_features_from_file(featlist[j])
        
        # 匹配描述符
        matches = sift.match_twosided(d1, d2)
        nbr_matches = np.sum(matches > 0)
        
        print('Number of matches =', nbr_matches)
        
        # 填充匹配得分矩阵
        matchscores[i, j] = nbr_matches

# 复制值以填充对称矩阵
for i in range(nbr_images):
    for j in range(i + 1, nbr_images):  # 不需要复制对角线
        matchscores[j, i] = matchscores[i, j]

2.3.3 可视化连接的图像

我们首先通过图像间是否具有匹配的局部描述子来定义图像间的连接,然后可视化这些连接情况。为了完成可视化,我们可以在图中显示这些图像,图的边代表连接。以下为示例关键代码:

import pydot

# 创建一个无向图
g = pydot.Dot(graph_type='graph')

# 添加节点0,设置字体颜色为透明
g.add_node(pydot.Node(str(0), fontcolor='transparent'))

# 添加其他节点及边
for i in range(5):
    # 添加节点 i+1
    g.add_node(pydot.Node(str(i + 1)))
    # 添加边连接节点 0 和 i+1
    g.add_edge(pydot.Edge(str(0), str(i + 1)))
    
    for j in range(5):
        # 添加节点 j+1-i+1
        g.add_node(pydot.Node(str(j + 1) + '-' + str(i + 1)))
        # 添加边连接节点 j+1-i+1 和 j+1
        g.add_edge(pydot.Edge(str(j + 1) + '-' + str(i + 1), str(j + 1)))

# 将图写入文件
g.write_png('graph.jpg', prog='neato')

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

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

相关文章

滥用 DHCP 管理员组来提升 Windows 域中的权限

介绍 从 Google Docs 到 Active Directory,访问管理几乎影响到组织中的每个角色。在讨论权限和访问控制时,如何最大限度地减少员工的挫败感而不增加不必要的风险是一个微妙的平衡——安全团队痛苦地意识到了这一点。 因此,“刚好足够的访问权限”是任何访问策略的关键要素…

鸿蒙内核源码分析(用户态锁篇) | 如何使用快锁Futex(上)

快锁上下篇 鸿蒙内核实现了Futex,系列篇将用两篇来介绍快锁,主要两个原因: 网上介绍Futex的文章很少,全面深入内核介绍的就更少,所以来一次详细整理和挖透。涉及用户态和内核态打配合,共同作用,既要说用户…

日志文件切割:以分隔割tomcat 的 catalina.out 文件为例子

文章目录 引言I 日志文件切割使用用crontab工具,定时执行任务通过Linux系统自带的切割工具logrotate来进行切割【推荐】基于其他日志框架进行分隔II 扩展logrotate 简介logrotate 用法引言 问题:tomcat 的 catalina.out 文件不会进行日志切割,当这个文件大于2G 时,会影响to…

归并排序、计数排序及排序大总结

一、归并排序 1.基本思想 归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide andConquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列&#x…

如何使用ssm实现社区管理与服务的设计与实现

TOC ssm031社区管理与服务的设计与实现jsp 第一章 绪论 1.1研究背景 当今时代是飞速发展的信息时代。在各行各业中离不开信息处理,这正是计算机被广泛应用于信息管理系统的环境。计算机的最大好处在于利用它能够进行信息管理。使用计算机进行信息控制&#xff0…

[Meachines] [Easy] grandpa IIS 6.0+CVE-2017-7269+MS14-070权限提升

信息收集 IP AddressOpening Ports10.10.10.14TCP:80 $ nmap -p- 10.10.10.14 --min-rate 1000 -sC -sV -Pn PORT STATE SERVICE VERSION 80/tcp open http Microsoft IIS httpd 6.0 |_http-server-header: Microsoft-IIS/6.0 |_http-title: Under Construction | htt…

一文了解机器学习顶会ICML 2024的研究热点

对人工智能研究领域前沿方向的跟踪是提高科研能力和制定科研战略的关键。本文通过图文并茂的方式介绍了ICML 2024的研究热点,帮助读者了解和跟踪机器学习和人工智能的前沿研究方向。本推文的作者是许东舟,审校为邱雪和黄星宇。 1 会议介绍 ICML&#x…

揭秘!挑选随身WiFi的终极攻略:一篇文章教会你怎么挑选随身WiFi,学会对比各项参数,随身WiFi哪个好?

对于不方便拉宽带的大流量使用者,随身WiFi尤为重要。面对市场上琳琅满目的随身WiFi品牌和型号,许多用户感到无从下手。不同随身WiFi在性能、价格、续航等方面各有优势,如何挑选一款适合自己的随身WiFi成为了一大难题。本文将为您详细解析随身…

22 Message 组件

Tkinter Message 组件使用指南 Tkinter 的 Message 组件用于显示多行文本消息。它通常用于显示提示信息、警告或状态更新。Message 组件能够自动换行,以适应其分配的空间。以下是对 Message 组件的详细说明和一个使用案例。 Message 组件属性 text: 要显示的文本…

3D 打印的突破:热引发剂在立体光刻中的应用

在当今科技飞速发展的时代,3D打印技术作为一项具有创新性和颠覆性的技术,正不断改变着我们的生产和生活方式。今天,向大家介绍的是一项关于3D打印的重要研究成果《3D printing by stereolithography using thermal initiators》发表于《Natur…

【前端面试】call、apply 、bind、箭头函数

函数除了传参,还有一个调用上下文this,使用call、apply 、bind可以改变函数的this 在实际开发中,选择使用 call、apply 还是 bind 取决于你的具体需求和场景。以下是一些使用这些函数的常见情况: 1. 使用 call 的情况: 当你需要调用一个函数,并且需要明确指定 this 的上下…

【HarmonyOS NEXT星河版开发实战】天气查询APP

目录 前言 界面效果展示 首页 添加和删除 界面构建讲解 1. 获取所需数据 2. 在编译器中准备数据 3. index页面代码讲解 3.1 导入模块: 3.2 定义组件: 3.3 定义状态变量: 3.4 定义Tabs控制器: 3.5 定义按钮样式: 3.6 页面显示时触发…

【django进阶知识点】

day04 django进阶知识点 今日概要: 模板中间件ORM操作(pymysql SQL语句)session和cookie缓存(很多种方式) 内容回顾 请求周期 路由系统 最基本路由关系动态路由(含正则)路由分发不同的app中…

如何通过数据互通提升销售效率与客户满意度

在快速变化的市场中,品牌商与经销商之间的数据互通已成为提升竞争力的关键。让我们以知名品牌——百威啤酒为例,探讨与经销商数据互通如何帮助这些企业解决实际问题,并为各个部门带来益处。 假如一个以下场景 夏日狂欢节 想象一下&#xff…

Viper快速使用(超简单)

Viper主要是用来在配置管理方面用的,只要是稍微大一点的项目都需要进行配置管理,而Viper支持多种配置格式(JSON、YAML、TOML)登,可以配置环境变量,命令行参数登,使得应用程序配置的管理变得非常…

《机器学习》 决策树剪枝、树模型参数及案例演示

目录 一、决策树剪枝 1、什么是决策树剪枝? 2、如何剪枝 3、剪枝剪哪个位置的叶子结点 二、树模型参数及用法 1、参数种类 2、参数解释 1)criterion:gini or entropy 2)splitter:best or random 3&#xff0…

【解析几何笔记】6.三阶行列式

6. 三阶行列式 6.1 三阶行列式的定义 对三阶方阵 ( a 1 a 2 a 3 b 1 b 2 b 3 c 1 c 2 c 3 ) \begin{pmatrix} a_{1} & a_{2} & a_{3}\\ b_{1} & b_{2} & b_{3}\\ c_{1} & c_{2} &c_{3} \end{pmatrix} ​a1​b1​c1​​a2​b2​c2​​a3​b3​c3​​ …

案例分享—国外金融软件界面设计

国外金融软件界面设计追求简洁,旨在减少用户认知负担,通过直观布局与清晰信息架构,提升操作效率与用户体验 其简洁性还源于对金融数据精准呈现的重视,避免冗余元素干扰,确保用户快速获取关键信息,做出明智决…

《机器学习》周志华-CH2(模型评估与选择)

2.1经验误差与过拟合 2.1.1典型的机器学习过程 2.1.2误差 当有 m m m个样本,其中 a a a个分类错误,则错误率为 E a / m Ea/m Ea/m;相应地, 1 − a / m 1-a/m 1−a/m称为精度。 2.1.3过拟合与欠拟合 过拟合:学习能力…

【LeetCode每日一题】——1046.最后一块石头的重量

文章目录 一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【题目提示】七【解题思路】八【时间频度】九【代码实现】十【提交结果】 一【题目类别】 优先队列 二【题目难度】 简单 三【题目编号】 1046.最后一块石头的重量 四【题目描述】 有…