
En esta guía, aprenderá cómo agregar modelos 3D al mundo real. La biblioteca ARCore de Google le permite agregar modelos 3D completos a una imagen 2D (imagen o video).
Debe proporcionar al sistema algún tipo de imagen de referencia, que ARCore buscará en el mundo real para agregar un modelo 3D a la imagen sobre la base. La realidad aumentada ya se usa ampliamente, por ejemplo, en libros, periódicos, revistas, etc.
Antes de sumergirse en este tutorial, debe familiarizarse con los dos artículos anteriores sobre este tema que le presentarán los términos básicos de AR:
¿Qué son las imágenes de realidad aumentada?
Según la documentación para desarrolladores , las imágenes de realidad aumentada en ARCore le permiten crear aplicaciones de realidad aumentada que pueden "animar" imágenes 2D, como carteles o empaques de productos.
Sube algunas imágenes de referencia a ARCore y luego le informa acerca de su detección durante la sesión de AR, por ejemplo, al grabar un video. Y esta información se utiliza para colocar el modelo 3D en una imagen 2D.
Limitaciones del uso de imágenes de realidad aumentada
Estas son algunas de las limitaciones que puede encontrar al usar imágenes de realidad aumentada:
- ARCore solo puede procesar hasta 20 imágenes de referencia a la vez.
- El plano físico en el mundo real debe ser plano, y su área debe ser superior a 15 cm x 15 cm.
- ARCore no puede rastrear imágenes y objetos en movimiento.
Elegir la imagen de referencia correcta
Aquí hay algunos consejos para elegir una buena imagen de referencia para ARCore:
- Las imágenes de realidad aumentada admiten formatos PNG, JPEG y JPG.
- No importa si la imagen es en color o en blanco y negro, lo principal es que tenga un alto contraste.
- La resolución de la imagen debe ser de al menos 300 x 300 píxeles.
- Usar imágenes de alta resolución no significa mejorar el rendimiento.
- Se deben evitar las imágenes con patrones repetitivos (como patrones o lunares).
- Use la herramienta arcoreimg para evaluar qué tan bien funciona su imagen. Se recomienda una calificación de al menos 75 puntos.
Cómo usar la herramienta arcoreimg:
- Descargue el SDK de ARCore para Android desde este enlace .
- Descomprima el contenido del archivo en cualquier ubicación.
- En la carpeta extraída, vaya a herramientas> arcoreimg> windows (incluso si tiene Linux o macOS).
- Abra un símbolo del sistema en este directorio.
- E ingrese este comando:
arcoreimg.exe eval-img --input_image_path=dog.png
Reemplace dog.png con la ruta completa a su imagen.
Comenzando con la aplicación de realidad aumentada
Ahora que se ha familiarizado con ARCore y ha seleccionado una buena imagen con una calificación de más de 75, es hora de comenzar a escribir el código de la aplicación.
Creación de fragmentos
Crearemos un fragmento y lo agregaremos a nuestra Actividad. Cree una clase llamada CustomArFragment
y herede de ArFragment
. Aquí está el código para 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; } }
En primer lugar, desactivamos la detección de avión. Al hacer esto, eliminamos el icono de la mano de la pantalla que aparece inmediatamente después de que se inicializa el fragmento y le dice al usuario sobre la necesidad de mover su teléfono inteligente para encontrar el avión. Ya no necesitamos esto, porque no encontramos planos aleatorios, sino una imagen concreta.
Luego configuramos el modo de actualización para la sesión LATEST_CAMERA_IMAGE
. Esto garantiza que seremos informados sobre las actualizaciones de imágenes cada vez que se actualice el marco de la cámara.
Configuración de la base de datos de imágenes
Agregue la imagen de referencia seleccionada (que desea encontrar en el mundo físico) a la carpeta de activos (créelo si aún no lo está). Ahora podemos agregar imágenes a nuestra base de datos.
Crearemos esta base de datos tan pronto como se cree el fragmento. En los registros mostramos el resultado de esta operación:
if ((((MainActivity) getActivity()).setupAugmentedImagesDb(config, session))) { Log.d("SetupAugImgDb", "Success"); } else { Log.e("SetupAugImgDb","Faliure setting up db"); }
CustomArFragment
se verá 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; } }
Pronto agregaremos el método MainActivity
a MainActivity
. Ahora agreguemos CustomArFragment
a nuestra 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>
Agregar una imagen a la base de datos
Ahora configuraremos nuestra base de datos de imágenes, encontraremos la imagen de referencia en el mundo real y agregaremos un modelo 3D a la imagen.
Comencemos configurando nuestra base de datos. Cree un método público setupAugmentedImagesDb
en la clase 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; }
También creamos un método loadAugmentedImage
que carga una imagen desde una carpeta de recursos y devuelve un mapa de bits.
En setupAugmentedImagesDb
primero inicializamos nuestra base de datos para la sesión actual y luego agregamos la imagen a esta base de datos. Llamamos a nuestra imagen tigre . Luego instalamos esta base de datos en la configuración y devolvemos true
, lo que indica que la imagen se agregó con éxito.
Detección de imágenes de referencia del mundo real
Ahora comenzaremos a descubrir nuestras imágenes de referencia en el mundo real. Para hacer esto, crearemos un oyente que se llamará cada vez que se actualice el cuadro de video, y este cuadro se analizará para detectar la presencia de una imagen de referencia allí.
Agregue esta línea al método onCreate()
en MainActivity
:
arFragment.getArSceneView().getScene().addOnUpdateListener(this::onUpdateFrame);
Ahora agregue el método MainActivity
a 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; } } } }
En la primera línea obtenemos el cuadro en sí. Se puede imaginar un marco como una captura de pantalla normal de un video. Si está familiarizado con el funcionamiento del video, sabe que es solo una colección de imágenes que se cambian muy rápidamente, dando la impresión de que algo se mueve. Solo tomamos una de estas fotos.
Después de recibir el marco, lo analizamos para detectar la presencia de nuestra imagen de referencia en él. Tomamos una lista de todos los elementos rastreados por ARCore usando frame.getUpdatedTrackables
. Luego iteramos sobre él y verificamos si nuestra imagen de tigre está presente en el marco.
Si se encuentra una coincidencia, simplemente tomamos y colocamos el modelo 3D encima de la imagen detectada.
Nota El indicador shouldAddModel
usa para que agreguemos el modelo 3D solo una vez.
Colocar un modelo 3D sobre una imagen de referencia
Ahora que hemos encontrado nuestra imagen de referencia en el mundo real, podemos agregar un modelo 3D encima. Agregue los addNodeToScene
placeObject
y addNodeToScene
:
placeObject
: este método se usa para construir un objeto renderizado usando un Uri
dado. Una vez que se completa la representación, el objeto se pasa al método addNodeToScene
, donde el objeto se adjunta al nodo, y este nodo se coloca en la escena.addNodeToScene
: este método crea un nodo a partir del ancla resultante, crea otro nodo al que se une el objeto visualizado, luego agrega este nodo al nodo ancla y lo coloca en el escenario.
Así es como se ve 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(); } }
Ahora ejecuta tu aplicación. Debería ver la pantalla como se muestra a continuación. Mueva el teléfono ligeramente por encima del objeto de referencia. Y tan pronto como ARCore detecta la imagen de referencia en el mundo real, le agrega su modelo 3D.

Lea también: Crear su primera aplicación ARCore