研究開発部の堤と申します。国内最大級のiOSカンファレンスであるiOSDC Japan 2023にて「iOSではじめるフォトグラメトリ」というタイトル 1 で登壇しました。
いろいろ忙しく開催から2ヶ月近く経ってしまいましたが、発表について資料をあらためて「記事形式で」再構成して、紹介させていただきます。
(本記事を書いているちょうど今日、iOSDC公式YouTubeチャンネルで動画が公開されたようです。デモの様子など動画でしかわからないこともあるので、よろしければこちらもぜひ御覧ください。)
発表内容/最終成果物
写真から3Dモデルを生成する「フォトグラメトリ」という技術について、そのしくみや、iOS/macOSのObject Capture APIを用いた実装方法について解説しました。
結構長いスライドなので、先に最終成果物を載せておきます。
こちら、iPhone片手持ちで標準カメラアプリで普通に歩きながら撮影した動画から、iOS/macOSのAPIだけで(有料アプリは使用せず)生成した3Dモデルです。作り方は↑の発表資料を参照。 #iosdc #iosdc2023 pic.twitter.com/gKwygnBmmQ
— 堤修一 / Shuichi Tsutsumi (@shu223) 2023年9月3日
ツイート内にも書いていますが、標準カメラアプリで、iPhone片手持ちで普通に歩きながら撮影 した動画から、iOS/macOSのAPIだけで(有料アプリは使用せず) 生成した3Dモデルです。まだまだ粗はありますが、まずまずの出来ではないでしょうか。
それでは以下、スライドを記事として再構成したものになります。どなたかのお役に立てば幸いです。
自己紹介 + アジェンダ
上位3つだけ貼っておきます。
- iOSDC Japan 2017 09/17 Track B 13:30 / 飛び道具ではないMetal / 堤 修一 - YouTube
- 9/1 A04 Depth in Depth / 堤 修一 - YouTube
- 海外カンファレンスに登壇する - YouTube
フォトグラメトリとは
デモ
会場ではその場でぬいぐるみをiPhoneでスキャンしてオンデバイスで3Dモデルを生成するデモを行いました。
以下は予備としてあらかじめ撮影しておいたデモ動画:
iOS 17のObject Capture APIを用いた3Dスキャンのデモ。こちらは予備として用意しておいた録画ですが、昨日の #iosdc では壇上でその場でスキャンを行うデモを行いました。 pic.twitter.com/bBkaTctmmk
— 堤修一 / Shuichi Tsutsumi (@shu223) 2023年9月4日
↑のスキャンにより生成された3Dモデル #iosdc pic.twitter.com/ECDBSLEM7w
— 堤修一 / Shuichi Tsutsumi (@shu223) 2023年9月4日
フォトグラメトリの原理
ユースケース
本日話すこと・話さないこと
フォトグラメトリの実装
Object Capture APIを用いたフォトグラメトリの実装
let session = try PhotogrammetrySession(input: inputFolderUrl) try session.process(requests: [.modelFile(url: outputFile)])
- 最小実装はたったの2行!
PhotogrammetrySession
の初期化process(requests:)
メソッドを呼ぶ
フォトグラメトリ実践編
動画からのフォトグラメトリ
Object Capture APIもReality Composer Proも動画を入力とすることはできない
→ 動画のフレーム画像を抽出するアプリを書いた
let generator = AVAssetImageGenerator(asset: asset) generator.generateCGImagesAsynchronously(forTimes: times) { requestedTime, cgImage, actualTime, result, error in ...
撮影した動画
- iPhone片手持ちで撮影
- 通常モード
- 広角(0.5)
ブレの少ないフレームを抽出
元動画の改善
空マスク
PhotogrammetrySession
にマスクを渡す実装
PhotogrammetrySample
を利用する
// PhotogrammetrySampleの初期化 let pixelBuffer = createPixelBuffer(from: inputImage) var sample = PhotogrammetrySample(id: index, image: pixelBuffer) // マスク画像をobjectMaskプロパティにセット let maskPixelBuffer = createMaskPixelBuffer(from: maskImage) sample.objectMask = maskPixelBuffer
// PhotogrammetrySamples から PhotogrammetrySession を初期化 session = try PhotogrammetrySession(input: samples, configuration: configuration)
アプリケーションへの組み込み
- 3Dモデルの中を歩くようなアニメーション(SceneKit)
more
(おまけ)visionOSへの組み込み
- USDZをRealityKit Content Packageに入れて
Model3D
ビューで表示するだけ!
まとめ
3Dモデルのユースケースは無限大
- 写真の代替になり得る
Object Captureを用いたフォトグラメトリの基礎と実践
- 「オブジェクト」のキャプチャー性能は高い
- 「空間」も実はそこそこいける
- ブレ度合いの判定/撮影のコツ/空マスク