Contents — 10 sections

公開写真だけで、東大寺南大門をどこまで3D化できるか試した。

候補画像を165件集め、123枚を取得し、重複や低解像度、ブレなどを落として83枚まで絞った。

COLMAPでSfMを回すと、それらしい点群ができた。最初は順調に見えた。

ただ、カメラ位置を確認するとおかしい。

北側から撮られたはずの写真が、南側のカメラとして並んでいた。

建物が壊れたのではなく、SfMが北面と南面を同じ面として扱っていた。

83枚あっても、視点が偏っていれば足りない

入力した83枚は、撮影者40名、撮影年1999〜2023年の公開写真だった。

採用したライセンスは CC BY / CC BY-SA / CC0 / Public Domain に限定した。

画像選別では、

  • pHashによる重複
  • 1000px未満
  • 極端な縦横比
  • ブレ
  • 魚眼・円筒投影

などを落とした。

枚数だけ見れば十分に思える。

しかし観光写真は、撮られる場所が偏る。

南大門の場合、写真の多くが参道の軸線上、方位でいうとおよそ±7°へ集中していた。

つまり「83枚ある」のに、東西側面を見る写真がほとんどない。

この偏りは後でSide fidelityの低さとして、そのまま返ってきた。

一括SfMで前後面が混ざった

83枚を一括でMappingしたところ、北面写真14枚が南面側へ誤登録された。

南大門は前後がかなり似ている。

柱、軒、組物、開口のパターンが似ていれば、画像特徴だけでは「似た別の面」と「同じ面」を区別しにくい。

今回の失敗は、いわゆるDoppelganger問題だった。

面白いのは、再投影誤差だけを見ていると「それなりに正しそう」に見えることだ。

数値が低いから正しい、とは限らない。

誤った面に対しても、画像特徴の対応がうまく合えば、低い誤差で整合してしまう。

だからカメラ位置そのものを見る必要があった。

南面だけにある扁額を手掛かりにした

南面には扁額がある。

そこで扁額の3D位置を写真へ投影し、南面か北面かを分ける材料にした。

自動判定だけで確定できないものは目視も併用した。

南北を分けて再Mappingした結果、

  • 南面: 38 / 55枚
  • 北面: 16 / 16枚

が正しい面へ登録された。

全83枚に対して正しい面へ登録された枚数は54枚、65.1%。

平均再投影誤差は、

  • 南面: 1.18px
  • 北面: 0.75px

だった。

ただし、この回避策は南大門固有の扁額に依存している。

汎用的な対称誤登録の解決法ではない。

ここは成功談に変換しないで、そのまま制約として残す。

GPUなしだったのでDenseはOpenMVSへ逃がした

実行環境は、

  • Ubuntu 24.04
  • Intel Xeon 2.1GHz
  • 4 vCPU
  • RAM 16GB
  • GPUなし

だった。

COLMAPのDenseをそのまま使うにはCUDAが問題になったため、OpenMVS v2.2.0をCPUでビルドして使った。

最終的なDense pointは、

  • 南面: 941,404 points
  • 北面: 288,364 points

Raw Meshは、

  • 南面: 427,821 faces
  • 北面: 258,462 faces

まで作れた。

計算時間の合計は約1.2時間。

ただし、実際の経過時間はもっと長い。

画像取得中にWikimediaのCDNで429を踏み、約4時間止まった。

規約を迂回するような取得方法は使わず、最終的にはローカルPCで画像を取得した。

3D復元より先に、画像取得で止まるとは思っていなかった。

実寸は1点だけ使ってスケールを合わせた

外部の実寸値として使ったのは、間口28.79mの1点だけ。

これを柱芯の総長として解釈し、全体のスケールを合わせた。

そこからSfMや写真を使って、

  • 柱間: 5.34 / 6.13 / 5.84 / 6.13 / 5.34m
  • 基壇: 約1.0m
  • 下層軒先: 約12.1m
  • 上層軒先: 約18.7m
  • 棟の上端: 約26.9〜27.1m
  • 扁額: 約4.2 × 1.45m

などを得た。

ただし、ここでも「測れたもの」と「推定したもの」を混ぜないようにした。

モデル側には、可能な範囲で observed / estimated の区別を持たせた。

見えていない内部空間を、見栄えのためだけに創作することもしなかった。

最終モデルはゲーム向けLODまで落とした

最終Meshは、

  • LOD0: 24,470 tris
  • LOD1: 7,862 tris
  • LOD2: 1,454 tris

まで落とした。

出力は、

  • GLB: 12.7MB
  • FBX: 10.2MB
  • Texture: 1024² × 12枚

になった。

Textureは写真投影ではなく、実写から色相を拾った手続き生成。

風化、汚れ、丹塗りの残りなどを忠実に再現したものではない。

正面はかなり合った。側面はまだ弱い

比較5視点では、SfM点がモデルのシルエット内へ入る割合が93.3〜99.5%。

正面の点群とモデル面の距離中央値は約0.155mだった。

正面はかなり合っている。

背面も一定の一致は出た。

ただし北面は、南面で較正したモデルへICPで合わせている。

つまり完全に独立した品質評価ではない。

さらに側面は弱い。

観光写真が参道方向へ偏り、側面写真が十分に登録できなかったため、東西側面の多くは推定になった。

失敗は10個残した

このPoCでは、うまくいかなかったこともそのまま記録した。

  1. Wikimedia CDNで429
  2. 南北面のDoppelganger
  3. 北面の鉛直方向が4.9°傾く
  4. 軒下・内部・極端な近接写真17枚が登録できない
  5. 側面入力不足
  6. 人・鹿・暗い開口で地上階の点群が疎
  7. z=0基準に不確かさ
  8. GPUなしでCOLMAP Denseを使えずOpenMVSへ
  9. 幕・幟・灯籠など一時設置物
  10. 写真投影Texture未実装

特に対称誤登録は、合成データでも同種の現象を再現した。

偶然ではなく、構造的なリスクだった。

このPoCで足りなかったのは「もっと強いAI」ではなく入力画像だった

PoC判定は CONDITIONAL GO。

正面・背面の主要形状は作れた。

LOD化してGLB / FBXまで出せた。

比較数値もある程度出た。

一方で、側面は弱い。

対称誤登録の汎用解もない。

写真投影Textureも未実装。

次の改善要因はアルゴリズムより、入力画像の不足だった。

そのため次フェーズは現地撮影。

撮影仕様は約370枚、約1.5時間。

  • 外周2周
  • 35m / 20mの2距離
  • 5°刻み
  • 隣接画像70%以上overlap
  • 各立面80%以上overlap
  • 側面で間隔を空けない

成功目標は、

  • 登録率90%以上
  • 単一モデル
  • 周回カメラ360°連続
  • 側面の点群-モデル距離中央値0.10m以下
  • 全体中央値0.10m以下
  • 対称誤登録0件

とした。

いまの結論

Photogrammetryは、画像枚数を増やせば勝てるわけではなかった。

今回一番効いたのは、

何枚あるかより、どこから撮られているか。

そしてもう一つ。

低い誤差で綺麗に間違っている結果は普通に出る。

自動化するほど、結果を疑う仕組みが必要になる。

PicoTowaでは、こういう「それっぽく成功している失敗」をできるだけ残していく。