首页 > 编程语言 >Python计算机视觉 第2章-局部图像描述子

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

时间:2024-08-25 12:56:54浏览次数:12  
标签:plt img Python cv2 角点 图像 视觉 sigma

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=[Ix2​Ix​Iy​​Ix​Iy​Iy2​​]

      其中, 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​)=x∑​f(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​)=I1​I2​, 因此, c ( I 1 , I 2 ) = I 1 ⋅ I 2 c(I_1,I_2 )=I_1 · I_2 c(I1​,I2​)=I1​⋅I2​ , 其中· 表示向量乘法(按照行或者列堆积的像素)。 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​)=n−11​x∑​σ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 提出的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')

标签:plt,img,Python,cv2,角点,图像,视觉,sigma
From: https://blog.csdn.net/m0_62094120/article/details/141472503

相关文章

  • C++/python趣味实验之:互动游戏
    之前,我们已经使用python做出了可以根据C++数据变更的血条现在,拓展一下这个程序,制作一个可以互动的游戏既然是游戏,那就需要一个启动界面,所以我们可以制作一个蓝天白云的场景怎么实现呢?首先,我们要明白,这只是一个启动界面,所以一定是根据C++方面的数据而启动和关闭的,这时,就需要......
  • 前端必知必会-CSS 图片库和图像精灵
    文章目录CSS图片库CSS图像精灵图像精灵-简单示例图像精灵-创建导航列表图像精灵-悬停效果总结CSS图片库CSS可用于创建图片库。以下图片库使用CSS创建:示例<html><head><style>div.gallery{margin:5px;border:1pxsolid#ccc;float:left;......
  • 【8.2 python中的使用re模块实现正则表达式操作】
    python中的使用re模块实现正则表达式操作Python中的re模块提供了对正则表达式的支持。正则表达式(RegularExpression,简称regex或regexp)是一种文本模式,包括普通字符(例如,a到z之间的字母)和特殊字符(称为"元字符")。正则表达式使用单个字符串来描述、匹配一系列符合某个句法......
  • 【12.1 python中的异常概述】
    概述python中的异常Python中的异常(Exception)是一种在程序执行期间发生,且会扰乱程序正常流程的事件。异常是Python用来响应错误和异常情况的一种机制,它允许程序在遇到错误时优雅地处理它们,而不是突然崩溃并停止执行。异常处理对于开发健壮、可靠和用户友好的应用程序至关重......
  • Python消息轰炸脚本
    Python代码:frompynput.keyboardimportKey,Controllerimporttimekeyboard=Controller()messages=input("请输入你要轰炸的信息:")times=eval(input("请输入你要轰炸的次数:"))print("数据已被后台接受,请将光标移动至会话框")time.sleep(2)foriinrange(3):print(&qu......
  • Python安装教程
    第一步:先去官网上下载python安装包系统64位下载地址:系统32位下载地址:第二步:点击安装包要点击Addpython.exetoPATH这个是配置系统变量的然后点installNow就开始跑安装进度了打开终端输入代码python再输入print(123),如果输入123那么安装完成,可以整活了......
  • 全面提升!上海交大等联合发布MegaFusion:无须微调的高效高分辨率图像生成方法
    文章链接:https://arxiv.org/pdf/2408.11001项目链接:https://haoningwu3639.github.io/MegaFusion/亮点直击提出了一种无需调优的方法——MegaFusion,通过截断与传递策略,以粗到细的方式高效生成百万像素的高质量、高分辨率图像;结合了膨胀卷积和噪声重新调度技术,......
  • 在Python虚拟环境中利用PyInstaller高效构建可执行EXE文件的专业指南
    使用虚拟环境(如venv或conda)来打包Python程序为exe文件是一个很好的实践,因为它可以确保应用程序在不同的环境中具有一致性和可移植性。然而,需要注意的是,虚拟环境本身并不直接提供将Python程序打包成exe文件的功能。这通常需要使用专门的打包工具,如PyInstaller、cx_Freeze或py......
  • 浦语Camp3:入门2-Python基础
    任务类型任务内容闯关任务python实现wordcount闯关任务Vscode连接InternStudiodebug笔记1.python实现wordcount请实现一个wordcount函数,统计英文字符串中每个单词出现的次数。返回一个字典,key为单词,value为对应单词出现的次数text="""Gotthispandaplushtoyformyd......
  • Python wxauto 微信 机器人复读机
    fromwxautoimport*importtimeimportrandomrepeat_rate=.3#回复概率wait_seconds=5#查询时间start_num=20#语料库少于这个数,就先攒一攒file_name='db.txt'#语料库路径,可用数据库替代split_tag='6lol6'#分隔符,可改,如果用数据库,就不需要这个c......