ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。
-
iOSのObject Captureについて
iOSアプリで直接エンドツーエンドのObject Capture体験を提供し、ユーザーがオブジェクトをすぐに使える3Dモデルに変換できるようにする方法を紹介します。サンプルアプリを使用して、完全に自動化されたObject Captureのスキャンフローを作成する方法と、モデルに最適なコンテンツを自動的にキャプチャする方法をご紹介します。また、LiDARデータの解説やオブジェクトをスキャンするためのベストプラクティスも共有します。
リソース
関連ビデオ
WWDC23
-
ダウンロード
♪ メロウ インストロメンタル ヒップホップ ♪ ♪ Lei Zhou:こんにちは Object Capture TeamのLeiです このセッションでは同僚のMonaと一緒に iOSのObject Captureを 紹介します その前にObject Captureとは何か 現在の仕組みを おさらいしておきましょう Object Captureは 最先端のコンピュータビジョン技術により 様々な角度から 撮影された一連の画像から 本物そっくりの3Dモデルを作成します この画像をMacに転送し Object Capture APIを使用し 数分で3Dモデルを再構築できます Mac用APIのリリース以来 多くのアプリが Object Captureを活用して 高品質の3Dモデルを 制作しているのを目にしました そして 皆様から多くのご意見を いただきました ついにObject Captureの体験を iOSに提供するための 大きな一歩を踏み出しました つまりユーザーフレンドリーな インターフェースと デバイス上でのモデル再構築で キャプチャと再構築の両方を 手のひらの上で 行えるようになったのです またこのワークフローを iOSで実演するための サンプルアプリも提供します 実際に見てみましょう サンプルアプリを使って 美しい花瓶の3Dモデルを さっと作ってみます サンプルアプリを開き オブジェクトに向けます キャプチャを開始する前に 自動生成された 境界ボックスが表示されます Object Captureが自動で 画像をキャプチャする間 対象物の周りをぐるりと囲みます より多くの画像が必要な 領域を視覚的にガイダンスし さらにフィードバックメッセージを 提供することで 最高品質の写真を 撮影できるようになります 1周し終えたら オブジェクトを反転させて 底を撮影します 3つのセグメントのスキャンが 完了したら 今度はiOSデバイス上でローカルに 実行される 再構築ステージに進みます わずか数分でUSDZモデルが 使えるようになります 開発者向けドキュメントの一部として このアプリのソースコードを 提供しているので ダウンロードしてすぐにお試しいただけます また独自アプリを作成する際の 取っ掛かりとしても利用いただけます さて新しいサンプルアプリで Object Captureの デモを見たところで 今年の新機能の紹介に移ります まずLiDARを使用しより多くのスキャンを サポートできるようになったという Object Captureにおける 改良点を紹介します 次にオブジェクトの データキャプチャを簡略化する ガイド付きキャプチャ機能の デモを行います 次にObject Capture APIを使って iOS上でのObject Captureフローの 作成方法を説明します 最後にモデル再構築機能の 新たな強化点を紹介します まずLiDARによる対象オブジェクトの 拡大を確認してみましょう 高品質な3Dモデルを作るには 良質な特徴を持つものを選択することが 重要です Object Captureシステムは 十分なテクスチャの詳細を持つ オブジェクトの場合に最適な挙動になります 今年はさらに改良を加えました LiDARスキャナを活用し テクスチャの少ないオブジェクトの 再構築をサポートしました この椅子を例にとって見てみましょう テクスチャの詳細に欠けるため Object Captureで良いモデルを 作成するのは困難です しかしLiDARを使うことで より高品質に再構築することが できるようになりました キャプチャ時に椅子の RGB画像を撮影しています しかし座面や背面には テクスチャがないため 完全なモデルを復元することはできません RGB画像に加え LiDARによる点群データも APIで収集します それによって対象物の 3D形状を網羅的に表現し カバー率と密度を高めることができます 最後に融合された点群データから 完全な3Dモデルが生成されます LiDARを活用することで質感が 向上した物体のモデルの例がこちらです
ローテクスチャのオブジェクトが この度サポートされますが 一部のオブジェクトには まだ課題が残されています 反射するもの 透明なもの 非常に薄い構造のものは 避けたほうがよいでしょう さてどんなオブジェクトを サポートしているか確認したところで ガイド付きキャプチャを使用して オブジェクトをスキャンする方法を 詳しく見ていきましょう 画像やLiDARデータを 自動的にキャプチャする ガイド付きキャプチャを提供します またキャプチャの際に役立つ フィードバックも提供します さらにオブジェクトを 反転させるべきかどうかの ガイダンスも提供します 手動で良い画角を選んで ボタンを押すのではなく データ取得を自動化します 対象物の周りを一周すると シャープネス 鮮明度 露出の良い 画像ショットが自動的に選択され 様々な画角からLiDARポイントを システムが収集します 被写体の細部までキャプチャするには できるだけ多くの角度から 撮影することをお勧めします どの部分に十分な画像があるかを示す キャプチャダイヤルを提供します 対象物をあらゆる角度から スキャンすることで キャプチャダイヤルを完全に 埋めることを推奨しています 自動キャプチャに加え キャプチャ時のリアルタイム フィードバックを提供し みなさんをサポートします まず正確な色を表現するために 良い照明環境であることを確認します 暗すぎる場合は照明の調節を促すような お知らせが表示されます 物体表面での反射や ハイライトを抑えるために 拡散照明を使用することをお勧めします 次にブレを防ぐため カメラを安定させながら ゆっくり滑らかに被写体の周りを 移動させることです スピードが速すぎると 自動キャプチャが停止して スピードを落とすように指示します 3つ目はカメラと被写体の間に 適切な距離を保ち 被写体がカメラのフレームに 適切に収まるようにすることです 距離が遠すぎたり近すぎたりすると リマインダーのテキストが表示されます 最後に常にオブジェクトを フレーム内に入れておくことです 視野から外れると 自動撮影は一時停止され 矢印マークが表示され 視野の向きを調整することができます
オブジェクトの完全な 3Dモデルを得るためには すべての側面を キャプチャすることが重要です そのためにはオブジェクトを 反転させることが有効です しかし物体を反転させるかどうかは その物体の性質によって異なります 対象物が硬い場合は 反転させるのがよいでしょう しかし変形してしまうような オブジェクトの場合 形状が変わりやすいので 動かさない方が良いでしょう テクスチャが豊富なオブジェクトでは 反転を推奨しますが 対称的なテクスチャや反復的な テクスチャを持つオブジェクトの 反転はシステムにとって誤解を 招く可能性があるため 避けることが重要です またテクスチャのないオブジェクトの反転は 異なるセグメントをつなぎ合わせるために 十分なテクスチャが必要なため Object Captureでは 困難な場合があります そのためにオブジェクトが 反転に十分なテクスチャを 持っているかどうかを 示唆するAPIを提供しています 反転させる場合は 3つの方向からスキャンすると すべての面の画像が得られます また被写体表面への影や映り込みを 最小限に抑えるために 拡散光を使用するのがベストです 異なるスキャンパス間の 画像の重なりも重要です スキャンパスにおける オブジェクトの一部は 前のパスでキャプチャされている 必要があります 物体を正しく反転させる方法を 視覚的にガイドします 反転できないものは 3つの高さから撮影して いろいろな角度から 撮影することをお勧めします テクスチャのないオブジェクトは テクスチャのある背景に置いて 目立たせることをお勧めします Object CaptureはiPhone 12 Pro iPad Pro 2021 およびそれ以降の モデルで利用できます お使いのデバイスがObject Captureに 対応しているかどうか 簡単に確認できるAPIを提供しています 次にMonaから Object Capture APIについて 詳しくお伝えします Mona Yousofshahi: ありがとう Lei サンプルアプリの動作を確認したところで Object Capture APIを使用して アプリを作成した過程を確認しましょう デモでご覧いただいたように Object Captureは 画像キャプチャとモデル再構築の 2つのステップがあります まずイメージキャプチャから見てみましょう Image Capture APIは セッションとSwiftUIビューの 2つのパートを持ちます このセッションではイメージキャプチャ中の ステートマシンのフローを観察し 制御することができます SwiftUIビューはカメラの フィードを表示し セッションの状態に基づいて 提示するUI要素を 自動的に適応させます このSwiftUIは 2Dテキストやボタンがありません これによりアプリの見た目を カスタマイズしたり 既存のアプリにObject Captureを より簡単に取り入れることができます Object Captureのステートマシンを 詳しく見てみましょう セッションは作成時に初期化状態で 開始されます その後関数コールをして 進めていきます ready detecting capturing finishingと セッションが移行していきます finishingステートになると セッションは自動的に completedステートに移行します この時点で安全に分解して オンデバイスでの再構築に 進むことができます では実際の使い方をみてみましょう まずRealityKitとSwiftUIを インポートして始めます そしてObject Capture セッションのインスタンスを作成 参照型なのでセッションが完了するまで 永続的な状態としてグランド トゥルースデータモデル内に 保存することをお勧めします これによりセッションは 初期化状態で開始されます 続けてキャプチャした画像を 保存するディレクトリを指定して start()関数を呼び出します また設定にチェックポイント ディレクトリを設け 後でそれを使って再構成処理を 高速化することも可能です この呼び出しの後セッションは readyステートに移行します ObjectCaptureViewで セッションを利用する方法の紹介です 他のSwiftUIビューのように ObjectCaptureViewを使用します それを別のビューのbody内に配置し 先ほど作成した グランドトゥルースセッションを渡します ObjectCaptureViewは常にセッションの ステートに対応したUIを表示します このreadyステートのように ビューにはカメラのフィードが表示され レチクルを使って キャプチャするオブジェクトを 選択するようガイドします ステートを進めるにはアプリが セッションにオブジェクト検出の開始を 指示するUIを提供する必要があります ここではObjectCaptureView上に 続行ボタンを重ねています 押されるとstartDetecting()関数を 呼び出して 境界ボックス検出ステートに移行します detectingステートでは現在検出されている オブジェクトを囲む 境界ボックスが表示されるよう 自動的にビューが変更されます 必要に応じて境界ボックスの サイズや向きを 手動で調整することができます またサンプルアプリでは 別のオブジェクトを選択したい場合に備え オブジェクトの選択処理を再開できるよう リセットボタンを用意しています これによりセッションは readyステートに戻ります readyからdetectingへの移行と同様に オブジェクトの選択に満足したら キャプチャを開始するよう セッションに対し指示するボタンを 提供する必要があります ここではstartCapturing()関数を 呼び出す キャプチャ開始ボタンを使用しています この呼び出しの後セッションは capturingステートに移行します capturingステートでは 対象物の周りをゆっくり移動しながら セッションが自動的に撮影を行います このビューでは点群と対象物の十分な画像を 収集できた場所と まだキャプチャが必要な場所を 示すキャプチャダイヤルが表示されます キャプチャダイヤルが完全に埋まると スキャンパスが完了します キャプチャダイヤルが 完了するとセッションは userCompletedScanPass プロパティをtrueに設定します この時点でサンプルアプリは セッションを終了するか さらに撮影を続けるかの 選択肢を提示します 各オプションにボタンを割り当てています 最良のモデル再構築のためには 3回のスキャンパスを 完了することをお勧めします 次のスキャンパスへの 移行方法を確認しましょう オブジェクトを反転させるかどうかによって 2通りの方法で新しい スキャンパスを開始できます 反転させることで 現在のパスでは見えないオブジェクトの側面 例えばオブジェクトの底面を キャプチャすることができます beginNewScanPassAfterFlip()を 呼び出して ステートをreadyに戻しています その後新しい方向でボックスセレクションを 行う必要があります もし反転させないのであれば その代わりに高さを変えて 撮影することもできます このためにbeginNewScanPass()を 呼び出します これによりキャプチャダイヤルは リセットされますが 境界ボックスは変更されていないため セッションはcapturingステートのままです すべてのパスが完了すると サンプルアプリでは 完了ボタンが用意されています このボタンはfinish()関数を呼び出し 画像の取り込みが 終わったことをセッションに伝え 仕上げ処理を開始させることができます finishingステートにある間 セッションはすべてのデータが 保存されるのを待ちます 終了するとセッションは 自動的にcompletedステートに移行します 安心して分解しオンデバイスでの再構築を 開始することができます 画像ディレクトリが 突然利用できなくなるなど 回復不可能なエラーが 発生した場合セッションは failedステートに移行します その場合新たにセッションを 作成する必要があります また点群を表示することで オブジェクトの初期配置や 最後の反転から どの部分がスキャンされたかを プレビューできます これはObjectCapturePointCloudViewと ObjectCaptureViewを 入れ替えることで実現します キャプチャセッションを一時停止し 点群に触れて あらゆる角度からプレビューできます ここでは文字やボタンと組み合わせて 表示していますが 点群を全画面表示することも可能です さて対象物の画像を取り込んだところで その3Dモデルを作成する方法を説明します 今年からiOSで再構築APIを 実行できるようになりました これにより画像の取り込みと再構築を 同じデバイスで実行することができます ここでは非同期再構築APIの使い方を おさらいしておきます iOSでもmacOSと 同じように動作します まず作成したビューに タスクモディファイアを 付けるところから始めます タスクモディファイアでは フォトグラメトリセッションを作成し 画像をポイントします オプションとして 画像キャプチャ時に使用したものと 同じチェックポイントディレクトリを 提供することで 再構築処理を高速化することができます 次にprocess()関数を呼び出して modelFileを要求します 最後にループで メッセージストリームを待ち受け 受信した出力メッセージを処理します 詳しくは前回のトークを ぜひご覧ください モバイルデバイスでの モデルの生成・閲覧に 最適化するためiOSでは reduced詳細レベルのみを サポートしています 再構成されたモデルには拡散 アンビエントオクルージョン 法線テクスチャマップが含まれ モバイルディスプレイ用デザインになります 他の詳細レベルのモデルを 生成したい場合は 画像をMacに転送して 再構築することができます 今年のMacでの再構築は 画像に保存している LiDARデータも活用しています 新しいObject Captureセッションは このフローにも対応しています デフォルトではiOSデバイスの 再構築制限に達すると Object Captureのセッションは 画像のキャプチャを停止します macOSの再構築では デバイス上の再構築が使用できる 以上の画像をセッションで 撮影できるように変更できます そのためには セッションの設定で isOverCaptureEnabledを trueに設定します これらの追加ショットは デバイス上での再構築には 使用されませんが イメージフォルダに保存されます macで画像を再構築するためには コードを書く必要すらありません Object Captureは Reality Composer Proという新しい macOSアプリに統合されています 画像をアプリに取り込み 詳細レベルを選択するだけで モデルを手に入れることができます このアプリについてもっと知りたい方は Reality Composer Proの セッションをご覧ください 新しいiOS APIを使った 3Dモデルの作成方法に ついて見てきましたが ここでは要望の多かった 再構築機能の強化について 簡単に説明します macでのモデル品質と 再構築処理速度を向上させました 進捗率に加え 再構築の見込み時間を提示するようにしました ポーズ出力とカスタム詳細レベルの 2つの追加機能について より詳しく見てみましょう 画像ごとに高画質な ポーズをリクエストできるようになりました 各ポーズにはコンピュータ ビジョンアルゴリズムに基づき その画像のカメラの位置と 向きを推定しています ポーズを取得するには process()関数呼び出しに ポーズリクエストを追加します そしてポーズの出力が 出力メッセージストリームに 送られてきたらそれを処理します ポーズはモデルが生成される前の 再構築プロセスの 初期に返されることになります また今年はmacOS向けに 新たにカスタム小足レベルを追加し 再構築されたモデルを完全に コントロールできるようになりました 従来は reduced medium full rawの 詳細レベルから 選択することができました カスタム詳細レベルでは メッシュのデシメーション量 テクスチャマップの解像度 フォーマット どのテクスチャマップを 含めるかなどを コントロールできます iOSのObject Captureについては 以上となります Object Captureでは LiDARのサポートにより より多くのオブジェクトを スキャン可能になりました iOSデバイス上でモデルを 完全にキャプチャし 再構築し表示する方法を紹介しました iOSのObject Captureは Eコマース デザイン 教育 ゲームなど さまざまなアプリケーションで 新しいワークフローを実現します みなさんがObject Captureを どのようにアプリに取り入れるか 楽しみにしています ご視聴ありがとうございました! ♪
-
-
10:03 - Instantiating ObjectCaptureSession
import RealityKit import SwiftUI var session = ObjectCaptureSession()
-
10:25 - Starting the session
var configuration = ObjectCaptureSession.Configuration() configuration.checkpointDirectory = getDocumentsDir().appendingPathComponent("Snapshots/") session.start(imagesDirectory: getDocumentsDir().appendingPathComponent("Images/"), configuration: configuration)
-
10:50 - Creating ObjectCaptureView
import RealityKit import SwiftUI struct CapturePrimaryView: View { var body: some View { ZStack { ObjectCaptureView(session: session) } } }
-
11:20 - Transition to detecting state
var body: some View { ZStack { ObjectCaptureView(session: session) if case .ready = session.state { CreateButton(label: "Continue") { session.startDetecting() } } } }
-
11:36 - Showing ObjectCaptureView
var body: some View { ZStack { ObjectCaptureView(session: session) } }
-
12:04 - Transition to capturing state
var body: some View { ZStack { ObjectCaptureView(session: session) if case .ready = session.state { CreateButton(label: "Continue") { session.startDetecting() } } else if case .detecting = session.state { CreateButton(label: "Start Capture") { session.startCapturing() } } } }
-
12:27 - Showing ObjectCaptureView
var body: some View { ZStack { ObjectCaptureView(session: session) } }
-
12:50 - Completed scan pass
var body: some View { if session.userCompletedScanPass { VStack { } } else { ZStack { ObjectCaptureView(session: session) } } }
-
14:03 - Transition to finishing state
var body: some View { if session.userCompletedScanPass { VStack { CreateButton(label: "Finish") { session.finish() } } } else { ZStack { ObjectCaptureView(session: session) } } }
-
15:00 - Point cloud view
var body: some View { if session.userCompletedScanPass { VStack { ObjectCapturePointCloudView(session: session) CreateButton(label: "Finish") { session.finish() } } } else { ZStack { ObjectCaptureView(session: session) } } }
-
15:50 - Reconstruction API
var body: some View { ReconstructionProgressView() .task { var configuration = PhotogrammetrySession.Configuration() configuration.checkpointDirectory = getDocumentsDir() .appendingPathComponent("Snapshots/") let session = try PhotogrammetrySession( input: getDocumentsDir().appendingPathComponent("Images/"), configuration: configuration) try session.process(requests: [ .modelFile(url: getDocumentsDir().appendingPathComponent("model.usdz")) ]) for try await output in session.outputs { switch output { case .processingComplete: handleComplete() // Handle other Output messages here. }}}}
-
17:02 - Capturing for Mac
// Capturing for Mac var configuration = ObjectCaptureSession.Configuration() configuration.isOverCaptureEnabled = true session.start(imagesDirectory: getDocumentsDir().appendingPathComponent("Images/"), configuration: configuration)
-
18:40 - Pose output
// Pose output try session.process(requests: [ .poses .modelFile(url: modelURL), ]) for try await output in session.outputs { switch output { case .poses(let poses): handlePoses(poses) case .processingComplete: handleComplete() } }
-
-
特定のトピックをお探しの場合は、上にトピックを入力すると、関連するトピックにすばやく移動できます。
クエリの送信中にエラーが発生しました。インターネット接続を確認して、もう一度お試しください。