【以图搜图代码实现2】--faiss工具实现犬类以图搜图

第一篇:【以图搜图代码实现】–犬类以图搜图示例 使用保存成h5文件,使用向量积来度量相似性,实现了以图搜图,说明了可以优化的点。
第二篇:【使用resnet18训练自己的数据集】 准对模型问题进行了优化,取得了显著性的效果。
本篇继续第一篇中所说的优化方向,使用faiss实现以图搜图。

1.faiss使用介绍

Faiss的全称是Facebook AI Similarity Search,是FaceBook针对大规模相似度检索问题开发的一个工具,底层是使用C++代码实现的,提供了python的接口,号称对10亿量级的索引可以做到毫秒级检索。

使用faiss的基本步骤
1、数据转换:把原始数据转换为"float32"数据类型的向量。
2、index构建:用 faiss 构建index
3、数据添加:将向量add到创建的index中
4、通过创建的index进行检索

1.创建索引

import faissdef create_index(datas_embedding):# 构建索引,L2代表构建的index采用的相似度度量方法为L2范数# 必须传入一个向量的维度,创建一个空的索引index = faiss.IndexFlatL2(datas_embedding.shape[1])  # 把向量数据加入索引index.add(datas_embedding)   return index

2.保存索引

def faiss_index_save(faiss_index, save_file_location):faiss.write_index(faiss_index, save_file_location)

3.加载索引

def faiss_index_load(faiss_index_save_file_location):index = faiss.read_index(faiss_index_save_file_location)return index

4.向索引中添加向量

def index_data_add(faiss_index, img_path):# 获得索引向量的数量print(faiss_index.ntotal)img_embedding = extract_image_features(img_path)faiss_index.add(img_embedding)print(faiss_index.ntotal)

5.删除索引中的向量

def index_data_delete(faiss_index):print(faiss_index.ntotal)# remove, 指定要删除的向量id,是一个np的arrayfaiss_index.remove_ids(np.array([0]))print(faiss_index.ntotal)

可以看出使用Faiss工具更加的灵活,可以向索引中添加和删除向量。

2.faiss实现以图搜图

本篇代码有部分是在前两篇的基础之上的,这里使用11类犬类数据集微调之后的resnet18进行特征提取。
第一篇:【以图搜图代码实现】–犬类以图搜图示例
第二篇:【使用resnet18训练自己的数据集】

数据集准备和下载可以去看第二篇文章。

1.模型加载

为了更好的适配,对第一篇中的resnet18的初始化方法进行了修改,如下:

