Face-Detector SDK

Face-Detector SDK te permite obtener un archivo en formato base64 a través de dos métodos. Puedes tomar una foto y/o video desde la cámara, o subir una imagen o video desde el almacenamiento del dispositivo. Además se agrega detección de rostros al activar la cámara.


Objetivo


Obtener archivos base64 de tipo Rostro, ya sea tomando una foto o video directamente desde la cámara del dispositivo o desde el almacenamiento del dispositivo Android.


Características Clave


  • Simplicidad de integración: Con solo unas pocas líneas de código, puedes agregar capacidades para tomar fotos o videos con la cámara u obtener archivos desde el almacenamiento.
  • Recuperación de base64: El SDK proporciona un archivo base64 obtenido de la cámara o el almacenamiento del dispositivo.
  • Detección de rostros: Modelo de detección de rostros al activar la cámara.

Funcionalidades


  • El SDK proporciona funcionalidades para:
    • Tomar una foto con la cámara del dispositivo Android y devolver un archivo base64.
    • Grabar un video con la cámara del dispositivo Android y devolver un archivo base64.
    • Recuperar una imagen desde el almacenamiento del dispositivo Android y devolver un archivo base64.
    • Recuperar un video desde el almacenamiento del dispositivo Android y devolver un archivo base64.

Empezando


Antes de integrar el SDK en tu proyecto, asegúrate de cumplir con los siguientes requisitos:

  • Android Studio: Tener instalada la versión recomendada de Iguana de Android Studio.
  • Gradle: Usar la versión recomendada de Gradle 8.4.
  • Android Gradle Plugin: Tener la versión recomendada del plugin de Gradle 8.3.2.
  • Compilación del SDK: Configurar la compilación con SDK 35.
  • Compatibilidad de Source y Target: Utilizar las versiones recomendadas de source y target compatibility 18.
  • minSdkVersion: Establecer la versión mínima del SDK en 26.
  • targetSdkVersion: Configurar la versión del SDK objetivo en 33.
  • Groovy DS: La configuración del build gradle, debe de estar en Groovy DSL.

Configuración

  1. Crear una aplicacion

Al crear un proyecto debe de elegirse como No Activity y en la opción de build Configuration Language se debe de elegir: Groovy DSL (build,gradle)

  1. Remplaza el contenido de build.gradle del proyecto por:
buildscript {
    ext.kotlin_version = "1.9.22"
    ext.hilt_version = '2.46'
    repositories {
        google()
        mavenCentral()
        maven {
            url 'https://us-maven.pkg.dev/jaak-platform/jaak-android'
        }
        maven {
            url 'https://jitpack.io'
        }
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:8.3.2'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"
        classpath 'com.google.gms:google-services:4.4.2'
    }
}
tasks.register('clean', Delete) {
    delete rootProject.buildDir
}
  1. Remplaza en el archivo settings.gradle el siguiente bloque de dependencyResolutionManagement:
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
        maven { url 'https://jitpack.io' }
        maven {
            url 'https://us-maven.pkg.dev/jaak-platform/jaak-android'
        }
    }
}
  1. Remplaza la sección de plugins en el archivo build.gradle de app
plugins {
    id 'com.android.application'
    id 'kotlin-android'
    id 'kotlin-kapt'
    id 'dagger.hilt.android.plugin'
}

Remplaza la sección de dependencias en el archivo build.gradle de app

dependencies {
  // Bibliotecas de Kotlin
implementation("org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version")
// Android Jetpack
implementation("androidx.core:core-ktx:1.15.0")
implementation("androidx.appcompat:appcompat:1.7.0")
implementation("androidx.fragment:fragment-ktx:1.8.5")
implementation("androidx.activity:activity-ktx:1.9.3")
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.7")
implementation("androidx.constraintlayout:constraintlayout:2.2.0")
implementation 'com.google.android.material:material:1.12.0'

// Inyección de Dependencias
implementation("com.google.dagger:hilt-android:$hilt_version")
kapt("com.google.dagger:hilt-android-compiler:$hilt_version")
// jaakdocumentdetector
implementation("com.jaak.facedetectorsdk:jaakfacedetector-sdk:2.0.5")
}

Agrega el siguiente bloque en Android en el archivo build.gradle de app

android {
    //Código previo
    //..
    //.
    buildFeatures{
        viewBinding = true
    }
}
  1. Crea una clase kotlin que extienda de Application y agrega la anotación de HiltAndroidApp
import android.app.Application
import dagger.hilt.android.HiltAndroidApp

