ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

VGG16图像特征提取与余弦相似度检索实战

VGG16图像特征提取与余弦相似度检索实战 简介这是一套基于服装图像数据构建的端到端图像检索与分类系统适用于计算机科学、人工智能、电子信息等专业学生的课程设计、期末大作业及毕业设计参考。系统采用Python实现融合VGG16特征提取、CNN模型训练与Web前端交互支持上传图片进行相似服装检索与类别判别。资源包共86个文件涵盖14个核心Python脚本如retrieval.py、extract_cnn_vgg16_keras.py、preprocess_img.py、13张示例服装图、7个HTML页面及配套JS/CSS静态资源完整呈现前后端协同架构压缩包仅1.05MB轻量易部署。已有153人学习下载提供可直接运行的源码、清晰的项目说明文档README.md、调试日志debug.log及典型服装图像样本便于理解图像预处理、特征向量索引、相似度匹配等关键流程并支持在本地快速验证与二次开发。1. 用 VGG16 提取服装图像特征再靠余弦相似度做检索——这不是 Demo是能跑通的端到端系统你手头有一批电商上架的服装图T恤、连衣裙、牛仔裤想快速找出“和这张蓝色条纹衬衫视觉最接近的 5 款上衣”而不是靠人工翻页或关键词搜索。这个 ZIP 包里装的就是一个从原始图像输入、到特征提取、索引构建、再到在线查询返回 Top-K 相似图的完整闭环系统。它不依赖云服务全部基于本地 Python 运行核心模型用的是 Keras 封装的 VGG16ImageNet 预训练权重但做了关键裁剪——去掉最后全连接层只保留卷积全局平均池化输出 512 维固定长度向量检索层没用 Faiss 或 Annoy而是用 NumPy Scikit-learn 的NearestNeighbors构建内存索引启动快、无依赖、适合课程设计阶段验证算法逻辑。如果你正在写计算机视觉课设、毕设开题需要可运行基线或想搞懂“特征向量怎么变成搜索结果”这个包比论文伪代码更真实——它连debug.log都留着process_image.py里还藏着对 JPEG 色彩空间异常的容错处理。2. 为什么选 VGG16 做特征提取器从模型裁剪到特征归一化的全流程实现2.1 VGG16 的结构适配性为什么不是 ResNet 或 ViT在服装图像这类细粒度识别任务中VGG16 的优势在于其浅层卷积核对纹理如格子、条纹、蕾丝响应稳定且全局平均池化GAP后输出的 512 维向量维度适中比 ResNet50 的 2048 维更省内存又比 MobileNetV2 的 1280 维更易收敛更重要的是Keras 官方预训练权重在imagenet上已充分验证其泛化能力无需从头训练。本项目在keras_vgg.py中完成三步裁剪from keras.applications import VGG16 from keras.models import Model from keras.layers import GlobalAveragePooling2D base_model VGG16(weightsimagenet, include_topFalse, input_shape(224, 224, 3)) x base_model.output x GlobalAveragePooling2D()(x) # 替代 flatten抗尺度扰动更强 feature_extractor Model(inputsbase_model.input, outputsx)提示include_topFalse是关键它跳过原模型最后三层全连接含 1000 类 Softmax只保留卷积主干GlobalAveragePooling2D比Flatten更鲁棒——当输入图像存在轻微裁剪偏移时池化操作对空间位置不敏感而Flatten会放大像素级位移带来的向量差异。2.2 图像预处理链从原始 JPG 到模型输入张量的标准化路径服装图像常存在白平衡偏差、JPEG 压缩块效应、尺寸不一等问题。preprocess_img.py定义了严格流水线from keras.applications.vgg16 import preprocess_input from PIL import Image import numpy as np def load_and_preprocess_image(img_path, target_size(224, 224)): img Image.open(img_path).convert(RGB) # 强制转 RGB规避 RGBA 透明通道干扰 img img.resize(target_size, Image.BILINEAR) # 双线性插值保留边缘细节 img_array np.array(img, dtypenp.float32) img_array np.expand_dims(img_array, axis0) # 添加 batch 维度 (1, 224, 224, 3) img_array preprocess_input(img_array) # 减均值[103.939, 116.779, 123.68]按 BGR 顺序Keras 兼容 return img_array注意preprocess_input的减均值操作必须与 VGG16 训练时一致否则特征分布偏移导致检索失效convert(RGB)是硬性要求——若原始图是 PNG 带 Alpha 通道直接np.array()会产生 4 通道数组触发 Keras 输入维度报错expand_dims不可省略否则feature_extractor.predict()会因 batch 维缺失而崩溃。2.3 特征向量归一化为什么余弦相似度比欧氏距离更合理服装图像特征空间中向量模长反映图像整体亮度/对比度强度而非语义信息。例如一张过曝的白衬衫图其原始特征向量模长可能远大于正常曝光的同款图导致欧氏距离误判。因此extract.py在保存特征前强制 L2 归一化from sklearn.preprocessing import normalize def extract_features(image_paths, model): features [] for path in image_paths: preprocessed load_and_preprocess_image(path) feat model.predict(preprocessed).flatten() # (512,) features.append(feat) features np.array(features) features_normalized normalize(features, norml2, axis1) # 每行独立归一化 return features_normalized # 保存为 .npy 文件供后续检索加载 np.save(features_clothes.npy, features_normalized)逻辑说明normalize(..., axis1)对每个样本即每张图的 512 维向量单独做 L2 归一化使其模长恒为 1此时两向量点积 余弦相似度值域 [-1,1]越接近 1 表示视觉越相似。这比直接算欧氏距离更能解耦光照影响。参数含义本项目取值不匹配后果target_size输入模型的图像尺寸(224, 224)小于该值会模糊失真大于则被裁剪丢失信息norml2归一化范数类型l2若用l1向量稀疏性增强但服装纹理特征易被削弱axis1归一化作用轴1行方向若误设axis0会对所有图的同一维特征做归一化彻底破坏语义3. 构建可查询的图像索引从特征文件到实时 Top-K 检索的工程落地3.1 索引构建用 Scikit-learn 的 NearestNeighbors 实现轻量级内存索引index.py负责将归一化后的特征矩阵构建成可查询索引。它不依赖 Redis 或 Elasticsearch纯内存操作启动即用from sklearn.neighbors import NearestNeighbors import numpy as np # 加载预提取的归一化特征 features np.load(features_clothes.npy) # shape: (N, 512) filenames np.load(filenames_clothes.npy) # 对应图像路径列表 # 构建索引metriccosine 自动计算 1 - 余弦相似度sklearn 最小化距离 nn_index NearestNeighbors(n_neighbors10, metriccosine, algorithmbrute) nn_index.fit(features) # 保存索引对象需配合 joblib非 pickle因 sklearn 版本兼容性更强 import joblib joblib.dump(nn_index, clothes_nn_index.joblib) joblib.dump(filenames, filenames.joblib)逻辑说明metriccosine是核心——它让kneighbors()返回的距离值等于1 - cosine_similarity因此距离越小表示越相似algorithmbrute明确指定暴力搜索虽不如 KD-Tree 或 BallTree 快但在 N5000 时延迟低于 10ms且避免高维空间下树结构退化问题n_neighbors10设定默认返回 Top-10后续 Web 查询可动态调整。3.2 在线检索接口retrieval.py 封装查询逻辑并返回结构化结果retrieval.py是系统对外暴露的检索入口接收单张查询图路径返回相似图路径及相似度分数import joblib import numpy as np from keras.models import Model from keras.applications.vgg16 import preprocess_input from PIL import Image def retrieve_similar_images(query_path, nn_index, filenames, feature_extractor, top_k5): # 步骤1预处理查询图 query_img Image.open(query_path).convert(RGB).resize((224, 224), Image.BILINEAR) query_array np.array(query_img, dtypenp.float32) query_array np.expand_dims(query_array, axis0) query_array preprocess_input(query_array) # 步骤2提取归一化特征 query_feat feature_extractor.predict(query_array).flatten() query_feat_norm query_feat / np.linalg.norm(query_feat) # 手动 L2 归一化 # 步骤3查询最近邻 distances, indices nn_index.kneighbors([query_feat_norm], n_neighborstop_k) # 步骤4组装结果距离转相似度过滤自身 results [] for i, idx in enumerate(indices[0]): if filenames[idx] query_path: # 跳过查询图自身 continue similarity 1 - distances[0][i] # 转回余弦相似度 results.append({ image_path: filenames[idx], similarity: float(similarity), rank: len(results) 1 }) if len(results) top_k: break return results # 示例调用 nn_index joblib.load(clothes_nn_index.joblib) filenames joblib.load(filenames.joblib) feature_extractor ... # 加载 keras_vgg.py 中定义的模型 results retrieve_similar_images(query.jpg, nn_index, filenames, feature_extractor)参数说明top_k控制返回数量默认 5similarity以浮点数形式返回0.0~1.0前端可直接用于进度条渲染rank字段确保结果严格按相似度降序排列避免因浮点精度导致排序错乱。3.3 Web 服务集成main.py 启动 Flask 服务并路由静态资源main.py用 Flask 搭建最小可行 Web 界面templates/下的 HTML 文件通过 Jinja2 渲染结果from flask import Flask, request, render_template, jsonify, send_from_directory import os from retrieval import retrieve_similar_images import joblib app Flask(__name__) app.config[UPLOAD_FOLDER] uploads os.makedirs(app.config[UPLOAD_FOLDER], exist_okTrue) # 加载全局模型与索引启动时加载避免每次请求重建 nn_index joblib.load(clothes_nn_index.joblib) filenames joblib.load(filenames.joblib) feature_extractor ... # 模型加载逻辑 app.route(/) def index(): return render_template(index.html) app.route(/upload, methods[POST]) def upload_file(): if file not in request.files: return jsonify({error: No file part}), 400 file request.files[file] if file.filename : return jsonify({error: No selected file}), 400 filepath os.path.join(app.config[UPLOAD_FOLDER], file.filename) file.save(filepath) # 执行检索 results retrieve_similar_images(filepath, nn_index, filenames, feature_extractor) return jsonify({results: results}) app.route(/static/path:filename) def serve_static(filename): return send_from_directory(static, filename)关键配置os.makedirs(..., exist_okTrue)确保uploads/目录自动创建send_from_directory安全地提供静态资源防止路径遍历攻击jsonify返回标准 JSON前端fetch()可直接解析。整个服务仅需pip install flask scikit-learn keras numpy pillow即可运行。4. 排查常见失败场景从 debug.log 日志定位到特征维度不匹配的根因4.1 debug.log 中高频错误模式解析与修复方案打开debug.log你会看到类似以下三类典型报错它们指向不同层级的问题# 错误1模型输入维度不匹配 ValueError: Error when checking input: expected input_1 to have shape (224, 224, 3) but got array with shape (224, 224, 4) # 错误2特征向量未归一化导致相似度溢出 UserWarning: invalid value encountered in true_divide similarity 1 - distances[0][i] # 错误3索引文件加载失败 FileNotFoundError: [Errno 2] No such file or directory: clothes_nn_index.joblib对应修复动作错误1检查preprocess_img.py是否漏掉convert(RGB)。PNG 图像常含 Alpha 通道4 通道必须显式转换错误2确认extract.py中normalize(..., axis1)已执行且retrieval.py中查询向量也做了相同归一化见代码中query_feat_norm query_feat / np.linalg.norm(query_feat)错误3运行python extract.py和python index.py生成索引文件再启动main.py切勿跳过索引构建步骤。4.2 特征维度验证用 NumPy 快速诊断向量是否符合预期在 Python 交互环境中执行以下命令可秒级验证特征质量import numpy as np # 检查特征文件维度与归一化状态 features np.load(features_clothes.npy) print(特征矩阵形状:, features.shape) # 应为 (N, 512) print(各向量模长统计:, np.linalg.norm(features, axis1).round(3)) # 全部应 ≈ 1.0 # 检查单个向量是否为单位向量 sample_vec features[0] print(首向量模长:, np.linalg.norm(sample_vec)) # 应为 1.000... print(首向量最大值:, sample_vec.max()) # VGG16 GAP 输出通常 0.5若 1.0 则归一化失败 # 检查索引文件是否可加载 import joblib nn_index joblib.load(clothes_nn_index.joblib) print(索引支持邻居数:, nn_index.n_neighbors) # 应为 10或你设定的值逻辑说明np.linalg.norm(features, axis1)对每行即每张图计算 L2 模长若输出非全 1 数组则归一化步骤有误sample_vec.max()过高如 2.0表明未归一化或模型输出未截断会导致余弦相似度计算溢出NaN。4.3 检索结果可信度验证用已知相似对做人工校验选取clothes/目录下两张明显相似的图如id_00000051_01_1_front.jpg与另一张同款多角度图手动执行检索并观察相似度# 在 Python 中直接测试 results retrieve_similar_images( clothes/id_00000051_01_1_front.jpg, nn_index, filenames, feature_extractor, top_k1 ) print(最相似图:, results[0][image_path]) print(相似度得分:, results[0][similarity]) # 正常应 0.75若得分低于 0.6需检查两张图是否都经过相同预处理尤其resize插值方式特征提取模型是否加载了正确权重weightsimagenet是否误用了未归一化的原始特征进行检索。5. 提升检索精度的三个实操技巧从数据增强到特征融合的渐进优化5.1 技巧一对查询图做多尺度裁剪取平均特征提升鲁棒性原始实现对单张图只提取一次特征易受局部遮挡影响。retrieval_test.py中提供了多尺度增强方案def extract_multi_scale_features(img_path, model, scales[0.8, 1.0, 1.2]): features [] for scale in scales: # 按比例缩放后中心裁剪 224x224 img Image.open(img_path).convert(RGB) w, h img.size new_w, new_h int(w * scale), int(h * scale) img_resized img.resize((new_w, new_h), Image.BILINEAR) left (new_w - 224) // 2 top (new_h - 224) // 2 img_cropped img_resized.crop((left, top, left 224, top 224)) # 预处理并提取 arr np.array(img_cropped, dtypenp.float32) arr np.expand_dims(arr, axis0) arr preprocess_input(arr) feat model.predict(arr).flatten() features.append(feat / np.linalg.norm(feat)) # 对多个尺度特征取平均并归一化 avg_feat np.mean(features, axis0) return avg_feat / np.linalg.norm(avg_feat) # 使用方式替换 retrieval.py 中的单尺度提取逻辑 query_feat_norm extract_multi_scale_features(query_path, feature_extractor)效果在服装数据上该技巧可使 Top-1 准确率提升约 12%尤其改善袖口/领口局部变形导致的误检。5.2 技巧二融合颜色直方图特征缓解纹理相似但色系迥异的问题VGG16 特征擅长纹理但对色系不敏感。cv.py提供 HSV 颜色直方图提取import cv2 import numpy as np def extract_color_hist(img_path, bins32): img cv2.imread(img_path) img_hsv cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # 分别对 H色相、S饱和度、V明度计算直方图 hist_h cv2.calcHist([img_hsv], [0], None, [bins], [0, 180]) hist_s cv2.calcHist([img_hsv], [1], None, [bins], [0, 256]) hist_v cv2.calcHist([img_hsv], [2], None, [bins], [0, 256]) hist np.concatenate([hist_h.flatten(), hist_s.flatten(), hist_v.flatten()]) return hist / np.sum(hist) # 归一化为概率分布 # 融合策略加权拼接VGG 特征权重 0.7颜色直方图 0.3 vgg_feat ... # 512 维 color_hist extract_color_hist(query_path) # 96 维 fused_feat np.concatenate([ vgg_feat * 0.7, color_hist * 0.3 ]) fused_feat fused_feat / np.linalg.norm(fused_feat)参数说明bins32平衡区分度与维度过高如 64易过拟合过低如 8丢失色相细节权重0.7/0.3经交叉验证确定在服装数据上 F1-score 最优。5.3 技巧三用retrieval_images.py批量生成可视化报告快速定位系统瓶颈运行python retrieval_images.py --query_dir queries/ --output report/自动生成 HTML 报告包含每张查询图的 Top-5 检索结果缩略图相似度分数柱状图失败案例高亮相似度 0.5 的查询报告中report/failures.csv列出所有低分查询路径供你针对性分析是图像质量问题还是类别本身难区分如黑色西装 vs 黑色风衣这比盲调参数更高效。实操建议先用retrieval_images.py跑通 10 张图观察哪些图 consistently 得分低再聚焦优化——比如对低分图批量加白平衡校正而非全局修改预处理逻辑。本文还有配套的精品资源点击获取
返回列表