Python计算机视觉 第7章-图像搜索

news2024/9/25 7:16:58

Python计算机视觉 第7章-图像搜索

7.1 基于内容的图像检索

在大型图像数据库上,CBIR(Content-Based Image Retrieval,基于内容的图像检索)技术用于检索在视觉上具相似性的图像。这样返回的图像可以是颜色相似、纹理相似、图像中的物体或场景相似;总之,基本上可以是这些图像自身共有的任何信息。

对于高层查询,比如寻找相似的物体,将查询图像与数据库中所有的图像进行完全比较(比如用特征匹配)往往是不可行的。在数据库很大的情况下,这样的查询方式会耗费过多时间。在过去的几年里,研究者成功地引入文本挖掘技术到CBIR中处理问题,使在数百万图像中搜索具有相似内容的图像成为可能。

从文本挖掘中获取灵感——矢量空间模型

矢量空间模型是一个用于表示和搜索文本文档的模型。我们将看到,它基本上可以应用于任何对象类型,包括图像。该名字来源于用矢量来表示文本文档,这些矢量是由文本词频直方图构成的。换句话说,矢量包含了每个单词出现的次数,而且在其他别的地方包含很多0元素。由于其忽略了单词出现的顺序及位置,该模型也被称为BOW表示模型。

通过单词计数来构建文档直方图向量v,从而建立文档索引。通常,在单词计数时会忽略掉一些常用词,如“这”“和”“是”等,这些常用词称为停用词。由于每篇文档长度不同,故除以直方图总和将向量归一化成单位长度。对于直方图向量中的每个元素,一般根据每个单词的重要性来赋予相应的权重。通常,数据集(或语料库)中一个单词的重要性与它在文档中出现的次数成正比,而与它在语料库中出现的次数成反比。

7.2 视觉单词

为了将文本挖掘技术应用到图像中,我们首先需要建立视觉等效单词;这通常可以采用2.2节中介绍的SIFT局部描述子做到。它的思想是将描述子空间量化成一些典型实例,并将图像中的每个描述子指派到其中的某个实例中。这些典型实例可以通过分析训练图像集确定,并被视为视觉单词。所有这些视觉单词构成的集合称为视觉词汇,有时也称为视觉码本。对于给定的问题、图像类型,或在通常情况下仅需呈现视觉内容,可以创建特定的词汇。

从一个(很大的训练图像)集提取特征描述子,利用一些聚类算法可以构建出视觉单词。聚类算法中最常用的是K-means,这里也将采用K-means。视觉单词并不高端,只是在给定特征描述子空间中的一组向量集,在采用K-means进行聚类时得到的视觉单词是聚类质心。用视觉单词直方图来表示图像,则该模型便称为BOW模型。

创建词汇
为创建视觉单词词汇,首先需要提取特征描述子。运行下面的代码,可以得到每幅图像提取出的描述子,并将每幅图像的描述子保存在一个文件中:

nbr_images = len(imlist)
featlist = [imlist[i][:-3] + 'sift' for i in range(nbr_images)]

for i in range(nbr_images):
    sift.process_image(imlist[i], featlist[i])

下面的代码创建一个词汇类,以及在训练图像数据集上训练出一个词汇的方法:

from scipy.cluster.vq import *
import vlfeat as sift

