当前位置: 首页 > news >正文

通过Faiss和DINOv2进行场景识别

目标:通过Faiss和DINOv2进行场景识别,确保输入的照片和注册的图片,保持内容一致。

MetaAI 通过开源 DINOv2,在计算机视觉领域取得了一个显着的里程碑,这是一个在包含1.42 亿张图像的令人印象深刻的数据集上训练的模型。产生适用于图像级视觉任务(图像分类、实例检索、视频理解)以及像素级视觉任务(深度估计、语义分割)的通用特征。

Faiss是一个用于高效相似性搜索和密集向量聚类的库。它包含的算法可以搜索任意大小的向量集,甚至可能无法容纳在 RAM 中的向量集。

#!usr/bin/env python
# -*- coding:utf-8 -*-# pip install transformers faiss-gpu torch Pillow
import torch
import os
import concurrent.futures
from transformers import AutoImageProcessor, AutoModel
from PIL import Image
import faiss
from tqdm import tqdm
import numpy as np
from utils_img import *os.environ["CUDA_VISIBLE_DEVICES"] = "1"class SceneRecognition:def __init__(self, dimension=384, threshold=0.8, batch_size=128):"""初始化 SceneRecognition 类Parameters:dimension (int): 向量的维度,默认为 384"""# 加载模型和处理器self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')self.processor = AutoImageProcessor.from_pretrained('models/dinov2-small')self.model = AutoModel.from_pretrained('models/dinov2-small').to(self.device)# 保存特征向量的维度self.dimension = dimension# 搭配 faiss.normalize_L2 创建 Faiss 的余弦相似度索引self.index = faiss.IndexFlatIP(self.dimension)# 保存图片向量对应的 idself.ids = []# 保存特征向量数据库self.db_path = "vector.index"# 图片路径self.images_path = []# 相似度阈值self.threshold = thresholdself.batch_size = batch_size# 初始化self.init()def read_image_open(self, image_path):"""打开图像并返回图像和图像路径Parameters:image_path (str): 图像的路径Returns:Image: 打开的图像str: 图像的路径"""# 默认以 RGB 模式打开image = Image.open(image_path)return image, image_pathdef read_images_from_folder(self, file_path):"""从文件夹中读取图像Parameters:file_path (str or list): 文件夹的路径或文件路径列表Returns:list: 图像列表list: 图像路径列表"""image_list = []image_path_list = []try:if type(file_path) is not list:task_list = get_files(file_path)else:task_list = file_path# 使用线程池执行器with concurrent.futures.ThreadPoolExecutor(max_workers=6) as executor:res = executor.map(self.read_image_open, task_list)image_list, image_path_list = list(zip(*res))return image_list, image_path_listexcept Exception as e:return None, Nonedef download_model(self):"""从 huggingface_hub 下载模型"""from huggingface_hub import snapshot_downloadsnapshot_download(repo_id="facebook/dinov2-small",  # 模型 IDlocal_dir="./models/dinov2-small")  # 指定本地地址保存模型def init(self):"""初始化模型"""batch_images = np.zeros((self.batch_size, 1920, 1080, 3),dtype=np.int8)batch_inputs = self.processor(images=batch_images,return_tensors="pt").to(self.device)batch_outputs = self.model(**batch_inputs)def add_vector_to_index(self, embedding, index):"""将向量添加到索引中Parameters:embedding (torch.Tensor): 特征向量index (faiss.Index): Faiss 索引"""vector = embedding.detach().cpu().numpy()vector = np.float32(vector)faiss.normalize_L2(vector)index.add(vector)def create_database_from_images(self, file_path):"""从图像创建数据库Parameters:file_path (str or list): 图像文件夹的路径或图像路径列表"""image_list, self.images_path = self.read_images_from_folder(file_path)self.extract_features_form_images(image_list)def create_database_from_batch_images(self, file_path):"""从批量图像创建数据库Parameters:file_path (str or list): 图像文件夹的路径或图像路径列表"""image_list, self.images_path = self.read_images_from_folder(file_path)self.extract_features_form_batch_images(image_list)def extract_features_form_images(self, images):"""从图像列表提取特征Parameters:images (list): 图像列表"""for image_id, img in enumerate(images):with torch.no_grad():inputs = self.processor(images=img,return_tensors="pt").to(self.device)outputs = self.model(**inputs)features = outputs.last_hidden_state.mean(dim=1)self.add_vector_to_index(features, self.index)# 记录特征向量的 idself.ids.append(image_id)# faiss.write_index(self.index, self.db_path)def extract_features_form_batch_images(self, image_list):"""从批量图像中提取特征Parameters:image_list (list): 图像列表"""img_num = len(image_list)for beg_img_no in tqdm(range(0, img_num, self.batch_size),desc="Extracting features"):end_img_no = min(img_num, beg_img_no + self.batch_size)batch_image = image_list[beg_img_no:end_img_no]with torch.no_grad():batch_inputs = self.processor(images=batch_image,return_tensors="pt").to(self.device)batch_outputs = self.model(**batch_inputs)batch_features = batch_outputs.last_hidden_state.mean(dim=1)for image_id, features in enumerate(batch_features):self.add_vector_to_index(features.reshape(1, -1),self.index)# 记录特征向量的 idimage_id += beg_img_noself.ids.append(image_id)# faiss.write_index(self.index, self.db_path)def search_similar_batch_images(self, user_image_path, k=1):"""批量搜索相似图像Parameters:user_image_path (str or list): 用户图像的路径或路径列表k (int): 搜索的近邻数量Returns:list: 相似图像的路径列表"""image_list, image_path_list = self.read_images_from_folder(user_image_path)img_num = len(image_list)similar_base_images = []similar_query_images = []for beg_img_no in tqdm(range(0, img_num, self.batch_size),desc="Searching similar images"):end_img_no = min(img_num, beg_img_no + self.batch_size)batch_image = image_list[beg_img_no:end_img_no]batch_image_path = image_path_list[beg_img_no:end_img_no]with torch.no_grad():batch_inputs = self.processor(images=batch_image,return_tensors="pt").to(self.device)batch_outputs = self.model(**batch_inputs)query_features = batch_outputs.last_hidden_state.mean(dim=1)batch_query_vector = query_features.detach().cpu().numpy()batch_query_vector = np.float32(batch_query_vector)faiss.normalize_L2(batch_query_vector)batch_distances, batch_indices = self.index.search(batch_query_vector, k)if len(batch_distances) > 0:for image_path, dis, ind in zip(batch_image_path,batch_distances,batch_indices):# 保存超过阈值的最相似特征向量if dis[0] > self.threshold:similar_base_images.append(self.images_path[ind[0]])similar_query_images.append(image_path)dissimilar_images = list(set(image_path_list).difference(set(similar_query_images)))return similar_query_imagesdef search_similar_images(self, query_image_path, k=1):"""搜索相似图像Parameters:query_image_path (str): 查询图像的路径k (int): 搜索的近邻数量Returns:list: 相似图像的路径列表"""img = Image.open(query_image_path).convert('RGB')with torch.no_grad():inputs = self.processor(images=img,return_tensors="pt").to(self.device)outputs = self.model(**inputs)query_features = outputs.last_hidden_state.mean(dim=1)query_vector = query_features.detach().cpu().numpy()query_vector = np.float32(query_vector)faiss.normalize_L2(query_vector)distances, indices = self.index.search(query_vector, k)similar_base_images = []similar_query_images = []if len(distances) > 0:for dis, ind in zip(distances, indices):# 保存超过阈值的最相似特征向量if dis > self.threshold:similar_base_images.append(self.images_path[ind[0]])similar_query_images.append(query_image_path)return similar_query_imagesdef remove_image_by_id(self, image_id):"""根据 ID 删除图像Parameters:image_id (int): 图像的 ID"""# 先删除高索引的元素,再删除低索引的元素,避免索引错位的问题。index_to_remove = [i for i, stored_id in enumerate(self.ids) if stored_id == image_id]  # 找到需要删除的特征向量的索引for i in sorted(index_to_remove, reverse=True):# 从 Faiss 索引中删除对应的特征向量self.index.remove_ids(np.array([i]))# 从 id 列表中删除对应的 iddel self.ids[i]def get_num_images(self):"""获取保存的图像数量Returns:int: 保存的图像数量"""# 返回保存的图片向量数量return len(self.ids)def clear_data_base(self):"""清空数据库"""# 重置 Faiss 索引self.index.reset()# 清空 id 列表self.ids.clear()if __name__ == '__main__':# 创建一个 SceneRecognition 实例scene_rec = SceneRecognition()scene_rec.create_database_from_batch_images('imgs')scene_rec.search_similar_batch_images('images')

参考网址:

  1. https://blog.csdn.net/level_code/article/details/137772620
  2. https://blog.csdn.net/weixin_38739735/article/details/136979083
  3. https://blog.csdn.net/u010970956/article/details/134945210
  4. https://blog.csdn.net/hh1357102/article/details/135066581
  5. https://blog.csdn.net/sinat_34770838/article/details/137021023
  6. https://zhuanlan.zhihu.com/p/704250322
  7. https://zhuanlan.zhihu.com/p/668148439
  8. https://blog.51cto.com/u_14273/10165547
  9. https://blog.csdn.net/ResumeProject/article/details/135350945
  10. https://www.zhihu.com/question/637818872/answer/3380169469
  11. https://zhuanlan.zhihu.com/p/644077057

相关文章:

通过Faiss和DINOv2进行场景识别

目标:通过Faiss和DINOv2进行场景识别,确保输入的照片和注册的图片,保持内容一致。 MetaAI 通过开源 DINOv2,在计算机视觉领域取得了一个显着的里程碑,这是一个在包含1.42 亿张图像的令人印象深刻的数据集上训练的模型…...

新手入门基础Java

一:基础语法 1.Java的运行机制 2. Java基本语法 1.注释、标识符、关键字; 2.数据类型(四类八种) 3.类型转换 1.自动转换;2.强制转换; 4.常量和变量 1.常量;2.变量; 3.变量的作用域 5.运算符 1.算数运算符;2.赋值运算符;3.关系运算符; 4.逻辑运算符;5.自…...

