ARKit 1.5で画像認識ができるようになりました。

先日、iOS 11.3のベータがリリースされました。 ARKitがアップデートされて、ARKit1.5となり、画像認識や垂直面の認識などができるようになりました。

(この記事は、公開されている情報に基づいて書いています。)

ARKit 1.5

ARKit1.5でのアップデート内容はこちらです。

  • 垂直面の平面認識の追加
  • ARKit内での画像認識
  • ビデオ系処理の改善

それぞれの項目についてみてみましょう。

垂直面の平面認識

今までのARKitでも平面認識はできましたが、認識できたのは床などの水平面だけでした。 ARKit1.5からは、壁などの垂直面も認識できるようにになりました。

コードでみてみましょう。

まず、Xcodeで新規プロジェクトを選び、Augmented Reality App を選択します。

このプロジェクトはデフォルトでARが使えるようになっているので、初期設定を変えるだけで平面認識ができます。

viewWillAppearに下記の1行を追加しましょう。

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
        
    let configuration = ARWorldTrackingConfiguration()

    // この行を追加
    configuration.planeDetection = [.horizontal,.vertical]

    sceneView.session.run(configuration)
}

平面が認識されると、下記のメソッドがよばれます。

func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {

    guard let planeAnchor = anchor as? ARPlaneAnchor else { return }

    print("✈️Plain detected...?")
}

ちなみに、iPhoneXにiOS11.3(β1)をいれて試してみましたが、私の部屋ではうまく垂直面が認識されませんでした。 まだ初期βなので、認識精度についてはこれから改善されていくでしょう。

(1/26追記:所 友太 / ToKoRo Yuta (@tokorom) | Twitterさんに教えてもらって壁にポスターをはったら垂直画面が認識されるようになりました。なにもない白い壁は認識しづらいんですね。)

ARKit内での画像認識

さて、次は画像認識です。

技術的には今までもARを使いながらの画像認識処理は可能でした。

ARKitでは、認識時のカメラ画像がそのまま取得できるので、その画像でVisionフレームワークのQRコード認識処理や顔認識処理をしたり、CoreMLで画像認識モデルで処理をしたりすることができました。

今回のARKit1.5の変更では、他のライブラリを使わずにARKit単体で画像処理ができるので、かなり便利になっています。

これもコードで試してみましょう。

まず、同じようにXcodeで新規プロジェクトを選び、Augmented Reality Appを選択します。

次に認識用の画像リソースを作成します。

アセットカタログの左下の + を押すと、アセット追加用のメニューが表示されるので、このなかから New AR Resouce Group というのを選びます。

(Xcodeβの画面キャプチャーはNDAのため載せられないので、これはXcode9.2の画面キャプチャーです。この画像にはありませんが、Xcode9.3でひらくと、New AR Resouce Group を選ぶことができます。) f:id:toyship:20180126111812p:plain

New AR Resouce Groupを作ったら、ファインダー上で認識したい画像ファイルをいくつか選び、Drag&Dropでいれてみましょう。

このAR用のリソースには、認識されるはずの実物の物理サイズを設定することができます。 サイズを設定しておくと認識率が向上するので、入力しておきましょう。

それから、viewWillAppearに画像認識用のコードを追加しましょう。

  override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    let configuration = ARWorldTrackingConfiguration()
 
    // ARリソースをよびだす
    guard let referenceImages = ARReferenceImage.referenceImages(inGroupNamed: "AR Resources", bundle: nil) else {
            fatalError("Missing expected asset catalog resources.")
        }

    // ARリソースを認識用画像として設定する
    configuration.detectionImages = referenceImages

    sceneView.session.run(configuration)
}

これで、先ほどの平面認識と同様に、AR空間内のイメージを認識することができます。

うまく画像認識できると、こちらがよばれます。

func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {

    guard let imageAnchor = anchor as? ARImageAnchor else { return }
    let referenceImage = imageAnchor.referenceImage

    print("image is detected: \(String(describing: referenceImage.name))")
}

自分のiPhoneX(β1)で試してみたところ、ロゴイメージなどはかなり高精度で認識されています。 他のフレームワークを使うのにくらべると実装が圧倒的に楽ですね。

AppleからARKitの画像認識のサンプルコードとガイド記事もでています。 Recognizing Images in an AR Experience | Apple Developer Documentation

上記のガイド記事には、画像認識しやすくするための注意点が記載されています。

  • ハイコントラストの画像を選ぼう
  • ARリソースに設定した時に、物理サイズを設定しておこう
  • 平面でなく、曲面に表示されたもの(ワインボトルのラベルなど)は認識されにくい
  • 光の状態にも注意。光を反射するものにイメージが表示されている場合、光の反射で認識されにくくなることがある。

ARKit 1.5その他

今回から、ARKitでオートフォーカスが使えるようになりました。 画像認識しているときなど、特定の面にオートフォーカスできるようになり、認識精度が向上しています。

あと、個人的には、今回から認識された座標軸を再設定することができるようになった点なども試してみようかと思っています。