@HiltAndroidApp
class TestApp : Application()
  1. Crea una clase kotlin con la anotación @AndroidEntryPoint, que extienda de AppCompatActivity() e implementa el listener FaceDetectorListener

Ejemplo de Activity
Nota: Este ejemplo utiliza viewBinding por lo que se debe de crear un layout donde el nombre es como se armara la clase binding.

Ejemplo: layout: activity_main.xml --> El nombre del binding se llamaría ActivityMainBinding
Ejemplo 2: layout: main_activity.xml --> El nombre del binding se llamaría MainActivityBinding

class MainActivity : AppCompatActivity(), FaceDetectorListener {

    private lateinit var binding: MainActivityBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = MainActivityBinding.inflate(layoutInflater)
        setContentView(binding.root)
    }

    override fun onSuccessFaceDetector(typeProcess: Int, uri: Uri?) {
    }
    
    override fun onErrorFaceDetector(text: String) {
    }

Crea una xml para utilizar los viewBinding

Nota: Al crear el xml se debe de agregar la línea:
xmlns:tools="http://schemas.android.com/tools" y la línea: tools:context="nombre_clase_kotlin"

Ejemplo 1: tools:context="com.example.test.MainActivity"
Ejemplo 2: tools:context="com.example.test.ActivityMain"

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 
  xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context="com.example.test.MainActivity">

</androidx.constraintlayout.widget.ConstraintLayout>
  1. Agrega los permisos al archivo AndroidManifest
<manifest>  
 //Código previo
    //..
    //..
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
        tools:replace="android:maxSdkVersion"
        android:maxSdkVersion="28"/>
</manifest>

Agrega las siguientes líneas a application para agregar nuestra App previamente creada, además de unas excepciones

 <application
              //Código previo
    //..
    //..
        android:name="com.example.test.TestApp"
        tools:replace="android:theme,android:name">

Agrega la actividad principal que se creó previamente

<application ..>
  //Código previo
    //..
    //..
        <activity android:name="com.example.test.MainActivity"
            android:exported="true"
            android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

Crearemos un archivo en res/xml/file_paths.xml que contendrá la ruta donde queremos que almacene los videos:

<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- Ruta para acceder a archivos en el directorio de archivos externos privados de la aplicación -->
    <external-path name="my_images" path="Pictures/" />
    <external-path name="my_files" path="Android/data/nombre-de-tu-paquete/files/nombre-de-tu-root-name/" />
</paths>

Aqui está un ejemplo de su llenado:

<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- Ruta para acceder a archivos en el directorio de archivos externos privados de la aplicación -->
    <external-path name="my_images" path="Pictures/" />
    <external-path name="my_files" path="Android/data/com.example.test/files/Test/" />
</paths>

Agregaremos el file provider al Manifest:

Nota: en android:authorities debe de ir el nombre del paquete del proyecto:
Ejemplo 1: android:authorities="com.example.jaakfacedetectorsdk" Ejemplo 2: android:authorities="com.example.test"

<application ..>
  //Código previo
    //..
    //..
        <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="com.example.test"
            android:exported="false"
            android:grantUriPermissions="true"
            tools:replace="android:authorities">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>  
</application>
  1. Implementa la librería de face detector sdk:
private lateinit var faceDetectorSDK: FaceDetectorSDK

Agregue su configuración:

private fun configFaceDetectorSDK(){
        faceDetectorSDK = FaceDetectorSDK(this,this)
        faceDetectorSDK.setEnableCamera(true)
        faceDetectorSDK.setEnableDisk(true)
        faceDetectorSDK.setEnableCameraPhoto(true)
        faceDetectorSDK.setEnableCameraVideo(true)
        faceDetectorSDK.setEnableDiskPhoto(true)
        faceDetectorSDK.setEnableDiskVideo(true)
        faceDetectorSDK.setEnableDiskImageVideo(true)
        faceDetectorSDK.setFacesOrDocuments(true)
        faceDetectorSDK.setEnableModelFaces(true)
        faceDetectorSDK.setImageFormat("image/*")
        faceDetectorSDK.setVideoFormat("video/*")
        faceDetectorSDK.setImageSize(3)
        faceDetectorSDK.setVideoSize(10)
    }

Ejecutar el SDK:

Nota: Si se quiere tener el menú de obtener video por cámara o por almacenamiento, se manda 0.
Si se quiere solo obtener video por cámara se manda 2 y si solo por almacenamiento se manda 4

