---
title: 最近の深度推定モデルの話 - Core ML+ARKit+Metalで「LiDARなし」の3Dスキャンアプリを自作する #kanagawa_swift
tags:  #coreml #swift #ios  
author: [Shuichi Tsutsumi](https://docswell.com/user/shu223)
site: [Docswell](https://www.docswell.com/)
thumbnail: https://bcdn.docswell.com/page/57G1DPNDEL.jpg?width=480
description: [Kanagawa.swift #3 - connpass](https://japan-region-swift.connpass.com/event/389036/) での発表資料です。
published: October 31, 26
canonical: https://docswell.com/s/shu223/ZPRPX2-depth-estimation-ios
---
# Page. 1

![Page Image](https://bcdn.docswell.com/page/57G1DPNDEL.jpg)

最近の深度推定モデルの話
Core ML+ARKit+Metalで「LiDARなし」の3Dスキャンアプリを自作する


# Page. 2

![Page Image](https://bcdn.docswell.com/page/4EQD12QXJP.jpg)

堤 修一
フリーランスiOSエンジニア
ID: shu223
GitHub
Docswell（スライド）
Zenn Qiita
note はてなブログ
YouTube Podcast
著書：商業出版4冊、個人出版多数
X (Twitter)


# Page. 3

![Page Image](https://bcdn.docswell.com/page/KJ4ZRLN271.jpg)

今日話すこと
• 所用で深度推定モデルの最適化の検討をする機会があった
• 久々に深度推定モデルを触ると、いろいろ高機能なことに気づいて
勉強になったので共有します


# Page. 4

![Page Image](https://bcdn.docswell.com/page/LE1RQL5KEG.jpg)

深度推定モデルとは
入力
出力
画素ごとの奥行きを推定
深度推定モデル
画像
深度（デプスマップ）


# Page. 5

![Page Image](https://bcdn.docswell.com/page/GEW1MV5P72.jpg)

2019年：初の深度推定モデルが公式Core MLページで公開
FCRN （Fully Convolutional Residual Networks）
二眼カメラの視差情報なしでも、
リアルタイムに深度を推定できる


# Page. 6

![Page Image](https://bcdn.docswell.com/page/47ZPQ4N6E3.jpg)

Depth Anything 3 Small (DA3-Small)
FCRN
DA3-Small
発表
2016年
2025年
開発元
Laina ほか
ByteDance Seed Team
約255 MB（32ビット）
約69 MB（16ビット、公開の1枚入力版）
入力
304×228
504×504
出力
160×128
504×504
Core ML版の大きさ
大きさの差には重みのビット数の差（32ビットと16ビット）も含む


# Page. 7

![Page Image](https://bcdn.docswell.com/page/YJ6M638L7V.jpg)

FCRN v.s. DA3-Small
入力画像
FCRN
近い
DA3-Small
遠い
それぞれの出力の最小〜最大で色を付けた（距離の値は比べられない）


# Page. 8

![Page Image](https://bcdn.docswell.com/page/GJ5Z6L9ME4.jpg)

デモ


# Page. 9

![Page Image](https://bcdn.docswell.com/page/9E2RML2RJR.jpg)

単眼深度推定とマルチビュー深度推定
単眼：画像を独立に処理
画像A
単眼推定
マルチビュー：画像間の情報も使う
深度A
画像A
画像間のAttention
画像B
単眼推定
深度B
画像B
同時に渡した画像の特徴を参照して、
各視点の深度を推定する
深度A ＋ 深度B


# Page. 10

![Page Image](https://bcdn.docswell.com/page/D7YDXQY57M.jpg)

DA3-Smallの入力と出力
こうだと思っていたが……
入力
画像
モデル
DA3-Small
出力
深度


# Page. 11

![Page Image](https://bcdn.docswell.com/page/VEN61KP4E8.jpg)

DA3-Smallの入力と出力
マルチビュー深度推定をサポートしている
入力
モデル
出力
画像 1〜S枚
カメラ姿勢
カメラの内部パラメータ
DA3-Small
各視点の深度
カメラ姿勢（推定）


# Page. 12

![Page Image](https://bcdn.docswell.com/page/Y79L5V34J3.jpg)

マルチビュー深度推定対応のCore MLモデル
公開のCore ML版は1枚入力
→ マルチビュー・姿勢入力を使えるよう、coremltoolsで変換し直す
公開のCore ML版
入力：RGB 504 × 504 を1枚
出力：深度 [1, 504, 504]
公式PyTorch
自前の変換
入力：RGB 504 × 504 をS枚
カメラ姿勢 [1, S, 4, 4]
カメラの内部パラメータ [1, S, 3, 3]
出力：深度 [1, S, 504, 504]
推定したカメラ姿勢 [1, S, 9]
（位置3・回転の四元数4・視野角2）
trace → ML Program（FP16）
Sは2・3・4で固定し、枚数別のモデルを作る


# Page. 13

![Page Image](https://bcdn.docswell.com/page/G78XYPMVED.jpg)

深度から3D点群への変換
ピンホールカメラモデル
画素 (u, v)、深度 z、カメラの内部パラメータ K
x = (u − cx) z / fx
y = (v − cy) z / fy
カメラ座標の点 = (x, y, z)
fx, fy：焦点距離、cx, cy：主点（いずれも画素単位）
z：光軸方向の深度
カメラ姿勢でワールド座標へ変換し、観測を重ねる


# Page. 14

![Page Image](https://bcdn.docswell.com/page/L7L8413RJR.jpg)

DA3の深度のメートルへの換算
推定したカメラ位置を、基準となるメートルのカメラ位置と重ねて、
相対深度をメートルに直す倍率を求める
Umeyama法：対応する位置の集合を、回転・平行移動・倍率を含む変換で重ねる方法
基準となるカメラ位置（m）
x₁
2視点なら
DA3が推定したカメラ位置（姿勢 [1, S, 9] の先頭3つ）
x₂
y₁
s = ‖y₂ − y₁‖ / ‖x₂ − x₁‖
メートル深度 z = 相対深度 d / s（位置合わせのうち、倍率sだけを使う）
y₂


# Page. 15

![Page Image](https://bcdn.docswell.com/page/4EM6KWDP7W.jpg)

ARKitから得るカメラ姿勢とカメラの内部パラメータ
カメラ姿勢と内部パラメータはARKitから取れる
ARKitの座標系から、DA3の入力の座標系に変換して渡す
カメラ姿勢の位置は、Umeyama法の基準のメートルのカメラ位置にもなる
ARKitから得る情報
画像 S枚
カメラ姿勢 T
DA3-Small
カメラ姿勢を条件に、
各視点の深度を推定
カメラの内部パラメータ K
入力仕様：T [1,S,4,4]、K [1,S,3,3]（Float32）
Tはworld→camera、Kは入力画像の画素座標に合わせる


# Page. 16

![Page Image](https://bcdn.docswell.com/page/PERPXY4Y79.jpg)

推論の繰り返しと同じ空間への蓄積
モデル：画像の組を更新して推論
A＋B
2視点推定
深度B
B＋C
2視点推定
深度C
アプリ：点を同じ空間に積む
深度
3D点群へ変換
カメラ姿勢で座標変換
保持


# Page. 17

![Page Image](https://bcdn.docswell.com/page/P7X36G24EX.jpg)

カメラ姿勢を入れた3視点の深度推定のデモ


# Page. 18

![Page Image](https://bcdn.docswell.com/page/37KY14MPED.jpg)

重ねたときの同じ場所のずれ
推定深度の画像は
それらしく見える
空間に置くと、
床や机が何重にもなる


# Page. 19

![Page Image](https://bcdn.docswell.com/page/LJ39QLY4J5.jpg)

推論の組ごとに変わる距離の倍率
青と赤は、同じ画像を
別の組で推定した結果
深度と、Umeyama法で求めた
換算倍率が組ごとに変わり、
同じ表面が違う距離に置かれる
横から見た図（縦軸は高さ、m）
scale：1 mあたりの相対深度、median：光軸深度の中央値（m）


# Page. 20

![Page Image](https://bcdn.docswell.com/page/8JDG9N55JG.jpg)

ARKitの平面を基準にした倍率の補正
Umeyama法の倍率の代わりに
ARKitの平面
DA3の深度
z：メートルの深度
d：モデルが返す相対深度
カメラ光線と平面の交点
メートルの深度
同じ画素の相対深度
s = median(d / z)
メートル深度 = d / s
s：1 mあたりの相対深度、median：対応画素の比の中央値
2枚の間の小さな移動（約5 cm）から倍率を求めないので、組ごとに揺れにくい


# Page. 21

![Page Image](https://bcdn.docswell.com/page/VEP3Z5GD78.jpg)

倍率の補正で床の高さをそろえる
床の高さの幅（上下5%の外れを除く）
補正前 86.1 cm
補正後 1.7 cm
床を写した32回の推論で、点群から床の高さを求めて比べた
1.7 cmは推論どうしの床のそろい方で、実際の寸法との誤差ではない
補正にARKitの床の平面を使うので、床がそろうのは補正の作り方による


# Page. 22

![Page Image](https://bcdn.docswell.com/page/27V4WP6GEQ.jpg)

推論ごとに足されるだけの点群
推論のたびに、新しい点群が足される
推論の間で、同じ面を1つにそろえる処理は無い
倍率の補正後に積んだ床の点を横から見たもの（色は推論ごと）


# Page. 23

![Page Image](https://bcdn.docswell.com/page/5JG1DP2D7L.jpg)

重なった深度をまとめる（TSDF）
空間を細かい格子に分け、格子ごとに表面までの符号つき距離を平均し、
0になるところを面として取り出す
TSDF（Truncated Signed Distance Function）：切り詰めた符号つき距離関数
カメラ側：δ &gt; 0
表面の奥：δ &lt; 0
δ = z_obs − z_voxel
（両方とも光軸方向の深度、m）
φ = clip(δ / μ, −1, 1)
δ=0
F ← (wF + φ) / (w + 1)
z_obs：換算後の観測深度、z_voxel：格子中心の深度、μ：切り詰め幅（m）
F：統合値、w：蓄積した重み（δ &lt; −μ の格子は更新しない）
図は1観測の断面の模式図


# Page. 24

![Page Image](https://bcdn.docswell.com/page/47QD12PXEP.jpg)

倍率の補正後に積んだ点とまとめた面
点を積んだもの
まとめた面（点で表示）


# Page. 25

![Page Image](https://bcdn.docswell.com/page/KE4ZRLY2J1.jpg)

格子からの三角形の面の生成
Marching Cubes
隣接する格子点の値から
F = 0の位置を補間し、
三角形でつなぐ
三角形の集まりを、
面として描画する


# Page. 26

![Page Image](https://bcdn.docswell.com/page/L71RQL6K7G.jpg)

倍率補正+TSDF+メッシュ生成のデモ


# Page. 27

![Page Image](https://bcdn.docswell.com/page/G7W1MVWPJ2.jpg)

枚数とともに増える推論時間とメモリ
2枚入力で、1枚の約5倍の時間とメモリ
入力の枚数
推論時間の中央値
メモリ（アプリ側＋Neural Engine側）
1枚
83.7 ms
174 MiB
2枚
438.5 ms
868 MiB
3枚
603.4 ms
1,195 MiB
4枚
933.2 ms
1,717 MiB
12 Pro・固定画像・カメラ姿勢を渡さないモデル単体の記録、各75秒（3枚だけ別の日の120秒）
メモリは定常の値（3枚だけ記録の中央値）


# Page. 28

![Page Image](https://bcdn.docswell.com/page/4JZPQ45673.jpg)

視点数とともに大きくなる画像間のAttentionの行列
S：視点数
N = (504 / 14)² ＋ 1 = 1,297 tokens / 視点
画像間のAttentionの1つのhead・blockで、score行列は (S × N)² 要素
14×14画素のパッチとカメラトークン1個
4N
2N
2枚入力
4枚入力
要素数は4倍


# Page. 29

![Page Image](https://bcdn.docswell.com/page/YE6M639LJV.jpg)

Qだけの分割と全体を参照するK・V
softmax(QKᵀ / √d) V
Qを分割して順に計算
分割前
Q1 × K全体 → Vを集約
Q全体 × K全体
Q2 × K全体 → Vを集約
Q3 × K全体 → Vを集約
Q：照合する側、K：照合される側、V：集める特徴、d：Q/Kの1 headの次元（図は模式）
coremltoolsのQ分割パスを画像間のAttentionへ適用（実装は16分割）


# Page. 30

![Page Image](https://bcdn.docswell.com/page/GE5Z6LNM74.jpg)

3枚入力での推論時間とメモリの削減
推論時間（ms）
603.4
メモリ（MiB、アプリとNeural Engineの中央値の合計）
1,195
480.1
624
分割前
分割後
推論時間 約20%減
分割前
分割後
メモリ 約48%減
12 Pro・3枚の固定画像・各120秒の記録の中央値（測定方法は付録）


# Page. 31

![Page Image](https://bcdn.docswell.com/page/972RML5RER.jpg)

試した最適化と結果
推論時間には効かなかった
動かなかった・出力が壊れた
重みの量子化・パレット化（ファイルとメモリは減る）
途中の値もINT8にする量子化（W8A8。調査中）
CPUに置かれる演算を無くすグラフの書き換え（数%だけ）
一部の量子化（OSの版で壊れる変種が違う）
iOS 18のまとめたAttentionの演算
Core AI版のパレット化（4ビットで出力が壊れる）
Q分割の数を16より細かく
Core AI版（Core ML版より遅い）
機種・枚数で効き方が変わった
トレードオフがあった
演算器をNeural Engineに絞る
Core AIのbackboneの書き直し（調査中）
（12 Proの2枚だけ速く、4枚は遅い）
（速くなるがメモリが増え、Core ML版より遅い）
入力解像度を下げる（速くなるが、深度が少し変わる）
はっきり効いたのは、画像間のAttentionのQ分割
12 Pro、3枚入力で推論時間 約20%減・メモリ 約48%減


# Page. 32

![Page Image](https://bcdn.docswell.com/page/DJYDXQK5JM.jpg)

メッシュへのテクスチャの貼り付け
• 格子の1マス（3 cm）に1色のメッシュに、
カメラの画像を貼る
• 撮影中：推論ごとに、画像・カメラ姿勢・
カメラの内部パラメータ・深度を保存
• 撮影後：三角形ごとに、隠れずに写っている視点のうち、
正面から近くで見ている視点の画像を選んで貼る
17 Proで作ったモデル


# Page. 33

![Page Image](https://bcdn.docswell.com/page/V7N61KR478.jpg)

デモ（最適化＋テクスチャ）


# Page. 34

![Page Image](https://bcdn.docswell.com/page/YJ9L5VM4E3.jpg)

まとめ
• 最近の深度推定モデルはマルチビュー深度推定をサポートしていたりと高機能
• 姿勢情報を入力してLiDARなしの3Dスキャンアプリの自作も可能
• 相対深度を実際のメートルに補正するためにARKitの情報を使った
• Core ML最適化を色々試した


# Page. 35

![Page Image](https://bcdn.docswell.com/page/GJ8XYPLV7D.jpg)

付録：最近の深度推定モデルの機能の比較
1枚の画像を入力にするモデル
複数の画像を入力にするモデル
モデル
発表
大きさ
DA2 Metric（Small）
2024 約25M
MoGe-2（ViT-S）
メートルの
深度
大きさ
メートルの カメラ姿勢 カメラ姿勢
深度
の入力
の推定
モデル
発表
○
DA3-Small
2025 約80M
―
○
○
2025 約35M
○
VGGT
2025
約1B
―
―
○
MoGe-3（ViT-L）
2026 約370M
○
VGGT-Ω
2026
約1B
―
―
○
DA3Metric-Large
2025 約350M
○
MapAnything 2025 約1.2B
○
○
○
Depth Pro
2024
―
○
Pi3X
近似
○
○
Metric3D v2
2024
―
○
UniDepthV2
2025
―
○
2025 約1.4B
2026年10月31日時点 大きさ：パラメータ数（版が複数あるモデルはいちばん小さい版で、括弧はその版の名前）
―：公式のREADME・モデルカードに記載なし 近似：READMEの「approximate metric scale」


# Page. 36

![Page Image](https://bcdn.docswell.com/page/LJL841LRER.jpg)

付録：Q分割の比較の推論時間・メモリの測定方法
推論時間
各120秒の記録から、1回目の推論を除いた中央値
3枚の固定画像2組を繰り返し入力
メモリ
アプリ側とNeural Engine側の、それぞれの中央値を合算
単位：MiB（1,048,576 bytes）
ピーク値やモデルのファイルサイズではない


# Page. 37

![Page Image](https://bcdn.docswell.com/page/47M6KWMPJW.jpg)

参考資料：モデルとAppleの実行環境
深度推定モデルとはの図
Core ML
Koch et al. (2018) / iBims-1 ↗
Apple / Core ML ↗
マルチビューのイラスト
TUM CVG / Multiple View Geometry (SS2025) ↗
FCRN（2019年に試したモデル）
Laina et al. (2016) / FCRN-DepthPrediction ↗
Depth Anything 3
公式コード・機能 ↗
DA3-SMALL モデルカード ↗
論文 / Recovering the Visual Space from Any Views ↗
DA3公式 / 姿勢の入力と正規化 ↗
Apple / PyTorch Conversion Workﬂow ↗
利用した公開Core ML版 ↗
ARKit
Apple / Understanding World Tracking ↗


# Page. 38

![Page Image](https://bcdn.docswell.com/page/P7RPXYVYJ9.jpg)

参考資料：幾何計算とAttention
OpenCV / ピンホールカメラモデルと座標変換 ↗
Umeyama (1991) / 相似変換の最小二乗推定 ↗
Fischler &amp; Bolles (1981) / RANSAC ↗
Curless &amp; Levoy (1996) / 距離場への体積統合 ↗
Lorensen &amp; Cline (1987) / Marching Cubes ↗
Vaswani et al. (2017) / Scaled Dot-Product Attention ↗
Apple / coremltools 9.0のQ分割パス ↗