class Vocabulary(object):
    def __init__(self, name):
        self.name = name
        self.voc = []
        self.idf = []
        self.trainingdata = []
        self.nbr_words = 0

    def train(self, featurefiles, k=100, subsampling=10):
        """用含有 k 个单词的 K-means 列出在 featurefiles 中的特征文件训练出一个词汇。
        对训练数据下采样可以加快训练速度"""
        nbr_images = len(featurefiles)
        
        # 从文件中读取特征
        descr = []
        descr.append(sift.read_features_from_file(featurefiles[0])[1])
        descriptors = descr[0]  # 将所有的特征并在一起,以便后面进行 K-means 聚类
        
        for i in arange(1, nbr_images):
            descr.append(sift.read_features_from_file(featurefiles[i])[1])
            descriptors = vstack((descriptors, descr[i]))
        
        # K-means: 最后一个参数决定运行次数
        self.voc, distortion = kmeans(descriptors[::subsampling, :], k, 1)
        self.nbr_words = self.voc.shape[0]
        
        # 遍历所有的训练图像,并投影到词汇上
        imwords = zeros((nbr_images, self.nbr_words))
        for i in range(nbr_images):
            imwords[i] = self.project(descr[i])
        
        nbr_occurences = sum((imwords > 0) * 1, axis=0)
        self.idf = log((1.0 * nbr_images) / (1.0 * nbr_occurences + 1))
        self.trainingdata = featurefiles

    def project(self, descriptors):
        """将描述子投影到词汇上,以创建单词直方图"""
        # 图像单词直方图
        imhist = zeros((self.nbr_words))
        words, distance = vq(descriptors, self.voc)
        for w in words:
            imhist[w] += 1
        return imhist

Vocabulary 类包含了一个由单词聚类中心 VOC 与每个单词对应的逆向文档频率构成的向量,为了在某些图像集上训练词汇,train() 方法获取包含有 .sift 描后缀的述子文件列表和词汇单词数 k。在 K-means 聚类阶段可以对训练数据下采样,因为如果使用过多特征,会耗费很长时间。

现在在你计算机的某个文件夹中,保存了图像及提取出来的 sift 特征文件,下面的代码会创建一个长为 k ≈ 1000 的词汇表。这里,再次假设 imlist 是一个包含了图像文件名的列表:

import pickle
import vocabulary

nbr_images = len(imlist)
featlist = [imlist[i][:-3] + 'sift' for i in range(nbr_images)]

voc = vocabulary.Vocabulary('ukbenchtest')
voc.train(featlist, 1000, 10)

# 保存词汇
with open('vocabulary.pkl', 'wb') as f:
    pickle.dump(voc, f)

print('vocabulary is:', voc.name, voc.nbr_words)

代码最后部分用 pickle 模块保存了整个词汇对象以便后面使用。

7.3 图像索引

在开始搜索之前,我们需要建立图像数据库和图像的视觉单词表示。

7.3.1 建立数据库

在索引图像前,我们需要建立一个数据库。这里,对图像进行索引就是从这些图像中提取描述子,利用词汇将描述子转换成视觉单词,并保存视觉单词及对应图像的单词直方图。从而可以利用图像对数据库进行查询,并返回相似的图像作为搜索结果。

7.3.2 添加图像

有了数据库表单,我们便可以在索引中添加图像。为了实现该功能,我们需要在Indexer 类中添加 add_to_index() 方法。将下面的方法添加到 imagesearch.py 中:

def add_to_index(self, imname, descr):
    """获取一幅带有特征描述子的图像,投影到词汇上并添加进数据库"""
    if self.is_indexed(imname):
        return
    print('indexing', imname)
    
    # 获取图像 id
    imid = self.get_id(imname)
    
    # 获取单词
    imwords = self.voc.project(descr)
    nbr_words = imwords.shape[0]
    
    # 将每个单词与图像链接起来
    for i in range(nbr_words):
        word = imwords[i]
        # wordid 就是单词本身的数字
        self.con.execute(
            "insert into imwords(imid, wordid, vocname) values (?, ?, ?)",
            (imid, word, self.voc.name)
        )
    
    # 存储图像的单词直方图
    # 用 pickle 模块将 NumPy 数组编码成字符串
    self.con.execute(
        "insert into imhistograms(imid, histogram, vocname) values (?, ?, ?)",
        (imid, pickle.dumps(imwords), self.voc.name)
    )