@Project :ImageRec
@File    :resnet18.py
@IDE     :PyCharm
@Author  :菜菜2024
@Date    :2024/9/30
'''
from PIL import Image
from torchvision import transforms
import torch
import torch.nn as nn
from torchvision import modelsclass ResNet18:def __init__(self,out_feature = 11,model_path='E:\\xxx\\ImageRec\\weights\\resnet18.pth'):self.trans = transforms.Compose([transforms.Resize(size=(256, 256)),transforms.CenterCrop(224),transforms.ToTensor(),transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])])print("-----------loading resnet18------------")self.model = models.resnet18()num_feats = self.model.fc.in_featuresself.model.fc = nn.Linear(num_feats, out_feature)self.model.load_state_dict(torch.load(model_path))self.model.eval()def extract_image_features(self, img_path):image = Image.open(img_path).convert('RGB')image_tensor = self.trans(image).unsqueeze(0)with torch.no_grad():features = self.model(image_tensor)return features

其中out_feature 根据自己的数据集的类别个数进行更改,我这里的犬类是11种。model_path是训练好的保存的权重文件【训练过程可以去看第二篇】

2.文件名映射

在第一篇:【以图搜图代码实现】–犬类以图搜图示例 中使用的是保存成h5文件,索引是没有要求是整数的,这里faiss要求是整数,搞了一个映射方法,同时也是为了在后面可视化的时候,能根据索引再解码得到对应的文件路径。

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
'''
@Project :ImageRec 
@File    :Imgmap.py
@IDE     :PyCharm 
@Author  :菜菜2024
@Date    :2024/9/29 18:02 
'''
import os
import uuid
import numpy as npdef getImgMap(img_path):# 为类别生成一个映射文件subnames = [f.split('\\')[-1] for f in os.listdir(img_path)]element_mapping = {}for i in range(len(subnames)):unique_id = str(i+2024)element_mapping[unique_id] = subnames[i]return element_mappingdef valueGetKey(mapping, target_value):for key, value in mapping.items():if value == target_value:# print(f"值 '{target_value}' 对应的键是: {key}")breakreturn keydef nameMap(imgnames, img_path='E:\\xxx\\datas\\pet_dog\\train'):'''getImagVector函数得到的image_ids在保存为h5文件时进行了编码现在faiss工具中index需要是int类型的,这里进行映射转化:param img_path: 数据集目录,来得到类别映射:param imgnames: 需要映射的图片名称,解码之后是“中华田园犬_0”格式这里传参是列表:return:'''element_mapping = getImgMap(img_path)decode_names = [imgname.decode('utf-8') for imgname in imgnames]name_ids=[]for decode_name in decode_names:cla_name = decode_name.split("_")[0]img_name = decode_name.split("_")[-1]key = valueGetKey(element_mapping, cla_name)name_id = key+img_namename_ids.append(name_id)name_ids=np.array(name_ids).astype('int32')return name_idsif __name__ == "__main__":database = 'E:\\xxx\\datas\\pet_dog\\train'element_mapping = getImgMap(database)print(element_mapping)print(element_mapping.get("2024"))

映射文件:

{‘2024’: ‘中华田园犬’, ‘2025’: ‘吉娃娃’, ‘2026’: ‘哈士奇’, ‘2027’: ‘德牧’, ‘2028’: ‘拉布拉多’, ‘2029’: ‘杜宾’, ‘2030’: ‘柴犬’, ‘2031’: ‘法国斗牛’, ‘2032’: ‘萨摩耶’, ‘2033’: ‘藏獒’, ‘2034’: ‘金毛’}
nameMap函数是将之前编码的图像名称进行解码,然后重新编码,编码成20240,20301,分别表示的中华田园犬文件夹下的0.jpg, 柴犬下面的1.jpg。这都是为了可视化的时候进行追溯,得到文件路径。
在这里插入图片描述

3.以图搜图实现

定义了一个类ImageRetrival,使用faiss实现创建索引,保存索引,加载索引和图像检索功能

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
'''
@Project :ImageRec 
@File    :faiss_index.py
@IDE     :PyCharm 
@Author  :菜菜2024
@Date    :2024/9/30 15:04 
'''import os
import faiss
from utils.split_data import array_norm
from utils.Imgmap import nameMap, getImgMap
from model import ResNet18
from save_feature import getImagVectors
import matplotlib.image as mpimg
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import rc
# 设置全局字体为支持中文的字体
rc('font', family='SimHei')  # 黑体class ImageRetrival:def __init__(self, model_path,index_dim=None):self.index_dim = index_dimself.index = faiss.IndexFlatL2(self.index_dim)self.model_path = model_pathdef build_index(self, image_files):# image_vectors图片特征,image_ids对应的标签image_vectors, image_ids = getImagVectors(image_files)# image_ids 在之前保存为h5文件时进行了编码,这里进行映射name_ids = nameMap(image_ids)index = faiss.IndexIDMap(self.index)index.add_with_ids(image_vectors, name_ids)return indexdef save_index(self, index, index_path):faiss.write_index(index, index_path)def load_index(self, index_path):return faiss.read_index(index_path)def image_topK_search(self, index, input_image, topK=None):resnet18 = ResNet18(out_feature=11,model_path=self.model_path)queryVec = resnet18.extract_image_features(input_image)dist, ind = index.search(queryVec, topK)dist, ind = dist.flatten(), ind.flatten()res = array_norm(dist, ind)return res

4.运行调用

if __name__=="__main__":model_path='E:\\xxx\\Pycharm_files\\ImageRec\\weights\\resnet18.pth'# 1.创建索引imageRetrival = ImageRetrival(model_path=model_path,index_dim=11)image_files = 'E:\\xxx\\datas\\pet_dog\\train'save_index = "./weights/dog.index"index = imageRetrival.build_index(image_files)# # 2.保存索引imageRetrival.save_index(index, save_index)# 3.加载索引index_load = imageRetrival.load_index(save_index)## # 4.相似度匹配input_image = './data/pic/德牧.jpg'out = imageRetrival.image_topK_search(index_load, input_image, topK=3)print(out)showFaissRes(image_files, input_image, out)

运行时选择性注销其中的某一步骤。
最后是可视化实现showFaissRes

5.可视化实现


def showFaissRes(image_files, input_image, faissRes):'''对faiss得到的结果进行可视化:param image_files: 图片数据库:param input_image: 查询图片路径:param faissRes: 返回的topk跟距离最近的结果[(ind, score), (ind, score)]:return:'''scores = []imgs = []info = []# 1.得到图片名称的映射element_mapping = getImgMap(image_files)imgs.append(mpimg.imread(input_image))info.append(input_image.split("/")[-1])for i in range(len(faissRes)):score = faissRes[i][1]ind = str(faissRes[i][0])scores.append(score)# 根据索引构建原本的图像路径ind格式:20276,前四个是类别表示claName = element_mapping.get(ind[:4])imgName = ind[4:]+".jpg"imgpath = image_files +"\\"+ claName+ "\\"+imgNameimgs.append(mpimg.imread(imgpath))info.append(claName+"_"+ imgName+"_"+ str(score))print("图片名称是: " + claName+ imgName + " 对应得分是: %f" %score)num = int((len(faissRes) + 1) // 2)+1fig, axs = plt.subplots(nrows=num, ncols=num, figsize=(10, 10))# 确保即使只有一个子图,也可以进行索引if not isinstance(axs, np.ndarray):axs = np.array([[axs]])# 显示图像flat_index = 0for i in range(num):for j in range(num):if flat_index < len(imgs):img = imgs[flat_index]axs[i, j].imshow(img, cmap='gray')axs[i, j].axis('off')axs[i, j].set_title(info[flat_index])flat_index += 1else:axs[i, j].set_visible(False)plt.tight_layout()plt.show()

3.效果对比

第一篇:【以图搜图代码实现】–犬类以图搜图示例 预训练的resnet18

第二篇:【使用resnet18训练自己的数据集】 微调的resnet18
在这里插入图片描述

本章 Faiss实现: 分数不重要,本篇对分数进行了归一化。
在这里插入图片描述
准确性更高了。

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

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

相关文章

【完-网络安全】Windows用户

文章目录 内置账号用户组通过命令行管理用户 内置账号 通过注销切换用户账号 Administrator用户 该帐号为系统默认的管理员帐号&#xff0c;该帐户具有Windows的最高管理权限&#xff0c;默认禁用。 Guest用户&#xff0c;来宾账户 可运行部分抵权限程序&#xff0c;查看部分文…

【STM32单片机_(HAL库)】4-0【定时器TIM】定时器中断配置步骤

定时器工作原理 定时器计数模式 定时器溢出时间计算 定时器中断实验配置步骤 msp 函数是对 MCU 相关的硬件进行初始化设置&#xff0c;通常被设计用于处理特定硬件外设或功能的底层初始化工作。

redis的数据结构,内存处理,缓存问题

redisObject redis任意数据的key和value都会被封装为一个RedisObject&#xff0c;也叫redis对象&#xff1a; 这就redis的头信息&#xff0c;占有16个字节 redis中有两个热门数据结构 1.SkipList&#xff0c;跳表&#xff0c;首先是链表&#xff0c;和普通链表有以下差异&am…

前端工程规范-2:JS代码规范(Prettier + ESLint)

Prettier 和 ESLint 是两个在现代 JavaScript 开发中广泛使用的工具&#xff0c;它们结合起来可以提供以下作用和优势&#xff1a; 代码格式化和风格统一&#xff1a; Prettier 是一个代码格式化工具&#xff0c;能够自动化地处理代码的缩进、空格、换行等格式问题&#xff0c;…

【STM32单片机_(HAL库)】4-2【定时器TIM】定时器输出PWM配置步骤

PWM介绍 PWM波形&#xff08;Pulse Width Modulation&#xff0c;脉冲宽度调制波形&#xff09;是一种占空比可变的脉冲波形。 频率 1/Ts 占空比 Ton / Ts 分辨率 占空比变化步距 定时器输出PWM配置

2024年十大热门人力资源管理系统对比与推荐

本文介绍了ZohoPeople、金蝶云、用友、北森等10款热门HRMS系统&#xff0c;包括各自特点如ZohoPeople的全球化管理、北森的全面人才管理等。建议企业先试用再决定购买&#xff0c;以找到最适合的系统。 一、Zoho People Zoho People 是一个基于云的全球化人力资源管理系统 (HR…

啤酒在文学中的浪漫形象:精酿啤酒的诗意之旅

在文学的浩瀚星空中&#xff0c;啤酒并非仅仅是醉人的琼浆&#xff0c;它更是一种情感的载体&#xff0c;一种浪漫的符号。尤其是当提及Fendi Club精酿啤酒时&#xff0c;我们仿佛能闻到那从古老酒窖中飘出的馥郁香气&#xff0c;感受到它在文字间流淌的诗意与温情。 一、啤酒…

鸿蒙开发(NEXT/API 12)【请求用户授权】手机侧应用开发

为保护用户隐私&#xff0c;Wear Engine的API需要用户授权才可以正常访问。建议开发者在用户首次调用Wear Engine开放能力的时候执行本章节操作。 申请用户穿戴设备权限 应用拉起华为账号登录和授权界面&#xff0c;由用户授权相应的数据访问权限。用户可以自主选择授权的数据…

建筑中的文化表达与地方特色:演绎地域之魂

在浩瀚的城市风貌中&#xff0c;每一座建筑都是文化的载体&#xff0c;无声地讲述着地域的故事与精神。建筑不仅需要满足功能需求&#xff0c;更应成为文化传承与创新的舞台。本文旨在深度剖析建筑设计如何在尊重与弘扬地方文化的基础上&#xff0c;巧妙融合现代元素&#xff0…

【含文档】基于Springboot+Vue的公园管理系统(含源码+数据库+lw)

1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springboot,mybatis,mysql,vue 2.视频演示地址 3.功能 系统定…

前端css样式设置元素的绝对定位和相对定位,要注意宽度和高度的设置

vue3子div position absolute,父div positon relative 。如果不设置子div的 width 和height,那么子div中如果数据变长,子div相对父div位置会变化。子div数据超过&#xff0c;显示... 如何实现 <template><div class"parent"><div class"child&q…

开源实战分享 | 新书:《大型语言模型实战手册》随书代码分享

《大型语言模型实战手册》(英文版)目前电子版在亚马逊有售&#xff0c;纸质版预计在2024年10月15日开售。该书通过超过275张定制插图&#xff0c;深入探索大型语言模型的世界&#xff0c;为Python开发者提供使用大型语言模型所需的实用工具和概念。 如果对于插图没有特别执念的…

商务英语口语柯桥外语学习|ass是“屁股”,save是“救”,那 save my ass是什么意思?

有些人活着&#xff0c;屁股却已经“死”了 工作工作&#xff0c;上工就“坐”&#xff0c;“久坐”几乎是无法避免的事情&#xff0c;但你知道吗&#xff0c;长期久坐可能会患上死臀综合症&#xff08;Dormant Butt Syndrome&#xff09;&#xff01; 如果你坐久了就觉得屁股痛…

PCL库简单的icp配准

#include <pcl/io/pcd_io.h> #include <pcl/point_types.h> #include <pcl/registration/icp.h>int main(int argc, char** argv) {// 确保提供了两个PCD文件作为输入if (argc ! 3) {PCL_ERROR("请提供两个PCD文件作为输入。\n");return (-1);}// …

Spring系列 BeanPostProcessor

文章目录 BeanPostProcessor注册时机执行时机 InstantiationAwareBeanPostProcessorSmartInstantiationAwareBeanPostProcessor 本文源码基于spring-beans-5.3.31 参考&#xff1a;https://docs.spring.io/spring-framework/reference/core/beans/factory-extension.html#beans…

C#实战|人员管理系统[1]:项目主体框架如何搭建

哈喽,你好啊,我是雷工! 有人的地方就有江湖,有江湖的地方就得用人员管理系统,今天开始练习实现一个人员管理系统。 以下为练习笔记。 01 UI层 这里使用的版本是:VS2022 创建一个Windows窗体应用程序,命名为:PeopleManger 可以添加一个通用类文件夹,集中放置通用的一些…

mybatis-plus ==> 入门教程

文章目录 为什么要学呢&#xff1f;注意事项 简单入门案例配置日志雪花算法更改 ID 的方法 CRUD插入&#xff08;不解释了&#xff0c;代码非常简单&#xff09;更新查询&#xff08;批量查询&#xff09;按条件查询分页查询删除&#xff08;批量、通过条件、逻辑删除&#xff…

AutoSar 通信服务架构,CAN通信诊断详解

文章目录 Com&#xff08;通信服务模块&#xff09;PDU的定义和结构PDU的分类IPDU Mux 模块PDU R 模块&#xff08;路由&#xff09;Bus TP 模块BUS InterfaceCanIf模块LinIf模块 发送数据示例&#xff08;CAN报文&#xff09;接收数据示例&#xff08;CAN报文&#xff09;通信…

基于SpringBoot的休闲娱乐代理售票系统设计与实现

1.1研究背景 21世纪&#xff0c;我国早在上世纪就已普及互联网信息&#xff0c;互联网对人们生活中带来了无限的便利。像大部分的企事业单位都有自己的系统&#xff0c;由从今传统的管理模式向互联网发展&#xff0c;如今开发自己的系统是理所当然的。那么开发休闲娱乐代理售票…

CSS外边距

元素的外边距&#xff08;margin&#xff09;是围绕在元素边框以外&#xff08;不包括边框&#xff09;的空白区域&#xff0c;这片区域不受 background 属性的影响&#xff0c;始终是透明的。 为元素设置外边距 默认情况下如果不设置外边距属性&#xff0c;HTML 元素就是不会…