faceDetectorSDK.startFaceDetector(0)
  1. Obtener el video y convertirlo en base64

En los métodos override del listener FaceDetectorListener, al ser correcto, este devuelve la ubicación del video y para no llenar la memoria al manejar base64
se tiene el siguiente ejemplo para obtener el video:

 override fun onSuccessFaceDetector(typeProcess: Int, uri: Uri?) {
        var base64Proccess = ""
        when (typeProcess) {
            2 -> {
                base64Proccess = Utils.videoCameraUriToBase64(uri!!)!!
            }
            4 -> {
                base64Proccess = Utils.videoFileUriToBase64(contentResolver, uri!!)!!
            }
        }
        Log.e("base64",uri.toString())
    }

El integrador decide cómo proceder con las imágenes en base64


Ejemplo de Código


build.gradle Project

buildscript {
    ext.kotlin_version = "1.9.22"
    ext.hilt_version = '2.46'
    repositories {
        google()
        mavenCentral()
        maven {
            url 'https://us-maven.pkg.dev/jaak-platform/jaak-android'
        }
        maven {
            url 'https://jitpack.io'
        }
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:8.3.2'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"
        classpath 'com.google.gms:google-services:4.4.2'
    }
}
tasks.register('clean', Delete) {
    delete rootProject.buildDir
}

settings.gradle

pluginManagement {
    repositories {
        google {
            content {
                includeGroupByRegex("com\\.android.*")
                includeGroupByRegex("com\\.google.*")
                includeGroupByRegex("androidx.*")
            }
        }
        mavenCentral()
        gradlePluginPortal()
    }
}
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
        maven { url 'https://jitpack.io' }
        maven {
            url 'https://us-maven.pkg.dev/jaak-platform/jaak-android'
        }
    }
}

rootProject.name = "Test"
include ':app'

build.gradle App

plugins {
    id 'com.android.application'
    id 'kotlin-android'
    id 'kotlin-kapt'
    id 'dagger.hilt.android.plugin'
}

android {
    namespace 'com.example.test'
    compileSdk 35

    defaultConfig {
        applicationId "com.example.test"
        minSdk 26
        targetSdk 35
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_11
        targetCompatibility JavaVersion.VERSION_11
    }
    kotlinOptions {
        jvmTarget = '11'
    }
    buildFeatures{
        viewBinding = true
    }
}

dependencies {
    // Bibliotecas de Kotlin
    implementation("org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version")
// Android Jetpack
    implementation("androidx.core:core-ktx:1.15.0")
    implementation("androidx.appcompat:appcompat:1.7.0")
    implementation("androidx.fragment:fragment-ktx:1.8.5")
    implementation("androidx.activity:activity-ktx:1.9.3")
    implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.7")
    implementation("androidx.constraintlayout:constraintlayout:2.2.0")
    implementation 'com.google.android.material:material:1.12.0'

// Inyección de Dependencias
    implementation("com.google.dagger:hilt-android:$hilt_version")
    kapt("com.google.dagger:hilt-android-compiler:$hilt_version")
// jaakdocumentdetector
    implementation("com.jaak.facedetectorsdk:jaakfacedetector-sdk:2.0.5")

}

res/xml/file_paths.xml

<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- Ruta para acceder a archivos en el directorio externo privado de archivos de la aplicación -->
    <external-path name="my_images" path="Pictures/" />
    <external-path name="my_files" path="Android/data/com.example.test/files/Test/" />
</paths>

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
        tools:replace="android:maxSdkVersion"
        android:maxSdkVersion="28"/>

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Test"
        tools:targetApi="31"
        android:name="com.example.test.TestApp"
        tools:replace="android:theme,android:name">
        <activity android:name="com.example.test.MainActivity"
            android:exported="true"
            android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="com.example.test"
            android:exported="false"
            android:grantUriPermissions="true"
            tools:replace="android:authorities">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>
    </application>

</manifest>

TestApp.kt

package com.example.test

import android.app.Application
import dagger.hilt.android.HiltAndroidApp

@HiltAndroidApp
class TestApp : Application()

res/layout/main_activity.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context="com.example.test.MainActivity">


</androidx.constraintlayout.widget.ConstraintLayout>

MainActivity

package com.example.test

import android.net.Uri
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import com.example.test.databinding.MainActivityBinding
import com.jaak.jaakfacedetectorsdk.ui.adapter.FaceDetectorListener
import com.jaak.jaakfacedetectorsdk.ui.view.FaceDetectorSDK
import com.jaak.jaakfacedetectorsdk.utils.Utils
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
class MainActivity : AppCompatActivity(), FaceDetectorListener {

