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)

二、效果

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

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

相关文章

【鸿蒙开发】第十一章 Stage模型应用组件-任务Mission

目录 1 任务(Mission)管理场景 2 任务&#xff08;Mission&#xff09;与启动模式 2.1 singleton单实例模式 2.2 multiton多实例模式 2.3 specified指定实例模式 3 页面栈及任务链 3.1 页面栈 3.2 任务链 4 设置任务快照的图标和名称 4.1 设置任务快照的图标&#xf…

探索 HTML 和 CSS 实现的模拟时钟

效果演示 这段代码是一个模拟时钟的 HTML 和 CSS 代码。它创建了一个简单的数字时钟界面&#xff0c;包括时针、分针和秒针。 HTML <div class"face"><p class"v-index">II</p><p class"h-index">II</p><d…

CSS预编译器:让样式编写更高效的秘密武器(6)

在现代前端开发中&#xff0c;CSS 预编译器是一种非常有用的工具&#xff0c;它通过扩展 CSS 语言的功能&#xff0c;帮助开发者更高效地编写和维护样式代码。本文将介绍 CSS 预编译器的基本原理&#xff0c;并重点讲解 LESS 的安装和使用方法。 1. 基本原理 编写 CSS 时&…

Vue3中实现插槽使用

目录 一、前言 二、插槽类型 三、示例 四、插槽的分类实现 1. 基本插槽 2. 命名插槽 3. 默认插槽内容 4. 作用域插槽&#xff08;Scoped Slots&#xff09; 5. 多插槽与具名插槽组合 一、前言 在 Vue 3 中&#xff0c;插槽&#xff08;Slot&#xff09;用于实现组件的内…

爬虫——Requests库的使用

在爬虫开发中&#xff0c;HTTP请求是与服务器进行交互的关键操作。通过发送HTTP请求&#xff0c;爬虫可以获取目标网页或接口的数据&#xff0c;而有效地处理请求和响应是爬虫能够高效且稳定运行的基础。Requests库作为Python中最常用的HTTP请求库&#xff0c;因其简洁、易用和…

如何使用EasyExcel生成多列表组合填充的复杂Excel示例

作者&#xff1a;Funky_oaNiu 一、&#xff08;需求&#xff09;生成的表格效果&#xff1a;二、搞一个模板文件三、建立对应的表格实体类四、开始填充五、Vue3前端发起请求下载六、官方文档及AI问答 一、&#xff08;需求&#xff09;生成的表格效果&#xff1a; 其中只有顶部…

三、计算机视觉_02计算机视觉领域的四大基本任务

0、前言 计算机视觉是人工智能领域的一个重要分支&#xff0c;它是一个跨学科的领域&#xff0c;涉及计算机科学、人工智能、机器学习、图像处理、神经科学等多个学科的知识 计算机视觉使用计算机技术来模拟人类视觉系统的功能&#xff0c;使计算机能够从图像或多维数据中提取…

Docker: ubuntu系统下Docker的安装

安装依赖 操作系统版本 Ubuntu Kinetic 22.10Ubuntu Jammy 24.04 (LTS)Ubuntu Jammy 22.04 (LTS)Ubuntu Focal 20.04 (LTS)Ubuntu Bionic 18.04 (LTS) CPU架构支持 ARMx86_64 查看我们的系统版本信息 uname -a通过该命令查得cpu架构是x86_64的&#xff1b; cat /etc/*re…

【已解决】 Tomcat10.1.x使用JSTL标签库

IDEA创建Java EE项目&#xff0c;使用Spring Spring MVC MyBatis框架&#xff0c;使用maven管理依赖。项目当前的环境是&#xff1a; Tomat 10.1.28Maven 3.6.3JDK 17 项目的功能&#xff1a;读取数据库的report表中的数据&#xff0c;返回一个List集合对象reportList在JSP…

LeetCode74. 搜索二维矩阵(2024冬季每日一题 6)

