Caras Aumentadas con ARCore en Android

Augmented Faces permite que la aplicación distinga de forma natural varias regiones de la cara de una persona y utilice esas áreas para superponer recursos, por ejemplo, superficies y modelos de una manera que coincida adecuadamente con los contornos y las regiones de una cara individual. ARCore es un escenario para construir aplicaciones de realidad aumentada en Android. Augmented Face es un subsistema de ARCore que permite que su aplicación:  

  • Naturalmente, reconozca varias áreas del rostro identificado de cualquier persona y utilice esas regiones para superponer recursos, por ejemplo, superficies y modelos de una manera que coincida adecuadamente con los contornos y las regiones de un rostro individual.
  • Utilice la malla facial de 468 puntos proporcionada por ARCore para aplicar una textura personalizada sobre una cara distinguida.

Por ejemplo, podemos crear efectos como máscaras animadas, gafas, sombreros virtuales, realizar retoques de piel o la próxima aplicación de Snapchat.

¿Cómo funciona todo?

Las caras aumentadas no requieren hardware poco común o especial, como un sensor de profundidad. Más bien, utiliza la cámara del teléfono y el aprendizaje automático para proporcionar tres fragmentos de datos:

  1. Genera una malla facial: una malla facial 3D densa de 468 puntos, que le permite panoramizar texturas detalladas que siguen con precisión los momentos faciales.
  2. Reconoce la Pose: puntos en la cara de una persona, anclados en función de la Malla facial generada, que es útil para colocar efectos en o cerca de la sien y la nariz.
  3. Superposiciones y texturas de posición y modelos 3D basados ​​en la malla facial generada y regiones reconocidas.

¿Cómo puede ARCore proporcionar una malla de cara 3D a partir de una imagen 2D sin ningún hardware de profundidad?

Utiliza modelos de aprendizaje automático que se construyen sobre la plataforma TensorFlow Lite para lograr esto y la tubería de cruce está optimizada para ejecutarse en el dispositivo en tiempo real. Utiliza una técnica llamada aprendizaje de transferencia en la que entrenamos la red neuronal para dos objetivos, uno, predecir vértices 3D y predecir contornos 2D. Para predecir vértices 3D, lo entrenamos con un conjunto de datos 3D sintéticos y usamos esta red neuronal como punto de partida para la siguiente etapa de entrenamiento.

En esta siguiente etapa, utiliza el conjunto de datos anotados, el conjunto de datos del mundo real anotados para entrenar el modelo para la predicción de contornos 2D. La red resultante no solo predice vértices 3D a partir de un conjunto de datos sintéticos, sino que también puede funcionar bien a partir de imágenes 2D. Para asegurarse de que la solución funcione para todos, los desarrolladores de ARCore entrenan la red con conjuntos de datos geográficamente diversos para que funcione para todo tipo de rostros, rostros más anchos, rostros más altos y todo tipo de colores de piel. 

Y para habilitar estos complejos algoritmos en dispositivos móviles, tenemos múltiples algoritmos adaptables integrados en ARCore. Estos algoritmos detectan dinámicamente cuánto tiempo se ha tardado en procesar imágenes anteriores y ajustan en consecuencia varios parámetros de la canalización. Utiliza múltiples modelos ML, uno optimizado para una mayor calidad y otro optimizado para un mayor rendimiento cuando calcular los recursos es realmente desafiante. También ajusta los parámetros de la canalización, como las tasas de inferencia, para que omita algunas imágenes y, en su lugar, las reemplace con datos de interpolación. Con todas estas técnicas, lo que obtiene es una experiencia de velocidad de fotogramas completa para su usuario. Por lo tanto, proporciona mallas faciales y poses de región a la velocidad máxima de fotogramas de la cámara mientras maneja todas estas técnicas internas del ARCore.

Identificación de una malla de cara aumentada

Para superponer adecuadamente texturas y modelos 3D en una cara identificada, ARCore proporciona regiones detectadas y una malla de cara aumentada. Esta malla es una representación virtual de la cara y comprende los vértices, las regiones faciales y el punto focal de la cabeza del usuario. En el momento en que la cámara identifica el rostro de un usuario, ARCore realiza los siguientes pasos para generar la malla facial aumentada, así como las poses centrales y regionales:

  • Se distingue la pose del centro y una malla facial.
    • La pose central, situada detrás de la nariz, es el punto central real de la cabeza del usuario (en otras palabras, dentro del cráneo).
    • La malla facial se compone de muchos vértices que forman la cara y se caracteriza en relación con la pose central.

  • La clase AugmentedFace utiliza la malla facial y la pose central para distinguir las regiones faciales presentes en la cara del cliente. Estas regiones son:
    • Ceja derecha (RIGHT_FOREHEAD)
    • Sien izquierda (LEFT_FOREHEAD)
    • Punta de la nariz (NOSE_TIP)