该方法获取图像文件名与 Numpy 数组,该数组包含的是在图像找到的描述子。这些描述子投影到词汇上,并插入到 imwords(逐字)和 imhistograms 表单中。我们使用两个辅助函数:is_indxed() 用来检查图像是否已经被索引,get_id() 则对一幅图像文件名给定 id 号。将下面的代码添加进 imagesearch.py:

def is_indexed(self, imname):
    """如果图像名字(imname)被索引到,就返回 True"""
    im = self.con.execute(
        "select rowid from imlist where filename='%s'" % imname
    ).fetchone()
    return im is not None

def get_id(self, imname):
    """获取图像 id,如果不存在,就进行添加"""
    cur = self.con.execute(
        "select rowid from imlist where filename='%s'" % imname
    )
    res = cur.fetchone()
    
    if res is None:
        cur = self.con.execute(
            "insert into imlist(filename) values ('%s')" % imname
        )
        return cur.lastrowid
    else:
        return res[0]

7.4 在数据库中搜索图像

建立好图像的索引,我们就可以在数据库中搜索相似的图像了。

7.4.1 利用索引获取候选图像

我们可以利用建立起来的索引找到包含特定单词的所有图像,在 Searcher 类中加入 candidates_from_word() 方法:

def candidates_from_word(self, imword):
    """获取包含 imword 的图像列表"""
    im_ids = self.con.execute(
        "select distinct imid from imwords where wordid=%d" % imword
    ).fetchall()
    return [i[0] for i in im_ids]

上面会给出包含特定单词的所有图像 id 号。

7.4.2 用一幅图像进行查询

利用一幅图像进行查询时,没有必要进行完全的搜索。为了比较单词直方图,Searcher类需要从数据库读入图像的单词直方图。将下面的方法添加到 Searcher 类中:

def get_imhistogram(self, imname):
    """返回一幅图像的单词直方图"""
    im_id = self.con.execute(
        "select rowid from imlist where filename='%s'" % imname
    ).fetchone()
    
    if im_id is None:
        return None

    s = self.con.execute(
        "select histogram from imhistograms where rowid='%d'" % im_id[0]
    ).fetchone()
    
    # 用 pickle 模块从字符串解码 Numpy 数组
    return pickle.loads(s[0])

这里,为了在字符串和 NumPy 数组间进行转换,我们再次用到了 pickle 模块,这次使用的是 loads()。

现在,我们可以全部合并到查询方法中:

def query(self, imname):
    """查找所有与 imname 匹配的图像列表"""
    h = self.get_imhistogram(imname)
    if h is None:
        return []

    candidates = self.candidates_from_histogram(h)
    matchscores = []

    for imid in candidates:
        # 获取名字
        cand_name = self.con.execute(
            "select filename from imlist where rowid=%d" % imid
        ).fetchone()[0]

        cand_h = self.get_imhistogram(cand_name)
        if cand_h is None:
            continue

        # 用 L2 距离度量相似性
        cand_dist = sqrt(sum(self.voc.idf * (h - cand_h) ** 2))
        matchscores.append((cand_dist, imid))

    # 返回排序后的距离及对应数据库 ids 列表
    matchscores.sort()
    return matchscores

该 query() 方法获取图像的文件名,检索其单词直方图及候选图像列表

尝试对图像进行查询

src = imagesearch.Searcher('test.db', voc)
print('try a query...')
print(src.query(imlist[0])[:10])

这会再次打印前 10 个结果,包括候选图像与查询图像间的距离,结果应该和下面类似:

在这里插入图片描述

图1 结果 ### 7.4.3 确定对比基准并绘制结果

为了评价搜索结果的好坏,我们可以计算前 4 个位置中搜索到相似图像数。计算分数的函数,将它添加到 imagesearch.py 中:

