
01. 为什么 MASt3R 很值得一看
MASt3R 的论文题目是 Grounding Image Matching in 3D with MASt3R。如果说 DUSt3R 让“从图片到三维点图”变得直接,那么 MASt3R 更进一步:它把 图像匹配 和 三维几何理解 绑在一起,让匹配点不再只是 2D 图像上的相似纹理,而是带有 3D 语义和空间约束的对应关系。
一句话概括它的亮点:
MASt3R 不是单纯“找相似点”,而是在问:这些像素在三维世界里是不是同一个地方?✨
这件事非常关键。视觉定位、SfM、三维建图、机器人导航、AR 空间锚定都离不开稳定匹配。传统特征匹配在弱纹理、重复纹理、大视角变化、光照变化时容易掉链子;MASt3R 则尝试用预训练三维视觉模型,把匹配从“图像相似性”升级为“3D-grounded correspondence”。
02. 项目整体架构
本地项目的关键模块如下:
| 模块 | 作用 | 典型文件 |
|---|---|---|
| 模型主体 | 继承 DUSt3R 骨架,增加 MASt3R 局部特征头 | mast3r/model.py |
| 预测头 | 同时输出 3D pointmap、descriptor、confidence | mast3r/catmlp_dpt_head.py |
| 快速匹配 | reciprocal nearest neighbors,支持 GPU block 计算 | mast3r/fast_nn.py |
| 图像对构建 | complete / swin / logwin / oneref / retrieval | mast3r/image_pairs.py |
| 稀疏全局对齐 | 匹配、粗对齐、细化、三角化、相机参数优化 | mast3r/cloud_opt/sparse_ga.py |
| 检索建图 | 基于相似度图选择关键图与连接边 | mast3r/retrieval/ |
| Demo 与部署 | Gradio demo、Docker、GLB 导出 | demo.py, mast3r/demo.py, docker/ |
| 视觉定位 | Aachen、InLoc、7-Scenes、Cambridge 等定位实验入口 | visloc.py |
整体流程可以简化成:

03. 核心技术一:从 DUSt3R 骨架长出“匹配大脑”
mast3r/model.py 中,MASt3R 模型类继承自 DUSt3R 的 AsymmetricCroCo3DStereo:
class AsymmetricMASt3R(AsymmetricCroCo3DStereo):
def __init__(self, desc_mode=('norm'), two_confs=False, desc_conf_mode=None, **kwargs):
self.desc_mode = desc_mode
self.two_confs = two_confs
self.desc_conf_mode = desc_conf_mode
super().__init__(**kwargs)
这个设计很聪明:它复用了 DUSt3R 已经具备的双图编码、非对称解码和 3D 点图预测能力,同时增加 descriptor 相关配置。这样 MASt3R 不需要从零搭建三维视觉骨架,而是把注意力放在“匹配能力增强”上。
模型加载也兼容本地权重和 Hugging Face:
@classmethod
def from_pretrained(cls, pretrained_model_name_or_path, **kw):
if os.path.isfile(pretrained_model_name_or_path):
return load_model(pretrained_model_name_or_path, device='cpu')
else:
return super(AsymmetricMASt3R, cls).from_pretrained(pretrained_model_name_or_path, **kw)
对工程部署来说,这意味着你可以:
- 用
naver/MASt3R_ViTLarge_BaseDecoder_512_catmlpdpt_metric自动下载模型。
- 也可以使用本地
.pth权重,便于离线部署和版本锁定。
04. 核心技术二:CatMLP+DPT Head,同时预测点和特征
MASt3R 的关键创新集中在 catmlp_dpt_head.py。它的预测头不是只输出 3D 点,而是同时输出:
pts3d:三维点图。
conf:3D 回归置信度。
desc:每个像素的局部描述子。
desc_conf:描述子匹配置信度。
后处理代码很直观:
def postprocess(out, depth_mode, conf_mode, desc_dim=None, desc_mode='norm', two_confs=False, desc_conf_mode=None):
if desc_conf_mode is None:
desc_conf_mode = conf_mode
fmap = out.permute(0, 2, 3, 1) # B,H,W,D
res = dict(pts3d=reg_dense_depth(fmap[..., 0:3], mode=depth_mode))
if conf_mode is not None:
res['conf'] = reg_dense_conf(fmap[..., 3], mode=conf_mode)
if desc_dim is not None:
start = 3 + int(conf_mode is not None)
res['desc'] = reg_desc(fmap[..., start:start + desc_dim], mode=desc_mode)
if two_confs:
res['desc_conf'] = reg_dense_conf(fmap[..., start + desc_dim], mode=desc_conf_mode)
else:
res['desc_conf'] = res['conf'].clone()
return res
其中 descriptor 会进行归一化:
def reg_desc(desc, mode):
if 'norm' in mode:
desc = desc / desc.norm(dim=-1, keepdim=True)
else:
raise ValueError(f"Unknown desc mode {mode}")
return desc
这让后续用点积相似度做匹配更自然,也更高效。你可以把它理解为:MASt3R 给每个像素发了一张“局部身份证”,这张身份证又是和三维几何一起训练出来的。挺妙的,是吧 😄
05. 核心技术三:编码器输出 + 解码器输出拼接,兼顾语义和几何
MASt3R 的 Cat_MLP_LocalFeatures_DPT_Pts3d 会把 encoder 和 decoder 的 token 拼接起来:
enc_output, dec_output = decout[0], decout[-1]
cat_output = torch.cat([enc_output, dec_output], dim=-1) # concatenate
随后一边用 DPT 分支预测 3D 点,一边用 MLP 分支预测局部特征:
pts3d = self.dpt(decout, image_size=(img_shape[0], img_shape[1]))
local_features = self.head_local_features(cat_output) # B,S,D
local_features = local_features.transpose(-1, -2).view(B, -1, H // self.patch_size, W // self.patch_size)
local_features = F.pixel_shuffle(local_features, self.patch_size) # B,d,H,W
out = torch.cat([pts3d, local_features], dim=1)
这里有两个值得注意的点:
1. encoder token 更偏向原始图像内容和局部纹理。
2. decoder token 已经融合了跨视图几何关系。
把两者拼接后再预测 descriptor,相当于让局部特征同时知道“我长什么样”和“我在三维关系里像谁”。这也是 MASt3R 区别于传统 SIFT/SuperPoint 类 2D 特征的关键。
06. 核心技术四:快速互近邻匹配,稳一点,也快一点
README 中的基础匹配示例非常简洁:
from mast3r.model import AsymmetricMASt3R
from mast3r.fast_nn import fast_reciprocal_NNs
import mast3r.utils.path_to_dust3r
from dust3r.inference import inference
from dust3r.utils.image import load_images
device = 'cuda'
model_name = "naver/MASt3R_ViTLarge_BaseDecoder_512_catmlpdpt_metric"
model = AsymmetricMASt3R.from_pretrained(model_name).to(device)
images = load_images(['image1.png', 'image2.png'], size=512)
output = inference([tuple(images)], model, device, batch_size=1, verbose=False)
desc1 = output['pred1']['desc'].squeeze(0).detach()
desc2 = output['pred2']['desc'].squeeze(0).detach()
matches_im0, matches_im1 = fast_reciprocal_NNs(
desc1, desc2, subsample_or_initxy1=8,
device=device, dist='dot', block_size=2**13
)
fast_nn.py 中的 bruteforce_reciprocal_nns 支持 GPU 分块计算,避免一次性构造过大的距离矩阵:
if block_size is None or len(A) * len(B) <= block_size**2:
dists = dist_func(A, B)
_, nn_A = argmin(dists, dim=1)
_, nn_B = argmin(dists, dim=0)
else:
dis_A = torch.full((A.shape[0],), float('inf'), device=device, dtype=A.dtype)
dis_B = torch.full((B.shape[0],), float('inf'), device=device, dtype=B.dtype)
nn_A = torch.full((A.shape[0],), -1, device=device, dtype=torch.int64)
nn_B = torch.full((B.shape[0],), -1, device=device, dtype=torch.int64)
...
它还使用 reciprocal nearest neighbors:A 中点的最近邻是 B 中某点,同时 B 中该点的最近邻也要回到 A。这种双向一致性筛选能明显减少误匹配。
while notyet.any():
_, xy2[notyet] = to_numpy(tree2.query(pts1[xy1[notyet]], **matcher_kw))
if not ret_basin:
notyet &= (old_xy2 != xy2)
_, xy1[notyet] = to_numpy(tree1.query(pts2[xy2[notyet]], **matcher_kw))
if ret_basin:
basin[old_xy1[notyet]] = xy1[notyet]
notyet &= (old_xy1 != xy1)
这部分是很实用的工程设计:密集 descriptor 带来大量候选点,互近邻和分块计算则让匹配既可靠又不至于把显存“点燃”。
07. 核心技术五:图像对构建不止 complete,还有 retrieval
多图场景里,若对所有图片两两匹配,计算量会快速膨胀。MASt3R 在 image_pairs.py 中提供了多种图像对策略:
def make_pairs(imgs, scene_graph='complete', prefilter=None, symmetrize=True, sim_mat=None):
pairs = []
if scene_graph == 'complete':
for i in range(len(imgs)):
for j in range(i):
pairs.append((imgs[i], imgs[j]))
elif scene_graph.startswith('swin'):
...
elif scene_graph.startswith('logwin'):
...
elif scene_graph.startswith('oneref'):
...
elif scene_graph.startswith('retrieval'):
mode, Na, k = scene_graph.split('-')
assert sim_mat is not None, "sim_mat is required for retrieval mode"
fps_pairs, anchor_idxs = make_pairs_fps(sim_mat, Na=int(Na), tokK=int(k), dist_thresh=None)
for i, j in fps_pairs:
pairs.append((imgs[i], imgs[j]))
这里的 retrieval 很适合大规模图片集合:先通过检索得到相似度矩阵,再决定哪些图像值得匹配。retrieval/graph.py 里使用 farthest point sampling 选择关键图:
def make_pairs_fps(sim_mat, Na=20, tokK=1, dist_thresh=None):
dist_mat = 1 - sim_mat
pairs = set()
keyimgs_idx = np.array([])
if Na != 0:
keyimgs_idx, _ = farthest_point_sampling(dist_mat, N=Na, dist_thresh=dist_thresh)
# 1. Complete graph between key images
for i in range(len(keyimgs_idx)):
for j in range(i + 1, len(keyimgs_idx)):
idx_i, idx_j = keyimgs_idx[i], keyimgs_idx[j]
pairs.add((idx_i, idx_j))
# 2. Connect non-key images to the earest key image
keyimg_dist_mat = dist_mat[:, keyimgs_idx]
for i in range(keyimg_dist_mat.shape[0]):
if i in keyimgs_idx:
continue
j = keyimg_dist_mat[i].argmin()
i1, i2 = min(i, keyimgs_idx[j]), max(i, keyimgs_idx[j])
if i1 != i2 and (i1, i2) not in pairs:
pairs.add((i1, i2))
这就像给大场景建图先安排“骨架节点”,再把普通图片接到最近的关键节点上。很工程,也很聪明。
08. 核心技术六:Sparse Global Alignment,把匹配线变成三维场景
MASt3R 的 demo 并不止于展示匹配线,而是用 sparse_global_alignment 继续做重建:
scene = sparse_global_alignment(filelist, pairs, cache_dir,
model, lr1=lr1, niter1=niter1, lr2=lr2, niter2=niter2, device=device,
opt_depth='depth' in optim_level, shared_intrinsics=shared_intrinsics,
matching_conf_thr=matching_conf_thr, **kw)
sparse_ga.py 中的主流程写得很清楚:
def sparse_global_alignment(imgs, pairs_in, cache_path, model, subsample=8, desc_conf='desc_conf',
kinematic_mode='hclust-ward', device='cuda', dtype=torch.float32, shared_intrinsics=False, **kw):
# Convert pair naming convention from dust3r to mast3r
pairs_in = convert_dust3r_pairs_naming(imgs, pairs_in)
# forward pass
pairs, cache_path = forward_mast3r(pairs_in, model,
cache_path=cache_path, subsample=subsample,
desc_conf=desc_conf, device=device)
# extract canonical pointmaps
tmp_pairs, pairwise_scores, canonical_views, canonical_paths, preds_21 =
prepare_canonical_data(imgs, pairs, subsample, cache_path=cache_path, mode='avg-angle', device=device)
# smartly combine all useful data
imsizes, pps, base_focals, core_depth, anchors, corres, corres2d, preds_21 =
condense_data(imgs, tmp_pairs, canonical_views, preds_21, dtype)
后续优化会把相机外参、焦距、主点和深度纳入同一个优化框架:
quats = [nn.Parameter(vec0001.clone()) for _ in range(len(imgs))]
trans = [nn.Parameter(torch.zeros(3, device=device, dtype=dtype)) for _ in range(len(imgs))]
pps = [nn.Parameter(pp.to(dtype)) for pp in pps]
log_focals = [nn.Parameter(f.view(1).log().to(dtype)) for f in base_focals]
这使得 MASt3R 很自然地走向 SfM:先找到可靠对应,再让几何优化把这些对应“拉”成一致的三维场景。
09. 训练目标:3D 回归 + 匹配学习,一手抓几何,一手抓对应
MASt3R 的训练不只是三维点回归,还加入了匹配损失。README 里的训练命令展示了这条思路:
--train_criterion "ConfLoss(Regr3D(L21, norm_mode='?avg_dis'), alpha=0.2) + 0.075*ConfMatchingLoss(MatchingLoss(InfoNCE(mode='proper', temperature=0.05), negatives_padding=0, blocksize=8192), alpha=10.0, confmode='mean')"
losses.py 中的 InfoNCE 实现说明了 descriptor 如何被拉近和推远:
class InfoNCE(MatchingCriterion):
def loss(self, desc1, desc2, valid_matches=None, euc=False):
B, N, D = desc1.shape
sim = get_similarities(desc1, desc2, euc) / self.temperature
sim[sim.isnan()] = -torch.inf
sim = sim.exp_()
positives = sim.diagonal(dim1=-2, dim2=-1)
if self.mode == 'proper':
loss = -(torch.log((positives / sim.sum(dim=-2)).clip(self.eps)) +
torch.log((positives / sim.sum(dim=-1)).clip(self.eps)))
return loss[valid_matches]
这段代码背后的直觉很简单:真实对应点的 descriptor 要更相似,非对应点要被拉开。再配合 3D pointmap 监督,模型学到的就不是普通外观相似,而是更贴近三维空间一致性的匹配。
10. Demo 与部署:从图片到 GLB
MASt3R demo 可以把结果导出为 .glb,便于浏览和集成到 3D 工具链中:
scene.export(file_obj=outfile)
return outfile
在 mast3r/demo.py 中,导出逻辑会把点云、mesh 和相机一起放进 trimesh.Scene:
scene = trimesh.Scene()
if as_pointcloud:
pts = np.concatenate([p[m.ravel()] for p, m in zip(pts3d, mask)]).reshape(-1, 3)
col = np.concatenate([p[m] for p, m in zip(imgs, mask)]).reshape(-1, 3)
valid_msk = np.isfinite(pts.sum(axis=1))
pct = trimesh.PointCloud(pts[valid_msk], colors=col[valid_msk])
scene.add_geometry(pct)
else:
meshes = []
for i in range(len(imgs)):
pts3d_i = pts3d[i].reshape(imgs[i].shape)
msk_i = mask[i] & np.isfinite(pts3d_i.sum(axis=-1))
meshes.append(pts3d_to_trimesh(imgs[i], pts3d_i, msk_i))
这对于产品原型非常友好:上传图片,生成可视化三维结果,再把 .glb 接入 Web 3D、Blender、Unity、数字孪生平台或内部审阅系统。
11. 技术应用领域与前景 🌍

1. 视觉定位与重定位
MASt3R 的强匹配能力非常适合视觉定位。README 中也给出了 Aachen-Day-Night、InLoc、7-Scenes、Cambridge Landmarks 等数据集的 visloc.py 命令。对于昼夜变化、室内重复纹理、大视角变化,3D-grounded matching 是很有吸引力的路线。
2. SfM 与三维建图
MASt3R-SfM 的核心就是 make_pairs + sparse_global_alignment。它可以把图像集合组织成图,再通过匹配和几何优化恢复相机位姿与稀疏/半稠密结构。对文化遗产、建筑巡检、场景采集、无人机建图都很有潜力。
3. 机器人与具身智能
机器人需要知道“我在哪里”和“眼前物体与环境如何对应”。MASt3R 可以提供跨视角稳定匹配和三维锚点,为导航、回环检测、操作前的场景对齐提供基础能力。
4. AR 空间锚定
AR 应用需要把虚拟内容稳定绑定到真实世界。传统特征匹配一旦漂移,虚拟物体就会抖。MASt3R 这类三维约束匹配,有机会提升复杂场景下的空间锚定稳定性。
5. 数据标注与三维资产生产
在离线数据生产中,MASt3R 可以辅助生成匹配、相机位姿、点云和粗 mesh,为自动驾驶、机器人、影视、游戏和数字孪生提供空间数据底座。
12. 部署应用建议
1. 环境准备
README 推荐 Python 3.11 + PyTorch CUDA 环境:
conda create -n mast3r python=3.11 cmake=3.14.0
conda activate mast3r
conda install pytorch torchvision pytorch-cuda=12.1 -c pytorch -c nvidia
pip install -r requirements.txt
pip install -r dust3r/requirements.txt
pip install -r dust3r/requirements_optional.txt
MASt3R 还建议安装 ASMK,用于 retrieval pairing:
pip install cython
git clone https://github.com/jenicek/asmk
cd asmk/cython/
cythonize *.pyx
cd ..
pip install .
如果使用 CUDA,建议编译 RoPE kernel:
cd dust3r/croco/models/curope/
python setup.py build_ext --inplace
cd ../../../../
2. 模型与权重管理
主模型权重:
mkdir -p checkpoints/
wget https://download.europe.naverlabs.com/ComputerVision/MASt3R/MASt3R_ViTLarge_BaseDecoder_512_catmlpdpt_metric.pth -P checkpoints/
若要使用 retrieval 模式,还需要 retrieval 模型和 codebook:
wget https://download.europe.naverlabs.com/ComputerVision/MASt3R/MASt3R_ViTLarge_BaseDecoder_512_catmlpdpt_metric_retrieval_trainingfree.pth -P checkpoints/
wget https://download.europe.naverlabs.com/ComputerVision/MASt3R/MASt3R_ViTLarge_BaseDecoder_512_catmlpdpt_metric_retrieval_codebook.pkl -P checkpoints/
生产部署建议:
- 固定模型权重版本和 checksum。
- 将 checkpoint 作为只读 volume 挂载。
- 缓存 pairwise forward 结果,避免重复跑模型。
- 记录每次任务的 scene graph、阈值、迭代次数和输出版本。
3. 图像对策略怎么选
| 场景 | 推荐策略 | 说明 |
|---|---|---|
| 图片少于 10 张 | complete |
简单直接,匹配边覆盖充分 |
| 视频或连续拍摄 | swin / logwin |
控制计算量,并保留局部连续性 |
| 有主参考图 | oneref |
适合围绕一个中心视角的轻量任务 |
| 图片很多且顺序未知 | retrieval |
先检索相似图,再构建稀疏图 |
| 大场景建图 | retrieval + sparse_global_alignment |
更适合工程化扩展 |
4. 服务化架构建议
可以拆成五层:
API 层:上传图片、选择任务模式、设置输出格式
预处理层:图像解码、缩放、质量检测、关键帧抽取
匹配层:make_pairs -> inference -> desc matching
优化层:sparse_global_alignment -> refinement -> triangulation
产物层:保存 matches、camera poses、pointcloud、GLB、日志
部署时要重点关注:
- 显存:
complete图像对会随图片数平方增长。
- 缓存:pairwise 推理结果应落盘缓存,MASt3R demo 中已经使用
cache_dir。
- 异步任务:重建任务不适合阻塞式 HTTP 请求,建议队列化。
- 参数暴露:普通用户只给“速度/质量”档位,专家用户再开放 lr、niter、matching_conf_thr。
- 输出校验:对点云数量、相机轨迹连通性、重投影误差、匹配数量做基本检查。
5. Docker 部署
项目提供 Docker 启动脚本:
cd docker
bash run.sh --with-cuda --model_name="MASt3R_ViTLarge_BaseDecoder_512_catmlpdpt_metric"
脚本会下载权重并选择 CUDA 或 CPU compose:
download_model_checkpoint() {
if [ -f "./files/checkpoints/${model_name}" ]; then
echo "Model checkpoint ${model_name} already exists. Skipping download."
return
fi
wget "https://download.europe.naverlabs.com/ComputerVision/MASt3R/${model_name}" -P ./files/checkpoints
}
生产环境建议不要在容器启动时临时下载权重,而是在镜像构建或部署阶段提前准备,减少外网依赖和冷启动时间。
13. 质量评估与常见问题

| 问题 | 可能原因 | 建议 |
|---|---|---|
| 匹配点很少 | 图像重叠不足、画面模糊、尺度差异过大 | 增加中间视角,做图像质量筛选 |
| 错误匹配较多 | 重复纹理、反光、动态物体 | 提高置信阈值,过滤边缘和动态区域 |
| 重建断裂 | scene graph 不连通 | 使用 retrieval 或 logwin 增加跨区域连接 |
| 显存压力大 | 图片多、complete graph 边数过多 | 改用 swin/logwin/retrieval,启用缓存 |
| 相机轨迹飘 | 尺度或内参优化不稳定 | 尝试 shared_intrinsics,加入已知内参或筛掉坏图 |
14. 与传统特征匹配 / SfM 的关系
| 维度 | 传统 SIFT/SuperPoint + SfM | MASt3R |
|---|---|---|
| 匹配依据 | 2D 局部纹理或学习特征 | 3D-grounded descriptor + pointmap |
| 输出 | 匹配点、相机位姿、稀疏点云 | descriptor、3D 点图、置信度、重建结果 |
| 优势 | 成熟、可解释、生态丰富 | 大视角和复杂场景下潜力更强 |
| 局限 | 弱纹理/重复纹理易失败 | 计算量较大,依赖模型泛化和权重许可 |
| 最佳实践 | 作为成熟几何后端 | 作为强匹配与几何先验前端 |
更现实的落地方向,是让 MASt3R 作为强前端,与 COLMAP、GLOMAP、PnP、BA、SLAM 后端结合。项目里也提供了 demo_glomap.py、kapture_mast3r_mapping.py 这类尝试,说明它天然适合进入经典三维视觉工具链。
15. 合规与使用边界
项目代码使用 CC BY-NC-SA 4.0,也就是非商业、署名、相同方式共享许可。README 和 CHECKPOINTS_NOTICE 还特别提醒:模型训练数据和 checkpoint 相关许可证需要额外检查,其中 Map-free 数据集许可尤其严格。
因此建议:
- 内部学习、研究、原型验证可以作为优先场景。
- 商业产品、客户交付、SaaS 服务、硬件集成前必须做许可证审查。
- 若使用 retrieval、DUNE 或外部数据集训练权重,也要分别核查依赖许可。
- 对机器人、自动驾驶、安全巡检等高风险场景,不应只依赖 MASt3R 单一路径做最终决策。
16. 小结:MASt3R 的真正价值 ✨
MASt3R 最有意思的地方,是它把过去分开的两件事合在了一起:
- 一边理解图片中的三维结构。
- 一边生成能跨视角稳定匹配的局部描述子。
这让它不仅能“看见图像”,还能更像一个建图系统那样理解“这些图像如何在三维世界中连接起来”。
如果用一句欢快但严谨的话收尾:MASt3R 像是给传统 SfM 装上了一副更懂三维的眼睛 👀。它不是万能魔法,但它已经把图像匹配、视觉定位和三维重建推向了更统一、更智能、也更值得期待的新阶段。