Spanish (Español) translation by CYC (you can also view the original English article)
Introducido con las bibliotecas de Vision en Play Services 8.1, Face Detection te facilita, como desarrollador, analizar un video o una imagen para localizar rostros humanos. Una vez que tienes una lista de caras detectadas en una imagen, puedes recopilar información sobre cada cara, como orientación, probabilidad de sonreír, si alguien tiene los ojos abiertos o cerrados y puntos de referencia específicos en su rostro.
Esta información puede ser útil para múltiples aplicaciones, como una aplicación de cámara que toma automáticamente una foto cuando todos en el cuadro sonríen con los ojos abiertos o para aumentar las imágenes con efectos tontos, como los cuernos de unicornio. Es importante tener en cuenta que la detección de rostros no es un reconocimiento facial. Si bien se puede recopilar información sobre un rostro, la biblioteca de Visión no utiliza esa información para determinar si dos caras provienen de la misma persona.
Este tutorial utilizará una imagen fija para ejecutar la API de detección de rostros y recopilar información sobre las personas en la foto, al tiempo que ilustra esa información con gráficos superpuestos. Todo el código para este tutorial se puede encontrar en GitHub.

1. Configuración del proyecto
Para agregar la biblioteca de Vision a tu proyecto, debes importar Play Services 8.1 o superior. Este tutorial solo importa la biblioteca Play Services Vision. Abre el archivo build.gradle de tu proyecto y agrega la siguiente línea de compilación al nodo de dependencias
.
compile 'com.google.android.gms:play-services-vision:8.1.0'
Una vez que hayas incluido Play Services en tu proyecto, puedes cerrar el archivo build.gradle de tu proyecto y abrir AndroidManifest.xml. Debes agregar un elemento de meta-data
que defina la dependencia de la cara en el nodo application
de tu manifiesto. Esto le permite a la biblioteca de Vision saber que tienes previsto detectar rostros dentro de tu aplicación.
<meta-data android:name="com.google.android.gms.vision.DEPENDENCIES" android:value="face"/>
Una vez que hayas terminado de configurar AndroidManifest.xml, puedes continuar y cerrarlo. A continuación, debes crear una nueva clase llamada FaceOverlayView.java. Esta clase extiende View
y contiene la lógica para detectar caras en el proyecto, mostrando el mapa de bits que se analizó y dibujando en la parte superior de la imagen para ilustrar los puntos.
Por ahora, comienza agregando las variables miembro en la parte superior de la clase y definiendo los constructores. El objeto Bitmap
se utilizará para almacenar el mapa de bits que se analizará y los objetos SparseArray
de Face
almacenarán cada cara que se encuentre en el mapa de bits.
public class FaceOverlayView extends View { private Bitmap mBitmap; private SparseArray<Face> mFaces; public FaceOverlayView(Context context) { this(context, null); } public FaceOverlayView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public FaceOverlayView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } }
A continuación, agrega un nuevo método dentro de FaceOverlayView
llamado setBitmap
(Bitmap bitmap). Por ahora, esto simplemente guardará el mapa de bits que se le pasó, sin embargo, más adelante utilizarás este método para analizar la imagen.
public void setBitmap( Bitmap bitmap ) { mBitmap = bitmap; }
Luego, necesitas un mapa de bits. He incluido uno en el proyecto de muestra en GitHub, pero puedes usar cualquier imagen que desees para jugar con Face Detection y ver qué funciona y qué no. Cuando hayas seleccionado una imagen, colócala en el directorio res/raw. Este tutorial supondrá que la imagen se llama face.jpg.
Después de haber colocado tu imagen en el directorio res/raw, abre res/layout/activity_main.xml. Este diseño contiene una referencia a FaceOverlayView
para que se muestre en MainActivity
.
<?xml version="1.0" encoding="utf-8"?> <com.tutsplus.facedetection.FaceOverlayView xmlns:android="https://schemas.android.com/apk/res/android" android:id="@+id/face_overlay" android:layout_width="match_parent" android:layout_height="match_parent" />
Con el diseño definido, abre MainActivity
y configura FaceOverlayView
desde onCreate()
. Para ello, obtén una referencia a la vista, lee el archivo de imagen face.jpg del directorio sin formato como flujo de entrada y conviértelo en un mapa de bits. Una vez que tengas el mapa de bits, puedes llamar a setBitmap
en FaceOverlayView
para pasar la imagen a tu vista personalizada.
public class MainActivity extends AppCompatActivity { private FaceOverlayView mFaceOverlayView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mFaceOverlayView = (FaceOverlayView) findViewById( R.id.face_overlay ); InputStream stream = getResources().openRawResource( R.raw.face ); Bitmap bitmap = BitmapFactory.decodeStream(stream); mFaceOverlayView.setBitmap(bitmap); } }
2. Detectando Caras
Ahora que tu proyecto está configurado, es hora de comenzar a detectar caras. En setBitmap (Bitmap bitmap)
necesitas crear un FaceDetector
. Esto se puede hacer utilizando un FaceDetector.Builder
, que te permite definir múltiples parámetros que afectan la rapidez con que se detectarán las caras y qué otros datos generará FaceDetector
.
La configuración que elijas dependerá de lo que estés intentando hacer en tu aplicación. Si habilitas la búsqueda de puntos de referencia, las caras se detectarán más lentamente. Al igual que con la mayoría de las cosas en la programación, todo tiene sus ventajas y desventajas. Para obtener más información sobre las opciones disponibles para FaceDetector.Builder
, puedes encontrar la documentación oficial en el sitio web para desarrolladores Android.
FaceDetector detector = new FaceDetector.Builder( getContext() ) .setTrackingEnabled(false) .setLandmarkType(FaceDetector.ALL_LANDMARKS) .setMode(FaceDetector.FAST_MODE) .build();
También necesitas un control para ver si FaceDetector
está operativo. Cuando un usuario usa la detección de rostros por primera vez en su dispositivo, Play Services debe salir y obtener un conjunto de pequeñas bibliotecas nativas para procesar la solicitud de su aplicación. Aunque esto casi siempre se hará antes de que tu aplicación haya terminado de iniciarse, es importante manejar la contingencia de que esto ha fallado.
Si FaceDetector
está operativo, puedes convertir su mapa de bits en un objeto Frame
y pasarlo al detector para recopilar datos sobre las caras en la imagen. Cuando hayas terminado de detectar rostros, invoca invalidate() para activar el redibujado de la vista. Cuando hayas terminado de detectar rostros, invoca invalidate()
para activar el redibujado de la vista.
if (!detector.isOperational()) { //Handle contingency } else { Frame frame = new Frame.Builder().setBitmap(bitmap).build(); mFaces = detector.detect(frame); detector.release(); } invalidate();
Ahora que has detectado las caras en tu imagen, es hora de usarlas. Para este ejemplo, simplemente dibujarás un cuadro verde alrededor de cada cara. Como se llamó a invalidate()
después de que se detectaron las caras, puedes agregar toda la lógica necesaria en onDraw (Canvas canvas)
. Este método asegura que el mapa de bits y las caras están configurados, luego dibuja el mapa de bits en el lienzo y luego dibuja un cuadro alrededor de cada cara.
Dado que los diferentes dispositivos tienen diferentes tamaños de pantalla, también se hará un seguimiento del tamaño de la escala de bits para que toda la imagen esté siempre visible en el dispositivo y todas las superposiciones se dibujen adecuadamente.
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if ((mBitmap != null) && (mFaces != null)) { double scale = drawBitmap(canvas); drawFaceBox(canvas, scale); } }
El método drawBitmap (Canvas canvas)
dibuja su mapa de bits en el lienzo y lo dimensiona de forma adecuada al mismo tiempo que devuelve un multiplicador para escalar sus otras dimensiones correctamente.
private double drawBitmap( Canvas canvas ) { double viewWidth = canvas.getWidth(); double viewHeight = canvas.getHeight(); double imageWidth = mBitmap.getWidth(); double imageHeight = mBitmap.getHeight(); double scale = Math.min( viewWidth / imageWidth, viewHeight / imageHeight ); Rect destBounds = new Rect( 0, 0, (int) ( imageWidth * scale ), (int) ( imageHeight * scale ) ); canvas.drawBitmap( mBitmap, null, destBounds, null ); return scale; }
El método drawFaceBox (Canvas canvas, double scale)
se vuelve un poco más interesante. Cada cara que se detectó y guardó tiene un valor de posición arriba y a la izquierda de cada cara. Este método tomará esa posición y dibujará un rectángulo verde a partir de él para abarcar cada cara en función de su ancho y alto.
Debes definir tu objeto Paint
y luego recorrer cada Face
en tu SparseArray
para encontrar su posición, ancho y alto, y dibujar el rectángulo en el lienzo usando esa información.
private void drawFaceBox(Canvas canvas, double scale) { //paint should be defined as a member variable rather than //being created on each onDraw request, but left here for //emphasis. Paint paint = new Paint(); paint.setColor(Color.GREEN); paint.setStyle(Paint.Style.STROKE); paint.setStrokeWidth(5); float left = 0; float top = 0; float right = 0; float bottom = 0; for( int i = 0; i < mFaces.size(); i++ ) { Face face = mFaces.valueAt(i); left = (float) ( face.getPosition().x * scale ); top = (float) ( face.getPosition().y * scale ); right = (float) scale * ( face.getPosition().x + face.getWidth() ); bottom = (float) scale * ( face.getPosition().y + face.getHeight() ); canvas.drawRect( left, top, right, bottom, paint ); } }
En este punto, deberías poder ejecutar tu aplicación y ver tu imagen con rectángulos alrededor de cada cara que se ha detectado. Es importante tener en cuenta que la API de detección de rostros todavía es bastante nueva en el momento de escribir este documento y es posible que no detecte todos los rostros. Puedes jugar con algunas de las configuraciones en el objeto FaceDetector.Builder
para, afortunadamente, recopilar más datos, aunque no está garantizado.

3. Comprender los hitos
Los puntos de referencia son puntos de interés en una cara. La API de detección de rostros no usa puntos de referencia para detectar una cara, sino que más bien detecta una cara en su totalidad antes de buscar puntos de referencia. Es por eso que descubrir puntos de referencia es una configuración opcional que se puede habilitar a través del FaceDetector.Builder
.
Puedes utilizar estos puntos de referencia como una fuente de información adicional, como por ejemplo dónde están los ojos del sujeto, para que pueda reaccionar adecuadamente dentro de tu aplicación. Hay doce puntos de referencia que se pueden encontrar:
- ojo izquierdo y derecho
- oreja izquierda y derecha
- punta de oído izquierdo y derecho
- base de la nariz
- mejilla izquierda y derecha
- esquina izquierda y derecha de la boca
- base de la boca
Los puntos de referencia disponibles dependen del ángulo de la cara detectada. Por ejemplo, alguien mirando hacia un lado solo tendrá un ojo visible, lo que significa que el otro ojo no será detectable. La siguiente tabla describe qué puntos de referencia deberían ser detectables según el ángulo Y de Euler (dirección izquierda o derecha) de la cara.
Euler Y | Puntos de referencia visibles |
---|---|
<-36 ° | ojo izquierdo, boca izquierda, oreja izquierda, base nasal, mejilla izquierda |
-36° a -12° | boca izquierda, base de la nariz, boca inferior, ojo derecho, ojo izquierdo, mejilla izquierda, punta de la oreja izquierda |
-12° a 12° | ojo derecho, ojo izquierdo, base de la nariz, mejilla izquierda, mejilla derecha, boca izquierda, boca derecha, boca inferior |
12° a 36° | ojo derecho, ojo izquierdo, base de la nariz, mejilla izquierda, mejilla derecha, boca izquierda, boca derecha, boca inferior |
> 36° | ojo derecho, boca derecha, oreja derecha, base de nariz, mejilla derecha |
Los puntos de referencia también son increíblemente fáciles de usar en tu aplicación, ya que los has incluido durante la detección de rostros. Simplemente necesitas llamar a getLandmarks()
en un objeto Face
para obtener una lista
de objetos Landmark
con los que puedes trabajar.
En este tutorial, pintarás un pequeño círculo en cada punto de referencia detectado llamando a un nuevo método, drawFaceLandmarks (Canvas canvas, double scale)
, de onDraw (canvas canvas)
en vez de drawFaceBox (Canvas canvas, double scale)
. Este método toma la posición de cada punto de referencia, lo ajusta a la escala del mapa de bits y luego muestra el círculo indicador de punto de referencia.
private void drawFaceLandmarks( Canvas canvas, double scale ) { Paint paint = new Paint(); paint.setColor( Color.GREEN ); paint.setStyle( Paint.Style.STROKE ); paint.setStrokeWidth( 5 ); for( int i = 0; i < mFaces.size(); i++ ) { Face face = mFaces.valueAt(i); for ( Landmark landmark : face.getLandmarks() ) { int cx = (int) ( landmark.getPosition().x * scale ); int cy = (int) ( landmark.getPosition().y * scale ); canvas.drawCircle( cx, cy, 10, paint ); } } }
Después de llamar a este método, deberías ver pequeños círculos verdes que cubren las caras detectadas, como se muestra en el siguiente ejemplo.

4. Datos faciales adicionales
Si bien la posición de una cara y sus puntos de referencia son útiles, también puedes encontrar más información sobre cada cara detectada en tu aplicación a través de algunos métodos integrados del objeto Face
. Los métodos getIsSmilingProbability()
, getIsLeftEyeOpenProbability()
y getIsLightEyeOpenProbability()
intentan determinar si los ojos están abiertos o si la persona detectada sonríe al devolver un float que va de 0.0 a 1.0. Cuanto más cerca de 1.0, es más probable que la persona esté sonriendo o tenga abierto el ojo izquierdo o derecho.
También puedes encontrar el ángulo de la cara en los ejes Y y Z de una imagen al verificar sus valores de Euler. El valor de Z Euler siempre se informará, sin embargo, debes usar el modo preciso cuando detectes rostros para recibir el valor X. Puedes ver un ejemplo de cómo obtener estos valores en el siguiente fragmento de código.
private void logFaceData() { float smilingProbability; float leftEyeOpenProbability; float rightEyeOpenProbability; float eulerY; float eulerZ; for( int i = 0; i < mFaces.size(); i++ ) { Face face = mFaces.valueAt(i); smilingProbability = face.getIsSmilingProbability(); leftEyeOpenProbability = face.getIsLeftEyeOpenProbability(); rightEyeOpenProbability = face.getIsRightEyeOpenProbability(); eulerY = face.getEulerY(); eulerZ = face.getEulerZ(); Log.e( "Tuts+ Face Detection", "Smiling: " + smilingProbability ); Log.e( "Tuts+ Face Detection", "Left eye open: " + leftEyeOpenProbability ); Log.e( "Tuts+ Face Detection", "Right eye open: " + rightEyeOpenProbability ); Log.e( "Tuts+ Face Detection", "Euler Y: " + eulerY ); Log.e( "Tuts+ Face Detection", "Euler Z: " + eulerZ ); } }
Conclusión
En este tutorial, has aprendido acerca de uno de los componentes principales de la biblioteca de Play Services Vision, Face Detection. Ahora sabes cómo detectar rostros en una imagen fija, cómo reunir información y encontrar puntos de referencia importantes para cada rostro.
Usando lo que has aprendido, deberías poder agregar algunas características excelentes a tus propias aplicaciones para aumentar las imágenes fijas, las pistas de seguimiento en una transmisión de video o cualquier otra cosa que puedas imaginar.
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Update me weeklyEnvato Tuts+ tutorials are translated into other languages by our community members—you can be involved too!
Translate this post