ARKitの物体検出(Object Detection)
物体検出機能はARKit2から利用可能になった機能で、あらかじめスキャンした物体のデータを登録しておくと作成したARアプリケーションから登録済みの物体を検出することができるようになります。
この機能についてはUnityを使った事例はいくつか記事になっているのですが、UE4を使った事例は見つかりませんでした。
今回どうしてもこの機能をUE4(4.22)で使いたくて、色々試し動かすことに成功したのでやり方をメモしておきます。
オブジェクトのスキャン
まずは検出する物体のスキャンをします。
UE4を使ったスキャン
UE4を使ってスキャンする場合は、まずARSessionConfigのSession Typeを「Object Scanning」にしてから、「Get AR Candidate Object」を使用して行うらしいです。
上で「らしい」という言葉を使ったのは理由があり、現状上記やり方ではスキャンは成功してないです。
「Get AR Candidate Object」をコールした際にアプリケーションが落ちてしまいスキャンはできませんでした。
成功した方がいらっしゃったら、教えてください。
Apple提供ツールを使ったスキャン
以下のサイトの上部にある「Download」ボタンを押すと、オブジェクトスキャンをするためのiOSアプリのプロジェクト一式がダウンロードできます。
Scanning and Detecting 3D Objects | Apple Developer Documentation
ダウンロードしたプロジェクトをXCodeを使って、自分のiOS端末にいれて使用します。 使い方は結構直観的に分かり、最初に黄色いBoxで領域を確定した後、各面毎にスキャンを行います。
黄色いBoxの中に小さい黄色い点(多分物体の特徴点)がたくさんあったほうが後の検出率が高いような気がしています。
スキャンが終わると*.arobjectという拡張子のファイルが生成されるので、iCloudとかを利用して開発マシンまでファイルを持っていきます。
XCodeやUnityを利用したARアプリ開発の場合は上記方法で完結しており、*arobjectのファイルがそのまま利用できます。
UE4の場合はそのままは利用できず、ダウンロードしたスキャンアプリを一部書き換える必要があります。
ViewController.swiftのcreateAndShareReferenceObjectメソッド
変更前
try object.export(to: documentURL, previewImage: testRun.previewImage)
変更後
try NSKeyedArchiver.archivedData(withRootObject: object, requiringSecureCoding: false).write(to: documentURL)
上記書き換え部分はファイルを生成する部分なのですが、利用する関数が違います。
変更前はARReferenceObjectクラスのexportを使っているのですが、これをNSKeyedArchiverを使ってバイナリ化した後そのままファイルに書き込むように変えました。
またオリジナルと区別するためファイルの拡張子を(*.arobject2)に今回はしています。
これはUE4のARKitプラグインでバイナリを復元する際(FAppleARKitConversion::ToARReferenceObjectSet)に使われているのがNSKeyedUnarchiverだからです。
最初書き換えなしで*.arobjectのファイルを読み込ませたところ、ARReferenceObjectの復元に失敗したため調査したところ上記書き換えで成功するようになりました。
arobjectファイルにはUnityで読み込むと静止画のサムネイルが表示されていたので、そういった付加情報が*.arobjectには入っており後者のファイルとはバイナリに保存される内容が違うのが原因かなと思っています。
スキャンデータのUE4への取り込み
ARCandidateObjectアセットの作成
スキャンして生成された*.arobject2ファイルをUE4に取り込みたいのですが、今回は専用のアセット生成クラス(UFactoryを継承したクラス)をC++で書きました。
ファイルの中身は以下になります。
ここで気を付ける点としては、上記C++クラスはEditorの機能を利用するため、UnrealEdモジュールへの参照追加の必要があります。
また自分のプロジェクトのRuntimeモジュールにいれてしまうとアプリの書き出し時にエラーがでるので、Editorモジュールにいれてください。
このモジュールについては以下のヒストリアさんのサイトが分かりやすいです。
[UE4] モジュールについて|株式会社ヒストリア
上記ファイルをプロジェクトに追加してビルドすると*.arobject2ファイルをドラッグすることでファイルがインポートされてARCandidateObjectのデータアセットが作られます。
アセットを開くと「Candidate Object Data」の配列に大きな数字が入っているのが分かると思います。
ここに*.arobject2ファイルの中身がバイナリ形式で入っています。(配列を開くと数が多いのでとても重いです。開かないほうがいいと思います)
あと、この画面で「Friendly Name」に名前をつけておきます。この名前は検出時に利用できます。
画面下部の「Bounding Boxについては、ARKitプラグインのソースを見ても利用されていなかったので現状入力しなくて良いと思います。
ARSessionConfigへの登録
作成したARCandidateObjectアセットはARSessionConfigに登録します。
この辺りはイメージ検出の時と同じです。
ARSessionConfigアセットの「Candidate Objects」に作成したアセットをいれます。
オブジェクトの検出
いよいよオブジェクトの検出になります。
「Get All AR Geometries」を呼ぶと検出されているすべての認識物(平面とかイメージとかとか)がとれるので、そこから「ARTrackedObject」にキャストできたものを選択しています。
「Get Friendly Name」で事前に登録しておいたNameが取得できるので、これを使ってその後の処理を振り分けることが可能です。
実行イメージ
これで実行するとこんな感じになります。
プリキュアのキャラの人形を認識して青いBoxを生成しています。
やったー、ついにUE4でARKitのObject Detectionが成功した。
— ayuma (@ayuma_x) August 15, 2019
久々に頑張った気がする。これでこの機能だけのためにUnityに変えなくて済むわ。#UE4 #ARKit pic.twitter.com/UB32f5fMsh
まとめ
今回どうしてもUE4を使って物体検出がしたかったので、試行錯誤してどうにか成功しました。
結果的に動いたので良いのですが、もうちょっと簡単にできたらいいのになあと思います。 理想的にはUnityと同じように*.arobjectをそのまま取り込めると誰でも使えて良いですよね。
ARKitプラグインを書き換えればそのようにもできそうですが、今後のエンジンアップの度にやるのも嫌なので当分は今回のやり方でいこうと思います。
もしもっと簡単にできるやり方があればどなたか教えて下さい!