見出し画像

ARKit4 関連調査 その2 「Location Anchors」

AR アドベントカレンダー2020の2日目担当します。
ARKit4の主要機能として紹介されたLocation AnchorsについてiOS14リリース前にまとめた内容に少し加筆しました。

Location Anchorsとは

ARKitで検出した空間を特定の現実空間として認識してくれる機能です。

これまで誤差数メートルはあった位置情報ベースの表現を、誤差数センチ以内の細かい精度で可能になりました。
事前に用意した「画像・モノ・検出済みの空間情報」等を認識して認識対象へのAR表現を行っていましたが、それらを用意せずとも「緯度・経度・高度・カメラに映る建物の映像」を元に、現実にあるどこの空間かを認識が可能です。

スクリーンショット 2020-07-01 1.12.19

これにより、例えば 事前に渋谷駅の空間検出をせずともハチ公像をARAnchorとした表現が出来たり、ハチ公象の下や後ろの草むらではなくきちんと頭の上に表示するなど、より現実空間の延長として意識しやすい表現が可能になります。
また、広範囲の空間情報を利用したような個人では難しかったレベルのアプリケーション開発も簡単に出来そうです。

利用制限

利用するには以下の制限があります。

・A12 Bionic以上(iPhone XS以降の端末)
・位置情報とネットワークが利用可能な環境
・特定の地域(San Francisco Bay Area, Los Angeles, New York, Chicago, Miami)

日本は対象地域外の為、現時点で使えません。
なるべく早く使えると嬉しいですが、iOS13から搭載されたLookAround機能の対応 もまだ完了していないようなので、昨今の状況も踏まえるとリリースは大分先と思っています。。
尚、後述のサンプルは位置情報を変えて動かしました。

処理フローとAPI解説

Location Anchorsは主に4つのサイクルで利用します。

1.検出モードを設定する
2.位置空間情報を検出する
3.Anchorを設置する(Anchorが保存されていればその前に読込)
4.設置したAnchor情報を保存する

空間検出→worldTracking、位置検出→CoreLocationと意味が被るので、Location Anchors機能で検出する対象を以降 位置空間情報と記載してます。
各処理とAPIを一つずつ分けて解説します。

1.検出モードの設定

スクリーンショット 2020-07-01 0.12.02

検出モードの設定には ARGeoTrackingConfiguration を利用します。

arView.session.run(ARGeoTrackingConfiguration())

去年出たarViewによりsceneViewの時と少し変わりましたが、設定方法はWorldTrackingやImageTrackingと同様です。
検出モードとして設定する為、他モードとの併用は出来ません。(例:BodyTrackingしながら位置空間検出をする等は不可)
追跡系は無理ですが、平面と画像と物体の検出は可能なようです。
また、制限がある為、利用前に可用性を確認することが推奨されています。

isSupported
ARGeoTrackingConfigurationをデバイスが使えるかどうか確認します。BodyTrackingConfiguration等と同様の確認方法です。

if !ARGeoTrackingConfiguration.isSupported {
    //使えないデバイス用のエラー処理
}

checkAvailability(completionHandler:)
現在の位置が対象地域かどうか確認します。

ARGeoTrackingConfiguration.checkAvailability { (available, error) in
    if !available {
        //使えない地域用のエラー処理
    }
}

位置空間情報の検出モードが開始されると、ARSessionが起動します。

2.位置空間情報を検出する

Location Anchorsは、緯度経度情報と大量の画像データによる機械学習結果で、現実空間の認識を行っています。
その為、位置空間情報の検出には、位置情報と位置にあったLocalization Image(Appleが地域毎に撮影した街の画像群)が必要になります。このLocalization Imageの取得をローカライズとよんでいます。
ローカライズの状態はARSession(ARSessionDelegate)内で確認可能で、状態は4種類あります。

ARGeoTrackingStatus

スクリーンショット 2020-07-01 0.11.21

initializing:初期化中
localizing:ローカライズ中
localized:ローカライズ済み(利用可能)
notAvailable:利用不可
func session(_ session: ARSession, didChange geoTrackingStatus: ARGeoTrackingStatus) {

    if geoTrackingStatus.state == .localized {
        // 使えます
    } else {
        // 使えません
        // 使えない理由を確認出来ます
        print(geoTrackingStatus.stateReason)
    }
}

使えない状態の場合は、モードの再起動や適切なオペレーションを指示しましょう。
使える場合は、取得したLocalization Imageとカメラ映像の比較から、今いる場所が把握出来ます。

3.Anchorを設置する(Anchorが保存されていればその前に読込)

検出した位置空間内にオブジェクト追加する為には、アンカーを設置しなければいけません。位置空間内には専用のアンカーを設置出来ます。
ARGeoAnchor

位置空間情報のアンカーを設置するには、以下の流れが必要です。

①空間に対してraycast(HItTest)
②raycast(HItTest)で取得した場所から緯度経度と高度を判定
③緯度経度と高度からアンカーを作成
④アンカーを設置

①空間に対してraycast(HItTest)

@objc
func handleTapOnARView(_ sender: UITapGestureRecognizer) {

    let point = sender.location(in: view)
    if let result = arView.raycast(from: point, allowing: .estimatedPlane, alignment: .any).first {
        addGeoAnchor2(at: result.worldTransform.translation)
    }
}

②raycast(HItTest)で取得した場所から緯度経度と高度を判定

func addGeoAnchor2(at worldPosition: SIMD3<Float>) {

    arView.session.getGeoLocation(forPoint: worldPosition) { (location, altitude, error) in
    	//エラー処理
    }
    self.addGeoAnchor3(at: location, altitude: altitude)
}

③緯度経度と高度からアンカーを作成

func addGeoAnchor3(at location: CLLocationCoordinate2D, altitude: CLLocationDistance? = nil) {
    
    var geoAnchor: ARGeoAnchor!
    if let altitude = altitude {
        geoAnchor = ARGeoAnchor(coordinate: location, altitude: altitude)
    } else {
        //高度がない場合は、高度0としてアンカーを作成出来ます。
        geoAnchor = ARGeoAnchor(coordinate: location)
    }
    
    addGeoAnchor4(geoAnchor)
}

④アンカー設置

func addGeoAnchor4(_ geoAnchor: ARGeoAnchor) {
    
    guard isGeoTrackingLocalized else {
		//エラー処理 (検知状態が悪い時はアンカーを設置出来ないようです)
    }
    arView.session.add(anchor: geoAnchor)
}

タッチした箇所から従来の空間検知系と同じ感じで処理を組めるのは嬉しいです。4段階あるのが面倒な場合は1処理にまとめても良いと思います。

なお、調査の過程で従来のHitTest方法が非推奨になっているのを知りました。

ARKitリリース時から使われていた方法でしたが、早いうちにARSCNViewからarViewに移行し、HitTestではなくraycastを使うようにしましょう。

4.設置したAnchor情報を保存する

追加要素です。Location Anchorsは、あくまで位置空間情報の基準を提供する機能なので、自分が設置したAnchorの再現性を保持する為には、Anchor情報を各自で保存しなくてはいけません。
ARworldMapのExport/Importと似てますが、検出環境全てではなくARGeoAnchor情報だけを出力出来ます。(もしかして昔からAnchor別で出力出来たのかな?)

func saveAnchors() {

    var geoAnchors: [ARGeoAnchor] = []
    geoAnchors = currentAnchors.compactMap({ $0 as? ARGeoAnchor })
    guard !geoAnchors.isEmpty else {
        // エラー処理 (ARGeoAnchorがなかった時)
    }
    // 後はgeoAnchorsを好きなように保存してください。
}

再開する時は、位置空間情報モード開始時に保存していたAnchorをAddAnchorしなおしてください。

同一アプリ内に完結しますが、Anchor情報をサーバで共有すれば、
ARcloudのような機能を実装出来ますね。


Appleサンプルコードの確認結果

Appleのサンプルコードを一部改変して動かしてみました。
※iOS14のリリースに伴い、スクリーンショットも公開しました。

検証画面

無題のプレゼンテーション

例の如くAppleのサンプルコードが長かった...ので、シンプル化していましたが、対象地域外なので途中までしか動作検証出来ていません。
現状は、普通に使うと対象外というエラーまでは見れて、位置情報を偽装して使うとトラッキング結果が一致しないというエラーまでは見れます。

シンプル化したサンプルコードは、検証出来たら公開にしようと思います。

まとめ

処理サイクルを一度理解すれば難しくなさそうですが、Localization Imageを毎回ダウンロードしないといけないことは面倒そうです。
屋外での利用が主になるのでサイズによってはユーザーが利用し辛い機能になります。検出精度を確認する為にも早く使ってみたい。。

以上、ここまでご講読ありがとう御座いました!


この記事が気に入ったらサポートをしてみませんか?