基于VGG16+Milvus的以图搜图系统实现教程
一、项目简介
以图搜图技术作为计算机视觉领域的热门应用,能够帮助用户快速从海量图片库中找到相似度最高的目标图片。本项目基于VGG16特征提取模型+Milvus向量检索引擎,结合FlaskWeb框架与Docker容器化技术,实现了高效、稳定的以图搜图功能。系统支持上传图片后自动提取特征,通过欧氏距离计算相似度,最终返回Top30相似图片,适用于图片素材管理、版权检索等场景。
二、核心技术栈
1. 特征提取
- 模型:VGG16(预训练权重imagenet,微调适配图像特征提取)
- 框架:Keras + TensorFlow(模型搭建与训练)
2. 向量检索与并行计算
- Milvus:开源向量数据库,高效处理海量特征向量的相似度检索
- Docker:容器化部署Milvus,保证环境一致性与可移植性
3. 前后端开发
- 前端:HTML + jQuery(页面布局与交互,图片流展示)
- 后端:Python Flask(接口开发、请求处理与逻辑调度)
4. 数据存储
- SQLite:存储图片元信息
- Milvus:存储图片特征向量
三、环境搭建步骤
1. Docker与Milvus部署
Milvus作为向量检索核心,需通过Docker容器启动,步骤如下:
(1)查看Docker容器状态
打开终端,执行以下命令查看当前Docker中运行的容器:
shell
docker ps -a
若出现如下结果,说明Milvus容器已存在但处于退出状态(CONTAINER ID为120aa8c0fd25,名称milvus_cpu):
| CONTAINER ID | IMAGE | STATUS | PORTS | NAMES |
|---|---|---|---|---|
| 120aa8c0fd25 | milvusdb/milvus:0.8.0-cpu-xxx | Exited (255) 2min ago | 0.0.0.0:9091->9091/tcp, 0.0.0.0:19121->19121/tcp, 0.0.0.0:19530->19530/tcp | milvus_cpu |
(2)重启Milvus容器
通过容器ID重启Milvus(替换为你的容器ID):
shell
docker restart 120aa8c0fd25
重启后再次执行docker ps -a,若STATUS显示为Up,则说明Milvus启动成功。
2. 项目依赖安装
创建Python虚拟环境,安装所需依赖包:
shell
# 创建虚拟环境
python -m venv search_env
# 激活环境(Windows)
search_env\Scripts\activate
# 激活环境(Linux/Mac)
source search_env/bin/activate
# 安装依赖
pip install keras tensorflow flask milvus numpy pillow
四、项目启动流程
1. 项目结构(核心文件)
SearchImage/
├── model/ # 模型文件目录(VGG16权重)
├── temp/ # 临时图片存储目录(用户上传图片)
├── static/ # 静态资源(CSS/JS)
├── templates/ # 前端模板(image.html)
├── manage.py # 项目入口文件
└── search_image.py # 特征提取与检索核心逻辑
2. 启动Flask项目
(1)打开核心入口文件
找到项目根目录下的manage.py文件,确保包含Flask应用初始化代码(关键代码示例):
python
from flask import Flask, render_template
import os
app = Flask(__name__)
basedir = os.path.abspath(os.path.dirname(__file__))
# 图片搜索接口
@app.route('/search/<string:image>')
def search(image):
root = os.path.join(basedir, 'temp')
path = os.path.join(root, image)
if IsValidImage(path): # 图片有效性校验函数
return render_template("image.html", my_list=search_image.search(path))
else:
return '请保证图片的完整性!'
if __name__ == '__main__':
app.run(debug=True)
(2)运行项目
在终端执行:
shell
python manage.py
若启动成功,会显示类似日志:
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with stat
(3)访问系统
打开浏览器,输入地址:http://127.0.0.1:5000/,即可进入以图搜图首页。
五、核心功能实现
1. VGG16特征提取模型(STEP1:训练与初始化)
VGG16模型负责将图片转化为高维特征向量,核心代码如下:
python
# -*- coding: utf-8 -*-
import keras
import numpy as np
from numpy import linalg as LA
from keras.applications.vgg16 import VGG16
from keras.preprocessing import image
from keras.applications.vgg16 import preprocess_input
class VGGNet:
def __init__(self):
keras.backend.clear_session()
# 模型配置:输入尺寸224x224x3,使用imagenet预训练权重,max pooling
self.input_shape = (224, 224, 3)
self.weight = 'imagenet'
self.pooling = 'max'
# 初始化VGG16模型(不含顶层全连接层,用于特征提取)
self.model = VGG16(weights=self.weight,
input_shape=(self.input_shape[0], self.input_shape[1], self.input_shape[2]),
pooling=self.pooling, include_top=False)
# 预热模型(可选:加载自定义微调权重)
# self.model.load_weights(r'./model/vgg16_use6.h5', by_name=True)
self.model.predict(np.zeros((1, 224, 224, 3))) # 初始化预测
# 提取图片特征向量
def extract_feat(self, img_path):
img = image.load_img(img_path, target_size=(self.input_shape[0], self.input_shape[1]))
x = image.img_to_array(img)
x = np.expand_dims(x, axis=0)
x = preprocess_input(x)
feat = self.model.predict(x) # 特征提取
norm_feat = feat[0] / LA.norm(feat[0]) # 归一化
return norm_feat
VGG16特征提取流程详解
- 输入图像:尺寸调整为224x224x3(RGB三通道);
- 卷积层:经64→128→256→512→512通道的卷积核(3x3)多次卷积,每次卷积后用ReLU激活;
- 池化层:每轮卷积后通过2x2 max pooling降维,图像尺寸减半;
- 全连接层:最终通过Flatten拉平为25088维向量,经3层全连接层处理;
- 特征输出:去除顶层softmax,输出512维特征向量(max pooling后)。
2. 相似度检索(STEP2:Milvus向量匹配)
核心逻辑
- 训练集预处理:将所有图片通过VGG16提取特征向量,存入Milvus向量数据库与SQLite(关联图片路径);
- 用户上传图片:提取特征向量后,通过Milvus计算与数据库中所有向量的欧氏距离;
- 结果排序:按欧氏距离从小到大排序,取前30个相似度最高的结果。
关键代码(search_image.py)
python
from milvus import Milvus, IndexType, MetricType
from VGGNet import VGGNet
import sqlite3
# Milvus连接配置
MILVUS_HOST = '127.0.0.1'
MILVUS_PORT = 19530
collection_name = 'image_features'
# 初始化Milvus客户端与VGG模型
milvus = Milvus(MILVUS_HOST, MILVUS_PORT)
vgg_model = VGGNet()
def search(img_path, top_k=30):
# 提取上传图片特征
query_feat = vgg_model.extract_feat(img_path)
# Milvus相似度检索(欧氏距离)
search_param = {"nprobe": 16}
results = milvus.search(collection_name=collection_name,
query_records=[query_feat],
top_k=top_k,
params=search_param,
metric_type=MetricType.L2)
# 从SQLite查询图片路径(根据Milvus返回的id关联)
conn = sqlite3.connect('image_db.sqlite')
cursor = conn.cursor()
similar_imgs = []
for res in results[0]:
img_id = res.id
distance = res.distance
# 计算相似度(距离越小相似度越高,此处映射为百分比)
similarity = (1 - distance / np.max(results[0][0].distance)) * 100
cursor.execute("SELECT img_path FROM images WHERE id=?", (img_id,))
img_path = cursor.fetchone()[0]
similar_imgs.append({"path": img_path, "similarity": round(similarity, 2)})
conn.close()
return similar_imgs
3. 前端展示(STEP3:HTML页面渲染)
通过Flask模板将相似度结果渲染到前端,核心代码(templates/image.html):
html
<!DOCTYPE html>
<html>
<head>
<title>以图搜图 - 相似结果</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<style>
.img-item { float: left; margin: 10px; text-align: center; }
.img-item img { width: 200px; height: auto; border: 1px solid #eee; }
.similarity { color: red; font-weight: bold; }
</style>
</head>
<body>
<h1>相似图片结果(Top30)</h1>
<div class="img-container">
{% for item in my_list %}
<div class="img-item">
<img src="{{ url_for('static', filename=item.path) }}" alt="相似图片">
<p>相似度:<span class="similarity">{{ item.similarity }}%</span></p>
</div>
{% endfor %}
</div>
</body>
</html>
六、系统演示
1. 首页界面
访问http://127.0.0.1:5000/,上传本地图片(支持JPG、PNG等格式):
2. 检索结果展示
上传图片后,系统自动跳转至结果页,展示Top30相似图片及对应相似度:
示例结果:
- 相似度56.90%(最高匹配)
- 相似度55.65%
- 相似度50.49%
...
七、关键问题与解决方案
1. Milvus容器启动失败
- 检查端口是否被占用(19530、19121、9091),执行
netstat -ano | findstr 19530查看占用进程并关闭; - 重新拉取Milvus镜像:
docker pull milvusdb/milvus:0.8.0-cpu-d041520-464400。
2. 特征提取速度慢
- 优化:使用GPU加速(替换Milvus GPU版本+TensorFlow GPU版);
- 批量处理:训练集图片提前提取特征并入库,避免实时计算。
3. 相似度准确率低
- 微调VGG16模型:使用自定义数据集重新训练顶层全连接层;
- 调整相似度计算方式:改用余弦相似度(MetricType.IP),需同步修改特征归一化逻辑。
八、项目扩展方向
- 支持更多图片格式(WebP、SVG等)与批量上传;
- 加入图片预处理(去噪、缩放、旋转不变性优化);
- 结合Redis缓存热门查询结果,提升响应速度;
- 开发移动端适配界面,支持手机端上传图片检索。
总结
本项目通过VGG16模型实现高效特征提取,结合Milvus向量数据库的快速检索能力,构建了一套完整的以图搜图系统。Docker容器化部署确保了环境一致性,Flask+jQuery简化了前后端开发流程。系统可直接用于小型图片库检索,通过微调模型与优化配置,也可扩展至百万级图片库场景。