ARCore 拡張画像

ARCore は、Android で拡張現実アプリを作成するためのプラットフォームです。拡張画像では、事前登録された画像を認識し、この画像に仮想コンテンツを追加することができる AR アプリを作成できます。

この Codelab では、既存の ARCore サンプルアプリを変更して、移動する拡張画像や固定された拡張画像を組み込む方法を説明します。

作業内容

この Codelab では、既存の ARCore サンプルアプリに基づいてアプリを作成します。この Codelab を終了すると、アプリで次のことが可能になります。

  • 画像ターゲットを検出して、そのターゲットに仮想迷路を追加する。視覚効果のサンプルを以下に示します。
  • ビュー内を移動するターゲットを追跡する

6bc6605df89de525.gif

ARCore アプリを作成するのは今回が初めてですか?

はい いいえ

この Codelab でサンプルコードを作成しますか、あるいはこれらのページを読むだけでよろしいですか?

サンプルコードを作成する このページを読む

学習内容

  • Java の ARCore で拡張画像を使用する方法。
  • ARCore の画像認識機能を評価する方法。
  • 画像に仮想コンテンツを追加し、その動きを追跡する方法。

必要なもの

この Codelab を開始する前に必要な準備は次のとおりです。

  • USB ケーブル経由で開発マシンに接続された対応している ARCore デバイス
  • ARCore 1.9 以降。通常、この APK は Play ストアからデバイスに自動的にインストールされます。必要なバージョンの ARCore がデバイスにインストールされてない場合は、Play ストアからいつでも入手できます。
  • Android Studio(v3.1 以降)がインストールされた開発マシン。
  • 開発中のライブラリをダウンロードするためにインターネットへのアクセス。

準備が整ったので、さっそく始めましょう。

まず、GitHub から ARCore Java SDK arcore-android-sdk-1.18.1.zip をダウンロードします。このファイルを任意の場所に解凍します。抽出フォルダの名前は arcore-android-sdk-1.18.1 になります。

Android Studio を起動して、[Open an existing Android Studio project] をクリックします。

5fbf2b21609187cc.png

次の解凍されたフォルダに移動します。

arcore-android-sdk-1.18.1/samples/augmented_image_java

[Open] をクリックします。

Android Studio によるプロジェクトの同期が完了するまで待ちます。Android Studio に必要なコンポーネントがインストールされていない場合は同期が失敗し、「不足しているプラットフォームをインストールし、プロジェクトを同期します」というメッセージが表示されることがあります。画面の手順に沿って問題を修正します。

ARCore アプリ プロジェクトを正常に実行できるようになったので、テスト実行を行ってみましょう。

ARCore デバイスを開発マシンに接続し、メニュー [Run] > [Run 'app'] を使用してデバイス上でデバッグ バージョンを実行します。表示されるダイアログで、アプリを実行するデバイスを選択するよう求められます。

接続済みのデバイスを選択し、[OK] をクリックします。

1aa2c6faa7ecdbd0.png

92e4c144a632b4ca.png

このサンプル プロジェクトでは targetSdkVersion 28 を使用します。Failed to find Build Tools revision 28.0.3 などのビルドエラーが発生した場合は、Android Studio の指示に沿って、必要なバージョンの Android ビルドツールをダウンロードしてインストールします。

正常に完了すると、サンプルアプリがデバイス上で起動し、拡張画像用に写真や動画の撮影を許可するかどうかを確認するメッセージが表示されます。許可するには、[ALLOW] をタップします。

では、サンプルアプリで画像を参照させましょう。

Android Studio に戻り、[Project] ウィンドウで、[app] > [assets] に移動し、ファイル default.jpg をダブルクリックして開きます。

9b333680e7b9f247.jpeg

画面に表示されている地球の画像にデバイスのカメラを向け、指示に従ってスキャン中の画像をフォーカス範囲に合わせます。

以下に示すように、画像フレームが画像の上に重なって表示されます。

999e05ed35964f6e.png

次に、サンプルアプリを少し改善します。

この Codelab の冒頭で述べたように、画像にちょっとした迷路ゲームを 1 つ追加します。まず、poly.google.com にある迷路のモデルを探してみてください。ここには、CC-BY ライセンスに基づいて無料で利用できる、さまざまな 3D モデルが掲載されています。

この Codelab では、CC-BY 3.0 でライセンスされている Evol 提供の「Circle Maze - Green」モデルを使用します。

