ARCore – Erweiterte Bilder

1. Übersicht

ARCore ist eine Plattform zum Erstellen von Augmented-Reality-Apps für Android. Mit Augmented Images können Sie AR-Apps erstellen, die vorregistrierte 2D-Bilder in der realen Welt erkennen und virtuelle Inhalte darüber verankern können.

In diesem Codelab erfahren Sie, wie Sie eine vorhandene ARCore-Beispiel-App so modifizieren, dass erweiterte Bilder eingebunden werden, die an Ort und Stelle verschoben oder fixiert werden.

Aufgaben

In diesem Codelab bauen Sie auf einer bereits vorhandenen ARCore-Beispiel-App auf. Am Ende des Codelabs kannst du mit deiner App Folgendes tun:

  • Bildziel erkennen und virtuelles Labyrinth am Ziel anhängen
  • Bewegliches Ziel verfolgen, solange es sich im Sichtfeld der Kamera befindet

6bc6605df89de525.gif

Entwickeln Sie zum ersten Mal eine ARCore-App?

<ph type="x-smartling-placeholder"></ph> Ja Nein

Möchten Sie in diesem Codelab Beispielcode schreiben oder nur diese Seiten lesen?

<ph type="x-smartling-placeholder"></ph> Beispielcode schreiben Ich habe nur diese Seiten gelesen

Lerninhalte

  • Erweiterte Bilder in ARCore in Java verwenden
  • Wie kann man beurteilen, ob ein Bild von ARCore erkannt werden kann?
  • Wie man virtuelle Inhalte zu einem Bild hinzufügt und seine Bewegung verfolgt

Vorbereitung

Für dieses Codelab benötigst du bestimmte Hardware und Software.

Hardwareanforderungen

Softwareanforderungen

  • ARCore APK 1.9.0 oder höher. Dieses APK wird normalerweise automatisch über den Play Store auf dem Gerät installiert.
  • Entwicklungsmaschine mit Android Studio (Version 3.1 oder höher)
  • Internetzugriff, da Sie während der Entwicklung Bibliotheken herunterladen müssen

Jetzt, da du alles vorbereitet hast, kann es losgehen!

2. Entwicklungsumgebung einrichten

SDK herunterladen

Zuerst laden wir das neueste ARCore Android SDK von GitHub herunter. Entpacken Sie sie in den gewünschten Speicherort. In diesem Codelab ist die früheste SDK-Version 1.18.1. Der Ordner wird als arcore-android-sdk-x.xx.x bezeichnet. Der genaue Wert entspricht der SDK-Version, die Sie verwenden.

Starten Sie Android Studio und klicken Sie auf Open an bestehendes Android Studio project (Vorhandenes Android Studio-Projekt öffnen).

5fbf2b21609187cc.png

Gehen Sie zu diesem entpackten Ordner:

arcore-android-sdk-x.xx.x/samples/augmented_image_java

Klicken Sie auf Öffnen.

Warten Sie, bis Android Studio die Synchronisierung des Projekts abgeschlossen hat. Wenn Android Studio nicht über die erforderlichen Komponenten verfügt, schlägt möglicherweise ein Fehler mit der Meldung Install missing platform and sync project vor. Folgen Sie der Anleitung, um das Problem zu beheben.

Beispiel-App ausführen

Da du jetzt ein funktionierendes ARCore-App-Projekt hast, kannst du es ausprobieren.

Verbinden Sie Ihr ARCore-Gerät mit der Entwicklungsmaschine und verwenden Sie das Menü Ausführen > Führen Sie „app“ aus, um die Debug-Version auf dem Gerät auszuführen. Wählen Sie im Dialogfeld das gewünschte Gerät aus und klicken Sie auf OK.

1aa2c6faa7ecdbd0.png

92e4c144a632b4ca.png

In diesem Beispielprojekt wird targetSdkVersion 28 verwendet. Wenn ein Build-Fehler wie Failed to find Build Tools revision 28.0.3 auftritt, folgen Sie der Anleitung in Android Studio, um die erforderliche Version der Android Build Tools herunterzuladen und zu installieren.

Wenn alles erfolgreich war, wird die Beispiel-App auf dem Gerät gestartet und Sie werden aufgefordert, der Verwendung von „Augmented Image“ das Aufnehmen von Bildern und Videos zu erlauben. Tippen Sie auf ZULASSEN, um die Berechtigung zu erteilen.