Las API de AugmentedFace utilizan la malla de la cara, la pose central y la región de la cara como puntos de posicionamiento y regiones para colocar los recursos en su aplicación.

Malla de textura de cara de 468 puntos

Terminologías de referencia

  • Rastreable : Un Rastreable es una interfaz que ARCore puede seguir y algo desde lo cual se pueden conectar Anchors.
  • Ancla : Describe una ubicación fija y una orientación en el mundo real. Para permanecer en una ubicación fija en el espacio físico, la descripción numérica de esta posición se actualizará a medida que mejore la comprensión del espacio por parte de ARCore. Los anclajes se pueden modificar y, por ejemplo, se pueden usar como claves en HashMaps.
  • Pose : en el punto en el que necesita indicar en qué escena debe colocar el objeto y debe especificar la ubicación en términos de las coordenadas de la escena. La Pose es el medio por el cual afirmas esto.
  • Sesión: se ocupa del estado del marco AR y maneja el ciclo de vida de la sesión. Esta clase ofrece el pasaje principal a la API de ARCore. Esta clase permite al usuario realizar una sesión, configurarla, iniciarla o detenerla y, sobre todo, recibir fotogramas que permitan acceder a la imagen de la cámara y pose del dispositivo.
  • Texturas: las texturas son especialmente útiles para las caras aumentadas. Esto le permite hacer una superposición de luz que se alinee con las ubicaciones de las caras identificadas para agregar a su experiencia.
  • ArFragment: ARCore utiliza un ArFragment que proporciona muchas características, por ejemplo, búsqueda de aviones, manejo de permisos y configuración de cámaras. Puede utilizar el fragmento legítimamente en su actividad, sin embargo, en cualquier momento que necesite características personalizadas, por ejemplo, Caras aumentadas, debe extender ArFragment y establecer la configuración adecuada. Este fragmento es la capa que oculta todo el material compuesto (como OpenGL, modelos de renderizado, etc.) y brinda API de alto nivel para cargar y renderizar modelos 3D.
  • ModelRenderable: ModelRenderablerenderiza un modelo 3D al adjuntarlo a un archivo Node.
  • SDK de Sceneform: SDK de Sceneform es otra biblioteca para Android que permite la creación y combinación rápidas de experiencias AR en su aplicación. Se une a ARCore y un increíble renderizador 3D basado en la física.

Proyecto de ejemplo

Vamos a crear Snapchat, Instagram y TikTok como filtros faciales. qué

Augmented Faces with ARCore in Android Sample GIF

Paso 1: Crear un nuevo proyecto

Para crear un nuevo proyecto en Android Studio, consulte Cómo crear/iniciar un nuevo proyecto en Android Studio . Tenga en cuenta que seleccione Java como lenguaje de programación.

Paso 2: agregar el archivo de activos utilizado en este ejemplo

Agregue cualquier modelo 3D en la carpeta sampledata/models. Podemos hacer esto creando una nueva carpeta en el directorio de archivos del proyecto o directamente desde Android Studio. Las extensiones de modelo 3D permitidas son .fbx, .OBJ, .glTF. Hay muchos modelos gratuitos disponibles en Internet. Puedes visitar, aquí o más. Puede descargar los recursos utilizados en este ejemplo desde aquí . Consulte este artículo para crear una carpeta sin procesar en Android Studio . Luego simplemente copie y pegue el archivo fox_face.sfb en la carpeta sin formato. Del mismo modo, copie y pegue el archivo fox_face_mesh_texture.png en la carpeta dibujable

Paso 3: Agregar dependencias al archivo build.gradle(:app)

Agregue las siguientes dependencias al archivo build.gradle(:app)

// Proporciona sesión ARCore y recursos relacionados.

implementación ‘com.google.ar:core:1.16.0’

// Proporciona ArFragment y otros recursos de UX.

implementación ‘com.google.ar.sceneform.ux:sceneform-ux:1.15.0’

// Alternativamente, use ArSceneView sin la dependencia de UX.

implementación ‘com.google.ar.sceneform:core:1.8.0’

Agregue el siguiente fragmento de código al archivo build.gradle. Esto es necesario (solo una vez) para convertir el activo .fbx en .sfb y guardarlo en la carpeta sin procesar. O puede agregarlos usted mismo como lo hizo en el paso 2.

// requerido (solo una vez) para convertir el activo .fbx en .sfb

// y guardar eso en la carpeta raw

sceneform.asset(‘datos de muestra/modelos/fox_face.fbx’,

                        ‘defecto’,

                        ‘datos de muestra/modelos/fox_face.sfa’,

                        ‘src/main/res/raw/fox_face’)

