UTSUSHI ← 読みもの
How-to

Mac(Metal)だけで、動画→3D Gaussian Splatting

2026 · Apple M1 Max / macOS · 所要 30〜60分/本 · 追加費用ゼロ

CUDAの付いたNVIDIA GPUが無くても、Macだけで動画をガウシアン・スプラット(3DGS)にできます。実際にM1 Maxで動かし、詰まった箇所と直し方まで残します。

TL;DR

ffmpegでフレーム化 → COLMAPでカメラ位置推定 → Brush(Rust/wgpu, Metal対応)で学習 → .ply。量産だけクラウドのCUDAへ逃がす。ローカルは無料。

使うもの

流れ

動画 → [ffmpeg] フレーム → [COLMAP] SfM(カメラ位置) → 歪み補正
     → [Brush] 3DGS学習(Metal) → .ply → [splat-transform] .spz / 公開

実際に詰まった3つ(ここが本題)

1. COLMAP 4.x でGPUフラグが改名されている

ネット上の手順は古い名前のことが多いです。COLMAP 4系では次のように変わっています。

新(4.x)
--SiftExtraction.use_gpu--FeatureExtraction.use_gpu
--SiftMatching.use_gpu--FeatureMatching.use_gpu

2. Mac版COLMAPの既定マッチャがSIGSEGVで落ちる

CUDA無しでビルドされたHomebrewのCOLMAPは、既定のマッチング経路が落ちます(十分な特徴点があっても)。CPUブルートフォースを明示すると通ります。

colmap sequential_matcher --database_path db.db \
  --FeatureMatching.use_gpu 0 --SiftMatching.cpu_brute_force_matcher 1

3. COLMAPは“断片モデル”に分割することがある

sparse/0が必ずしも最大とは限りません。登録画像数が最多のモデル(=images.binが最大)を選ぶようにします。

BEST=$(for d in sparse/*/; do [ -f "$d/images.bin" ] && \
  echo "$(stat -f%z "$d/images.bin") $d"; done | sort -rn | head -1 | awk '{print $2}')

じつは“撮り方”が9割

公開映像を5本試して 成功3・失敗2。差はコードでなく素材でした。

素材結果要因
砂漠地形(日中)✅ 41/41静止・順光・高テクスチャ・視差
石塔(順光・周回)✅ 32/32近景の立体物+強い視差
岩稜(日中)✅ 42/42同上
記念像(逆光・ビル街)遠景で視差不足・反復パターン・逆光
海の岩塔(夕日)波が動く(非剛体)・逆光・空/海が大半

合言葉は「静止・順光・高テクスチャ・視差」。避けるのは、動く水・逆光/夕日・遠景・反復する人工物(ガラス張りビル)・無地/鏡面。周回(オービット)素材はexhaustive_matcherが安定します。

手順(コマンドの骨子)

# 1) フレーム抽出(4K素材は縮小しておくとCOLMAPが速い)
mkdir -p frames
ffmpeg -i in.mp4 -vf "fps=3,scale='min(iw,1152)':-2" -q:v 2 frames/%04d.jpg

# 2) 特徴抽出(CPU)
colmap feature_extractor --database_path db.db --image_path frames \
  --ImageReader.single_camera 1 --ImageReader.camera_model OPENCV \
  --FeatureExtraction.use_gpu 0

# 3) マッチング(Mac対策のCPUブルートフォース。周回はexhaustive)
colmap sequential_matcher --database_path db.db \
  --FeatureMatching.use_gpu 0 --SiftMatching.cpu_brute_force_matcher 1

# 4) 再構成 → 歪み補正
colmap mapper --database_path db.db --image_path frames --output_path sparse
colmap image_undistorter --image_path frames --input_path sparse/0 \
  --output_path dataset --output_type COLMAP

# 5) Brushで学習 → .ply(絶対パスで出力先を指定するのが安全)
brush-cli dataset --total-train-iters 30000 --max-resolution 1600 \
  --export-every 30000 --export-path "$PWD/out/" --export-name "scene_{iter}.ply"

結果

M1 Maxで、学習は7,000stepなら約5分、30,000stepでも十数分。3点の作例はこちら(ブラウザで歩けます)。

作例登録スプラット誤差
浸食地形41/41531,8400.28px
岩稜42/42306,4770.24px
石塔32/32198,2430.32px

軽量化して公開

生の.plyは数十〜百MB。.spzにすると約1/10(例:115MB→11MB)。そのまま SuperSplat にドラッグで表示・公開できます。

npx @playcanvas/splat-transform out/scene_30000.ply -N scene.spz
# .html(自己完結ビューア)や .webp(プレビュー)も出力可
注意

Sketchfabは2026年時点で3DGSをスプラットとしてネイティブ描画しません(点群表示になる)。露出はSuperSplat / Luma埋め込みを使います。

量産はクラウドCUDAへ

ローカルは少量向き。数を作るなら NerfstudiosplatfactoをクラウドのRTX4090で回します。前処理込みで1シーン30〜50分、概ね $0.17〜0.30。月30本でも数百〜千円台。中断あり価格(Vast.ai)はチェックポイント再開前提で。

素材のライセンス(これが一番大事)

「公開されている」=「使える」ではありません。3DGS化は二次的著作物なので、元映像に再利用ライセンスが要ります。

— 手を動かした記録として。質問や「この場所を見たい」があれば こちら へ。

← UTSUSHI トップへ