So erstellen Sie eine Augmented-Reality-Anwendung mit ARCore

Ursprünglicher Autor: Ayusch Jain
  • Übersetzung

So erstellen Sie eine Augmented-Reality-Anwendung mit ARCore


In diesem Handbuch erfahren Sie, wie Sie 3D-Modelle zur realen Welt hinzufügen. Mit der ARCore-Bibliothek von Google können Sie einem 2D-Bild (Bild oder Video) vollwertige 3D-Modelle hinzufügen.


Sie müssen dem System eine Art Referenzbild zur Verfügung stellen, nach dem ARCore in der realen Welt suchen wird, um dem darauf basierenden Bild ein 3D-Modell hinzuzufügen. Augmented Reality ist bereits weit verbreitet, zum Beispiel in Büchern, Zeitungen, Magazinen usw.


Bevor Sie in dieses Tutorial eintauchen, sollten Sie die beiden vorherigen Artikel zu diesem Thema lesen, in denen Sie die wichtigsten AR-Begriffe kennen lernen:



Was sind Augmented Reality-Bilder?


Laut Entwicklerdokumentation können Sie mit ARCores Augmented-Reality-Bildern Augmented-Reality-Anwendungen erstellen, die 2D-Bilder "animieren" können, beispielsweise Poster oder Produktverpackungen.


Sie laden einige Referenzbilder in ARCore und er informiert Sie dann über die Erkennung während einer AR-Sitzung, beispielsweise während einer Videoaufnahme. Diese Informationen werden verwendet, um das 3D-Modell auf einem 2D-Bild zu positionieren.


Einschränkungen bei der Verwendung von Augmented-Reality-Bildern


Hier einige Einschränkungen, die bei der Verwendung von Augmented Reality-Bildern auftreten können:


  • ARCore kann nur bis zu 20 Referenzbilder gleichzeitig verarbeiten.
  • Die physische Ebene in der realen Welt sollte flach sein und ihre Fläche sollte mehr als 15 cm x 15 cm betragen.
  • ARCore kann keine bewegten Bilder und Objekte verfolgen.

Auswahl des richtigen Referenzbildes


Hier sind einige Tipps zur Auswahl eines guten Referenzbildes für ARCore:


  • Augmented-Reality-Bilder unterstützen die Formate PNG, JPEG und JPG.
  • Es ist egal, ob es ein Farbbild oder ein Schwarzweißbild gibt. Hauptsache, es hat einen hohen Kontrast.
  • Die Bildauflösung sollte mindestens 300 x 300 Pixel betragen.
  • Die Verwendung von Bildern mit hoher Auflösung bedeutet keine Verbesserung der Leistung.
  • Bilder mit sich wiederholenden Mustern (wie Mustern oder Erbsen) sollten vermieden werden.
  • Verwenden Sie das arcoreimg- Tool , um zu beurteilen, wie gut Ihr Bild für die Arbeit geeignet ist. Eine Punktzahl von mindestens 75 Punkten wird empfohlen.

So verwenden Sie das Arcoreimg-Tool:


  • Laden Sie das ARCore SDK für Android von diesem Link herunter .
  • Entpacken Sie die Datei an einem beliebigen Ort.
  • Gehen Sie im entpackten Ordner zu den Pfadwerkzeugen> arcoreimg> windows (auch wenn Sie Linux oder macOS haben).
  • Öffnen Sie eine Eingabeaufforderung in diesem Verzeichnis.
  • Und geben Sie diesen Befehl ein:

arcoreimg.exe eval-img --input_image_path=dog.png

Ersetzen Sie dog.png durch den vollständigen Pfad zu Ihrem Bild.


Erste Schritte mit der Augmented Reality-Anwendung


Nachdem Sie ARCore gelesen und ein gutes Bild mit einer Bewertung von mehr als 75 ausgewählt haben, ist es an der Zeit, den Anwendungscode zu schreiben.


Fragment erstellen


Wir erstellen ein Snippet und fügen es unserer Aktivität hinzu. Erstellen Sie eine Klasse mit dem Namen CustomArFragmentund erben Sie sie von ArFragment. Hier ist der Code für CustomArFragment:


package com.ayusch.augmentedimages;
import android.util.Log;
import com.google.ar.core.Config;
import com.google.ar.core.Session;
import com.google.ar.sceneform.ux.ArFragment;
public class CustomArFragment extends ArFragment {
    @Override
    protected Config getSessionConfiguration(Session session) {
        getPlaneDiscoveryController().setInstructionView(null);
        Config config = new Config(session);
        config.setUpdateMode(Config.UpdateMode.LATEST_CAMERA_IMAGE);
        session.configure(config);
        getArSceneView().setupSession(session);
        return config;
    }
}

Zunächst deaktivieren wir die Ebenenerkennung. Auf diese Weise entfernen wir das Handsymbol vom Bildschirm, das unmittelbar nach der Fragmentinitialisierung angezeigt wird und den Benutzer anweist, sein Smartphone zur Suche nach dem Flugzeug zu bewegen. Wir brauchen das nicht mehr, da wir keine zufällige Ebene, sondern ein bestimmtes Bild finden.


Dann legen wir den Aktualisierungsmodus für die Sitzung fest LATEST_CAMERA_IMAGE. Dadurch wird sichergestellt, dass wir bei jeder Aktualisierung des Kamerarahmens über Bildaktualisierungen informiert werden.


Image Database Setup


Fügen Sie das ausgewählte Referenzbild (das Sie in der physischen Welt suchen möchten) zum Ordner " Assets" hinzu (erstellen Sie es, falls noch nicht vorhanden). Jetzt können wir Bilder in unsere Datenbank aufnehmen.


Wir werden diese Datenbank erstellen, sobald das Fragment erstellt wurde. In den Protokollen zeigen wir das Ergebnis dieser Operation:


if ((((MainActivity) getActivity()).setupAugmentedImagesDb(config, session))) {
    Log.d("SetupAugImgDb", "Success");
} else {
    Log.e("SetupAugImgDb","Faliure setting up db");
}

So wird es aussehen CustomArFragment:


package com.ayusch.augmentedimages;
import android.util.Log;
import com.google.ar.core.Config;
import com.google.ar.core.Session;
import com.google.ar.sceneform.ux.ArFragment;
public class CustomArFragment extends ArFragment {
    @Override
    protected Config getSessionConfiguration(Session session) {
        getPlaneDiscoveryController().setInstructionView(null);
        Config config = new Config(session);
        config.setUpdateMode(Config.UpdateMode.LATEST_CAMERA_IMAGE);
        session.configure(config);
        getArSceneView().setupSession(session);
        if ((((MainActivity) getActivity()).setupAugmentedImagesDb(config, session))) {
            Log.d("SetupAugImgDb", "Success");
        } else {
            Log.e("SetupAugImgDb","Faliure setting up db");
        }
        return config;
    }
}

Bald werden wir eine Methode hinzufügen setupAugmentedImagesDbzu MainActivity. Nun wollen wir CustomArFragmentzu unserem hinzufügen activity_main.xml:


<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    <fragment
        android:id="@+id/sceneform_fragment"
        android:name="com.ayusch.augmentedimages.CustomArFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</android.support.constraint.ConstraintLayout>

Bild zur Datenbank hinzufügen


Nun richten wir unsere Bilddatenbank ein, finden das Referenzbild in der realen Welt und fügen dem Bild ein 3D-Modell hinzu.


Beginnen wir mit dem Aufbau unserer Datenbank. Erstellen Sie eine öffentliche Methode setupAugmentedImagesDbin der Klasse MainActivity:


public boolean setupAugmentedImagesDb(Config config, Session session) {
    AugmentedImageDatabase augmentedImageDatabase;
    Bitmap bitmap = loadAugmentedImage();
    if (bitmap == null) {
        return false;
    }
    augmentedImageDatabase = new AugmentedImageDatabase(session);
    augmentedImageDatabase.addImage("tiger", bitmap);
    config.setAugmentedImageDatabase(augmentedImageDatabase);
    return true;
}
private Bitmap loadAugmentedImage() {
    try (InputStream is = getAssets().open("blanket.jpeg")) {
        return BitmapFactory.decodeStream(is);
    } catch (IOException e) {
        Log.e("ImageLoad", "IO Exception", e);
    }
    return null;
}