Mit einem Beispielbild testen

Nachdem Sie Ihre Entwicklungsumgebung eingerichtet haben, können Sie die Anwendung testen, indem Sie ihr ein Bild zum Anschauen bereitstellen.

Gehen Sie in Android Studio im Fenster Project (Projekt) zu app > Assets und klicken Sie doppelt auf die Datei default.jpg, um sie zu öffnen.

9b333680e7b9f247.jpeg

Richten Sie die Kamera Ihres Geräts auf das Bild der Erde auf dem Bildschirm und folgen Sie der Anleitung, um das Bild, das Sie scannen, in das Fadenkreuz zu passen.

Ein Bildrahmen überlagert das Bild wie folgt:

999e05ed35964f6e.png

Als Nächstes nehmen wir kleine Verbesserungen an der Beispiel-App vor.

3. Labyrinthmodell auf dem 2D-Bild präsentieren

Sie können erweiterte Bilder ausprobieren, indem Sie darüber ein 3D-Modell einblenden.

3D-Modell herunterladen

Für dieses Codelab verwenden wir Circle Maze – Green von Evol und lizenziert unter CC-BY 3.0. Ich habe eine Kopie dieses 3D-Modells im GitHub-Repository dieses Codelabs gespeichert, das Sie hier finden.

Führen Sie die folgenden Schritte aus, um das Modell herunterzuladen und in Android Studio einzubinden.

  1. Gehen Sie zum GitHub-Repository dieses Codelab, Drittanbieterverzeichnis.
  2. Klicken Sie auf GreenMaze_obj.zip und dann auf Herunterladen.

Dadurch wird eine Datei mit dem Namen GreenMaze_obj.zip heruntergeladen.

  1. Erstellen Sie in Android Studio das Verzeichnis green-maze unter app > Assets > Modelle
  2. Entpacken Sie GreenMaze_obj.zip und kopieren Sie den Inhalt an diesen Speicherort: arcore-android-sdk-x.xx.x/samples/augmented_image_java/app/src/main/assets/models/green-maze
  3. Navigiere in Android Studio zu App > Assets > Modelle > Green-Labyrinth.

In diesem Ordner sollten sich zwei Dateien befinden: GreenMaze.obj und GreenMaze.mtl.

a1f33a2d2d407e03.png

Labyrinth-Modell rendern

Führen Sie die folgenden Schritte aus, um das 3D-Modell GreenMaze.obj über dem vorhandenen 2D-Bild anzuzeigen.

Fügen Sie in AugmentedImageRenderer.java eine Member-Variable namens mazeRenderer hinzu, um das Labyrinth-Modell zu rendern. Da das Labyrinth an das Bild angehängt werden sollte, ist es sinnvoll, das mazeRenderer innerhalb der AugmentedImageRenderer-Klasse zu platzieren.

AugmentedImageRenderer.java

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

Laden Sie in der Funktion createOnGlThread() die GreenMaze.obj. Der Einfachheit halber verwenden Sie dieselbe Rahmentextur wie seine Textur.

AugmentedImageRenderer.java

  // 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);

  }

Ersetzen Sie die Definition der draw()-Funktion durch Folgendes. Dadurch wird die Größe des Labyrinths an die Größe des erkannten Bildes angepasst und auf dem Bildschirm gerendert.

AugmentedImageRenderer.java

  // Adjust size of detected image and render it on-screen
  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 mazeEdgeSize = 492.65f; // Magic number of maze size
    final float maxImageEdgeSize = Math.max(augmentedImage.getExtentX(), augmentedImage.getExtentZ()); // Get largest detected image edge size

    Pose anchorPose = centerAnchor.getPose();

    float mazeScaleFactor = maxImageEdgeSize / mazeEdgeSize; // 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
    // You mustWe 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 mazeModelLocalOffset = Pose.makeTranslation(
                                -251.3f * mazeScaleFactor,
                                0.0f,
                                129.0f * mazeScaleFactor);
    anchorPose.compose(mazeModelLocalOffset).toMatrix(modelMatrix, 0);
    mazeRenderer.updateModelMatrix(modelMatrix, mazeScaleFactor, mazeScaleFactor/10.0f, mazeScaleFactor); // This line relies on a change in ObjectRenderer.updateModelMatrix later in this codelab.
    mazeRenderer.draw(viewMatrix, projectionMatrix, colorCorrectionRgba, tintColor);
  }

Jetzt sollte das Labyrinth über dem default.jpg-Bild der Erde angezeigt werden.

Hinweis: Da Sie keine vollständige Kontrolle über dieses 3D-Beispielmodell haben, verwendet der obige Code ein paar magische Elemente. Zahlen. Die Abmessungen des Labyrinthmodells betragen 492,65 x 120 x 492,65, mit der Mitte (251,3, 60, -129,0). Der Bereich seiner Eckpunkte Die Werte für die X-, Y- und Z-Koordinaten sind [5,02, 497,67], [0, 120] bzw. [-375,17, 117,25]. Daher muss die Größe des Labyrinthmodells image_size / 492.65 sein. mazeModelLocalOffset wird eingeführt, weil das 3D-Modell des Labyrinths nicht um den Ursprung (0, 0, 0) zentriert ist.

Die Wand des Labyrinths ist immer noch etwas zu hoch, um auf das Bild zu passen. Erstelle eine Hilfsfunktion updateModelMatrix(), die X, Y und Z ungleichmäßig skalieren kann, um die Höhe des Labyrinths um 0,1 zu skalieren. Beachten Sie, dass Sie die vorhandene updateModelMatrix(float[] modelMatrix, float scaleFactor) beibehalten und die Funktionsüberlastung updateModelMatrix(float[] modelMatrix, float scaleFactorX, float scaleFactorY, float scaleFactorZ) als neue Funktion hinzufügen.

common/rendering/ObjectRenderer.java

// Scale X, Y, Z coordinates unevenly
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);
}

Führen Sie den Code aus. Das Labyrinth sollte nun perfekt über das Bild passen.

772cbe2a8baef3ba.png

4. Andy zum Labyrinth hinzufügen

Nun, da du ein Labyrinth hast, füge einen Charakter hinzu, der dich darin bewegen kann. Verwende die Datei andy.obj, die im ARCore Android SDK enthalten ist. Behalten Sie die Bildrahmentextur als Textur bei, da sie sich von dem grünen Labyrinth über dem Bild unterscheidet.

Füge in AugmentedImageRenderer.java eine private ObjectRenderer hinzu, um Andy zu rendern.

AugmentedImageRenderer.java

// Render for Andy
  private final ObjectRenderer andyRenderer = new ObjectRenderer();

Als Nächstes initialisieren Sie andyRenderer am Ende von createOnGlThread().

AugmentedImageRenderer.java

public void createOnGlThread(Context context) throws IOException {

    // Initialize andyRenderer
    andyRenderer.createOnGlThread(
        context, "models/andy.obj", "models/andy.png");
    andyRenderer.setMaterialProperties(0.0f, 3.5f, 1.0f, 6.0f);
  }

Rendere schließlich Andy im Labyrinth am Ende der Funktion draw().

AugmentedImageRenderer.java

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


    // Render 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);

  }

Führen Sie den Code aus. Du solltest Andy über dem Labyrinth sehen.

cb1e74569d7ace69.png

Zielbildqualität bestimmen

ARCore nutzt visuelle Funktionen, um Bilder zu erkennen. Aufgrund von Qualitätsunterschieden sind nicht alle Bilder leicht zu erkennen.

arcoreimg ist ein Befehlszeilentool, mit dem Sie festlegen können, wie erkennbar ein Bild für ARCore ist. Es wird eine Zahl zwischen 0 und 100 ausgegeben, wobei 100 am einfachsten zu erkennen ist.

. Hier ein Beispiel:

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

maze.jpg hat einen Wert von 100, sodass er von ARCore leicht erkannt wird.

5. Optional: Andy im Labyrinth bewegen

Schließlich können Sie Code hinzufügen, damit sich das andy im Labyrinth bewegt. Verwenden Sie zum Beispiel die Open-Source-Engine Physics jBullet, um die Physiksimulation durchzuführen. Es ist völlig in Ordnung, wenn Sie diesen Teil überspringen.

Laden Sie PhysicsController.java herunter und fügen Sie es Ihrem Projekt im Verzeichnis hinzu

