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

Clip结合Faiss+Flask简易版文搜图服务

一、实现

使用目录结构:

templates

        ---upload.html

 faiss_app.py

前端代码:upload.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Search and Show Multiple Images</title><style>#image-container {display: flex;flex-wrap: wrap;}#image-container img {max-width: 150px;margin: 10px;}</style>
</head>
<body><h1>Search Images</h1><!-- 搜索框 --><form id="search-form"><input type="text" id="search-input" name="query" placeholder="Enter search term" required><input type="submit" value="Search"></form><h2>Search Results</h2><!-- 显示搜索返回的多张图片 --><div id="image-container"></div><!-- 使用JS处理表单提交 --><script>document.getElementById('search-form').addEventListener('submit', async function(event) {event.preventDefault();  // 阻止表单默认提交行为const query = document.getElementById('search-input').value;  // 获取搜索框中的输入内容try {// 发送GET请求,将搜索关键词发送到后端const response = await fetch(`/search?query=${encodeURIComponent(query)}`, {method: 'GET',});// 确保服务器返回JSON数据const data = await response.json();// 清空图片容器const imageContainer = document.getElementById('image-container');imageContainer.innerHTML = '';// 遍历后端返回的图片URL数组,动态创建<img>标签并渲染data.image_urls.forEach(url => {const imgElement = document.createElement('img');imgElement.src = url;  // 设置图片的src属性为返回的URLimageContainer.appendChild(imgElement);  // 将图片添加到容器中});} catch (error) {console.error('Error searching for images:', error);}});</script>
</body>
</html>

后端代码 faiss_app.py:

from sentence_transformers import SentenceTransformer, util
from PIL import Image
from flask import Flask, request, jsonify, current_app, render_template, send_from_directory, url_for
from werkzeug.utils import secure_filename
import faiss
import os, glob
import numpy as np
from markupsafe import escape
import shutil#Load CLIP model
model = SentenceTransformer('clip-ViT-B-32')
IMAGE_EXTENSIONS = {'.jpg', '.jpeg', '.png', '.gif', '.bmp'}UPLOAD_FOLDER = 'uploads/'
IMAGES_PATH  = "C:\\Users\\xxxx\\Pictures\\"def generate_clip_embeddings(images_path, model):image_paths = []# 使用 os.walk 遍历所有子目录和文件for root, dirs, files in os.walk(images_path):for file in files:# 获取文件的扩展名并转换为小写ext = os.path.splitext(file)[1].lower()# 判断是否是图片文件if ext in IMAGE_EXTENSIONS:image_paths.append(os.path.join(root, file)) embeddings = []for img_path in image_paths:image = Image.open(img_path)embedding = model.encode(image)embeddings.append(embedding)return embeddings, image_pathsdef create_faiss_index(embeddings, image_paths, output_path):dimension = len(embeddings[0])# 分情况创建Faiss索引对象if len(image_paths) < 39 * 256:# 如果条目很少,直接用最普通的L2索引faiss_index = faiss.IndexFlatL2(dimension)elif len(image_paths) < 39 * 4096:# 如果条目少于39 × 4096,就只用PQ量化,不使用IVFfaiss_index = faiss.index_factory(dimension, 'OPQ64_256,PQ64x8')else:# 否则就加上IVFfaiss_index = faiss.index_factory(dimension, 'OPQ64_256,IVF4096,PQ64x8')res = faiss.StandardGpuResources()co = faiss.GpuClonerOptions()co.useFloat16 = Truefaiss_index = faiss.index_cpu_to_gpu(res, 0, faiss_index, co)#index = faiss.IndexFlatIP(dimension)faiss_index = faiss.IndexIDMap(faiss_index)vectors = np.array(embeddings).astype(np.float32)# Add vectors to the index with IDsfaiss_index.add_with_ids(vectors, np.array(range(len(embeddings))))# Save the indexfaiss_index = faiss.index_gpu_to_cpu(faiss_index)faiss.write_index(faiss_index, output_path)print(f"Index created and saved to {output_path}")# Save image pathswith open(output_path + '.paths', 'w') as f:for img_path in image_paths:f.write(img_path + '\n')return faiss_indexdef load_faiss_index(index_path):faiss_index = faiss.read_index(index_path)with open(index_path + '.paths', 'r') as f:image_paths = [line.strip() for line in f]print(f"Index loaded from {index_path}")if not faiss_index.is_trained:raise RuntimeError(f'从[{index_path}]加载的Faiss索引未训练')res = faiss.StandardGpuResources()co = faiss.GpuClonerOptions()co.useFloat16 = Truefaiss_index = faiss.index_cpu_to_gpu(res, 0, faiss_index, co)return faiss_index, image_pathsdef retrieve_similar_images(query, model, index, image_paths, top_k=3):# query preprocess:if query.endswith(('.png', '.jpg', '.jpeg', '.tiff', '.bmp', '.gif')):query = Image.open(query)query_features = model.encode(query)query_features = query_features.astype(np.float32).reshape(1, -1)distances, indices = index.search(query_features, top_k)retrieved_images = [image_paths[int(idx)] for idx in indices[0]]return query, retrieved_images# 检查文件扩展名是否允许
def allowed_file(filename):return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONSdef search():query = request.args.get('query')  # 获取搜索关键词safe_query = escape(query)if not query:return jsonify({"error": "No search query provided"}), 400index, image_paths = None, []OUTPUT_INDEX_PATH = f"{app.config['UPLOAD_FOLDER']}/vector.index"if os.path.exists(OUTPUT_INDEX_PATH):index, image_paths = load_faiss_index(OUTPUT_INDEX_PATH)else:embeddings, image_paths = generate_clip_embeddings(IMAGES_PATH, model)index = create_faiss_index(embeddings, image_paths, OUTPUT_INDEX_PATH)query, retrieved_images = retrieve_similar_images(query, model, index, image_paths, top_k=5)image_urls = []for path in retrieved_images:base_name = os.path.basename(path)shutil.copy(path, os.path.join(app.config['UPLOAD_FOLDER'], base_name))image_urls.append(url_for('uploaded_file_path', filename=base_name))return jsonify({"image_urls": image_urls})def index():return render_template('upload.html')# 提供静态文件的访问路径
def uploaded_file_path(filename):return send_from_directory(app.config['UPLOAD_FOLDER'], filename)if __name__ == "__main__":app = Flask(__name__)app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDERif not os.path.exists(UPLOAD_FOLDER):os.makedirs(UPLOAD_FOLDER)# 主页显示上传表单app.route('/')(index)app.route('/search', methods=['GET'])(search)app.route('/uploads/images/<filename>')(uploaded_file_path)app.run(host='0.0.0.0', port=8080, debug=True)

二、效果

相关文章:

Clip结合Faiss+Flask简易版文搜图服务

一、实现 使用目录结构&#xff1a; templates ---upload.html faiss_app.py 前端代码&#xff1a;upload.html <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content&quo…...

【机器学习】数学知识:欧式距离(Euclidean Distance)和曼哈顿距离(Manhattan Distance)

欧式距离和曼哈顿距离是两种常用的距离度量方法&#xff0c;用于衡量两点之间的相似性或差异性。它们在几何分析、数据挖掘、机器学习等领域有广泛应用。 1. 欧式距离 概念 欧式距离&#xff08;Euclidean Distance&#xff09;是最常见的直线距离度量方法&#xff0c;源于欧…...

Redis 概 述 和 安 装

安 装 r e d i s: 1. 下 载 r e dis h t t p s : / / d o w n l o a d . r e d i s . i o / r e l e a s e s / 2. 将 redis 安装包拷贝到 /opt/ 目录 3. 解压 tar -zvxf redis-6.2.1.tar.gz 4. 安装gcc yum install gcc 5. 进入目录 cd redis-6.2.1 6. 编译 make …...

数据仓库面试题集离线实时

一、Flink面试问题集 1、flinkkafka 如何保证精准一次 配置两阶段提交 2、Flink提交方式&#xff0c; 使用pre-job还是yarn-session模式&#xff0c;以及Application模式&#xff0c;好处&#xff1f; Flink提交模式模式对比 3、Flink UV统计实现 set布隆过滤器redis 有误…...

Spring Boot框架:电商系统的技术革新

4 系统设计 网上商城系统的设计方案比如功能框架的设计&#xff0c;比如数据库的设计的好坏也就决定了该系统在开发层面是否高效&#xff0c;以及在系统维护层面是否容易维护和升级&#xff0c;因为在系统实现阶段是需要考虑用户的所有需求&#xff0c;要是在设计阶段没有经过全…...

一键抠图:免费安全的在线图片去除背景工具

利用前端技术&#xff0c;轻松去除图片背景 得益于Webassembly技术的快速发展&#xff0c;前端可以实现的功能越来越多。本文将介绍一款基于briaai的 RMBG-1.4型号的 预训练模型实现的在线图片去除背景(抠图)工具。地址&#xff1a;https://www.potatotools.top/toolsEntrance…...

vue项目PC端和移动端实现在线预览pptx文件

通过PPTXjs插件,实现PPTX文件在线预览,需下载PPTXjs,将其引入HTML页面,并编写相应的HTML和JS代码,如果是移动端还需调整div大小,这是一种便捷的前端PPTX转HTML技术,适合网页展示使用 PPTX在线预览&#xff0c;使用jquery的插件《PPTXjs》&#xff0c;纯前端实现pptx转html进行…...

uniapp适配暗黑模式配置plus.nativeUI.setUIStyle适配DarkMode配置

uniapp适配暗黑模式配置 目录 uniapp适配暗黑模式配置setUIStyleDarkMode 适配app-plus manifest.json配置theme.json配置pages.json配置页面切换代码实现同步手机暗黑配置额外适配 参考官方文档&#xff1a;https://uniapp.dcloud.net.cn/tutorial/darkmode.html 主要用到api…...

EXCEL 或 WPS 列下划线转驼峰

使用场景&#xff1a; 需要将下划线转驼峰&#xff0c;直接在excel或wps中第一行使用公式&#xff0c;然后快速刷整个列格式即可。全列工下划线转为格式&#xff0c;使用效果如下&#xff1a; 操作步骤&#xff1a; 第一步&#xff1a;在需要显示驼峰的一列&#xff0c;复制以…...

走进Linux的历史发展史

目录 前言 Linux的发展史 UNIX发展的历史 Linux发展历史 开源 企业应用现状 Linux在服务器领域的发展 桌面领域 移动嵌入式领域 云计算/大数据领域 发行版 ​编辑 Linux环境搭建方式 前言 本节博客内容较水&#xff0c;主要介绍Linux的发展历史和其相关的学习内容&a…...

学习yum工具,进行安装软件

目录 1.Linux 软件包管理器 yum 什么是软件包 2.Linux下安装软件的方案 3.Linux软件生态 Linux下载软件的过程&#xff08;Ubuntu、Centos、other&#xff09; 操作系统的好坏评估--- ⽣态问题 为什么会有⼈免费特定社区提供软件&#xff0c;还发布&#xff1f;还提供云服…...

union介绍及使用

union格式 在C中&#xff0c;union是一种特殊的数据类型&#xff0c;它允许在相同的内存位置存储不同的数据类型&#xff0c;但在任意时刻只能使用一个成员。以下是union类型的基本格式说明&#xff1a; union UnionName {memberType1 memberName1;memberType2 memberName2;m…...

安全,服务器证书和SSL连接

业务报错&#xff1a; javax.net.ssl.SSLPeerUnverifiedException: Certificate for <10.5.20.137> doesn’t match any of the subject alternative names: [*.dt.zte.com.cn] at org.apache.http.conn.ssl.SSLConnectionSocketFactory.verifyHostname(SSLConnectionSoc…...

Java结合ElasticSearch根据查询关键字,高亮显示全文数据。

由于es高亮显示机制的问题。当全文内容过多&#xff0c;且搜索中标又少时&#xff0c;就会出现高亮结果无法覆盖全文。因此需要根据需求手动替换。 1.根据es的ik分词器获取搜索词的分词结果。 es部分&#xff1a; //中文分词解析 post /_analyze {"analyzer":"…...

Design Compiler:Topographical Workshop Lab2

相关阅读 Design Compilerhttps://blog.csdn.net/weixin_45791458/category_12738116.html?spm1001.2014.3001.5482 本文是对Synopsys Design Compiler Topographical/Graphical Workshop Lab Guide中Lab2的翻译&#xff0c;Lab文件可以从以下链接获取。 Synopsys Design Co…...

【C语言】连接陷阱探秘(1):声明与定义

目录 一、声明与定义的混淆 1.1. 声明(Declaration) 1.2. 定义(Definition) 1.3. 避免混淆的方法 1.4. 示例 二、声明与定义不匹配 2.1. 常见的不匹配情况 2.2. 解决方法 三、外部变量与静态变量的命名冲突 3.1. 外部变量命名冲突 3.2. 静态变量命名冲突 四、缺…...

ChatGPT学术专用版,一键润色纠错+中英互译+批量翻译PDF

ChatGPT academic项目是由中科院团队基于ChatGPT专属定制。论文润色、语法检查、中英互译、代码解释等可一键搞定&#xff0c;堪称科研神器。 功能介绍 我们以3.5版本为例&#xff0c;ChatGPT学术版总共分为五个区域&#xff1a;输入控制区、输出对话区、基础功能区、函数插件…...

python isinstance(True, int)

今天的bug 是布尔类型给的。 >>> a True >>> isinstance(a, int) True>>> a True >>> isinstance(a, bool) True‌Python中的布尔类型&#xff08;bool&#xff09;实际上是整数类型&#xff08;int&#xff09;的一个子类&#xff0c;…...

1.5寸**进口 128128带灰阶oled屏 spi串口 老王电子diy 设备 OLED 2024/11/15 arduino

名:1.5寸**进口 128128带灰阶oled屏 协:spi串口 铺:老王电子diy 设备: OLED 时间:2024/11/15 IDE: arduino 兜兜转转还是打通了,他的接口 用的i2c 标志 夭寿咯 MOSI&#xff08;Master Out Slave In&#xff09;&#xff1a;主机输出&#xff0c;从机输入。MISO&#xff…...

【EasyExcel】复杂导出操作-自定义颜色样式等(版本3.1.x)

文章目录 前言一、自定义拦截器二、自定义操作1.自定义颜色2.合并单元格 三、复杂操作示例1.实体(使用了注解式样式)&#xff1a;2.自定义拦截器3.代码4.最终效果 前言 本文简单介绍阿里的EasyExcel的复杂导出操作&#xff0c;包括自定义样式&#xff0c;根据数据合并单元格等。…...

简易版抽奖活动的设计技术方案

1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...

线程与协程

1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指&#xff1a;像函数调用/返回一样轻量地完成任务切换。 举例说明&#xff1a; 当你在程序中写一个函数调用&#xff1a; funcA() 然后 funcA 执行完后返回&…...

【大模型RAG】Docker 一键部署 Milvus 完整攻略

本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装&#xff1b;只需暴露 19530&#xff08;gRPC&#xff09;与 9091&#xff08;HTTP/WebUI&#xff09;两个端口&#xff0c;即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...

ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放

简介 前面两期文章我们介绍了I2S的读取和写入&#xff0c;一个是通过INMP441麦克风模块采集音频&#xff0c;一个是通过PCM5102A模块播放音频&#xff0c;那如果我们将两者结合起来&#xff0c;将麦克风采集到的音频通过PCM5102A播放&#xff0c;是不是就可以做一个扩音器了呢…...

高等数学(下)题型笔记(八)空间解析几何与向量代数

目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...

【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)

升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点&#xff0c;但无自动故障转移能力&#xff0c;Master宕机后需人工切换&#xff0c;期间消息可能无法读取。Slave仅存储数据&#xff0c;无法主动升级为Master响应请求&#xff…...

tree 树组件大数据卡顿问题优化

问题背景 项目中有用到树组件用来做文件目录&#xff0c;但是由于这个树组件的节点越来越多&#xff0c;导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多&#xff0c;导致的浏览器卡顿&#xff0c;这里很明显就需要用到虚拟列表的技术&…...

三分算法与DeepSeek辅助证明是单峰函数

前置 单峰函数有唯一的最大值&#xff0c;最大值左侧的数值严格单调递增&#xff0c;最大值右侧的数值严格单调递减。 单谷函数有唯一的最小值&#xff0c;最小值左侧的数值严格单调递减&#xff0c;最小值右侧的数值严格单调递增。 三分的本质 三分和二分一样都是通过不断缩…...

Qt 事件处理中 return 的深入解析

Qt 事件处理中 return 的深入解析 在 Qt 事件处理中&#xff0c;return 语句的使用是另一个关键概念&#xff0c;它与 event->accept()/event->ignore() 密切相关但作用不同。让我们详细分析一下它们之间的关系和工作原理。 核心区别&#xff1a;不同层级的事件处理 方…...