    private lateinit var binding: MainActivityBinding
    private lateinit var faceDetectorSDK: FaceDetectorSDK

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = MainActivityBinding.inflate(layoutInflater)
        setContentView(binding.root)
        configFaceDetectorSDK()
        faceDetectorSDK.startFaceDetector(0)
    }

    private fun configFaceDetectorSDK(){
        faceDetectorSDK = FaceDetectorSDK(this,this)
        faceDetectorSDK.setEnableCamera(true)
        faceDetectorSDK.setEnableDisk(true)
        faceDetectorSDK.setEnableCameraPhoto(true)
        faceDetectorSDK.setEnableCameraVideo(true)
        faceDetectorSDK.setEnableDiskPhoto(true)
        faceDetectorSDK.setEnableDiskVideo(true)
        faceDetectorSDK.setEnableDiskImageVideo(true)
        faceDetectorSDK.setFacesOrDocuments(true)
        faceDetectorSDK.setEnableModelFaces(true)
        faceDetectorSDK.setImageFormat("image/*")
        faceDetectorSDK.setVideoFormat("video/*")
        faceDetectorSDK.setImageSize(3)
        faceDetectorSDK.setVideoSize(10)
    }

    override fun onSuccessFaceDetector(typeProcess: Int, uri: Uri?) {
        var base64Proccess = ""
        when (typeProcess) {
            2 -> {
                base64Proccess = Utils.videoCameraUriToBase64(uri!!)!!
            }
            4 -> {
                base64Proccess = Utils.videoFileUriToBase64(contentResolver, uri!!)!!
            }
        }
        Log.e("base64",uri.toString())
    }

    override fun onErrorFaceDetector(text: String) {
    }
}

Actualización


Se actualizo los repositorios de jaak para la descarga de componentes, el cual es el siguiente:

 maven {
            url 'https://us-maven.pkg.dev/jaak-platform/jaak-android'
        }

Se debe de reemplazar este para que pueda descargar el SDK..

Se actualiza nombre de librería de Face Detector SDK, quedando de la siguiente manera:

dependencies {
implementation("com.jaak.facedetectorsdk:jaakfacedetector-sdk:2.0.5")
        }

Referencias


Ejemplo de uso del SDK en una aplicación Android.

En la siguiente sección, se detallan las opciones del SDK que han sido implementadas en los botones.

  1. Opción que permite obtener una imagen o un video directamente desde el almacenamiento del dispositivo Android.
  2. Opción que permite obtener una fotografía o video desde la cámara del dispositivo Android.




1. Subir imagen o video.

1. La opción Document Uploader brindará al usuario la capacidad de elegir entre "Video" o "Imagen" desde el menú desplegable en dispositivos Android. A continuación, el proceso seguirá con la opción seleccionada.

2. Seleccione el archivo a subir:

  • La opción Imagen abrirá las aplicaciones disponibles en Android que almacenan imágenes. Seleccione la aplicación donde almacena sus imágenes y cargue la que desee.
  • La opción Video abrirá las aplicaciones disponibles en Android que almacenan videos. Seleccione la aplicación donde almacena sus videos y cargue el que desee.

3. El SDK proporciona URIs para los archivos multimedia seleccionados, lo que facilita su incorporación en su aplicación. Permitiendo previsualizar el archivo seleccionado y confirmar si es adecuado o elegir otro.

Ejemplo de Aplicativo: La imagen o video seleccionado se muestra en la aplicación.


2. Tomar imagen o video.

1. La opción Foto ó Video Iniciara el proceso de captura desde el dispositivo.

2. Se despliega una previsualización de la cámara brindando instrucciones para centrar el rostro objetivo.

3. La opción aparecerá dependiendo las características del dispositivo, si la detección automática de rostros no es soportada.

4. Una vez centrado el rostro automáticamente iniciara la cuenta regresiva para capturar la imagen o video.

5. Durante el proceso de grabación, se mostrara un circulo punteado que representa el tiempo faltante para capturar el video además mostrara en un encuadro verde el rostro detectado.

6. Finalmente mostrara una previsualización de la foto o video capturado, permitiendo confirmar con el archivo capturado o volver a capturar.


Durante la captura de una foto o video, si Face-Detector se encuentra activo, proporcionara mensajes diferentes dependiendo la ubicación del rostro para ayudar a centrar el rostro a una distancia moderada.