Paso 4: Agregar dependencias al archivo build.gradle(:project)

Agrega las siguientes dependencias al archivo build.gradle(:project)

// Agregue la ruta de clase del complemento de Sceneform al proyecto

// nivel del archivo build.gradle

ruta de clase ‘com.google.ar.sceneform: complemento: 1.15.0’

Paso 5: Trabajar con el archivo AndroidManifest.xml

Agregue la siguiente línea al archivo AndroidManifest.xml .

// Tanto las aplicaciones «AR opcional» como las «AR requeridas» requieren permiso de CÁMARA.

<usos-permiso android:name=”android.permission.CAMERA” />

// Indica que la aplicación requiere ARCore («AR requerido»). Garantiza que la aplicación es solo

// visible en Google Play Store en dispositivos compatibles con ARCore.

// Para las aplicaciones «AR opcionales», elimine esta línea. →

<uses-feature android:name=”android.hardware.camera.ar” android:required=”true”/>

<aplicación>

   …

   // Indica que la aplicación requiere ARCore («AR requerido»). Causas Google

   // Play Store para descargar e instalar ARCore junto con la aplicación.

   // Para una aplicación «AR opcional», especifique «opcional» en lugar de «obligatorio».

   <metadatos android:name=”com.google.ar.core” android:value=”requerido” />

    …

 </aplicación>

A continuación se muestra el código completo del archivo AndroidManifest.xml .

XML

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.arsnapchat">
 
    <uses-feature
        android:name="android.hardware.camera"
        android:required="true" />
 
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.INTERNET" />
 
    <uses-feature
        android:name="android.hardware.camera.ar"
        android:required="true" />
    <uses-feature android:name="android.hardware.camera.autofocus" />
     
    <uses-feature
        android:glEsVersion="0x00020000"
        android:required="true" />
 
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <meta-data
            android:name="com.google.ar.core"
            android:value="required" />
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
 
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
 
</manifest>

 
Paso 6: Modifique el archivo activity_main.xml

Hemos agregado un fragmento al archivo activity_main.xml. A continuación se muestra el código para el  archivo  activity_main.xml .

XML

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
 
    <fragment
        android:id="@+id/arFragment"
        android:name="com.example.arsnapchat.CustomArFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
 
</androidx.constraintlayout.widget.ConstraintLayout>

Nota: 

Agregue el nombre de su paquete a este atributo.

android:name=”com.example.arsnapchat.CustomArFragment”

Paso 7: Crear una nueva clase de Java

Cree una nueva clase y nombre el archivo como CustomArFragment que extiende ArFragment . A continuación se muestra el código del  archivo CustomArFragment.java .

Java

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import androidx.annotation.Nullable;
import com.google.ar.core.Config;
import com.google.ar.core.Session;
import com.google.ar.sceneform.ux.ArFragment;
import java.util.EnumSet;
import java.util.Set;
 
public class CustomArFragment extends ArFragment {
    @Override
    protected Config getSessionConfiguration(Session session) {
        Config config = new Config(session);
 
        // Configure 3D Face Mesh
        config.setAugmentedFaceMode(Config.AugmentedFaceMode.MESH3D);
        this.getArSceneView().setupSession(session);
        return config;
    }
 
    @Override
    protected Set<Session.Feature> getSessionFeatures() {
        // Configure Front Camera
        return EnumSet.of(Session.Feature.FRONT_CAMERA);
    }
 
    // Override to turn off planeDiscoveryController.
    // Plane traceable are not supported with the front camera.
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        FrameLayout frameLayout = (FrameLayout) super.onCreateView(inflater, container, savedInstanceState);
        getPlaneDiscoveryController().hide();
        getPlaneDiscoveryController().setInstructionView(null);
        return frameLayout;
    }
}

Paso 8: Modifique el archivo MainActivity.java

A continuación se muestra el código del   archivo MainActivity.java . Se agregan comentarios dentro del código para comprender el código con más detalle.

Java

import android.os.Bundle;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.google.ar.core.AugmentedFace;
import com.google.ar.core.Frame;
import com.google.ar.core.TrackingState;
import com.google.ar.sceneform.rendering.ModelRenderable;
import com.google.ar.sceneform.rendering.Renderable;
import com.google.ar.sceneform.rendering.Texture;
import com.google.ar.sceneform.ux.AugmentedFaceNode;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
 
public class MainActivity extends AppCompatActivity {
    private ModelRenderable modelRenderable;
    private Texture texture;
    private boolean isAdded = false;
    private final HashMap<AugmentedFace, AugmentedFaceNode> faceNodeMap = new HashMap<>();
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        CustomArFragment customArFragment = (CustomArFragment) getSupportFragmentManager().findFragmentById(R.id.arFragment);
 
        // Use ModelRenderable.Builder to load the *.sfb
        // models at runtime.
        // Load the face regions renderable.
        // To ensure that the asset doesn't cast or receive
        // shadows in the scene, ensure that setShadowCaster
        // and setShadowReceiver are both set to false.
        ModelRenderable.builder()
                .setSource(this, R.raw.fox_face)
                .build()
                .thenAccept(rendarable -> {
                    this.modelRenderable = rendarable;
                    this.modelRenderable.setShadowCaster(false);
                    this.modelRenderable.setShadowReceiver(false);
 
                })
                .exceptionally(throwable -> {
                    Toast.makeText(this, "error loading model", Toast.LENGTH_SHORT).show();
                    return null;
                });
 
        // Load the face mesh texture.(2D texture on face)
        // Save the texture(.png file) in drawable folder.
        Texture.builder()
                .setSource(this, R.drawable.fox_face_mesh_texture)
                .build()
                .thenAccept(textureModel -> this.texture = textureModel)
                .exceptionally(throwable -> {
                    Toast.makeText(this, "cannot load texture", Toast.LENGTH_SHORT).show();
                    return null;
                });
 
        assert customArFragment != null;
 
        // This is important to make sure that the camera
        // stream renders first so that the face mesh
        // occlusion works correctly.
        customArFragment.getArSceneView().setCameraStreamRenderPriority(Renderable.RENDER_PRIORITY_FIRST);
        customArFragment.getArSceneView().getScene().addOnUpdateListener(frameTime -> {
            if (modelRenderable == null || texture == null) {
                return;
            }
            Frame frame = customArFragment.getArSceneView().getArFrame();
            assert frame != null;
 
            // Render the effect for the face Rendering the effect involves these steps:
            // 1.Create the Sceneform face node.
            // 2.Add the face node to the Sceneform scene.
            // 3.Set the face region Renderable. Extracting the face mesh and
            // rendering the face effect is added to a listener on
            // the scene that gets called on every processed camera frame.
            Collection<AugmentedFace> augmentedFaces = frame.getUpdatedTrackables(AugmentedFace.class);
 
            // Make new AugmentedFaceNodes for any new faces.
            for (AugmentedFace augmentedFace : augmentedFaces) {
                if (isAdded) return;
 
                AugmentedFaceNode augmentedFaceMode = new AugmentedFaceNode(augmentedFace);
                augmentedFaceMode.setParent(customArFragment.getArSceneView().getScene());
                augmentedFaceMode.setFaceRegionsRenderable(modelRenderable);
                augmentedFaceMode.setFaceMeshTexture(texture);
                faceNodeMap.put(augmentedFace, augmentedFaceMode);
                isAdded = true;
 
                // Remove any AugmentedFaceNodes associated with
                // an AugmentedFace that stopped tracking.
                Iterator<Map.Entry<AugmentedFace, AugmentedFaceNode>> iterator = faceNodeMap.entrySet().iterator();
                Map.Entry<AugmentedFace, AugmentedFaceNode> entry = iterator.next();
                AugmentedFace face = entry.getKey();
                while (face.getTrackingState() == TrackingState.STOPPED) {
                    AugmentedFaceNode node = entry.getValue();
                    node.setParent(null);
                    iterator.remove();
                }
            }
        });
    }
}

Salida: ejecutar en un dispositivo físico

Enlace del proyecto Github: https://github.com/raghavtilak/AugmentedFaces

Limitaciones de Ar Core

  1. Las caras aumentadas solo funcionan con la cámara frontal.
  2. No todos los dispositivos son compatibles con ARCore. Todavía hay una pequeña fracción de dispositivos que no son compatibles con AR Core. Puede consultar la lista de dispositivos compatibles con ARCore en https://developers.google.com/ar/discover/supported-devices .
  3. Para AR OptionalApp minSdkVersion debe ser 14 y para AR Required App minSdkVersion debe ser 24.
  4. Si su aplicación se encuentra en la categoría de aplicación AR requerida, entonces el dispositivo que la usa debe tener AR Core instalado.

Notas:

  1. Previo a realizar una Sesión, se debe verificar previamente que ARCore esté instalado y actualizado. Si ARCore no está instalado, la creación de la sesión podría fallar y cualquier instalación o actualización posterior de ARCore requeriría reiniciar la aplicación y podría provocar que la aplicación se cerrara.
  2. La orientación de la malla frontal es diferente para Unreal, Android y Unity.
  3. Llamar a Trackable.createAnchor(Pose) daría como resultado una IllegalStateException porque Augmented Faces solo admite la cámara frontal (selfie) y no admite la fijación de anclas.

Publicación traducida automáticamente

Artículo escrito por raghav14 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *