撸一个功能强大的基于语义的图像检索系统

news/2025/10/24 13:06:03/文章来源:https://www.cnblogs.com/codingtea/p/19162989

视频演示:

撸一个功能强大的基于语义的图像检索系统


 

大家好,这里是Coding茶水间。

在上一期视频中,我们介绍了Ultralytics框架下最新更新的语义检索功能,只需本地3行代码,就能构建一个基于文本语义的图像检索网站。

然而,框架自带的界面较为固定,如果需要自定义界面,还需额外开发;

此外,对中文支持不佳,使用中文检索时结果往往偏差;

还有小伙伴提出,能否实现以图搜图功能?

本期视频针对这些问题进行完善,如果你还没看过上一期,建议先回顾一下。

自定义界面的搭建

Ultralytics框架的VisualAISearch功能强大,但存在以下局限:

  • 界面固定:框架提供的界面无法满足个性化需求,需要自行编写GUI。
  • 中文支持差:直接用中文查询,语义理解不准,导致检索结果不理想。
  • 缺少以图搜图:原生仅支持文本检索,无法直接用图像查询相似图像。

本期我们构建了一个自定义界面,支持文本检索(兼容中文)和图像检索,全基于语义理解。

主界面


基于Kimi的中文转英文

我们使用PyQt5构建图形界面,集成Ultralytics的搜索功能,并借助Kimi AI处理中文翻译。

1. 中文测试

界面支持:

  • 文本检索:输入中文描述,如“一只欢乐的奔跑的狗”,系统后台自动翻译成英文后检索。
  • 图像检索:上传图像,系统基于语义相似度返回相似度最高的8个图像。
  • 显示相似度,并在网格中展示结果图像。

一只欢乐的奔跑的狗

检索速度快,文本检索的主要耗时在翻译网络请求上,实际搜索实时完成。

2. 集成Kimi AI

上文中我们搜索的时候,直接输入的是中文。

但是原模型对中文支持比较差,我们用Kimi AI翻译输入为英文。新用户注册Kimi获15元额度,足够多次翻译。注册后创建API Key,填入代码即可。

apikey

翻译类(KimiTranslator.py):

python

import requestsclass KimiTranslator:def __init__(self, api_key):self.api_key = api_keydef translate(self, text):if not self.api_key:raise ValueError("API key is empty")url = "https://api.moonshot.ai/v1/chat/completions"headers = {"Authorization": f"Bearer {self.api_key}","Content-Type": "application/json"}data = {"model": "moonshot-v1-8k","messages": [{"role": "system", "content": "You are a helpful and precise assistant for translating Chinese to English."},{"role": "user", "content": f"Translate the following Chinese text to English: {text}"}],"temperature": 0.3}response = requests.post(url, headers=headers, json=data)if response.status_code == 200:return response.json()["choices"][0]["message"]["content"]else:raise Exception(f"Error: {response.status_code} - {response.text}")

核心代码实现

主窗口类(MainWindow)继承PyQt5,初始化搜索器并连接按钮信号。

完整代码:

python

import sys
from PyQt5 import QtWidgets
import cv2
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import numpy as np
from PyQt5.QtWidgets import *
from ultralytics import solutions
import os
from main_window import Ui_MainWindow
from KimiTranslator import KimiTranslatorclass MainWindow(QMainWindow, Ui_MainWindow):def __init__(self):super().__init__()self.setupUi(self)self.dir = "JPEGImages"self.searcher = solutions.VisualAISearch(data=self.dir)# 填写 Kimi 的 API KeyAPI_KEY = ""  # 在这里替换为你的 API Key# 创建翻译器实例self.translator = KimiTranslator(API_KEY)# 初始化文件路径self.file_path = None# 连接按钮信号(假设 UI 中的对象名;如果不同,请调整)self.btnSelectImage.clicked.connect(self.selectImage)  # 选择图像按钮self.btnTextSearch.clicked.connect(self.searchText2Pic)  # 以文搜图按钮self.btnImageSearch.clicked.connect(self.searchPic2Pic)  # 以图搜图按钮def updateImage(self, path, qlabel):image = self.cv_imread(path)if image is not None:rgb_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)rows, cols, channels = rgb_image.shapebytesPerLine = channels * colsQImg = QImage(rgb_image.data, cols, rows, bytesPerLine, QImage.Format_RGB888)qlabel.setPixmap(QPixmap.fromImage(QImg).scaled(qlabel.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation))def selectImage(self):file_path, _ = QtWidgets.QFileDialog.getOpenFileName(self, "Select an Image", "", "Image Files (*.jpg *.jpeg *.png)")if file_path:self.file_path = file_pathself.updateImage(self.file_path, self.queryImagePreview)def cv_imread(self, path):cv_img = cv2.imdecode(np.fromfile(path, dtype=np.uint8), -1)return cv_imgdef searchText2Pic(self):query_text = self.textQueryEdit.toPlainText().strip()if not query_text:QtWidgets.QMessageBox.warning(self, "提示", "输入文本不能为空")returntranslated = self.translator.translate(query_text)results = self.searcher.search_text(translated)self.updateResults(results)def searchPic2Pic(self):if not self.file_path:QtWidgets.QMessageBox.warning(self, "提示", "请选择图像")returnresults = self.searcher.search_image(self.file_path)self.updateResults(results)def updateResults(self, results):image_paths = []similarities = []for image_path, similarity in results[:8]:if hasattr(image_path, '__str__'):image_path = str(image_path)# 拼接完整路径full_path = os.path.join(self.dir, image_path)image_paths.append(full_path)similarities.append(round(similarity, 4))# 更新图像和相似度,处理少于8个结果的情况for i in range(8):label = getattr(self, f'image_{i+1}')sim_label = getattr(self, f'similarity_{i+1}')if i < len(image_paths):self.updateImage(image_paths[i], label)sim_label.setText("相似度:" + str(similarities[i]))else:label.clear()sim_label.setText("")if __name__ == "__main__":app = QApplication(sys.argv)window = MainWindow()window.show()sys.exit(app.exec_())

依赖:PyQt5、opencv-python、ultralytics、requests。图像目录“JPEGImages”需预置图像。


使用效果演示

文本检索示例

“一个人抱着一只狗”——包含人与狗的语义图像。

一个人抱着一只狗

图像检索示例

上传一张实例图像,点击“以图搜图”,原图相似度1.0,其后是相似语义图像,如下图所示。

以图搜图


结语

这个系统完善了Ultralytics的语义检索,支持自定义界面和中文。

欢迎三连加关注,留言邮箱,我发源码给大家!如果有问题,评论区讨论。

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

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

相关文章

提交一张 PPT,参与 RTE2025 全球语音智能体云展示

无法亲临 RTE2025 大会?😢 没关系!🎉 我们特别为你的项目提供了一个云展示机会。只需提交一张 PPT,即可参与我们的「全球语音智能体云展示」,与众多领先的语音智能体一同在大会展区屏幕上轮播展示! 🤩项目提…

完整教程:深入解析AppCrawler:开源自动遍历测试工具配置指南

完整教程:深入解析AppCrawler:开源自动遍历测试工具配置指南pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Con…

解释 EIP-4337

简单来说,EIP-4337 旨在实现“账户抽象”,让智能合约钱包成为用户的默认和主流钱包,从而极大地改善用户体验和安全性。 下面我将从几个方面详细解释 EIP-4337: 1. 核心问题:以太坊的两种账户 在理解 EIP-4337 之前…

数论常见结论及例题

数论常见结论及例题 常见结论 球盒模型(八种) 参考链接。给定 \(n\) 个小球 \(m\) 个盒子。球同,盒不同、不能空隔板法: \(N\) 个小球即一共 \(N-1\) 个空,分成 \(M\) 堆即 \(M-1\) 个隔板,答案为 \(\dbinom{n-1…

材料包含与下载漏洞

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

N8N Workflow Collection - 专业级自动化工作流库 - 详解

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

完整教程:Elasticsearch面试精讲 Day 23:安全认证与权限控制

完整教程:Elasticsearch面试精讲 Day 23:安全认证与权限控制pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Con…

Min25 筛

Min25 筛 求解 \(1-N\) 的质数和,其中 \(N \le 10^{10}\) 。 namespace min25{const int N = 1000000 + 10;int prime[N], id1[N], id2[N], flag[N], ncnt, m;LL g[N], sum[N], a[N], T;LL n;LL mod;inline LL ps(LL …

莫比乌斯函数/反演

莫比乌斯函数/反演 莫比乌斯函数定义:\(\displaystyle {\mu(n) = \begin{cases} 1 &n = 1 \\ (-1)^k &n = \prod_{i = 1}^k p_i \text{ 且 } p_i \text{ 互质 } \\ 0 &else \end{cases}}\) 。莫比乌斯函数…

同余方程组、拓展中国剩余定理 excrt

同余方程组、拓展中国剩余定理 excrt 公式:\(x \equiv b_i(\bmod\ a_i)\) ,即 \((x - b_i) \mid a_i\) 。 int n; LL ai[maxn], bi[maxn]; inline int mypow(int n, int k, int p) {int r = 1;for (; k; k >>=…

完整教程:微软2025教育AI报告:教育群体采用AI的比例显著提升

完整教程:微软2025教育AI报告:教育群体采用AI的比例显著提升pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Con…

康拓展开

康拓展开 正向展开普通解法 将一个字典序排列转换成序号。例如:12345->1,12354->2。 int f[20]; void jie_cheng(int n) { // 打出1-n的阶乘表f[0] = f[1] = 1; // 0的阶乘为1for (int i = 2; i <= n; i++)…

求解连续数字的正约数集合——倍数法

求解连续数字的正约数集合——倍数法 使用规律递推优化,时间复杂度为 \(\mathcal{O}(N\log N)\) ,如果不需要详细的输出集合,则直接将 vector 换为普通数组即可(时间更快) 。 #include <bits/stdc++.h> usi…

git回滚代码

回滚上一次提交是指撤销最近一次的git提交操作。在实际使用中,有两种常见的方法可以实现这个操作: 方法一:使用git revert命令回滚 1. 首先,通过命令`git log`查看提交记录,找到要回滚的提交的hash值。 2. 使用命…

Apache POI 在 Linux 无图形界面环境下因字体配置问题导致Excel导出失败的解决方案 - 详解

Apache POI 在 Linux 无图形界面环境下因字体配置问题导致Excel导出失败的解决方案 - 详解2025-10-24 12:52 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !importan…

扩展欧几里得 exgcd

扩展欧几里得 exgcd 求解形如 \(a\cdot x + b\cdot y = \gcd(a,b)\) 的不定方程的任意一组解。 int exgcd(int a, int b, int &x, int &y) {if (!b) {x = 1, y = 0;return a;}int d = exgcd(b, a % b, y, x);y…

离散对数 bsgs 与 exbsgs

离散对数 bsgs 与 exbsgs 以 \(\mathcal O(\sqrt {P})\) 的复杂度求解 \(a^x \equiv b(\bmod P)\) 。其中标准 \(\tt BSGS\) 算法不能计算 \(a\) 与 \(MOD\) 互质的情况,而 exbsgs 则可以。 namespace BSGS { LL a, …

防爆模乘

防爆模乘 借助浮点数实现 以 \(\mathcal O(1)\) 计算 \(a\cdot b\bmod p\) ,由于不取模,常数比 int128 法小很多。其中 \(1 \le n, k, p \le 10^{18}\) 。 int mul(int a, int b, int m) {int r = a * b - m * (int)…

欧拉筛(线性筛)

欧拉筛(线性筛) 时间复杂度为 \(\mathcal{O}(N\log\log N)\) 。 vector<int> prime; // 这里储存筛出来的全部质数 auto euler_Prime = [&](int n) -> void {vector<int> v(n + 1);for (int i = …

常见数列

常见数列 调和级数 满足调和级数 \(\mathcal O\left( \dfrac{N}{1} +\dfrac{N}{2}+\dfrac{N}{3}+\dots + \dfrac{N}{N} \right)\),可以用 $ \approx N\ln N$ 来拟合,但是会略小,误差量级在 \(10\%\) 左右。本地可以…