新闻详情

新闻详情

首页 / 资讯中心 / 详情

基于VGG16的图像检索系统:从特征提取到相似度检索实践

发布时间:2026/9/20 8:48:35来源:尧图网络
基于VGG16的图像检索系统:从特征提取到相似度检索实践
简介这份资源是一套基于VGG16深度学习模型的图像检索系统毕业设计项目面向需要完成图像匹配、以图搜图相关课题的高校学生也适合入门深度学习的开发者作为完整实践案例。项目采用Python与Keras实现涵盖图像预处理、VGG16特征提取、余弦相似度计算、检索界面展示等流程代码与数据封装完整下载解压后即可直接运行。资源包共30个文件压缩包大小约47.96MB主要包含8个Python源码文件、5张示例图片、3个JS脚本、2个HTML页面、2个CSS样式文件以及说明文档、数据库文件等结构清晰便于按模块阅读修改。目前已有428人学习浏览适合用于毕业设计参考、课程项目实战以及深度学习图像检索入门。通过这套代码读者可以掌握如何调用预训练模型进行特征表示、构建相似度检索逻辑并在此基础上替换数据集完成自己的检索实验省去从零搭建的时间。1. 毕业设计做图像检索为什么第一步要把 VGG16 当作特征提取器图像检索这个题目在毕业设计里出现频率很高但很多人的方案还停留在 SIFT 特征点匹配或者直方图比较跑出来的效果往往是一张图换一个角度就找不到。它的核心问题在于“用什么描述一张图片”——如果用像素级或者手工特征描述能力不够检索精度上不去。把 VGG16 接入进来之后问题被转换成“用深度网络提取的向量去描述图片”这个向量的语义层次远高于 SIFT 和颜色直方图很多在传统方案里折腾半天的场景光照变化、角度偏移、同类物体不同外观都能自动容忍。这里说的“基于 VGG16 的图像检索系统”本质是一条清晰的技术链路用预训练 VGG16 去掉最后的分类层把每张图片映射成一个固定长度的特征向量然后对这些向量做建库、归一化、相似度计算查询时同样提取查询图的向量在库中找出最接近的 Top-K 张图返回。这套系统完全适合作为本科毕业设计的核心工作量因为代码量可控、训练成本为零直接用 ImageNet 预训练权重、评估指标明确而且数据可以自己随便凑。读者如果是打算拿这个题目开题这篇内容会把你从“不知道特征从哪儿来”带到“能跑通一个带评估的完整流程”。2. VGG16 取哪一层做特征原理、选型与数据库构建实现2.1 为什么取 fc7 而不是 pool5也不是 softmax 输出VGG16 的网络结构可以拆成两部分一组卷积层负责提取从边缘到纹理再到物体部件的层级特征后面接三个全连接层 fc6、fc7、fc8 负责把特征映射到类别得分最后 softmax 输出 1000 类概率。做检索时softmax 输出不能用因为它的维度被压缩成 1000 类语义类别里没有“这张图是什么样”只有“这张图最像哪类”。真正有用的是倒数第二层 fc7 输出的 4096 维向量或者 pool5 输出的 7×7×512 特征图经过全局池化后的向量。常见做法是取 fc7 输出。原因是 fc7 经过两层全连接的非线性变换后特征被进一步抽象成全局语义表示在度量学习里它比 raw 卷积特征更稳定。pool5 保留更多空间细节适合做物体定位但直接用于全局检索时冗余太大。需要注意 VGG16 的输入规范是 224×224 的 RGB 图并且需要按 ImageNet 的均值方差做归一化这一步漏掉特征质量会明显下降检索结果经常出现颜色相近但内容无关的图。2.1.1 特征提取的最小可运行代码下面这段 PyTorch 代码可以在单卡上完成建库环节的特征提取。它接收一个图片文件夹输出一个特征矩阵和一个文件名列表分别保存为features.npy和filenames.pkl。import torch import torchvision.transforms as T from torchvision import models from PIL import Image import numpy as np import pickle import os from tqdm import tqdm model models.vgg16(pretrainedTrue) # 取 fc7 输出去掉 fc8 和 softmax model.classifier torch.nn.Sequential(*list(model.classifier.children())[:6]) model.eval() device torch.device(cuda if torch.cuda.is_available() else cpu) model.to(device) transform T.Compose([ T.Resize((224, 224)), T.ToTensor(), T.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]) ]) def extract_features(img_path): img Image.open(img_path).convert(RGB) x transform(img).unsqueeze(0).to(device) with torch.no_grad(): feat model(x).cpu().numpy().flatten() # L2 归一化让内积等价于余弦相似度 feat feat / np.linalg.norm(feat) return feat image_dir ./data/images features, filenames [], [] for fname in tqdm(os.listdir(image_dir)): if not fname.lower().endswith((.jpg, .jpeg, .png)): continue fpath os.path.join(image_dir, fname) try: fv extract_features(fpath) features.append(fv) filenames.append(fname) except Exception as e: print(f{fname} 提取失败: {e}) np.save(./data/features.npy, np.array(features)) with open(./data/filenames.pkl, wb) as f: pickle.dump(filenames, f)model.classifier 被截断到前 6 层也就是保留 fc6 和 fc7。最后一层 fc8 的输入是 4096 维输出是 1000 类得分检索用不到。特征做了 L2 归一化这样后续计算内积就等价于余弦相似度比欧氏距离更符合图像检索的直觉。提取失败时打印文件名而不是中断进程处理脏数据时很有用。2.2 数据库目录结构怎么组织数据从哪来毕业设计的数据不需要走公开大数据集自己拍或者下载 500 到 2000 张图就够支撑实验。推荐在项目根目录下这样组织project/ ├── data/ │ ├── images/ # 库图像直接平铺不分子目录 │ ├── query/ # 查询图像 │ ├── features.npy │ └── filenames.pkl ├── extract_features.py ├── build_index.py ├── search.py └── evaluate.pyimages 平铺而不按类别分子目录这是有意为之。如果分了子目录文件名里带上类别信息后面评估时容易产生“看文件名猜结果”的侥幸心理掩盖特征质量问题。数据集的组织方式与后续 mAP 评估直接相关如果用 Oxford5k 或 Paris6k需要额外准备查询图像和对应的 ground truth 标注文件自建数据则可以通过文件名前缀约定正样本关系比如cat_001.jpg、cat_002.jpg视为同一类。2.2.1 特征维度、显存占用与 batch 提取VGG16 fc7 输出维度固定为 4096一张图存成 float32 只有 16KB1000 张库图的特征矩阵不到 16MB后续检索阶段的内存压力可以忽略。但提取阶段如果一张一张地处理VGG16 的参数量約 138M单张推理虽然不慢数据量大时会很耗时更稳妥的做法是加一个 DataLoader 做 batch 提取。from torch.utils.data import Dataset, DataLoader class ImageFolderDataset(Dataset): def __init__(self, img_dir, transform): self.paths [os.path.join(img_dir, f) for f in os.listdir(img_dir) if f.lower().endswith((.jpg, .jpeg, .png))] self.transform transform def __len__(self): return len(self.paths) def __getitem__(self, idx): img Image.open(self.paths[idx]).convert(RGB) return self.transform(img), self.paths[idx] dataset ImageFolderDataset(./data/images, transform) loader DataLoader(dataset, batch_size32, num_workers4) features_dict {} for batch, paths in loader: with torch.no_grad(): fv model(batch.to(device)).cpu().numpy() for i, path in enumerate(paths): fv_i fv[i] / np.linalg.norm(fv[i]) features_dict[path] fv_ibatch_size 的选择取决于显存。VGG16 在 224×224 输入下batch_size 设为 32 时大约占用 4GB 显存如果只有 2GB 的旧卡把 batch_size 降到 8。num_workers 在 Windows 上经常被误解如果设置为 4 报错先改成 0 验证是代码问题还是系统问题。3. 检索核心相似度计算、Top-K 排序与查询链路3.1 查库时到底在算什么建库完成后系统里存了一个 n×4096 的特征矩阵n 是库图数量和一个长度 n 的文件名列表。查询阶段拿到查询图做同样的预处理得到 4096 维查询向量然后计算它与矩阵中每一行的相似度。由于特征已经 L2 归一化矩阵乘法直接得到全部余弦相似度取最大的 K 个索引即可。这一步有个容易做错的地方特征的归一化在提取阶段已经做过查询时就不能再次归一化否则相当于做了两次缩放虽然对内积的排序没有影响但会让后续调试时的分数值失真。另外如果用的是欧氏距离而不是内积那么建库时归一化会导致距离上限被限制在 0 到 2 之间检索结果会有微妙差异。始终基于余弦相似度做全链路设计代码最简洁。3.2 一个可落地的 search 脚本下面的脚本实现了完整查询链路读入查询图路径提取特征计算相似度矩阵返回 Top-K 结果并展示图片名和相似度分数。import numpy as np import pickle import argparse from extract_features import extract_features parser argparse.ArgumentParser() parser.add_argument(--query, typestr, requiredTrue, help查询图片路径) parser.add_argument(--k, typeint, default10) args parser.parse_args() features np.load(./data/features.npy) # shape: (N, 4096) with open(./data/filenames.pkl, rb) as f: filenames pickle.load(f) query extract_features(args.query) # shape: (4096,) # 余弦相似度 归一化向量的内积 scores features query top_k_idx np.argsort(scores)[::-1][:args.k] for rank, idx in enumerate(top_k_idx, 1): print(fTop-{rank}: {filenames[idx]} 相似度: {scores[idx]:.4f})scores features query在 numpy 里会把 features 的每一行与 query 做内积结果是一个长度为 N 的一维数组这个过程是向量化操作即使库图有 10 万张也就几十毫秒级别的开销。arg 是 argsort 降序排列后取前 K 个索引返回的是索引而不是文件名所以最后要通过 filenames 映射回去。注意这里没有判断--query指向的图片是否存在如果路径错误extract_features 里的 Image.open 会报错建议在外面加一层 os.path.exists 检查。3.2.1 线上检索与批量查询的差异如果一次查询一张图瓶颈在特征提取不在相似度计算。CPU 上跑 VGG16 单张约 200msGPU 上约 10ms。批量查询场景比如一次给 100 张查询图可以直接复用建库时的 batch 提取逻辑把所有查询图提取成 m×4096 矩阵然后用一次矩阵乘法results query_features features.T得到 m×N 的相似度矩阵。这种写法在毕业设计的答辩演示里也很实用——可以现场跑一批查询图展示多行检索结果。4. 评估指标与数据玩得转的关键mAP、训练集划分和可复现性4.1 检索结果怎么量化评价不能只给老师看几张检索出的图片毕业设计需要量化指标。最常用的评估指标是 mAPmean Average Precision它综合衡量了检索结果的相关性排序质量。mAP 计算的第一步是给每张查询图画 ground truth哪些库图是真正相关的其余的都是不相关。自建数据集时通常按文件名前缀定义相关性比如查询图dog_01.jpg与库中的所有dog_*.jpg相关。Average PrecisionAP的计算方式是按检索排序依次走到每个相关图片的位置累计计算该位置上的精确率最后取平均。mAP 是所有查询图的 AP 均值。下面的脚本实现了一个按文件名前缀匹配 ground truth 的评估流程。import numpy as np import pickle from collections import defaultdict def compute_ap(gt_mask, scores): gt_mask: bool 数组标记库中哪些与查询相关scores: 相似度分数 order np.argsort(scores)[::-1] gt_mask gt_mask[order] pos 0 ap 0.0 for i, is_rel in enumerate(gt_mask): if is_rel: pos 1 ap pos / (i 1) return ap / pos if pos 0 else 0.0 features np.load(./data/features.npy) with open(./data/filenames.pkl, rb) as f: filenames pickle.load(f) # 统计每个前缀类别下的图片索引 class_to_idx defaultdict(list) for i, name in enumerate(filenames): cls name.split(_)[0] # 通过文件名前缀判定类别 class_to_idx[cls].append(i) aps [] for cls, idx_list in class_to_idx.items(): gt np.zeros(len(filenames), dtypebool) gt[idx_list] True # 用该类第一张图模拟查询图 query_feat features[idx_list[0]] scores features query_feat ap compute_ap(gt, scores) aps.append(ap) print(fmAP: {np.mean(aps):.4f})评估时有一个细节查询图本身也在库中检索结果的第一名总是自己这会把 AP 拉高。避免方法是评估时将查询图从库中剔除或者保证查询图不参与建库。代码里模拟时直接把查询图包含在库中实测 mAP 会偏高 0.05 到 0.1。写实验报告时一定要说明这个细节否则数据可信度会打折扣。4.2 数据质量决定系统上限VGG16 的特征是预训练模型给的库图的内容越接近 ImageNet 的分布检索精度越高。用手机拍的产品图、截图、扫描件、卡通图混在一起做实验时通常效果很烂。一个实用的数据清洗规则是先跑一遍特征提取把特征矩阵求两两相似度找出相似度异常低的离群图人工检查是不是损坏图片或者纯色图。另外图片包含大段黑边时建议先用 OpenCV 做一次边缘裁剪再把图缩放至 224×224否则黑边会占据大部分卷积感受野特征向量被无效区域主导。这里可以用 Pillow 的ImageOps.expand检查或者直接上 OpenCVimport cv2 img cv2.imread(fpath) if img is None: # 文件已经损坏直接跳过 print(f跳过损坏图片: {fpath}) continue if np.mean(img) 5: # 接近纯黑图跳过或标灰 print(f跳过纯黑图: {fpath})4.2.1 避免训练集测试集重复的坑建库的 images 目录和查询图 query 目录在文件组织上要物理隔离。如果查询图就是库图本身评估出来的 mAP 没有参考价值答辩时也很容易被追问。正确做法是给每个类别准备两张以上的图一张进库一张作为查询。数据集类别数量建议在 20 到 50 类左右每类 10 到 30 张库图这样总数据量适中且类别区分度高特征描述能力差异更明显。5. 进阶优化PCA 降维、faiss 索引与查询图裁剪技巧5.1 把 4096 维压缩到 128 维检索速度提升但精度不掉4096 维在数据量小的时候不是问题但毕设如果能做到入库 10 万张暴力检索的计算量就有点看头了。用 PCA 把特征降到 128 维可以显著减少相似度计算耗时。关键是 PCA 要在库特征上拟合而不是用随机生成的矩阵。from sklearn.decomposition import PCA features np.load(./data/features.npy) pca PCA(n_components128, whitenTrue) features_pca pca.fit_transform(features) np.save(./data/features_pca.npy, features_pca) # 查询时也做同样的变换 query_pca pca.transform(query.reshape(1, -1)).flatten()whitenTrue 会把降维后的各维度方差归一化让特征分布更接近球状有利于后续内积检索。PCA 降维后检索速度接近原来的 32 倍mAP 通常只有 1 到 3 个百分点的损失。论文里的对比实验很适合放一组“4096 维 vs 128 维 mAP 对比表”用来体现优化思考。5.2 faiss 索引替换 numpy 暴力检索如果觉得 numpy 的暴力检索在答辩演示时不够“硬核”可以用 faiss 建索引。faiss 是 Facebook 开源的相似度检索库MIT 协议学术和商业都可以用它提供的 IndexFlatIP 与前面介绍的余弦相似度完全一致是最容易替换的起步索引。import faiss features np.load(./data/features.npy).astype(float32) index faiss.IndexFlatIP(features.shape[1]) index.add(features) query query.astype(float32).reshape(1, -1) scores, indices index.search(query, 10)faiss 返回的 scores 和 indices 的 shape 都是 (1, 10)。IndexFlatIP 没有训练过程直接 add 就能用。如果想展示更高级的方案可以换成 IndexIVFFlat它先对向量空间做 K-Means 聚类再在最近的聚类内搜索适合大规模库。参数 nlist 通常设为库数量的平方根量级nprobe 设为 10 到 20。但小数据量下 IVFFlat 反而比 IndexFlatIP 慢因为聚类中心分配也有开销这点在实验中要如实呈现。5.3 一个影响检索精度的小技巧查询图中心裁剪实际查询时查询图可能带水印、边框或大面积背景直接 Resize 到 224×224 会引入大量噪声。常见技巧是先做中心裁剪取图片短边的 80% 区域作为有效区域再缩放到 224×224。这个操作对包含主体居中的图片很有效在自建数据集上通常能带来几个点的 mAP 提升实现成本极低。from PIL import Image img Image.open(query_path).convert(RGB) w, h img.size short_side min(w, h) crop_size int(short_side * 0.8) left (w - crop_size) // 2 top (h - crop_size) // 2 img img.crop((left, top, left crop_size, top crop_size))中心裁剪比例 0.8 不是硬性标准可以做成参数在验证集上试 0.7、0.8、0.9 三档。如果查询图本身已经是很规整的物体图裁掉 20% 反而可能裁掉目标边缘建议只在查询图来自网络下载或手机拍摄时使用。这个判断标准写进论文的方法部分会让实验设计看起来更严谨。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

抖音主页批量下载教程:douyin-downloader 本地备份完整指南 2026/9/20 9:27:40

抖音主页批量下载教程:douyin-downloader 本地备份完整指南

抖音主页批量下载教程:douyin-downloader 本地备份完整指南 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and browser fallback …

阅读更多 →
普通鼠标在 Mac 上总差口气?Mac Mouse Fix 鼠标增强完整指南 2026/9/20 9:27:40

普通鼠标在 Mac 上总差口气?Mac Mouse Fix 鼠标增强完整指南

普通鼠标在 Mac 上总差口气?Mac Mouse Fix 鼠标增强完整指南 【免费下载链接】mac-mouse-fix Mac Mouse Fix - Make Your $10 Mouse Better Than an Apple Trackpad! 项目地址: https://gitcode.com/GitHub_Trending/ma/mac-mouse-fix 普通鼠标在 macOS 上总…

阅读更多 →
使用 GitKraken 完成开源首次贡献:first-contributions 项目 Fork、Clone 到 Pull Request 全流程实战指南 2026/9/20 9:27:40

使用 GitKraken 完成开源首次贡献:first-contributions 项目 Fork、Clone 到 Pull Request 全流程实战指南

文档教程开源治理 【免费下载链接】first-contributions 🚀✨ Help beginners to contribute to open source projects 项目地址: https://gitcode.com/gh_mirrors/fi/first-contributions 点击查看 免费下载 本篇指南以 first-contributions 开源仓库&…

阅读更多 →
Podman 与 docker-compose 协同实战:env_and_volume 环境变量与共享卷测试全解析 2026/9/20 9:27:40

Podman 与 docker-compose 协同实战:env_and_volume 环境变量与共享卷测试全解析

容器运行时云原生CLI 【免费下载链接】podman Podman: A tool for managing OCI containers and pods. 项目地址: https://gitcode.com/gh_mirrors/po/podman 点击查看 免费下载 导读 本文深入剖析 Podman 仓库中 test/compose/env_and_volume 这一 docker-compos…

阅读更多 →
OpenCLI 剑鱼标讯(jianyu)适配器实战:浏览器态招标公告搜索与详情证据抽取 2026/9/20 9:27:40

OpenCLI 剑鱼标讯(jianyu)适配器实战:浏览器态招标公告搜索与详情证据抽取

开发工具CLI人工智能AI 应用浏览器控制GUI 自动化 【免费下载链接】OpenCLI Make Any Website into CLI & Use your logged-in browser by AI agent. 项目地址: https://gitcode.com/gh_mirrors/ope/OpenCLI 点击查看 免费下载 导读 本文讲解 OpenCLI 仓库中…

阅读更多 →
开放研究实战:从数据管理到可复现流程的完整指南 2026/9/20 9:24:40

开放研究实战:从数据管理到可复现流程的完整指南

1. 开放研究(OpenResearch)是什么?从一次被审稿人拆穿的失败说起真正让我下定决心把整套流程改成 OpenResearch 式做法的,是一次特别难看的投稿经历。当时我拿着跑了大半个月的实验数据去投稿,自认为结果整理得足够漂亮…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