2024最新版虚拟便携空调小程序源码 支持流量主切换空调型号

产品截图 部分源代码展示 urls.js Object.defineProperty(exports, "__esModule", {value: !0 }), exports.default ["9c5f1fa582bee88300ffb7e28dce8b68_3188_128_128.png", "E-116154b04e91de689fb1c4ae99266dff_960.svg", "573eee719…...

前端在浏览器总报错,且获取请求头中token的值为null

前端请求总是失败说受跨域请求影响,但前后端配置已经没有问题了,如下: package com.example.shop_manage_sys.config;import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Conf…...

html+css前端作业 王者荣耀官网6个页面无js

htmlcss前端作业 王者荣耀官网6个页面无js 下载地址 https://download.csdn.net/download/qq_42431718/89571150 目录1 目录2 项目视频 王者荣耀6个页面(无js) 页面1 页面2 页面3 页面4 页面5 页面6...

在windows上使用Docker部署一个简易的web程序

使用Docker部署一个python的web服务🚀 由于是从事算法相关工作,之前在项目中,需要将写完的代码服务,部署在docker上,以此是开始接触了Docker这个工具,由于之前也没系统学习过,之后应该可能还会用…...

sqlalchemy使用mysql的json_extract函数查询JSON字段

sqlalchemy使用mysql的json_extract函数查询JSON字段 在SQLAlchemy中,如果你想要在MySQL中存储JSON字段,并且进行查询操作,可以按照以下步骤进行设置和查询: 1. 创建表格 首先,创建一个表格来存储包含JSON字段的数据。假设我们有一个名为 users 的表格,其中有一个名为…...

分类模型-逻辑回归和Fisher线性判别分析★★★★

该博客为个人学习清风建模的学习笔记,部分课程可以在B站:【强烈推荐】清风:数学建模算法、编程和写作培训的视频课程以及Matlab等软件教学_哔哩哔哩_bilibili 目录 1理论 1.1逻辑回归模型 1.2线性概率模型 1.3线性判别分析 1.4两点分布…...

JMeter介绍、安装配置以及快速入门

文章目录 1. JMeter简介2. JMeter安装配置3. JMeter快速入门 1. JMeter简介 Apache JMeter是一款开源的压力测试工具,主要用于测试静态和动态资源(如静态文件、服务器、数据库、FTP服务器等)的性能。它最初是为测试Web应用而设计的&#xff…...

GPT LangChain experimental agent - allow dangerous code

题意:GPT LangChain 实验性代理 - 允许危险代码 问题背景: Im creating a chatbot in VS Code where it will receive csv file through a prompt on Streamlit interface. However from the moment that file is loaded, it is showing a message with…...

1 LableMe安装下载

git:GitHub - labelmeai/labelme: Image Polygonal Annotation with Python (polygon, rectangle, circle, line, point and image-level flag annotation). 1 LabelMe介绍 LabelMe是一个图像标注工具,主要用于帮助研究人员和开发者创建有标签的数据集,这…...

rce漏洞-ctfshow(50-70)

Web51 if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\|\%|\x09|\x26/i", $c)){ system($c." >/dev/null 2>&1"); } Nl,绕过tac,cat,绕…...

vulntarget-a靶机-复现报告

靶机复现过程 测试标题 测试过程 测试外网ip 192.168.2.84 测试详情 第一步,我们先对其这个外网ip进行扫描,结果如下 结果我们发现这个ip开启了80和445端口,同时我们还可以看到这里是win7系统,我们先看看web页面是怎样的 结…...

为什么 FPGA 的效率低于 ASIC?

FPGA是“可重构逻辑”器件。先制造的芯片,再次设计时“重新配置”。 ASIC 不需要“重新配置”。你先设计,把它交给代工厂,然后制造芯片。 现在让我们看看这些芯片的结构是什么样的,以及它们的不同之处。 ● 逻辑单元:F…...

使用水星Mecury人形机器人搭建VR遥操作控制平台!

VR遥操作机械臂是一种将虚拟现实技术与机械臂控制相结合的系统,使用户可以通过虚拟现实设备操控和交互实际的机械臂。这种技术可以应用于多个领域,包括远程操作、培训、危险环境中的工作等。 双臂人形机器人是一种模拟人体上半身结构,包括头部…...

【学习笔记】无人机系统(UAS)的连接、识别和跟踪(三)-架构模型和概念

引言 3GPP TS 23.256 技术规范,主要定义了3GPP系统对无人机(UAV)的连接性、身份识别、跟踪及A2X(Aircraft-to-Everything)服务的支持。 3GPP TS 23.256 技术规范: 【免费】3GPPTS23.256技术报告-无人机系…...

uniapp bug解决:uniapp文件查找失败:‘uview-ui‘ at main.js:14

文章目录 报错内容解决方法main.js 文件中 uView 主 JS 库引入 uView 的全局 SCSS 主题文件内容修改引入 uView 基础样式内容修改配置 easycom 内容修改 报错内容 10:50:51.795 文件查找失败:uview-ui at main.js:14 10:59:39.570 正在差量编译... 10:59:43.213 文…...

Python 爬虫(爬取百度翻译的数据)

前言 要保证爬虫的合法性,可以从以下几个方面着手: 遵守网站的使用条款和服务协议:在爬取数据之前,仔细阅读目标网站的相关规定。许多网站会在其 robots.txt 文件中明确说明哪些部分可以爬取,哪些不可以。 例如&…...

【LeetCode:2766. 重新放置石块 + 哈希表】

🚀 算法题 🚀 🌲 算法刷题专栏 | 面试必备算法 | 面试高频算法 🍀 🌲 越难的东西,越要努力坚持,因为它具有很高的价值,算法就是这样✨ 🌲 作者简介:硕风和炜,…...

[C++]类的自动转换和强制类型转换

在C中,类的自动转换(也称为隐式转换)和强制类型转换(显式转换)是面向对象编程中处理类型之间转换的两种重要机制。这些转换允许程序员定义如何在不同类型(特别是自定义类型)之间安全地交换数据。…...

大数据学习栈记——Neo4j的安装与使用

本文介绍图数据库Neofj的安装与使用,操作系统:Ubuntu24.04,Neofj版本:2025.04.0。 Apt安装 Neofj可以进行官网安装:Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...

内存分配函数malloc kmalloc vmalloc

内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...

【WiFi帧结构】

文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...

React第五十七节 Router中RouterProvider使用详解及注意事项

前言 在 React Router v6.4 中&#xff0c;RouterProvider 是一个核心组件&#xff0c;用于提供基于数据路由&#xff08;data routers&#xff09;的新型路由方案。 它替代了传统的 <BrowserRouter>&#xff0c;支持更强大的数据加载和操作功能&#xff08;如 loader 和…...

从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)

设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile&#xff0c;新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...

dify打造数据可视化图表

一、概述 在日常工作和学习中&#xff0c;我们经常需要和数据打交道。无论是分析报告、项目展示&#xff0c;还是简单的数据洞察&#xff0c;一个清晰直观的图表&#xff0c;往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server&#xff0c;由蚂蚁集团 AntV 团队…...

C# 求圆面积的程序(Program to find area of a circle)

给定半径r&#xff0c;求圆的面积。圆的面积应精确到小数点后5位。 例子&#xff1a; 输入&#xff1a;r 5 输出&#xff1a;78.53982 解释&#xff1a;由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因为我们只保留小数点后 5 位数字。 输…...

rnn判断string中第一次出现a的下标

# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...

【Java学习笔记】BigInteger 和 BigDecimal 类

BigInteger 和 BigDecimal 类 二者共有的常见方法 方法功能add加subtract减multiply乘divide除 注意点&#xff1a;传参类型必须是类对象 一、BigInteger 1. 作用&#xff1a;适合保存比较大的整型数 2. 使用说明 创建BigInteger对象 传入字符串 3. 代码示例 import j…...

LeetCode - 199. 二叉树的右视图

题目 199. 二叉树的右视图 - 力扣&#xff08;LeetCode&#xff09; 思路 右视图是指从树的右侧看&#xff0c;对于每一层&#xff0c;只能看到该层最右边的节点。实现思路是&#xff1a; 使用深度优先搜索(DFS)按照"根-右-左"的顺序遍历树记录每个节点的深度对于…...