DELF 快速上手:基于 TensorFlow Models 的局部特征提取与图像匹配完整教程
DELF(DEep Local Features)是 Google 提出的带注意力机制的深度局部特征方法,用于实例级识别与图像检索场景下的关键点定位与描述子匹配。本文以 TensorFlow Models 仓库 research/delf/EXTRACTION_MATCHING.md 为主线,完整演示从环境安装、Oxford 建筑物数据集下载、预训练模型加载,到调用 extract_features.py 提取 .delf 特征、再经 match_images.py 完成最近邻匹配与 RANSAC 几何校验的端到端流程。读完本文,你将能够独立跑通一次 DELF 特征提取与两两图像匹配,并理解每一步背后对应的源码实现与配置含义。
一、准备工作:安装 DELF 库
DELF 代码依赖 TensorFlow、TF-Slim、protobuf、protoc 编译器及若干 Python 库。仓库提供了两种安装路径:
方式一:一键脚本安装(推荐)
进入 models/research/delf/delf/python/training 目录,直接运行:
# From models/research/delf/delf/python/training
bash install_delf.sh
该脚本(install_delf.sh)按顺序完成:安装 TensorFlow 2.2(CPU/GPU)→ 从源码安装 TF-Slim → 下载 protoc 并编译 DELF 的 Protocol Buffers → 安装 matplotlib、numpy、scikit-image、scipy、python3-tk → 安装 TensorFlow Object Detection API → 安装 DELF 包。需要说明的是,脚本只适用于 64 位 Linux,因为其中会自动下载与架构绑定的 protoc 二进制;其他架构需参照脚本中注释手动替换 protoc 的下载版本。
方式二:手工分步安装
若一键脚本失败,可参考 INSTALL_INSTRUCTIONS.md 逐步安装,核心步骤为:
# 1. TensorFlow(需 2.2 及以上)
pip3 install 'tensorflow>=2.2.0' # CPU
# pip3 install 'tensorflow-gpu>=2.2.0' # GPU
# 2. 从源码安装 TF-Slim(避免旧版依赖已废弃的 tf.contrib)
git clone git@github.com:google-research/tf-slim.git
cd tf-slim && pip3 install .
# 3. Python 依赖
pip3 install matplotlib numpy scikit-image scipy
sudo apt-get install python3-tk
# 4. 将 tensorflow/models 加入 PYTHONPATH(Object Detection API 需要)
# From tensorflow/models/research/
export PYTHONPATH=$PYTHONPATH:`pwd`
# 5. 编译 DELF protobuf(PATH_TO_PROTOC 为 protoc 下载目录,版本需 >= 3.3)
# From tensorflow/models/research/delf/
${PATH_TO_PROTOC?}/bin/protoc delf/protos/*.proto --python_out=.
# 6. 安装 delf 包
# From tensorflow/models/research/delf/
pip3 install -e .
安装完成后,执行 python3 -c 'import delf' 无报错即表示 DELF 包加载成功。若 pip3 install -e(editable 模式)报错,可去掉 -e;权限不足时在前面加 sudo。
二、下载 Oxford 建筑物数据集
本教程使用经典的 Oxford Buildings(Oxford5k) 数据集来演示。为与后续命令保持一致,请将数据解压到 models/research/delf/delf/python/examples 目录下:
# From tensorflow/models/research/delf/delf/python/examples/
mkdir data && cd data
wget http://www.robots.ox.ac.uk/~vgg/data/oxbuildings/oxbuild_images.tgz
mkdir oxford5k_images oxford5k_features
tar -xvzf oxbuild_images.tgz -C oxford5k_images/
cd ../
echo data/oxford5k_images/hertford_000056.jpg >> list_images.txt
echo data/oxford5k_images/oxford_000317.jpg >> list_images.txt
这里我们抽取了 hertford_000056.jpg(Hertford 学院)与 oxford_000317.jpg(牛津某建筑)两张图片,构造出 list_images.txt 图像列表文件;oxford5k_features 目录将用于存放后续产出的 .delf 特征文件。
三、下载预训练 DELF 模型
接着下载在 Google Landmarks 数据集 v1(Google-Landmarks)上预训练的 DELF 模型,该模型出自 Detect-to-Retrieve 论文,相比 ICCV'17 原版模型带来了可观的检索精度提升:
# From tensorflow/models/research/delf/delf/python/examples/
mkdir parameters && cd parameters
wget http://storage.googleapis.com/delf/delf_gld_20190411.tar.gz
tar -xvzf delf_gld_20190411.tar.gz
解压后的目录应包含模型目录与 PCA 参数文件,它们与 delf_config_example.pbtxt 中 model_path、mean_path、projection_matrix_path 所指向的相对路径一一对应(见第四节)。
四、DELF 特征提取:extract_features.py
4.1 运行命令
安装、数据与模型就绪后,运行以下命令即可为 list_images.txt 中的两张图片提取 DELF 特征:
# From tensorflow/models/research/delf/delf/python/examples/
python3 extract_features.py \
--config_path delf_config_example.pbtxt \
--list_images_path list_images.txt \
--output_dir data/oxford5k_features
从源码 extract_features.py 可以看到三个命令行参数的默认值与语义:
| 参数 | 默认值 | 说明 |
|---|---|---|
--config_path |
delf_config_example.pbtxt |
DelfConfig proto 文本配置文件路径,决定模型与提取策略 |
--list_images_path |
list_images.txt |
待提取特征图片路径列表(每行一张,须为 JPG) |
--output_dir |
test_features |
特征输出目录,每张图输出同名、扩展名为 .delf 的文件 |
脚本的实际处理逻辑(extract_features.py)值得注意:它会用 text_format.Merge 解析 DelfConfig;若输出目录不存在则自动创建;若某张图对应的 .delf 文件已存在则直接跳过(方便断点续跑);每隔 100 张图打印一次处理耗时。每张图经 extractor.MakeExtractor(config) 构造的提取函数处理后,将关键点位置 locations、描述子 descriptors、尺度 scales、注意力分数 attention 四组数组通过 feature_io.WriteToFile 序列化写入文件。
4.2 .delf 特征文件格式
写入的特征文件对应 protobuf 定义的 DelfFeatures 消息。通过 feature_io.py 可以看出,每个特征点包含 y/x 坐标、scale、orientation、strength(即注意力分数)以及一个序列化的浮点描述子向量;读取时则调用 ReadFromFile 还原为 locations[N,2]、scales[N]、descriptors[N,depth]、attention[N]、orientations[N] 五组 NumPy 数组,若文件内无特征则返回五个空数组。
4.3 配置解析:DelfConfig 与多尺度金字塔
示例配置 delf_config_example.pbtxt 完整内容如下:
model_path: "parameters/delf_gld_20190411/model/"
image_scales: .25
image_scales: .3536
image_scales: .5
image_scales: .7071
image_scales: 1.0
image_scales: 1.4142
image_scales: 2.0
delf_local_config {
use_pca: true
# 注意:本示例导出的模型将 layer_name 与 iou_threshold 硬编码进了 checkpoint,
# 因此此处这两个字段对提供的 extract_features.py 脚本不产生实际影响。
layer_name: "resnet_v1_50/block3"
iou_threshold: 1.0
max_feature_num: 1000
score_threshold: 100.0
pca_parameters {
mean_path: "parameters/delf_gld_20190411/pca/mean.datum"
projection_matrix_path: "parameters/delf_gld_20190411/pca/pca_proj_mat.datum"
pca_dim: 40
use_whitening: false
}
}
对照 delf_config.proto 的字段定义,可以深入理解每一项的底层影响:
model_path:指向导出的 TensorFlow SavedModel,MakeExtractor内部通过tf.saved_model.load加载(extractor.py)。image_scales:多尺度金字塔的缩放因子列表。DELF 会在每个尺度上分别提取特征后合并,示例中的 7 个尺度(0.25 → 2.0)用于提升尺度变化下的匹配鲁棒性。DELF 提取器会把全部尺度打包成input_scales张量一次性送入模型。delf_local_config.use_pca:是否对描述子做 PCA 降维。开启后,extractor.py 会预先从mean_path/projection_matrix_path读取 PCA 均值与投影矩阵(必要时含方差文件),随后在 feature_extractor.py 的后处理中按“先 L2 归一化 → PCA 投影(可加白化)→ 再次 L2 归一化”的顺序压缩描述子,本示例将 1024 维原始描述子降至 40 维。max_feature_num(默认 1000)与score_threshold(默认 100.0):控制关键点筛选——超过阈值数量的特征按注意力分数从高到低截断,分数低于阈值的特征被丢弃。它们被构造为input_max_feature_num、input_abs_thres张量传入模型。iou_threshold(默认 1.0,取值 0.0–1.0):NMS 的 IoU 阈值,两特征重叠度不超过该值则同时保留,否则仅保留注意力分数更高者。配置文件注释明确指出:该示例提供的导出模型把layer_name与iou_threshold固化在 checkpoint 内,因此改这两个字段不会生效。layer_name:目标卷积层名(如resnet_v1_50/block3),用于推算感受野参数,从而把特征反算回原图坐标。use_resized_coordinates(proto 默认 false):为 false 时返回的关键点坐标会换算回原始输入图像坐标系;为 true 则直接使用缩放后图像的坐标。从 extractor.py 可见,当该字段为 false 时会对坐标除以缩放因子scale_factors。
此外 proto 还支持 use_local_features / use_global_features 开关(至少其一为 true)、max_image_size / min_image_size / use_square_images 图像尺寸约束,以及用于 DELG 全局特征的 DelfGlobalFeatureConfig(image_scales_ind 选择参与全局描述子聚合的尺度,并对各尺度描述子做求和池化与 L2 归一化)。这些字段主要服务于 DELG 指令文档 中的检索流程。
五、图像匹配:match_images.py
5.1 运行命令
特征提取完成后,执行以下命令对两张图做特征匹配:
python3 match_images.py \
--image_1_path data/oxford5k_images/hertford_000056.jpg \
--image_2_path data/oxford5k_images/oxford_000317.jpg \
--features_1_path data/oxford5k_features/hertford_000056.delf \
--features_2_path data/oxford5k_features/oxford_000317.delf \
--output_image matched_images.png
match_images.py 共有 5 个参数(match_images.py):--image_1_path、--image_2_path(用于可视化读取的原图路径)、--features_1_path、--features_2_path(上一步产出的 .delf 特征文件),以及 --output_image(匹配结果图保存路径,默认 test_match.png)。
5.2 匹配原理:KD 树最近邻 + RANSAC 几何校验
脚本核心流程(match_images.py)包含三个阶段:
- 读取特征:调用
feature_io.ReadFromFile分别载入两图的 locations 与 descriptors,并打印各自特征数量。 - 最近邻搜索:用
scipy.spatial.cKDTree对图 1 的描述子建树,再对图 2 的每个描述子查询,搜索距离上界_DISTANCE_THRESHOLD = 0.8;距离超过该阈值的点对视为无匹配,从而得到初筛(putative)匹配对集合。 - 几何校验(RANSAC):用
skimage.measure.ransac以仿射变换AffineTransform为模型拟合内外点,参数为min_samples=3、residual_threshold=20、max_trials=1000,最后打印内点数量Found N inliers。这一步剔除了不符合整体几何约束的错误匹配。
最终脚本借助 matplotlib 将原图并排绘制,用 skimage.feature.plot_matches 标出内点对应连线,并调用 plt.savefig 输出到 --output_image 指定的图片。运行完成后生成的 matched_images.png 应与仓库内置的示例结果类似:
(该图为仓库随附的 matched_images_example.jpg 参考结果,位于 examples 目录,也见于 DELF 总览 README。)
六、常见问题排查(Troubleshooting)
6.1 matplotlib 报 no display name and no $DISPLAY environment variable
在无图形界面的服务器/容器中运行时,matplotlib 可能因找不到显示环境而报错。解决办法之一是创建(或编辑)~/.config/matplotlib/matplotlibrc,加入一行:
backend : Agg
这样 matplotlib 会强制使用非交互的 Agg 后端,只负责把图保存到文件。实际上 match_images.py 自身已在代码头部执行了 matplotlib.use('Agg')(match_images.py),可避免多数环境问题;若你的 Python 环境仍有拦截,通常与导入顺序或系统级配置有关,按上述方式显式配置 matplotlibrc 即可兜底。
6.2 scikit-image 相关报错
按安装文档默认装到的是 skimage 0.13.XX 或 0.14.1。若在使用 ransac、plot_matches、feature 等接口时遇到兼容性问题,升级到 0.14.1 以上版本即可:
pip3 install -U scikit-image
七、从快速入门到实际落地
跑通上面的流程后,你就掌握了 DELF 局部特征的完整链路:多尺度特征提取(extract_features.py)→ .delf 特征序列化(feature_io)→ KD 树匹配 + RANSAC 几何校验(match_images.py)。在此基础上,可以进一步深入本仓库的相邻模块:
- 若想把提取能力扩展为“局部特征 + 全局特征 + 检索打分”,参考 DELG 指令文档(
delg子目录下extract_features.py与perform_retrieval.py); - 若想先检测显著性区域再聚合特征做实例检索,参考 DETECTION.md 与 Detect-to-Retrieve 指令文档;
- 若需从零训练自己的 DELF 模型,参考 training/README.md。
围绕本文,值得回到源码对照的关键文件有:extract_features.py(提取入口)、extractor.py(提取器构造、多尺度与 PCA 参数装配)、feature_extractor.py(PCA/白化与后处理)、match_images.py(匹配算法)、feature_io.py(.delf 读写)、delf_config.proto(全部配置字段语义)以及 delf_config_example.pbtxt(可直接复用的示例配置)。迁移到自己的图片数据时,只需替换 list_images.txt 中的图像列表并保持配置与模型路径正确即可。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0627
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
