Depth Anything V3 - 深度推定から3D幾何理解へ
この記事は生成AIアドベントカレンダー16日目の記事です。
単眼深度推定モデルはいくつもあるけど、その中でもDepth Anythingが一番好きである。理由は以下の通り。
- ゼロショット性能が非常に高く、ドメイン汎化能力に優れている。Depth Anythingは事前学習時に大規模なunlabeled dataを活用しているため、未知のドメインに対しても安定した深度推定を提供してくれる。
- 推論速度とメモリ効率のバランスが良い。DPTベースのアーキテクチャながら最適化が効いており、プロダクション環境でバッチ処理する際にも現実的な処理時間で済む。特にV2ではさらにスケーラビリティが向上を達成していた。
- エッジや細部のディテール保持が優れている。他のモデルと比較して、オブジェクトの境界や細かい構造をより正確に捉えてくれるため、ロトスコープやマット生成など、エッジの精度が重要なタスクにおいて信頼性が高い。
- 解像度外挿性能が高い。学習時の解像度を超える高解像度画像に対しても品質を維持した深度推定が可能。
前バージョンの Depth Anything V2 の時点ですでにとても優秀であったが、2025/11月にV3がByteDanceよりリリース(V2までとリリース元が違います)。V2からV3への進化は、単なる性能向上ではなく、「深度推定」から「3D幾何理解」への根本的な転換 を掲げている。
1. Depth Anything V2の世界観
1.1 V2は相対的な深度マップを生成する
Depth Anything V2は、単一画像から深度マップを推定します。
入力: RGB画像(H×W×3)
出力: 深度マップ(H×W×1)
# V2の使い方
from depth_anything_v2.dpt import DepthAnythingV2
model = DepthAnythingV2(encoder='vitl', features=256,
out_channels=[256, 512, 1024, 1024])
model.load_state_dict(torch.load('depth_anything_v2_vitl.pth'))
raw_img = cv2.imread('image.jpg')
depth = model.infer_image(raw_img) # HxW の深度マップ
シンプルで強力です。しかし、重要な制約があります。
1.2 V2の制約 - カメラを知らない
V2の深度マップには、スケール(尺度)がありません。
# V2の出力 (例)
depth_v2 = [
[0.8, 0.6, 0.5],
[0.7, 0.1, 0.6],
[0.6, 0.5, 0.7]
]
# こういう感じの単純な[0,1]の「相対的な深度」
# 例えば、中央0.1と左上0.8の比は分かるが、実際の距離(メートル)は不明
V2はカメラ内部パラメータ(intrinsics)を考慮しない、というかそもそもpixelのDense Prediction をしているだけ。
カメラパラメータとは:
焦点距離
主点(画像中心)
センサーサイズ
これらがないと、「画像上の1ピクセル」が「3D空間のどの点」に対応するか分かりません。
カメラなし:
画像の (x, y) → 深度 d
しかし、3D座標 (X, Y, Z) は不明
カメラあり:
f( 画像の (x, y), 深度 d, カメラパラメータ ) → 3D座標 (X, Y, Z)
ここのでカメラパラメーターには前述の内部パラメーター+外部パラメーター(位置とポーズ)が含まれてます。
1.3 V2の出力 - 2D深度マップとDPTデコーダ
V2の実装を見てみましょう。
# depth_anything_v2/dpt.py (V2)
class DPTHead(nn.Module):
def __init__(self, ...):
# ... (中略)
# 4つのRefinement Block(階層的特徴融合)
self.scratch.refinenet1 = _make_fusion_block(features, use_bn)
self.scratch.refinenet2 = _make_fusion_block(features, use_bn)
self.scratch.refinenet3 = _make_fusion_block(features, use_bn)
self.scratch.refinenet4 = _make_fusion_block(features, use_bn)
# 出力ヘッド
self.scratch.output_conv2 = nn.Sequential(
nn.Conv2d(head_features_1 // 2, head_features_2,
kernel_size=3, stride=1, padding=1),
nn.ReLU(True),
nn.Conv2d(head_features_2, 1, kernel_size=1, stride=1, padding=0), # 1チャンネル
nn.ReLU(True),
nn.Identity(),
)
def forward(self, out_features, patch_h, patch_w):
# ... (refinementブロックで特徴融合)
out = self.scratch.output_conv1(path_1)
# 重要: フル解像度までアップサンプリング!
out = F.interpolate(out, (int(patch_h * 14), int(patch_w * 14)),
mode="bilinear", align_corners=True)
out = self.scratch.output_conv2(out)
return out # (B, 1, H, W) の高解像度深度マップ
V2の制約 :
- 出力: 1チャンネル(相対深度)
-
フル解像度への復元が必須
- DINOv2の出力: 中間特徴パッチトークンの4Layer分
- 最終出力: 元画像と同じ高解像度
- そのため、重いDPTデコーダ(階層的アップサンプリング + 特徴融合)が必要
-
2D深度マップ表現
- 出力は画像平面上の深度値
- 3D空間情報(カメラパラメータ等)は含まれない
2. V3 - Depth-Ray表現
2.1 問題意識 - 複数タスクへの拡張
V2の成功を受けて、次の質問が生まれます:
「深度推定だけでなく、もっと多くの3Dタスクを統一的に解けないか?」
例えば:
- 単眼深度推定(V2が得意)
- マルチビュー深度推定(複数カメラから整合的な深度)
- カメラポーズ推定(カメラの位置・向き)
- Novel View Synthesis(新しい視点の画像生成)
- メトリック深度推定(実際の距離を出力)
これらを別々のモデルで解くのではなく、統一的なアーキテクチャで解きたい。
2.2 Depth-Ray表現とは?
V3の中心アイデアは、深度とカメラ(intrinsics/extrinsics)をセットで扱い、各ピクセルを3Dへ自然に持ち上げられる形に寄せることです(論文では Depth-Ray という表現で説明されます)。
幾何としては、ピクセル (u, v) に対して
P = t + D(u, v) * d(u, v)
の形で3D点 P を書ける、という整理です(t はカメラ位置、d(u,v) は視線方向)。
このリポジトリの推論APIでは ray を直接返さないため、実用上は depth + intrinsics + extrinsics から unproject して点群へ変換する使い方になります。
2.3 なぜDepth-Rayなのか?
V2の視差ベースとの違いを見てみましょう。
| 表現方法 | V2 (視差) | V3 (Depth-Ray / 3Dブランチ) |
|---|---|---|
| 出力次元 | 1チャンネル(視差) | depth(+conf)+(rayは intr/extr + uv から決まる) |
| カメラパラメータ | 不要 | 必要(または推定) |
| 3D座標 | 計算不可 | 直接計算可能 |
| マルチビュー整合性 | 保証なし | 幾何的に整合 |
※ここでいうDepth-Rayは「3D表現のブランチ(DualDPTのauxやGS系)」の話です。シングルヘッド(DPT)はdepth(設定によりconf付き)しか出しません。
V3の利点:
- 幾何学的に正しい: 複数視点から見ても整合的
- カメラを陽に扱える: ポーズ推定やポーズ条件付き深度推定が可能
- 3D再構成が容易: 深度マップ → 3D点群 → Gaussian Splatting
2.4 V3のMinimal Modeling - なぜアーキテクチャを簡素化できるのか?
V3の設計方針のひとつが、**Minimal Modeling Strategy(最小限のモデリング戦略)**です。
論文の2つの中心的な問いかけ:
- 最小限の予測目標は何か? → Depth-Rayで十分
-
Single plain transformerで十分か? → YES
(2は平たくいうと「DINOv2/ViTのような素直なTransformerをそのまま使えるか?」という問い)
ここで言う “plain” の主旨は、マルチビュー対応のためにTransformerブロック自体を作り替えるのではなく、入力トークンの畳み方(local/global)でビュー間のSelf-Attentionを起こす設計で済ませる、という点です(後述 2.6)。実質、multiview間でのcross-attnのようなことになってます。非常に興味深い!
ブロック内部の重み形状はDINOv2/ViTと同じなので、事前学習重みを初期値としてある程度流用しやすい一方、マルチビューで破綻しないように追加学習・調整が必要になります。
V2のボトルネック:
問題: 2D深度マップ(H×W)を出力したい
→ 中間特徴パッチトークン(辺を1/14に圧縮) → 高解像度画像(元解像度)への変換が必須
→ 階層的アップサンプリング + スキップ接続 = 複雑なDPTデコーダ
V3の解決策:
(実装ベース)V3は出力解像度を `down_ratio` で調整でき、フル解像度出力が必須ではない設計にできる
→ 計算・メモリを状況に応じて調整可能
→ さらにDualDPTでは main(depth+conf) と aux(3D/GS向け) を分離して扱える
V3の実装(雰囲気):
# depth_anything_3/model/dualdpt.py (V3)
class DualDPT(nn.Module):
def __init__(self, ..., output_dim=2, down_ratio=1, ...):
# ... (中略)
self.down_ratio = down_ratio # 出力解像度を下げられる
self.scratch.output_conv2 = nn.Sequential(
nn.Conv2d(head_features_1 // 2, head_features_2,
kernel_size=3, stride=1, padding=1),
nn.ReLU(inplace=True),
nn.Conv2d(head_features_2, output_dim, kernel_size=1, stride=1, padding=0), # 2チャンネル
)
def forward(self, feats, H, W, patch_start_idx):
# ... (pyramid fusion)
# down_ratioに応じた解像度で出力(フル解像度への復元が必須ではない)
h_out = int(ph * self.patch_size / self.down_ratio)
w_out = int(pw * self.patch_size / self.down_ratio)
main_logits = self.scratch.output_conv2(fused_main) # (B, C_main, h_out, w_out)
last_aux_logits = self.scratch.output_conv2_aux[-1](...) # (B, C_aux, h_out, w_out)
# 戻り値は「main/aux + conf」の辞書(キー名は設定で変わる)
return {
self.head_main: main_pred.squeeze(-1), # 例: depth
f\"{self.head_main}_conf\": main_conf,
self.head_aux: aux_pred, # 例: gs / ray-map相当(内部用途)
f\"{self.head_aux}_conf\": aux_conf,
}
注意:このリポジトリの DepthAnything3.inference() が返す Prediction には、通常 aux(ray-map相当)は入りません(主に depth/conf と推定した intrinsics/extrinsics が返る想定)。
パラメータ数の比較:
パラメータ数の比較(参考):
| モデル | パラメータ数 | 差分 | 出力 |
|---|---|---|---|
| V2 DPTHead | 30.9M | - | 1ch (視差) |
| V3 DPT (シングルヘッド) | 29.8M | -3.8% | Depth (1ch) ※設定によりconf付きも可 |
| V3 DualDPT (デュアルヘッド) | 44.3M | +43.3% | Main + Aux |
要点:
- V3のシングルヘッドは、V2よりわずかに軽い(-3.8%)
- V3のDualDPTは、2つのヘッドを持つため重い(+43.3%)
- ただし「軽量」をパラメータ数だけで語るのはズレやすい
Minimal Modelingで狙っていること:
- アーキテクチャの簡素化: フル解像度への復元が必須ではない(down_ratioで調整可能)
- 計算効率の向上: 低解像度出力でも(DualDPT/GS系では)3D復元・レンダリングに繋げられる
-
タスクあたりの効率: 同程度のパラメータで6タスク対応(V2は1タスクのみ)
1に関して、以前のバージョンで色々試していた限りだと最後に解像度を戻すところで非常にメモリを消費してました。また、depthを出力対象にしないならここはスキップできる仕様になってるってことですね。もしくはサムネイル程度に出力。
シングルヘッド vs デュアルヘッド:
V3には2つのヘッド構成があります:
| モデル | 出力 | 解像度可変の意味 |
|---|---|---|
| DPT (シングル) | Depth (1ch) ※設定によりconf付きも可 | 計算効率のための最適化 |
| DualDPT | Main: Depth+Conf / Aux: 3D/GS向け(6ch)+Conf | 3Dブランチを分離して扱える |
| 観点 | V2 (DPT) | V3 シングル (DPT) | V3 デュアル (DualDPT) |
|---|---|---|---|
| 出力表現 | 2D深度マップ | 2D深度マップ | Depth-Ray (3D) |
| 出力解像度 | フル解像度(必須) | 可変(最適化用) | 可変(ただし細部は補間/サンプル密度依存) |
| デコーダ | 複雑なDPT | シンプルなConv層 | シンプルなConv層 (2ヘッド) |
| 3D復元 | 不可 | 不可 | 可能(3D点群/GSとして扱える) |
| 解像度拡張 | 訓練解像度に固定 | 補間のみ | 単一視点は補間のみ(超解像はしない) |
| パラメータ | 30.9M | 29.8M | 44.3M |
2.5 Depth-Rayでやりたいこと(Novel View / マルチビュー整合)
まず注意点です。このリポジトリの DepthAnything3.inference() が返す Prediction には通常 ray は含まれません(intrinsics/extrinsics と depth から幾何は復元する前提)。
その上で、V3(特にマルチビュー)で嬉しいのは次の2つです:
-
Novel View Synthesis(別視点レンダリング)
-
depth + intrinsics + extrinsicsから点群に unproject し、別のカメラ姿勢へ投影する流れを取りやすい
-
-
マルチビュー整合性
- 複数視点を同時に入れたとき、ビュー間の情報交換を通して「同じシーンに一貫した3D」を作りやすい
補足:マルチビューを統合して高密度化(見かけ上の高解像度化)するのは理論的にはあり得ますが、少なくともこのリポジトリには「深度統合→高密度点群化→再レンダリング」を自動でやる明示実装は見当たりません。
| 観点 | V2 | V3 DualDPT(マルチビュー時) |
|---|---|---|
| ビュー間の情報交換 | なし | あり(backbone内で混合) |
| 整合した3Dの作りやすさ | 低い | 高い |
| 別視点レンダリングへの繋げやすさ | 低い | 高い |
### 2.6 マルチビューでの特徴混合(local/global)
V3のbackboneは、同じTransformerブロックを使いながら「viewをどう畳むか」を切り替えることで、マルチビュー時にビュー間の情報交換を行います(詳細: docs/BACKBONE_MULTIVIEW.md)。
-
local:
[B, S, N, C] -> [B*S, N, C](各ビュー独立) -
global:
[B, S, N, C] -> [B, S*N, C](ビュー間で混合)
ここで重要なのは、単眼(S=1)だと global を通してもクロスビュー混合は起きない点です。したがって「単眼の歪み補正」という表現は、マルチビュー入力時に整合性が上がる、という文脈で使うのが安全です。
multi-viewをインプットとした深度マップ
single-viewをインプットとした深度マップ
## 3. アーキテクチャの進化 - デュアルヘッド
3.1 V2のシングルヘッド
V2は、単一のDPTヘッドで深度推定のみを行います。
シンプルですが、単一タスク専用です。
3.2 V3のデュアルヘッド
V3は、メインヘッド + 補助ヘッドの2つを持ちます。
メインヘッド:
- depth(+ confidence)を出力(推論APIの
Predictionに入る想定) - 出力解像度は
down_ratioで調整可能
補助ヘッド(Auxiliary Head):
- 追加タスク向けの特徴(+ confidence)を別経路で出す(内部用途)
- 内部的にはマルチスケールで扱う
3.3 なぜデュアルヘッドなのか?
V2の設計:
単一タスク(深度推定)のみ
→ 出力を「深度に最適化」できる
→ シンプルで効率的
V3の設計:
複数タスク(深度、ポーズ、GS、...)
→ 出力を「汎用的な3D表現」に最適化
→ しかし、各タスクには「最適な解像度・チャンネル数」が異なる
→ デュアルヘッドで柔軟に対応
マルチタスク学習の課題:
複数タスクを単一モデルで解く場合、以下のトレードオフが生じます:
課題: 複数タスクに対応するため、出力チャンネルを増やしたい
しかし、増やしすぎると、各タスクに不要な情報が混ざる
→ タスク間で干渉が起き、精度が低下
解決策: デュアルヘッド
- メインヘッド: コアタスク(深度推定)に特化
→ 2チャンネルのみ、高解像度
- 補助ヘッド: 追加タスク(GS、マルチスケール)向け
→ auxチャネル × 複数レベル、柔軟な解像度
- それぞれが独立して「必要な情報だけ」を抽出
これにより、V3はタスク間の干渉を抑えながら、複数タスクを高精度で解くことができます。
4. 新機能の実現 - カメラとマルチビュー
4.1 カメラエンコーダ/デコーダ
V3は、カメラパラメータを陽に扱います。
# depth_anything_3/model/da3.py
class DepthAnything3(nn.Module):
def __init__(self, net, head, cam_dec=None, cam_enc=None, ...):
self.backbone = net # DINOv2
self.head = head # DualDPT
self.cam_dec = cam_dec # カメラデコーダ(ポーズ推定)
self.cam_enc = cam_enc # カメラエンコーダ(ポーズ条件付け)
カメラデコーダ(Camera Decoder):
- タスク: ポーズ推定
- 入力: 画像特徴
- 出力: カメラの外部パラメータ(位置・向き)
# ポーズ推定(概念。実装ではまずpose encodingを出してから extrinsics/intrinsics に変換する)
extrinsics = ... # (B, N, 4, 4) の外部パラメータ(world-to-camera)
カメラエンコーダ(Camera Encoder):
- タスク: ポーズ条件付き深度推定
- 入力: カメラパラメータ
- 出力: 条件付き特徴(特徴マップに加算される)
# ポーズを条件として、深度を推定
intrinsics = ... # (B, N, 3, 3)
cam_features = model.cam_enc(extrinsics, intrinsics, (H, W))
features_conditioned = features + cam_features
depth = model.head(features_conditioned)
4.2 マルチビュー深度推定
V2の問題:
カメラ1から見た深度マップ: depth1
カメラ2から見た深度マップ: depth2
問題: depth1とdepth2は「幾何学的に整合しない」
→ 3D再構成すると、点群がズレる
V3の解決策:
# マルチビュー推論
views = [img1, img2, img3] # 複数視点の画像
# 各視点から depth + pose を推定(APIのPredictionにはrayは含まれない)
prediction = model.inference(views)
pts3d_1 = unproject(prediction.depth[0], prediction.intrinsics[0], prediction.extrinsics[0])
pts3d_2 = unproject(prediction.depth[1], prediction.intrinsics[1], prediction.extrinsics[1])
# 幾何学的に整合した点群が得られる
なぜ整合するのか?
Depth-Ray表現は、カメラ座標系での3D座標を直接表現します。
視点1: 3D点 = Camera1_pos + depth1 × ray1
視点2: 3D点 = Camera2_pos + depth2 × ray2
→ 両方とも「同じ3D空間の点」を指すように学習される
→ マルチビュー損失(photometric loss、geometric loss)で整合性を保証
5. 応用例 - 3D Gaussian Splatting
5.1 Gaussian Splattingとは?
3D Gaussian Splatting (3DGS) は、Novel View Synthesisの最新手法です。
アイデア:
- 3D空間に「ガウス分布」を配置
- 各ガウスは、位置・色・透明度・形状を持つ
- 任意の視点からレンダリング可能
従来手法(NeRF)との違い:
| 手法 | 表現 | レンダリング速度 |
|---|---|---|
| NeRF | 暗黙的(MLP) | 遅い(秒単位) |
| 3DGS | 明示的(ガウス) | 速い(リアルタイム) |
5.2 V3のGaussian Splatting対応
V3は、Gaussian Splattingを直接サポートします。
# depth_anything_3/model/da3.py
class DepthAnything3(nn.Module):
def __init__(self, ..., gs_head=None, gs_adapter=None):
self.gs_adapter = gs_adapter # Gaussianパラメータ変換
self.gs_head = gs_head # Gaussian予測ヘッド
推論の流れ:
# (実装イメージ)推論時は3DGS分岐を有効化してgaussiansを得る
prediction = model.inference([image], infer_gs=True)
gaussians = prediction.gaussians
# レンダリング(概念)
rendered_view = render_gaussians(gaussians, new_camera_pose)
なぜV3でGSが可能なのか?
Depth-Ray表現があるからです。
V2の出力: 相対深度マップ
→ 3D座標が計算できない
→ Gaussianの位置が定まらない
V3の出力: depth-ray → 3D座標
→ Gaussianの位置を直接計算
→ 複数視点から整合的なGSを構築
gausian-splattingのレンダリング(gifアニメ)
camera extrinsicを変更してカメラを高く上げてます。
6. 学習目標の変化 - マルチタスク学習
6.1 V2の学習目標
V2は、単一タスク(深度推定) に特化した損失関数で学習します。
# 単一タスク
loss = L1(depth_pred, depth_gt) + LPIPS(render(depth_pred), image)
シンプルで、最適化も容易です。
6.2 V3の学習目標
V3は、複数タスクを同時に学習します。
論文の学習目標(数式):
\mathcal{L} = \mathcal{L}_D(\hat{D}, D) + \mathcal{L}_M(\hat{R}, M) + \mathcal{L}_P(\hat{D} \odot d + t, P) + \beta \mathcal{L}_C(\hat{c}, v) + \alpha \mathcal{L}_{grad}(\hat{D}, D)
各項の意味:
| 記号 | 意味 |
|---|---|
| $\mathcal{L}_D$ | Depth loss(深度損失) |
| $\mathcal{L}_M$ | Ray map loss(ray map損失) |
| $\mathcal{L}_P$ | Point loss(点群損失) |
| $\mathcal{L}_C$ | Camera pose loss(ポーズ損失) |
| $\mathcal{L}_{grad}$ | Gradient loss(勾配損失) |
| $\beta, \alpha$ | 重み係数 |
# 実装例(疑似コード)
loss = (
L_D(depth_pred, depth_gt) # 深度損失
+ L_M(ray_pred, ray_map) # Ray map損失
+ L_P(depth_pred * d + t, points_3d) # 点群損失
+ beta * L_C(camera_pred, camera_gt) # ポーズ損失
+ alpha * L_grad(depth_pred, depth_gt) # 勾配損失
)
各損失関数の役割:
| 損失関数 | 役割 | 学習される特性 |
|---|---|---|
| Depth損失 ($\mathcal{L}_D$) | 深度の精度 | ピクセルごとの深度値 |
| Ray map損失 ($\mathcal{L}_M$) | Rayパラメータの精度 | カメラ位置・方向の正確性 |
| Point損失 ($\mathcal{L}_P$) | 3D構造の整合性 | 点群の幾何的一貫性 |
| Camera損失 ($\mathcal{L}_C$) | ポーズ推定精度 | カメラの位置・向き |
| Gradient損失 ($\mathcal{L}_{grad}$) | エッジの鮮明さ | 深度境界の精度 |
6.3 マルチタスク学習の課題
複数タスクを同時に学習する場合、以下の課題があります:
課題1: タスク間の干渉
深度推定を最適化すると、ポーズ推定が悪化する
ポーズ推定を最適化すると、GS品質が低下する
→ タスク間でトレードオフが生じる
課題2: 損失のバランス
どの損失をどれだけ重視すべきか?
→ 損失の重み付けが重要(ハイパーパラメータ調整)
V3の解決策: デュアルヘッド
メインヘッド: 深度推定に特化(L1損失、Photometric損失)
補助ヘッド: 追加タスク向け(GS損失、マルチスケール損失)
→ タスクごとに独立した出力経路を持つことで、干渉を最小化
7. まとめ
- V2は「単眼の相対深度」を高解像度に復元する設計で、DPTデコーダが重めになりがち
- V3シングル(DPT)は単眼深度(+設定でconf)を、よりシンプルなヘッドで出す方向の整理
- V3デュアル(DualDPT)は main と aux を分けて、追加タスク向けの表現を別経路で扱いやすくしている
- マルチビュー時は backbone 内の local/global 切替でビュー間の情報交換が起きる(単眼
S=1ではクロスビュー混合は起きない) - API の
Predictionは通常depth/confと推定したintrinsics/extrinsicsを返し、aux(ray-map相当)は返さない
| 観点 | V2 | V3 シングル | V3 デュアル (DualDPT) |
|---|---|---|---|
| 設計哲学 | 単一タスク特化 | V2の改良版 | Minimal Modeling Strategy |
| 出力表現 | 2D深度マップ (1ch) | 2D深度マップ (1ch) | Depth+Ray(3Dブランチ) |
| 予測目標 | 視差のみ | 深度のみ | Depth-Ray(最小かつ十分) |
| デコーダ | 複雑なDPT | シンプルなConv層 | シンプルなConv層 (2ヘッド) |
| パラメータ数 | 30.9M | 29.8M (-3.8%) | 44.3M (+43.3%) |
| 出力解像度 | フル解像度必須 | 可変(最適化用) | 可変(ただし細部は補間/サンプル密度依存) |
| カメラ | 不要 | 不要 | 陽に扱う(推定・条件付け) |
| 3D座標 | 計算不可 | 計算不可 | 直接計算可能 |
| タスク範囲 | 単眼深度のみ | 単眼深度のみ | 6タスク(深度、ポーズ、GS、...) |
| ヘッド構成 | シングル | シングル | デュアル(メイン + 補助) |
| Novel View Synthesis | 不可 | 不可 | 可能(視点変換) |
| マルチビュー処理 | 各ビュー独立 | 各ビュー独立 | Global Attention |
| ビュー間情報交換 | なし | なし | あり(相互正則化) |
| 単眼深度の歪み補正 | 不可 | 不可 | 可能(マルチビュー時) |
| バックボーン | DINOv2 + 特殊化 | DINOv2 | Single plain transformer |
参考:
- Depth Anything V2: https://github.com/DepthAnything/Depth-Anything-V2
- Depth Anything V3: https://github.com/DepthAnything/Depth-Anything-V3
- 3D Gaussian Splatting: https://repo-sam.inria.fr/fungraph/3d-gaussian-splatting/