Wir haben auch eine Methode erstellt loadAugmentedImage, mit der ein Bild aus dem Ressourcenordner geladen und ein Bitmap-Bild zurückgegeben wird.


Am setupAugmentedImagesDbersten initialisieren wir unsere Datenbank für die aktuelle Sitzung, und dann das Bild in die Datenbank aufzunehmen. Wir nannten unser Bildtiger . Dann setzen wir diese Datenbank auf config und kehren zurück trueund melden, dass das Image erfolgreich hinzugefügt wurde.


Referenzbilder in der realen Welt erkennen


Jetzt werden wir unsere Referenzbilder in der realen Welt erkennen. Dazu erstellen wir einen Listener, der bei jeder Aktualisierung des Videoframes aufgerufen wird, und dieser Frame wird auf das Vorhandensein des Referenzbildes dort analysiert.


Fügen Sie diese Zeile der Methode onCreate()in hinzu MainActivity:


arFragment.getArSceneView().getScene().addOnUpdateListener(this::onUpdateFrame);

Fügen Sie nun ein Verfahren onUpdateFramezu MainActivity:


@RequiresApi(api = Build.VERSION_CODES.N)
private void onUpdateFrame(FrameTime frameTime) {
    Frame frame = arFragment.getArSceneView().getArFrame();
    Collection<AugmentedImage> augmentedImages = frame.getUpdatedTrackables(AugmentedImage.class);
    for (AugmentedImage augmentedImage : augmentedImages) {
        if (augmentedImage.getTrackingState() == TrackingState.TRACKING) {
            if (augmentedImage.getName().equals("tiger") && shouldAddModel) {
                placeObject(arFragment, augmentedImage.createAnchor(augmentedImage.getCenterPose()), Uri.parse("Mesh_BengalTiger.sfb"));
                shouldAddModel = false;
            }
        }
    }
}

In der ersten Zeile bekommen wir den Rahmen selbst. Der Frame kann als regulärer Screenshot aus dem Video dargestellt werden. Wenn Sie mit der Funktionsweise von Videos vertraut sind, wissen Sie, dass dies nur eine Sammlung von Bildern ist, die sich sehr schnell gegenseitig ersetzen und den Eindruck vermitteln, dass sich etwas bewegt. Wir machen nur eines dieser Bilder.


Nachdem wir den Rahmen erhalten haben, analysieren wir ihn auf das Vorhandensein unseres Referenzbildes. Wir führen eine Liste aller Elemente, die von ARCore mitverfolgt wurden frame.getUpdatedTrackables. Dann durchlaufen wir es und prüfen, ob sich unser Tigerbild im Rahmen befindet .


Wenn eine Übereinstimmung gefunden wird, wird das 3D-Modell einfach über das erkannte Bild gelegt und platziert.


Hinweis Das Flag wird shouldAddModelverwendet, um ein 3D-Modell nur einmal hinzuzufügen.

Platzieren Sie das 3D-Modell über dem Referenzbild.


Nachdem wir unser Referenzbild in der realen Welt gefunden haben, können wir ein 3D-Modell darüber hinzufügen. Methoden hinzufügen placeObjectund addNodeToScene:


  • placeObject: Diese Methode wird zum Erstellen eines gerenderten Objekts für ein gegebenes Objekt verwendet Uri. Sobald das Rendern abgeschlossen ist, wird das Objekt an die Methode übergeben, addNodeToScenebei der das Objekt an den Knoten angehängt ist, und dieser Knoten wird auf der Bühne platziert.
  • addNodeToSceneDiese Methode erstellt einen Knoten aus dem resultierenden Anker, erstellt einen anderen Knoten, an den das gerenderte Objekt angehängt ist, fügt diesen Knoten dem Ankerknoten hinzu und platziert ihn in der Szene.