给你一个满足下述两条属性的 m x n 整数矩阵&#xff1a; 每行中的整数从左到右按非严格递增顺序排列。每行的第一个整数大于前一行的最后一个整数。 给你一个整数 target &#xff0c;如果 target 在矩阵中&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。…

数据分析24.11.13

Excel 函数 求和 函数 sum() sumif() SUMIF(range, criteria, [sum_range]) sumifs() average() count() max() min() 逻辑 函数 if() iferror() 查询函数 VLOOKUP()

DveOps-Git-版本控制

1. 概述 分布式版本控制系统 版本控制 2. Git极速上手指南 官方传送门:Git - Branching and Merging 2.1 安装 ## windows https: git-scm.com/download/## Linux(CentOS/Fedora/Rocky Linux/RHEL) yum install -y git ## MacOS brew install git## Ubuntu/Debian apt in…

DevOps工程技术价值流:加速业务价值流的落地实践与深度赋能

DevOps的兴起&#xff0c;得益于敏捷软件开发的普及与IT基础设施代码化管理的革新。敏捷宣言虽已解决了研发流程中的诸多挑战&#xff0c;但代码开发仅是漫长价值链的一环&#xff0c;开发前后的诸多问题仍亟待解决。与此同时&#xff0c;虚拟化和云计算技术的飞跃&#xff0c;…

Tensorflow基本概念

简介&#xff1a;本文从Graph讲到Session&#xff0c;同时讲解了tf.constant创建tensor的用法和variable需要初始化的知识点&#xff0c;可以给你打好一个学习Tensorflow的基础。本文都是基于TensorFlow1.14.0的版本下运行。 本专栏将会系统的讲解TensorFlow在1.14.0版本下的各…

【React】响应事件

1.添加事件处理函数 按照如下三个步骤&#xff0c;即可让它在用户点击时显示消息&#xff1a; 在 Button 组件 内部 声明一个名为 handleClick 的函数。实现函数内部的逻辑&#xff08;使用 alert 来显示消息&#xff09;。添加 onClick{handleClick} 到 <button> JSX …

初遇Python-----python/anaconda/PyCharm安装应用问题

作为一名医学生,小编之前从未用过python,一直将R视为数据分析的利器,至于到底R好用还是Python好用,一直是广大网友们争论的热点,小编资历尚浅,对此就不予评价了。最近需要对部分数据进行建模工作,奈何三方工具完全基于python语言编写的,迫不得已小编也只能挠头学习了。本…

基于reads的宏基因组与宏转录组医学分析流程正式上线!

随着生物医学领域的快速发展&#xff0c;宏基因组学和宏转录组学正逐渐成为研究微生物群落及其在人体健康与疾病中作用的关键技术。然而&#xff0c;医学研究样品往往存在微生物含量较低的情况&#xff0c;这给数据分析带来了挑战。为了解决这一难题&#xff0c;并适应不断增长…

使用Aria2实现离线下载

最近有需要BT下载&#xff0c;但有的资源很冷门&#xff0c;速度很慢&#xff0c;总不能一直开着电脑下载&#xff0c;于是想到部署个离线下载。想起之前用雨云服务器拿来部署兰空图床感觉效果不错&#xff0c;发现内存剩的还挺多&#xff0c;所以继续压榨一下&#x1f60f; 提…

第三百二十三节 Java线程教程 - Java同步器

Java线程教程 - Java同步器 同步器对象与一组线程一起使用。 它维护一个状态&#xff0c;根据它的状态&#xff0c;它让一个线程通过或强迫它等待。 本节将讨论四种类型的同步器&#xff1a; SemaphoresBarriersLatchesExchangers 信号量 信号量用于控制可以访问资源的线程…

HTB:Active[WriteUP]

目录 连接至HTB服务器并启动靶机 1.How many SMB shares are shared by the target? 使用nmap对靶机TCP端口进行开放扫描 2.What is the name of the share that allows anonymous read access? 使用smbmap通过SMB服务对匿名用户共享权限情况进行扫描 3.Which file has…