def compute_ukbench_score(src, imlist):
    """对查询返回的前 4 个结果计算平均相似图像数,并返回结果"""
    nbr_images = len(imlist)
    pos = zeros((nbr_images, 4))
    
    # 获取每幅查询图像的前 4 个结果
    for i in range(nbr_images):
        pos[i] = [w[1] - 1 for w in src.query(imlist[i])[:4]]
    
    # 计算分数,并返回平均分数
    score = array([(pos[i] // 4) == (i // 4) for i in range(nbr_images)]) * 1.0
    return sum(score) / nbr_images

该函数获得搜索的前 4 个结果,将 query() 返回的索引减去 1,因为数据库索引是从1 开始的,而图像列表的索引是从 0 开始的。然后,利用每 4 幅图像为一组时相似图像文件名是连续的这一事实,我们用整数相除计算得到最终的分数。分数为 4 时结果最理想;没有一个是准确的,分数为 0;仅检索到相同图像时,分数为 1;找到相同的图像并且其他三个中的两个相同时,分数为 3。

显示实际搜索结果的函数如下:

def plot_results(src, res):
    """显示在列表 res 中的图像"""
    plt.figure()
    nbr_results = len(res)
    
    for i in range(nbr_results):
        imname = src.get_filename(res[i])
        plt.subplot(1, nbr_results, i + 1)
        plt.imshow(array(Image.open(imname)))
        plt.axis('off')
    
    plt.show()

7.5 使用几何特性对结果排序

让我们简要地看一种用 BoW 模型改进检索结果的常用方法。BoW 模型的一个主要缺点是在用视觉单词表示图像时不包含图像特征的位置信息,这是为获取速度和可伸缩性而付出的代价。

在这里插入图片描述

图2 在 ukbench 数据集上用一些查询图像进行搜索给出的一些结果。查询图像在最左边,后面是检索到的前 5 幅图像

下面是一个载入所有模型文件并用单应性对靠前的图像进行重排的完整例子:

import pickle
import sift
import imagesearch
import homography

# 载入图像列表和词汇
with open('ukbench_imlist.pkl', 'rb') as f:
    imlist = pickle.load(f)
    featlist = pickle.load(f)

nbr_images = len(imlist)

with open('vocabulary.pkl', 'rb') as f:
    voc = pickle.load(f)

src = imagesearch.Searcher('test.db', voc)

# 查询图像的索引号和返回的搜索结果数目
q_ind = 50
nbr_results = 20

# 常规查询
res_reg = [w[1] for w in src.query(imlist[q_ind])[:nbr_results]]
print('top matches (regular):', res_reg)

# 载入查询图像特征
q_locs, q_descr = sift.read_features_from_file(featlist[q_ind])
fp = homography.make_homog(q_locs[:, :2].T)

# 用 RANSAC 模型拟合单应性
model = homography.RansacModel()
rank = {}

# 载入搜索结果的图像特征
for ndx in res_reg[1:]:
    locs, descr = sift.read_features_from_file(featlist[ndx])
    
    # 获取匹配数
    matches = sift.match(q_descr, descr)
    ind = matches.nonzero()[0]
    ind2 = matches[ind]
    
    tp = homography.make_homog(locs[:, :2].T)
    
    # 计算单应性,对内点计数。如果没有足够的匹配数则返回空列表
    try:
        H, inliers = homography.H_from_ransac(fp[:, ind], tp[:, ind2], model, match_theshold=4)
    except:
        inliers = []
    
    # 存储内点数
    rank[ndx] = len(inliers)

# 将字典排序,以首先获取最内层的内点数
sorted_rank = sorted(rank.items(), key=lambda t: t[1], reverse=True)
res_geom = [res_reg[0]] + [s[0] for s in sorted_rank]
print('top matches (homography):', res_geom)

# 显示靠前的搜索结果
imagesearch.plot_results(src, res_reg[:8])
imagesearch.plot_results(src, res_geom[:8])

首先,载入图像列表、特征列表(分别包含图像文件名和 SIFT 特征文件)及词汇。然后,创建一个 Searcher 对象,执行定期查询,并将结果保存在 res_reg 列表中。然后载入 res_reg 列表中每一幅图像的特征,并和查询图像进行匹配。单应性通过计算匹配数和计数内点数得到。最终,我们可以通过减少内点的数目对包含图像索引和内点数的字典进行排序。打印搜索结果列表到控制台,并可视化检索靠前的图像。

输出结果如下:

在这里插入图片描述

图3 输出结果样例

下图给出了常规查询和对常规查询重新排序后的一些样例结果

在这里插入图片描述

图4 基于几何一致性用单应性对搜索结果进行重排后一些实例搜索结果。在每一个例子中,上一行是没有常规查询的结果,下一行是重排后的结果

7.6 建立演示程序及Web应用

参考教材上的章节,仅作参考,具体开发可以依据个人见解进行个性化。演示代码采用 CherryPy 包,CherryPy 是一个纯 Python 轻量级 Web 服务器,使用面向对象模型。

7.6.2 图像搜索演示程序

首先,我们需要用一些 HTML 标签进行初始化,并用 Pickle 载入数据。另外,还需要有与数据库进行交互的 Searcher 对象词汇。创建一个名为 searchdemo.py 的文件,并添加下面具有两个方法的 Search Demo 类:

import cherrypy
import os
import urllib
import pickle
import random
import imagesearch

class SearchDemo(object):
    def __init__(self):
        # 载入图像列表
        with open('webimlist.txt') as f:
            self.imlist = f.readlines()
        
        self.nbr_images = len(self.imlist)
        self.ndx = list(range(self.nbr_images))
        
        # 载入词汇
        with open('vocabulary.pkl', 'rb') as f:
            self.voc = pickle.load(f)
        
        # 设置可以显示多少幅图像
        self.maxres = 15
        
        # html 的头部和尾部
        self.header = """
        <!doctype html>
        <html>
        <head>
            <title>Image search example</title>
        </head>
        <body>
        """
        
        self.footer = """
        </body>
        </html>
        """

    def index(self, query=None):
        self.src = imagesearch.Searcher('web.db', self.voc)
        html = self.header
        html += """
        <br />
        Click an image to search. <a href='?query='>Random selection</a> of images.
        <br /><br />
        """
        
        if query:
            # 查询数据库并获取靠前的图像
            res = self.src.query(query)[:self.maxres]
            for dist, ndx in res:
                imname = self.src.get_filename(ndx)
                html += "<a href='?query=" + urllib.parse.quote(imname) + "'>"
                html += "<img src='" + imname + "' width='100' />"
                html += "</a>"
        else:
            # 如果没有查询图像,则显示随机选择的图像
            random.shuffle(self.ndx)
            for i in self.ndx[:self.maxres]:
                imname = self.imlist[i].strip()
                html += "<a href='?query=" + urllib.parse.quote(imname) + "'>"
                html += "<img src='" + imname + "' width='100' />"
                html += "</a>"
        
        html += self.footer
        return html

    index.exposed = True

cherrypy.quickstart(SearchDemo(), '/', config=os.path.join(os.path.dirname(__file__), 'service.conf'))

在这里插入图片描述

图5 在 ukbench 数据集上进行搜索的示例。上方是开始页面,显示了一些随机选择的图像;下方是一些查询示例。左上角是查询图像,之后的是搜索到的一些结果靠前的图像

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

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

相关文章

优秀一点点

在职场中&#xff0c;想要获得晋升&#xff0c;重要的是比其他同事优秀一点点。这就好比百米短跑比赛&#xff0c;第一名比第二名可能之快了0.01秒&#xff0c;这个0.01秒&#xff0c;和跑一百米所花的10秒钟比起来&#xff0c;可能只有千分之一。也就是说&#xff0c;第一名比…

麦汁煮沸工艺

麦汁煮沸是啤酒酿造中至关重要的工艺环节之一&#xff0c;直接影响啤酒的风味。今天&#xff0c;天泰邀您一起深入探讨这一关键的酿造技术。 煮沸麦汁 在煮沸麦汁时&#xff0c;时间和温度控制至关重要。通常&#xff0c;麦汁煮沸持续 40 到 50 分钟&#xff0c;具体时间取决于…

OpenAI Embeddings API: How embeddings work?

题意&#xff1a;OpenAI 嵌入 API&#xff1a;嵌入是如何工作的&#xff1f; 问题背景&#xff1a; There are quite a few tutorials on embeddings in OpenAI. I cant understand how they work. 在OpenAI中有很多关于嵌入的教程&#xff0c;但我无法理解它们是如何工作的。…

轻松实现游戏串流,内网穿透

一、部署Gemini Gemini使用教程 二、部署Moonlight 过程大概说一下&#xff0c;网上有太多太多moonlight的东西了 需要运行游戏的机器上安装GFE&#xff08;GeForce Experience&#xff09;&#xff0c;登录并开启GAMESTREAM&#xff08;游戏串流&#xff09;功能 注&…

什么是 Flash Attention

Flash Attention 是 由 Tri Dao 和 Dan Fu 等人在2022年的论文 FlashAttention: Fast and Memory-Efficient Exact Attention with IO-Awareness 中 提出的&#xff0c; 论文可以从 https://arxiv.org/abs/2205.14135 页面下载&#xff0c;点击 View PDF 就可以下载。 下面我…

Php数组函数中的那些什么sort排序函数是不是很乱? 可以这样看。以及php搜索给定的值在数组中最后一次出现的位置的实现思考

一、Php数组函数中的那些什么sort排序函数是不是很乱? 可以这样看 PHP的数组函数真不少&#xff0c;甚至对一个程序员来说&#xff0c;在其整个程序生涯中有些方法他永远也不会用上。不过每一个方法都有其价值、或者在出现的时候有其价值。所以偶尔有空时还是可以去看看。在这…

并发编程:线程池(下)

一、线程池常用的阻塞队列有哪些&#xff1f; 新任务来的时候会先判断当前运行的线程数量是否达到核心线程数&#xff0c;如果达到的话&#xff0c;新任务就会被存放在队列中。 不同的线程池会选用不同的阻塞队列&#xff0c;我们可以结合内置线程池来分析。 容量为 Integer…

UE5 半透明阴影 快速解决方案

Step 1&#xff1a; 打开该选项 Step 2&#xff1a; 将半透明材质给到模型后&#xff0c;设置光照的Shadow Resolution Scale&#xff0c;越大&#xff0c;阴影的效果越好 Step 3&#xff1a; 用这种方式去做&#xff0c;阴影会因为半透明的程度&#xff0c;降低阴影的浓度 要…

Spring security 动态权限管理(基于数据库)

一、简介 如果对该篇文章不了解&#xff0c;请移步上一篇文章&#xff1a;spring security 中的授权使用-CSDN博客 当我们配置的 URL 拦截规则请求 URL 所需要的权限都是通过代码来配置的&#xff0c;这样就比较死板&#xff0c;如果想要调整访问某一个 URL 所需要的权限&…

【专项刷题】— 队列

1、N 叉树的层序遍历 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 每次遍历一层节点的时候就把当前节点的值添加到列表中再将当前层的节点的子节点添加到队列中每次遍历完一层之后就添加到总表中代码&#xff1a; public List<List<Integer>> levelO…

如何远程实时监控员工的电脑屏幕?远程桌面监控的五个可实现方法分享

想象一下&#xff0c;你在办公室喝着咖啡&#xff0c;员工的电脑屏幕却在数百公里之外实时呈现在你的眼前。你可以看到他们在干什么&#xff0c;是埋头工作还是悄悄摸鱼&#xff1f;远程桌面监控让这一切变得触手可及&#xff0c;简直像给了管理者一双“千里眼”&#xff01; 如…

RedisTemplate操作String的API

文章目录 1 String 介绍2 命令3 对应 RedisTemplate API❄️❄️ 3.1 添加缓存❄️❄️ 3.2 设置过期时间(单独设置)❄️❄️ 3.3 获取缓存值❄️❄️ 3.4 删除key❄️❄️ 3.5 顺序递增❄️❄️ 3.6 顺序递减 ⛄4 以下是一些常用的API⛄5 应用场景 1 String 介绍 String 类型…

9.10-AutoAWQ代码解析

1、首先要去官网下载源码。https://github.com/casper-hansen/AutoAWQ.githttps://github.com/casper-hansen/AutoAWQ.git 2、git clone后&#xff0c;下载AutoAWQ所需环境。 pip install -e . 3、查看quantize.py代码&#xff0c;修改model_path部分&#xff0c;修改为想要量…

系统架构师考试学习笔记第四篇——架构设计实践知识(19)嵌入式系统架构设计理论与实践

本章考点&#xff1a; 第19课时主要学习嵌入式系统架构设计的理论和工作中的实践。根据新版考试大纲&#xff0c;本课时知识点会涉及案例分析题&#xff08;25分&#xff09;。在历年考试中&#xff0c;案例题对该部分内容都有固定考查&#xff0c;综合知识选择题目中有固定分值…

您与该网站的连接不是私密连接,存在安全隐患

您与该网站的连接不是私密连接&#xff0c;存在安全隐患。 攻击者可能会试图窃取您的信息&#xff08;例如&#xff1a;密码、通讯内容或信用卡信息&#xff09;。为避免您的信息失窃&#xff0c;建议您停止访问该页面。了解详情 解决办法如下&#xff1a; 1、查看电脑时间&…

使用FastJson2将对象转成JSON字符串时,小数位“0”开头时转换出错

maven坐标&#xff1a; <dependency> <groupId>com.alibaba.fastjson2</groupId> <artifactId>fastjson2</artifactId> <version>2.0.40</version> </dependency> 问题现象&#xff1a; 问题原因&#xff1a; I…

IP路由选择

文章目录 1. 基本概念2. RIP(路由选择信息协议)3. OSPF 1. 基本概念 路由选择协议 路由选择协议让路由器能够动态地发现互联网络&#xff0c;并确保所有路由器的路由选择表都相同。路由选择协议还用于找出最佳路径&#xff0c;让分组穿越互联网络前往目的地的效率最高。RIP、R…

领夹麦克风哪个品牌好?无线领夹麦克风品牌大全,麦克风推荐

在这个全民直播、Vlog盛行的时代&#xff0c;一款轻便高效的无线领夹麦克风成了不少内容创作者的必备神器。但市面上产品五花八门&#xff0c;有的打着“超远传输、无损音质”的旗号&#xff0c;实则性能平平&#xff0c;甚至存在信号干扰、噪音大等问题&#xff0c;让人直呼交…

SpringBoot集成MyBatis-PlusDruid

目录 MyBatis-Plus简介 实例演示 创建Springboot项目 初始化Springboot项目 添加关键依赖 application.properties添加相关配置 启动类 编写实体类 编写mapper接口 条件构造器 分页插件 自定义 SQL 映射 MyBatis-Plus简介 MyBatis-Plus简介‌MyBatis-Plus‌&…

铁威马秋季新品即将上线,你想要的NAS我都有!

各位铁粉们&#xff0c;注意啦&#xff01; 一场关于存储的饕餮盛宴即将拉开帷幕 铁威马&#xff0c;带着九款全新力作NAS 将于9月19日席卷全球市场 是的&#xff0c;你没听错 九款&#xff01; 从入门级到专业级 从桌面型到机架式 全系搭载TOS 6 总有一款能击中你的心…