19fda40bab15b.png

"如果眼睛是心灵的窗户,那立体视觉就是智能的敲门砖。"


📌 三句话概括

维度 一言蔽之
是什么 NVIDIA 开源的 CVPR 2025 Oral + Best Paper Nominee 双目深度估计基础模型
牛在哪 零样本泛化登顶 Middlebury & ETH3D 双榜第一,不微调直接跨域开箱即用
怎么用 PyTorch → ONNX → TensorRT,3090 上最高 6× 加速,支持 Jetson 边缘部署

一、🌍 背景:为什么立体匹配需要「基础模型」?

双目深度估计(Stereo Matching)的本质,是模仿人类双眼 👀——左眼一张图、右眼一张图,通过视差推断距离。这个任务在自动驾驶、机器人抓取、AR/VR、3D 重建等领域至关重要。

但传统深度学习方法的痛点非常明显:

📉 训练域表现好 → 换一个场景就崩
📉 每个数据集都要单独微调 → 工程成本高
📉 泛化能力差 → 无法像 LLM 那样「一个模型走天下」

FoundationStereo 的出现,就是要把立体匹配从「专用模型」时代推进到「基础模型」时代。


二、🏗️ 核心技术解析:从代码看架构之美

2.1 整体数据流(一图胜千言)

19fda44c1933f.png

代码中的核心入口是 FoundationStereo.forward(),它的执行流程可以精炼为:

左图 ─┐                                                    ┌─ 视差图 (Disparity)
      ├─→ 🔬 Feature Extraction ─→ 📊 Cost Volume ─→ 🔄 Iterative GRU Update ─→ 📈 Upsample
右图 ─┘                                                    └─→ 深度图 / 点云

2.2 🔬 特征提取:Side-Tuning Adapter 的精妙设计

这是 FoundationStereo 最核心的创新之一。思路非常优雅:

冻结一个强大的单目深度基础模型(DepthAnything V2),用轻量 Adapter 把它「借」给立体匹配任务,既保留预训练知识,又避免灾难性遗忘。

看代码怎么实现的 👇

# extractor.py —— DepthAnythingFeature
class DepthAnythingFeature(nn.Module):
    model_configs = {
        'vitl': {'encoder': 'vitl', 'features': 256, ...},
        'vitb': {'encoder': 'vitb', 'features': 128, ...},
        'vits': {'encoder': 'vits', 'features': 64,  ...},
    }

    def __init__(self, encoder='vits'):
        depth_anything = DepthAnything(self.model_configs[encoder])
        self.depth_anything = depth_anything  # ✅ 完整大模型

    def forward(self, x):
        # 提取中间层特征(multi-scale)
        features = self.depth_anything.pretrained.get_intermediate_layers(
            x, self.intermediate_layer_idx[self.encoder], return_class_token=True
        )
        # 通过 depth_head 得到多尺度特征
        out, path_1, path_2, path_3, path_4, disp = 
            self.depth_anything.depth_head.forward(features, ...)
        return {'out': out, 'path_2': path_2, ...}

关键点解读:

设计决策 代码体现 作用
🧊 冻结 ViT self.dino = freeze_model(self.dino) 保留海量数据预训练得到的强大表征
🔀 多尺度特征 get_intermediate_layers() 取 4 层 浅层细节 + 深层语义全部利用
🎯 Side-Tuning Feature 类中 torch.no_grad() 包裹 ViT 前向 主网络只学 Adapter,参数量可控

再来看融合部分——这才是 Side-Tuning 的精髓:

# extractor.py —— Feature.forward()
def forward(self, x):
    # ① EdgeNeXt-S 提取多尺度特征(可训练)
    x4  = self.stages[0](self.stem(x))
    x8  = self.stages[1](x4)
    x16 = self.stages[2](x8)
    x32 = self.stages[3](x16)

    # ② 逐级上采样融合(FPN 风格)
    x16 = self.deconv32_16(x32, x16)
    x8  = self.deconv16_8(x16, x8)
    x4  = self.deconv8_4(x8, x4)

    # ③ 冻结的 ViT 特征(1/4 尺度)concat 进来
    with torch.no_grad():
        output = self.dino(x_resized)       # 🧊 无梯度
    vit_feat = output['out']
    vit_feat = F.interpolate(vit_feat, size=(H//4, W//4), ...)

    x4 = torch.cat([x4, vit_feat], dim=1)  # 🔗 拼接!
    x4 = self.conv4(x4)                    # 融合卷积

    return [x4, x8, x16, x32], vit_feat

💡 一句话总结:EdgeNeXt 负责「学立体匹配」,ViT 负责「提供看懂世界的先验知识」,两者通过 concat 握手。


2.3 📊 混合代价体(Hybrid Cost Volume)

立体匹配的「心脏」是代价体。FoundationStereo 用了 两种代价体拼接 的策略:

# foundation_stereo.py —— forward()
# ① Group-wise Correlation (GWC): 8 groups
gwc_volume = build_gwc_volume(features_left[0], features_right[0],
                              self.args.max_disp//4, self.cv_group)

# ② Concat Volume: 直接拼接左右特征
left_tmp  = self.proj_cmb(features_left[0])
right_tmp = self.proj_cmb(features_right[0])
concat_volume = build_concat_volume(left_tmp, right_tmp,
                                    maxdisp=self.args.max_disp//4)

# ③ 拼接 → 3D CNN 处理
comb_volume = torch.cat([gwc_volume, concat_volume], dim=1)  # 8+12=20ch
comb_volume = self.corr_stem(comb_volume)                     # 3D CNN 降维
comb_volume = self.corr_feature_att(comb_volume, features_left[0])  # 特征注意力
comb_volume = self.cost_agg(comb_volume, features_left)       # Hourglass 聚合
19fda471e7c7e.png

两种代价体的分工:

类型 计算方式 优势
GWC (Group-wise Correlation) 特征分 8 组,组内做余弦相似度 对光照变化鲁棒,信息紧凑
Concat 左右特征直接拼接沿视差维度 保留原始特征信息,不压缩

build_gwc_volume 的实现非常直观——逐视差偏移做分组相关:

# submodule.py
def build_gwc_volume(refimg_fea, targetimg_fea, maxdisp, num_groups):
    B, C, H, W = refimg_fea.shape
    volume = refimg_fea.new_zeros([B, num_groups, maxdisp, H, W])
    for i in range(maxdisp):
        if i > 0:
            volume[:, :, i, :, i:] = groupwise_correlation(
                refimg_fea[:, :, :, i:], targetimg_fea[:, :, :, :-i], num_groups)
        else:
            volume[:, :, i, :, :] = groupwise_correlation(
                refimg_fea, targetimg_fea, num_groups)
    return volume

2.4 🔄 AHCF:长距离上下文推理的核心

AHCF = APC(All-Pairs Correlation)+ Disparity Transformer

这是 FoundationStereo 区别于 RAFT-Stereo / IGEV 的关键模块。代码中有两条并行的注意力路径:

# foundation_stereo.py —— hourglass 模块内
self.atts = nn.ModuleDict({
    "4": CostVolumeDisparityAttention(
        d_model=in_channels, nhead=4,
        dim_feedforward=in_channels,
        num_transformer=4,
        max_len=self.cfg['max_disp']//16  # ← 在视差维度做注意力!
    ),
})
# submodule.py —— CostVolumeDisparityAttention
class CostVolumeDisparityAttention(nn.Module):
    def __init__(self, d_model, nhead, dim_feedforward, num_transformer=6, max_len=512):
        for _ in range(num_transformer):
            self.sa.append(FlashAttentionTransformerEncoderLayer(
                embed_dim=d_model, num_heads=nhead, ...))
        self.pos_embed0 = PositionalEmbedding(d_model, max_len=max_len)

核心洞察 🧠:传统 3D CNN 在代价体上的感受野有限,而 Transformer 可以在 disparity 维度 做全局注意力——这意味着模型能「一眼看到」所有可能的视差值并选出最优解。

19fda49a049db.png

2.5 🎯 迭代优化:Selective GRU 的「左右互搏」

FoundationStereo 沿用了 RAFT 系列的迭代优化思路,但做了重要改进——选择性 GRU:

# update.py —— SelectiveConvGRU
class SelectiveConvGRU(nn.Module):
    def __init__(self, hidden_dim=128, input_dim=256,
                 small_kernel_size=1, large_kernel_size=3):
        self.small_gru = RaftConvGRU(hidden_dim, input_dim, small_kernel_size)  # 1×1
        self.large_gru = RaftConvGRU(hidden_dim, input_dim, large_kernel_size)  # 3×3

    def forward(self, att, h, *x):
        x = torch.cat(x, dim=1)
        x = self.conv0(x)
        hx = torch.cat([x, h], dim=1)
        hx = self.conv1(hx)
        # 🔑 关键:用小核和大核的加权组合
        h = self.small_gru(h, x, hx) * att + self.large_gru(h, x, hx) * (1 - att)
        return h

这个设计的妙处在于:

组件 作用 类比
小核 GRU (1×1) 快速局部更新 精细微调
大核 GRU (3×3) 大范围上下文传播 全局修正
注意力门控 att 自适应选择用哪个 智能调度
# foundation_stereo.py —— 主循环
for itr in range(iters):
    disp = disp.detach()
    geo_feat = geo_fn(disp, coords, low_memory=low_memory)  # 几何编码
    net_list, mask_feat_4, delta_disp = self.update_block(
        net_list, inp_list, geo_feat, disp, att)
    disp = disp + delta_disp.float()  # 残差更新
    ...

🎮 打个比方:这就像玩「大家来找茬」——每轮迭代你都在上一轮答案的基础上,根据新的线索(几何特征)做小幅修正,越修越准。


2.6 📐 几何编码代价体(Geometry Encoding Volume)

这是 RAFT-Stereo 的经典设计,FoundationStereo 继承并优化:

# geometry.py —— Combined_Geo_Encoding_Volume
def __call__(self, disp, coords, low_memory=False):
    b, _, h, w = disp.shape
    out_pyramid = []
    for i in range(self.num_levels):
        geo_volume = self.geo_volume_pyramid[i]
        # 根据当前视差偏移采样
        x0 = self.dx + disp.reshape(b*h*w, 1, 1, 1) / 2**i
        y0 = torch.zeros_like(x0)
        disp_lvl = torch.cat([x0, y0], dim=-1)
        geo_volume = bilinear_sampler(geo_volume, disp_lvl, low_memory=low_memory)
        out_pyramid.append(geo_volume.reshape(b, h, w, -1))
    return torch.cat(out_pyramid, dim=-1).permute(0, 3, 1, 2)

核心思想:不是每次都重建代价体,而是 根据当前视差预测去「查表」,效率极高。


2.7 🏗️ 3D Hourglass + Feature Attention 聚合

# foundation_stereo.py —— hourglass
class hourglass(nn.Module):
    def __init__(self, cfg, in_channels, feat_dims=None):
        # 3 级下采样编码器
        self.conv1 = BasicConv(in_channels, in_channels*2, is_3d=True, stride=2, ...)
        self.conv2 = BasicConv(in_channels*2, in_channels*4, is_3d=True, stride=2, ...)
        self.conv3 = BasicConv(in_channels*4, in_channels*6, is_3d=True, stride=2, ...)
        # 3 级上采样解码器
        self.conv3_up = BasicConv(in_channels*6, in_channels*4, deconv=True, is_3d=True, ...)
        self.conv2_up = BasicConv(in_channels*4, in_channels*2, deconv=True, is_3d=True, ...)
        self.conv1_up = BasicConv(in_channels*2, in_channels,   deconv=True, is_3d=True, ...)

    def forward(self, x, features):
        conv1 = self.feature_att_8(conv1, features[1])   # ← 图像特征调制 3D 代价体
        conv2 = self.feature_att_16(conv2, features[2])
        conv3 = self.feature_att_32(conv3, features[3])
        ...

FeatureAtt 的作用:用 2D 图像特征的语义信息来「指导」3D 代价体的滤波,相当于给 3D 卷积加了语义先验。


三、🚀 部署实战指南

3.1 标准 PyTorch 推理

# 1️⃣ 安装环境
conda env create -f environment.yml
conda run -n foundation_stereo pip install flash-attn
conda activate foundation_stereo

# 2️⃣ 下载权重到 ./pretrained_models/23-51-11/

# 3️⃣ 跑 demo
python scripts/run_demo.py 
    --left_file ./assets/left.png 
    --right_file ./assets/right.png 
    --ckpt_dir ./pretrained_models/23-51-11/model_best_bp2.pth 
    --out_dir ./test_outputs/

3.2 🔥 ONNX → TensorRT 加速(推荐生产环境)

# ① 导出 ONNX
XFORMERS_DISABLED=1 python scripts/make_onnx.py 
    --save_path ./pretrained_models/foundation_stereo.onnx 
    --ckpt_dir ./pretrained_models/23-51-11/model_best_bp2.pth 
    --height 448 --width 672 --valid_iters 20

# ② 转 TensorRT(FP16)
trtexec --onnx=pretrained_models/foundation_stereo.onnx 
        --saveEngine=pretrained_models/foundation_stereo.plan 
        --fp16

# ③ 推理
python scripts/run_demo_tensorrt.py 
    --left_img ${PWD}/assets/left.png 
    --right_img ${PWD}/assets/right.png 
    --pretrained pretrained_models/foundation_stereo.plan 
    --height 448 --width 672 --pc --z_far 100.0

⚡ 实测效果:3090 上 TensorRT FP16 比 PyTorch 快约 6 倍!

3.3 📱 Jetson 边缘部署

官方提供了 readme_jetson.md,核心思路:

  • 使用 vit-small 模型(11-33-40)降低算力需求
  • TensorRT 量化到 INT8
  • 分辨率降至 224×336 或更低

四、🎯 应用建议与最佳实践

4.1 输入图像要求清单 ✅

要求 说明 不满足的后果
📐 极线校正 左右图水平对齐 视差搜索完全失效
🔄 左右不交换 左图必须来自左相机 视差符号反转
🖼️ PNG 格式 无压缩损失 JPEG 伪影影响精度
📏 分辨率适中 ≤1000px 用 --scale 1 OOM 或速度过慢

4.2 分辨率与精度的权衡

# 高分辨率场景(>1000px)
python run_demo.py --hiera 1 --valid_iters 32    # 慢但准

# 实时场景
python run_demo.py --scale 0.5 --valid_iters 16  # 快但略粗

# 极致速度(牺牲精度)
python run_demo_tensorrt.py --height 224 --width 336 --valid_iters 10

4.3 点云后处理参数推荐

# run_demo.py 中的关键参数
--remove_invisible 1    # 移除左右目不可见点(提高可靠性)
--denoise_cloud 1       # 去噪
--denoise_nb_points 30  # 邻域点数
--denoise_radius 0.03   # 半径(米)
--z_far 10              # 最远距离裁剪

五、🌐 应用领域与前景展望

5.1 当前适用场景

领域 应用方式 成熟度
🚗 自动驾驶 双目相机实时深度感知 ⭐⭐⭐⭐
🤖 机器人抓取 6DoF 位姿估计的前置深度 ⭐⭐⭐⭐
🏗️ 3D 重建 密集点云生成 ⭐⭐⭐⭐⭐
🥽 AR/VR 空间感知与遮挡处理 ⭐⭐⭐
🏭 工业检测 零件尺寸测量、缺陷检测 ⭐⭐⭐
🎬 影视特效 场景 3D 化、虚拟摄像 ⭐⭐⭐

5.2 未来展望 🔮

19fda4cf6ce33.png
  1. 🧠 与多模态大模型融合:立体视觉作为「空间理解」模块嵌入 VLA(Vision-Language-Action)模型
  1. 🎯 动态物体处理:扩展至视频立体匹配,加入时序一致性约束
  1. 📦 轻量化路线:知识蒸馏到 MobileViT 级别,实现手机端实时双目
  1. 🌍 自监督进化:利用海量无标注视频数据持续学习,进一步缩小 sim-to-real 差距

六、📊 与其他算法对比一览

方法 零样本泛化 精度 速度(PyTorch) 速度(TRT) 开源
FoundationStereo ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐⭐ ✅
RAFT-Stereo ⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐ ✅
IGEV-Stereo ⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐ ⭐⭐⭐ ✅
Selective-IGEV ⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐ ⭐⭐⭐ ✅
Monocular Depth ⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ ✅

七、🎬 总结:为什么 FoundationStereo 值得关注?

19fda52018989.png

FoundationStereo 的意义不仅在于 SOTA 精度 或 双榜第一,更在于它验证了这样一个范式:

🔑 「用海量合成数据 + 冻结的视觉基础模型 + 轻量适配」可以打造出真正通用的立体匹配模型。

这个范式很可能成为未来 3D 视觉基础模型的通用配方。对于工程师而言,它开箱即用、部署路径清晰;对于研究者而言,它的架构设计(Side-Tuning、AHCF、Selective GRU)充满了可借鉴的思想。

无论你是做自动驾驶、机器人、AR/VR 还是 3D 重建,FoundationStereo 都值得放进你的工具箱。 🧰


📚 参考资料


"The best way to predict the future is to build it." — 而 FoundationStereo 正在帮我们构建那个「机器能看见深度」的未来。🚀

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注