So sieht es jetzt aus MainActivity:


package com.ayusch.augmentedimages;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
import com.google.ar.core.Anchor;
import com.google.ar.core.AugmentedImage;
import com.google.ar.core.AugmentedImageDatabase;
import com.google.ar.core.Config;
import com.google.ar.core.Frame;
import com.google.ar.core.Session;
import com.google.ar.core.TrackingState;
import com.google.ar.sceneform.AnchorNode;
import com.google.ar.sceneform.FrameTime;
import com.google.ar.sceneform.rendering.ModelRenderable;
import com.google.ar.sceneform.rendering.Renderable;
import com.google.ar.sceneform.ux.ArFragment;
import com.google.ar.sceneform.ux.TransformableNode;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
public class MainActivity extends AppCompatActivity {
    ArFragment arFragment;
    boolean shouldAddModel = true;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        arFragment = (CustomArFragment) getSupportFragmentManager().findFragmentById(R.id.sceneform_fragment);
        arFragment.getPlaneDiscoveryController().hide();
        arFragment.getArSceneView().getScene().addOnUpdateListener(this::onUpdateFrame);
    }
    @RequiresApi(api = Build.VERSION_CODES.N)
    private void placeObject(ArFragment arFragment, Anchor anchor, Uri uri) {
        ModelRenderable.builder()
                .setSource(arFragment.getContext(), uri)
                .build()
                .thenAccept(modelRenderable -> addNodeToScene(arFragment, anchor, modelRenderable))
                .exceptionally(throwable -> {
                            Toast.makeText(arFragment.getContext(), "Error:" + throwable.getMessage(), Toast.LENGTH_LONG).show();
                            return null;
                        }
                );
    }
    @RequiresApi(api = Build.VERSION_CODES.N)
    private void onUpdateFrame(FrameTime frameTime) {
        Frame frame = arFragment.getArSceneView().getArFrame();
        Collection<AugmentedImage> augmentedImages = frame.getUpdatedTrackables(AugmentedImage.class);
        for (AugmentedImage augmentedImage : augmentedImages) {
            if (augmentedImage.getTrackingState() == TrackingState.TRACKING) {
                if (augmentedImage.getName().equals("tiger") && shouldAddModel) {
                    placeObject(arFragment, augmentedImage.createAnchor(augmentedImage.getCenterPose()), Uri.parse("Mesh_BengalTiger.sfb"));
                    shouldAddModel = false;
                }
            }
        }
    }
    public boolean setupAugmentedImagesDb(Config config, Session session) {
        AugmentedImageDatabase augmentedImageDatabase;
        Bitmap bitmap = loadAugmentedImage();
        if (bitmap == null) {
            return false;
        }
        augmentedImageDatabase = new AugmentedImageDatabase(session);
        augmentedImageDatabase.addImage("tiger", bitmap);
        config.setAugmentedImageDatabase(augmentedImageDatabase);
        return true;
    }
    private Bitmap loadAugmentedImage() {
        try (InputStream is = getAssets().open("blanket.jpeg")) {
            return BitmapFactory.decodeStream(is);
        } catch (IOException e) {
            Log.e("ImageLoad", "IO Exception", e);
        }
        return null;
    }
    private void addNodeToScene(ArFragment arFragment, Anchor anchor, Renderable renderable) {
        AnchorNode anchorNode = new AnchorNode(anchor);
        TransformableNode node = new TransformableNode(arFragment.getTransformationSystem());
        node.setRenderable(renderable);
        node.setParent(anchorNode);
        arFragment.getArSceneView().getScene().addChild(anchorNode);
        node.select();
    }
}

Führen Sie jetzt Ihre Anwendung aus. Sie sollten den Bildschirm wie unten gezeigt sehen. Bewegen Sie das Telefon etwas über das Referenzobjekt. Sobald ARCore ein Referenzbild in der realen Welt erkennt, fügt es Ihr 3D-Modell hinzu.


Das Ergebnis


Siehe auch: Erste ARCore-Anwendung erstellen

Jetzt auch beliebt: