Cómo construir una aplicación de seguimiento de sonrisa súper rápida

ARKit puede parecer intimidante, pero no es tan malo si ya tienes experiencia básica en la creación de aplicaciones iOS.

Soy un tipo de aprender haciendo, así que he estado jugando con ARKit, creando aplicaciones básicas para familiarizarme con él. En esta publicación, revisaré lo que aprendí al crear una aplicación de seguimiento facial simple.

Haré esto en 3 partes:

  1. Configuración inicial → Primero lo primero, obtenga los permisos de la cámara y asegúrese de que el dispositivo pueda usar ARKit.
  2. Seguimiento de sonrisas → Comience a rastrear sonrisas con ARKit. Esto es probablemente para lo que estás aquí.
  3. Interfaz de usuario → Agregue la interfaz de usuario para nuestra aplicación que reaccionará a las sonrisas.

Al momento de escribir esto, el simulador Xcode no es compatible con la cámara frontal, por lo que necesitará un dispositivo real para ejecutar la aplicación. Su dispositivo también necesitará tener una cámara TrueDepth (a partir del 8 de mayo de 2019, solo el iPhone X y el iPhone X Plus tienen una cámara TrueDepth).

Finalmente, para mis compañeros miembros del Copy Paste Club, todo el código está disponible en Github.

Configuración inicial

Comience abriendo Xcode y creando un nuevo proyecto llamado "SmileTracker" (o el nombre que prefiera).

Antes de que podamos entrar en el seguimiento facial, tendremos que hacer dos cosas:

  1. Asegúrese de que su dispositivo sea compatible con ARKit
  2. Obtenga permiso para acceder a la cámara de su dispositivo

En su nuevo proyecto, abra ViewController.swift. Cerca de la parte superior del archivo, debajo de import UIKit, agregue la línea: import ARKit. Esto nos permitirá acceder a todas las cosas que Apple nos ha proporcionado para hacer que el seguimiento facial sea muy fácil.

Ahora agregue el siguiente código dentro de viewDidLoad:

guard ARFaceTrackingConfiguration.isSupported else {
   fatalError ("El dispositivo no admite el seguimiento de rostros")
}

ARFaceTrackingConfiguration.isSupported es un valor booleano que será verdadero si el dispositivo que ejecuta la aplicación puede soportar el seguimiento facial y falso si no. En este caso, si el dispositivo no puede soportar el seguimiento facial, bloquearemos la aplicación con un error fatal.

A continuación, obtengamos permiso para usar la cámara. Agregue lo siguiente en viewDidLoad debajo de nuestra declaración de guardia:

AVCaptureDevice.requestAccess (para: AVMediaType.video) {concedido en
   si (concedido) {
      Dispatch.main.sync {
         // Vamos a implementar esta función en un minuto
         self.setupSmileTracker ()
      }
   } más {
      fatalError ("¡El usuario no otorgó permiso a la cámara!")
   }
}

Aquí le pedimos al dispositivo que solicite permisos de cámara. Si el usuario otorga permisos, ejecutaremos la función que configurará nuestro seguimiento de sonrisas (no se preocupe por el error, implementaremos esta función en un momento).

Envolvemos la función en Dispatch.main.sync porque agregaremos elementos de la interfaz de usuario en esta función, que solo se puede hacer en el hilo principal.

También necesitaremos agregar una Descripción del uso de la cámara a nuestra Lista de información. Abra Info.plist y agregue una nueva fila (puede hacerlo resaltando la última fila y presionando enter).

En la fila que acaba de crear, agregue Privacidad - Descripción del uso de la cámara a la columna Clave y asegúrese de que la columna Tipo esté configurada en cadena. Puede dejar la columna Valor en blanco o agregar un mensaje para explicar cómo usará la cámara para el usuario.

Su Info.plist ahora debería verse así:

Si desea probar su aplicación hasta ahora, puede comentar la línea donde llamamos a setupSmileTracker (). Solo recuerda comentarlo más tarde.

Si ejecuta su aplicación ahora, debería ver una ventana emergente que le pide que habilite los permisos de la cámara. Si dice que no, tendrá que ir a la configuración de la aplicación para habilitar esos permisos para que la aplicación se ejecute.

Si la aplicación falla, verifique en la consola uno de nuestros dos mensajes de error para ver qué salió mal.

Seguimiento de la sonrisa

Abra ViewController.swift y agregue la siguiente variable en la parte superior de ViewController:

clase ViewController: UIViewController {
   let sceneView = ARSCNView ()
   anular func viewDidLoad () {...}
}

ARSCNView viene equipado con una ARSession que su iPhone usa para coordinar experiencias de AR. Utilizaremos ARSession de sceneView para analizar la cara de nuestro usuario a través de la cámara frontal.

Agregue esta función a su archivo debajo de viewDidLoad:

func setupSmileTracker () {
   let configuration = ARFaceTrackingConfiguration ()
   sceneView.session.run (configuración)
   sceneView.delegate = self
   view.addSubview (sceneView)
}

Aquí creamos una configuración para manejar el seguimiento de rostros y la usamos para ejecutar nuestra sesión ARSession de sceneView.

Luego configuramos el delegado de sceneView en self y lo agregamos a nuestra vista.

Xcode le dirá que hay un problema ya que ViewController no se ajusta a ARSCNViewDelegate. Vaya a donde se declara ViewController cerca de la parte superior del archivo y cambie la línea a la siguiente:

clase ViewController: ViewController, ARSCNViewDelegate {
   ...
}

Ahora agregue esta función ARSCNViewDelegate en su clase de ViewController setupSmileTracker:

renderizador de funciones (_renderer: SCNSceneRenderer, nodo didUpdate: SCNNode, para el ancla: ARAnchor) {
}

el renderizador se ejecutará cada vez que nuestra escena se actualice y nos proporcione el ARAnchor que corresponde a la cara del usuario.

Para facilitar la creación de experiencias de seguimiento de rostros, Apple crea automáticamente un ARFaceAnchor y lo agrega a nuestra sesión cuando usamos un ARFacetrackingConfiguration para ejecutarlo. Este ARFaceAnchor se pasa al renderizador como un ARAnchor.

Agregue el siguiente código al renderizador:

renderizador de funciones (_renderer: SCNSceneRenderer, nodo didUpdate: SCNNode, para el ancla: ARAnchor) {
   // 1
   guardia deja faceAnchor = ancla como? ARFaceAnchor else {return}
   // 2
   let leftSmileValue = faceAnchor.blendshapes [.mouthSmileLeft] como! CGFloat
   let rightSmileValue = faceAnchor.blendShapes [.mouthSmileRight] como! CGFloat
   // 3
   print (leftSmileValue, rightSmileValue)
}

Hay muchas cosas dentro de esta función, así que he numerado los pasos (estilo Ray Wenderlich).

En el paso 1, convertimos el ARAnchor en un ARFaceAnchor y lo asignamos a la variable faceAnchor.

ARFaceAnchor contiene información sobre la posición y orientación actuales, la topología y la expresión facial de la cara que estamos rastreando.

ARFaceAnchor almacena información sobre expresiones faciales en su variable blendShapes. blendShapes es un diccionario que almacena los coeficientes correspondientes a varias características faciales. Si está interesado, le sugiero que consulte la lista completa de características faciales en la documentación de Apple. (Sugerencia: si desea agregar el seguimiento del ceño, encontrará una manera de hacerlo aquí).

En el paso 2, usamos faceAnchor.blendShapes para obtener un CGFloat que corresponde a cuánto sonríen los lados izquierdo y derecho de la boca del usuario usando las teclas mouthSmileLeft y mouthSmileRight.

Finalmente, el paso 3 simplemente imprime los dos valores para que pueda asegurarse de que funciona correctamente .

En este punto, debería tener una aplicación que:

  • Obtiene los permisos de cámara y seguimiento facial del usuario
  • Utiliza ARKit para rastrear las expresiones faciales de los usuarios
  • Imprime cuánto sonríe el usuario en los lados izquierdo y derecho de su boca a la consola

Hemos progresado mucho, así que tomemos un segundo para asegurarnos de que todo funcione correctamente.

Cuando ejecuta la aplicación por primera vez, se le debe preguntar si otorgará permisos de cámara. Asegúrate de decir que sí.

Luego se lo enviará a una pantalla en blanco, pero debería comenzar a ver los valores de CGFloat que se imprimen en la consola (puede haber un breve retraso antes de verlos).

Cuando sonríe a su teléfono, debe notar que los valores que se imprimen suben. Cuanto más sonríes, más altos son los números.

Si funciona correctamente, ¡felicidades! Si se encuentra con un error, verifique dos veces para asegurarse de que su dispositivo sea compatible con el seguimiento facial y que tenga activados los permisos de la cámara. Si ha seguido este informe desde el principio, la consola imprimirá errores en ambos casos.

Interfaz de usuario

Así que estamos rastreando caras, ahora construyamos la interfaz de usuario para reaccionar a las sonrisas.

Primero agregue un nuevo UILabel llamado smileLabel al principio del archivo, justo debajo de sceneView.

clase ViewController: UIViewController {
   let sceneView = ARSCNView ()
   deja que smileLabel = UILabel ()
   ...
}

Esta será la vista que reaccionará a las expresiones faciales del usuario.

Agregue el siguiente código en la parte inferior de su función setupSmileTracker:

smileLabel.text = ""
smileLabel.font = UIFont.systemFont (ofSize: 150)
view.addSubview (smileLabel)
// Establecer restricciones
smileLabel.translatesAutoresizingMaskIntoConstraints = false
smileLabel.centerXAnchor.constraint (equalTo: view.centerXAnchor) .isActive = true
smileLabel.centerYAnchor.constraint (equalTo: view.centerYAnchor) .isActive = true

Aquí, estamos agregando las propiedades básicas de la interfaz de usuario a nuestro smileLabel y configurando sus restricciones para que esté en el medio de la pantalla. Ahora, cuando ejecutas la aplicación, deberías ver un emoji gigante en el medio.

Una vez que vea aparecer los emoji, agregue la siguiente función a su ViewController:

func handleSmile (leftValue: CGFloat, rightValue: CGFloat) {
      let smileValue = (leftValue + rightValue) /2.0
      cambiar smileValue {
      caso _ donde smileValue> 0.5:
         smileLabel.text = ""
      caso _ donde smileValue> 0.2:
         smileLabel.text = ""
      defecto:
         smileLabel.text = ""
      }
}

Esta función cambiará los emoji en nuestro smileLabel dependiendo de cuánto esté sonriendo el usuario a la cámara. Calculamos el valor de sonrisa tomando el promedio de los valores de sonrisa izquierda y derecha que nos da nuestro ARFaceAnchor (muy científico, lo sé).

Conecte ese valor en la declaración de cambio, y cuanto más sonríe el usuario, más feliz se vuelve nuestro emoji.

Finalmente, regrese a nuestra función de renderizador y agregue esto en la parte inferior para conectar nuestros valores de sonrisa izquierda y derecha en handleSmile:

DispatchQueue.main.async {
   self.handleSmile (leftValue: leftSmileValue, rightValue: rightSmileValue)
}

Nuevamente, utilizamos DispatchQueue porque estamos haciendo cambios en la interfaz de usuario, que debe hacerse en el hilo principal.

Cuando ejecute la aplicación, ahora debería ver el cambio de emoji dependiendo de cuánto le sonríe.

En el siguiente gif, agregué mi rostro para que puedas verlo trabajando con la salida de la cámara junto con el emoji.

Agregué la salida de la cámara para mostrar cómo funciona

Su aplicación no tendrá la salida de la cámara, pero puede agregarla agregando nuestro ARSCNView, sceneView, a la supervista y dándole dimensiones.

Terminando

Espero que esta publicación te haya sido útil para comenzar a crear aplicaciones con ARKit.

Si desea ampliar aún más esta aplicación, consulte la lista que mencioné anteriormente con todas las otras características faciales que puede rastrear. Dejé una pista sobre cómo extender esto para buscar ceños fruncidos también.

Regrese y comente con cualquier proyecto genial que cree por su cuenta, todavía me estoy mojando los pies con estas cosas, así que estaría emocionado de ver aplicaciones más complejas.

Publiqué todo el código de esta aplicación en Github para recibir comentarios y preguntas. ¡Gracias por leer y buena suerte!

Gracias por leer! Si te gustó esta historia, sígueme en Twitter donde publico actualizaciones sobre las historias en las que estoy trabajando y lo que estoy haciendo.