832fc0f1b09fea1e.png

このモデルをダウンロードして Android Studio にインポートする手順は次のとおりです。

  1. Poly のモデルのページに移動します。
  2. [Download] をクリックし、[OBJ File] を選択します。

これにより、green-maze.zip という名前のファイルがダウンロードされます。

  1. green-maze.zip を解凍して、次の場所にコピーします。arcore-android-sdk-1.18.1/samples/augmented_image_java/app/src/main/assets/models/green-maze
  2. Android Studio で、[app] > [assets] > [models] > [green-maze] に移動します。

このフォルダには GreenMaze.objGreenMaze.mtl の 2 つのファイルがあります。

a1f33a2d2d407e03.png

次に、この OBJ ファイルを読み込んで、検出された画像の上に表示します。

3D モデル(GreenMaze.obj)をダウンロードしたら、画像の上に表示してみましょう。

  1. AugmentedImageRenderer.javamazeRenderer というメンバー変数を追加して迷路のモデルをレンダリングします。迷路は画像に追加する必要があるため、mazeRendererAugmentedImageRenderer クラス内に配置する必要があります。
  2. createOnGlThread 関数で、GreenMaze.obj を読み込みます。わかりやすくするため、画像のテクスチャと同じフレーム テクスチャを使用します。
  3. draw 関数で、検出された画像のサイズに合わせて迷路のサイズを調整し、これを描画します。

AugmentedImageRenderer.java で、次のように変更を加えます。

  // Add a member variable to hold the maze model.
  private final ObjectRenderer mazeRenderer = new ObjectRenderer();

  // Replace the definition of the createOnGlThread function with the
  // following code, which loads GreenMaze.obj.
  public void createOnGlThread(Context context) throws IOException {

    mazeRenderer.createOnGlThread(
        context, "models/green-maze/GreenMaze.obj", "models/frame_base.png");
    mazeRenderer.setMaterialProperties(0.0f, 3.5f, 1.0f, 6.0f);

  }

  // Replace the definition of the draw function with the
  // following code
  public void draw(
      float[] viewMatrix,
      float[] projectionMatrix,
      AugmentedImage augmentedImage,
      Anchor centerAnchor,
      float[] colorCorrectionRgba) {
    float[] tintColor =
        convertHexToColor(TINT_COLORS_HEX[augmentedImage.getIndex() % TINT_COLORS_HEX.length]);

    final float maze_edge_size = 492.65f; // Magic number of maze size
    final float max_image_edge = Math.max(augmentedImage.getExtentX(), augmentedImage.getExtentZ()); // Get largest detected image edge size

    Pose anchorPose = centerAnchor.getPose();

    float mazsScaleFactor = max_image_edge / maze_edge_size; // scale to set Maze to image size
    float[] modelMatrix = new float[16];

    // OpenGL Matrix operation is in the order: Scale, rotation and Translation
    // So the manual adjustment is after scale
    // The 251.3f and 129.0f is magic number from the maze obj file
    // We need to do this adjustment because the maze obj file
    // is not centered around origin. Normally when you
    // work with your own model, you don't have this problem.
    Pose mozeModelLocalOffset = Pose.makeTranslation(
                                -251.3f * mazsScaleFactor,
                                0.0f,
                                129.0f * mazsScaleFactor);
    anchorPose.compose(mozeModelLocalOffset).toMatrix(modelMatrix, 0);
    mazeRenderer.updateModelMatrix(modelMatrix, mazsScaleFactor, mazsScaleFactor/10.0f, mazsScaleFactor);
    mazeRenderer.draw(viewMatrix, projectionMatrix, colorCorrectionRgba, tintColor);
  }

上記のコード変更が完了すると、地球の default.jpg 画像の上に迷路を表示できます。

上記のコードではマジック ナンバーをいくつか使用しました。これらのマジック ナンバーは単に使用するだけなので(この 3D モデルを完全に制御できないため)、ご安心ください。ここでは、モデルの中心位置(x、y、z)とそのサイズを把握するために、obj ファイルを手動で解析しました。この Codelab では解析方法を紹介しないため、ここでは値を直接提示します。迷路のモデルのディメンションは 492.65 x 120 x 492.65 で、中央位置は(251.3、60、-129.0)です。この頂点の X、Y、Z 座標の範囲は [5.02, 497.67]、[0, 120]、[-375.17, 117.25] です。したがって、迷路のモデルのスケールを image_size / 492.65 で設定する必要があります。すでにお気づきかもしれませんが、迷路の 3D モデルの中心位置は原点(0, 0, 0)にないため、オフセット mozeModelLocalOffset を手動で導入する必要があります。

また、迷路の壁が今回の Codelab にはやや高いため、さらに 10 分の 1 だけ縮小します。このようにして壁の高さを低くすることができるので、壁と壁との間の距離が目立つようになります。これを行うには、X、Y、Z 座標を不均一にスケーリングできるヘルパー関数を導入する必要があります。

augmentedimage/rendering/ObjectRenderer.java で、次のように変更を加えます。

  public void updateModelMatrix(float[] modelMatrix, float scaleFactorX, float scaleFactorY, float scaleFactorZ) {
    float[] scaleMatrix = new float[16];
    Matrix.setIdentityM(scaleMatrix, 0);
    scaleMatrix[0] = scaleFactorX;
    scaleMatrix[5] = scaleFactorY;
    scaleMatrix[10] = scaleFactorZ;
    Matrix.multiplyMM(this.modelMatrix, 0, modelMatrix, 0, scaleMatrix, 0);
  }

ARCore 対応デバイスで実行してみましょう。迷路のサイズは画像のサイズと同じになります。

772cbe2a8baef3ba.png

次に、迷路の中を移動するオブジェクトを追加しましょう。この Codelab では説明を簡単にするために、ARCore Android SDK に含まれている Android フィギュアの andy.obj ファイルを使用します。また、フィギュアのテクスチャとして画像フレームのテクスチャを使用することで、画像の上にレンダリングする緑の迷路と視覚的に区別しやすくします。

次のコードを AugmentedImageNode.java に追加します。

// Add a private member to render andy
  private final ObjectRenderer andyRenderer = new ObjectRenderer();

  public void createOnGlThread(Context context) throws IOException {

    // Add initialization for andyRenderer at the end of the createOnGlThread function.
    andyRenderer.createOnGlThread(
        context, "models/andy.obj", "models/andy.png");
    andyRenderer.setMaterialProperties(0.0f, 3.5f, 1.0f, 6.0f);
  }

  public void draw(
      float[] viewMatrix,
      float[] projectionMatrix,
      AugmentedImage augmentedImage,
      Anchor centerAnchor,
      float[] colorCorrectionRgba) {

    // In draw() function, at the end add code to display the Andy, standing on top of the maze
    Pose andyModelLocalOffset = Pose.makeTranslation(
        0.0f,
        0.1f,
        0.0f);
    anchorPose.compose(andyModelLocalOffset).toMatrix(modelMatrix, 0);
    andyRenderer.updateModelMatrix(modelMatrix, 0.05f); // 0.05f is a Magic number to scale
    andyRenderer.draw(viewMatrix, projectionMatrix, colorCorrectionRgba, tintColor);

  }

では、デバイスで実行してみましょう。次のように表示されます。

cb1e74569d7ace69.png

ターゲット画像の品質を決める

ARCore は、画像を認識するために画像内の視覚的な特徴に依存します。すべての画像が同じ品質ではなく、容易に認識できるわけではありません。

ARCore Android SDK の arcoreimg ツールを使用すると、ターゲット画像の品質を確認できます。このコマンドライン ツールを実行して、ARCore による画像認識の難易度を決めます。このツールは、0~100 の数字を出力します。100 が最も簡単に認識できる値です。次の例をご覧ください。

arcore-android-sdk-1.18.1/tools/arcoreimg/macos$
$ ./arcoreimg  eval-img --input_image_path=/Users/username/maze.jpg
100

最後のセクションは ARCore とあまり関係ないものですが、サンプルアプリの作成をより楽しくするために追加で用意しました。この部分はスキップしてもかまいません。

ここでは、オープンソースの物理エンジンである jBullet を使用して、物理シミュレーションを処理します。

次の手順に沿ってこれを行います。

  1. GreenMaze.obj をプロジェクト アセットに追加し、実行時に読み込むことができるようにする。
  2. PhysicsController クラスを作成して、すべての物理関連関数を管理する。内部でこのクラスは JBullet 物理エンジンを使用します。
  3. 画像が認識されたら PhysicsController を呼び出し、次に updatePhysics を呼び出す。
  4. 現実世界の重力を使用して、迷路の中でボールを動かす。ボールが迷路壁の間を通過できるように、ボールのサイズを適切に調整する必要があります。

PhysicsController.java コードをダウンロードして、このプロジェクトの arcore-android-sdk-1.18.1/samples/augmented_image_java/app/src/main/java/com/google/ar/core/examples/java/augmentedimage/ ディレクトリに追加します。

次に、既存の Java コードに次の変更を加えます。以下のように、

Android Studio で、GreenMaze.obj

app > assets > models > green-maze

から以下にコピーします。

app > assets

app/build.gradle に、このコードを追加します。

    // Add these dependencies.
    implementation 'cz.advel.jbullet:jbullet:20101010-1'

    // Obj - a simple Wavefront OBJ file loader
    // https://github.com/javagl/Obj
    implementation 'de.javagl:obj:0.2.1'

AugmentedImageRenderer.java に、このコードを追加します。

// Add this line at the top with the rest of the imports.
  private Pose andyPose = Pose.IDENTITY;

  public void draw(
      float[] viewMatrix,
      float[] projectionMatrix,
      AugmentedImage augmentedImage,
      Anchor centerAnchor,
      float[] colorCorrectionRgba) {

    // Use these code to replace previous code for rendering the Andy object
    // Adjust andy's rendering position
    // Andy's pose is at Maze's vertex's coordinate
    Pose andyPoseInImageSpace = Pose.makeTranslation(
        andyPose.tx() * mazsScaleFactor,
        andyPose.ty() * mazsScaleFactor,
        andyPose.tz() * mazsScaleFactor);

    anchorPose.compose(andyPoseInImageSpace).toMatrix(modelMatrix, 0);
    andyRenderer.updateModelMatrix(modelMatrix, 0.05f);
    andyRenderer.draw(viewMatrix, projectionMatrix, colorCorrectionRgba, tintColor);
  }

  // Add a new utility function to receive Andy pose updates
  public void updateAndyPose(Pose pose) {
    andyPose = pose;
  }

AugmentedImageActivity.java に、このコードを追加します。

import com.google.ar.core.Pose;

  // Declare the PhysicsController class.
  private PhysicsController physicsController;

  // Update the case clause for TRACKING as below
  private void drawAugmentedImages(

    ...

        case TRACKING:
          // Have to switch to UI Thread to update View.
          this.runOnUiThread(
              new Runnable() {
                @Override
                public void run() {
                  fitToScanView.setVisibility(View.GONE);
                }
              });

          // Create a new anchor for newly found images.
          if (!augmentedImageMap.containsKey(augmentedImage.getIndex())) {
            Anchor centerPoseAnchor = augmentedImage.createAnchor(augmentedImage.getCenterPose());
            augmentedImageMap.put(
                augmentedImage.getIndex(), Pair.create(augmentedImage, centerPoseAnchor));

            physicsController = new PhysicsController(this);
          } else {
            Pose ballPose = physicsController.getBallPose();
            augmentedImageRenderer.updateAndyPose(ballPose);

            // Use real world gravity, (0, -10, 0) as gravity
            // Convert to Physics world coordinate (because Maze mesh has to be static)
            // Use it as a force to move the ball
            Pose worldGravityPose = Pose.makeTranslation(0, -10f, 0);
            Pose mazeGravityPose = augmentedImage.getCenterPose().inverse().compose(worldGravityPose);
            float mazeGravity[] = mazeGravityPose.getTranslation();
            physicsController.applyGravityToBall(mazeGravity);

            physicsController.updatePhysics();
          }
          break;

このようにして、下の図に示すようにボールを動かすことができます。

2f0df284705d3704.gif

どうぞお楽しみください!

この Codelab は以上で終了です。この Codelab で学習した内容をおさらいしましょう。

  • ARCore の AugmentedImage Java サンプルを作成して実行しました。
  • 画像のクローズアップ時にオートフォーカスし、画像フレームを画像サイズに合わせて調整するようサンプルを更新しました。
  • ユーザー指定の画像をターゲットとするようサンプルを更新しました。
  • 迷路のモデルが適切なスケールで画像の上に表示されるようサンプルを更新しました。
  • 画像のさまざまな配置を利用して楽しみました。

コード全体を確認するには、こちらからダウンロードできます。

この Codelab は楽しく学習できましたか?

はい いいえ

この Codelab で役に立つことを学習できましたか?

はい いいえ

この Codelab でアプリを作成できましたか?

はい いいえ

今後 6 か月以内に ARCore のアプリを作成しますか?

はい 未定 いいえ