arcore-android-sdk-x.xx.x/samples/augmented_image_java/app/src/main/java/com/google/ar/core/examples/java/augmentedimage/

Fügen Sie in Android Studio GreenMaze.obj zum Verzeichnis Projekt-Assets hinzu, damit es zur Laufzeit geladen werden kann. GreenMaze.obj aus App kopieren > Assets > models > Von green-maze zu app > Assets.

Fügen Sie der Datei build.gradle der Anwendung die folgenden Abhängigkeiten hinzu.

app/build.gradle

    // jbullet library
    implementation 'cz.advel.jbullet:jbullet:20101010-1'

Definieren Sie die Variable andyPose, um die Position von Andys aktuellen Pose zu speichern.

AugmentedImageRenderer.java

  // Create a new pose for the Andy
  private Pose andyPose = Pose.IDENTITY;

Ändern Sie AugmentedImageRenderer.java, um Andy mit der neuen Variablen andyPose zu rendern.

AugmentedImageRenderer.java

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 the Andy's rendering position
    // The Andy's pose is at the maze's vertex's coordinate
    Pose andyPoseInImageSpace = Pose.makeTranslation(
        andyPose.tx() * mazeScaleFactor,
        andyPose.ty() * mazeScaleFactor,
        andyPose.tz() * mazeScaleFactor);

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

Fügen Sie die neue Dienstprogrammfunktion „updateAndyPose()“ hinzu, um Updates zu Andy-Pose zu erhalten.

AugmentedImageRenderer.java

  // Receive Andy pose updates
  public void updateAndyPose(Pose pose) {
    andyPose = pose;
  }

Erstellen Sie in AugmentedImageActivity.java ein PhysicsController-Objekt, das die Physik-Engine JBullet zur Verwaltung aller physikbezogenen Funktionen verwendet.

AugmentedImageActivity.java

import com.google.ar.core.Pose;

  // Declare the PhysicsController object
  private PhysicsController physicsController;

In der Physik-Engine verwenden wir einen starren Ball, um Andy zu repräsentieren, und aktualisieren Andys Position mit der Ballposition. Rufe PhysicsController auf, um die Physik zu aktualisieren, sobald die App ein Bild erkennt. Um den Ball wie in der realen Welt zu bewegen, wenden Sie die Schwerkraft aus der realen Welt an, um ihn im Labyrinth zu bewegen.

AugmentedImageActivity.java

// Update the case clause for TRACKING to call PhysicsController
// whenever the app recognizes an image
  private void drawAugmentedImages(

    ...

        case TRACKING:
          // 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(maze mesh has to be static)
            // Use the converted coordinate 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;

Führen Sie die App aus. Andy sollte sich nun realistisch bewegen, wenn Sie das Bild neigen.

Im folgenden Beispiel wird das Bild auf einem anderen Smartphone angezeigt. Sie können ein beliebiges Tablet verwenden, den Umschlag eines gedruckten Buchs verwenden oder einfach ein bedrucktes Papier, das auf einem flachen Gegenstand befestigt ist.

2f0df284705d3704.gif

Fertig! Viel Spaß dabei, Andy durch das Labyrinth zu bringen. Hinweis: Der Exit ist einfacher zu finden, wenn du das Zielbild auf dem Kopf stehend hältst.

6. Glückwunsch

Glückwunsch! Sie sind am Ende dieses Codelab angelangt und somit:

  • Es wurde ein AugmentedImage Java-Beispiel für ARCore erstellt und ausgeführt.
  • Das Beispiel wurde aktualisiert, um ein Labyrinthmodell im Bild im richtigen Maßstab anzuzeigen.
  • Die Pose des Bildes wurde verwendet, um etwas Lustiges zu tun.

Den vollständigen Code können Sie hier herunterladen.

Hat Ihnen dieses Codelab Spaß gemacht?

<ph type="x-smartling-placeholder"></ph> Ja Nein

Haben Sie bei diesem Codelab etwas Nützliches gelernt?

<ph type="x-smartling-placeholder"></ph> Ja Nein

Haben Sie die App in diesem Codelab erstellt?

<ph type="x-smartling-placeholder"></ph> Ja Nein

Haben Sie vor, in den nächsten sechs Monaten eine ARCore-App zu entwickeln?

<ph type="x-smartling-placeholder"></ph> Ja Vielleicht Nein