HMS ML Kit detecta una sonrisa al tomar una fotografía
Tags: huawweimobileservices, hmscore, android
Published: 2020-10-05 23:43:40

Introducción

El Kit de Machine Learning(MLKit) es uno de los servicios más importantes.

¿Qué puede hacer ML KIT? ¿Cuál de los siguientes problemas se puede resolver durante el desarrollo de la aplicación?

Hoy, tomemos la detección de rostros como un ejemplo para mostrarle las poderosas funciones de MLKIT y la conveniencia que brinda a los desarrolladores.
1. Capacidades proporcionadas por MLKIT Face Detection

Primero, veamos la capacidad de detección de rostros de Huawei Machine Learning Service (MLKIT)

Como se muestra en la animación, el reconocimiento facial puede reconocer la dirección de la cara, detectar expresiones faciales (como feliz, disgustado, sorprendido, triste y enojado), detectar atributos faciales (como género, edad y accesorios) y detectar ya sea para abrir o cerrar los ojos, admite la detección coordinada de características tales como caras, narices, ojos, labios y cejas. Además, se pueden detectar varias caras al mismo tiempo.
![0 mOk7olj65JUPhTXt](https://dev-to-uploads.s3.amazonaws.com/i/1s2ho0vq8h6jn7favewu.gif)
 
Consejos: esta función es gratuita y cubre todos los modelos de Android.
Desarrollo de la función de fotografía de sonrisa

Hoy, usaremos las capacidades de reconocimiento de múltiples rostros y detección de expresión de MLKIT para escribir una pequeña demostración para una instantánea sonriente y realizar una práctica.
Preparaciones de desarrollo

Los preparativos para desarrollar el kit de Huawei HMS son similares. La única diferencia es que se agrega la dependencia Maven y se introduce el SDK.

   1. Agrega el repositorio de Huawei Maven al gradle de nivel de proyecto.

Agrega gradualmente las siguientes direcciones de Maven:
```
// Top-level build file where you can add configuration options common to all sub-projects/modules.buildscript {ext.kotlin_version = "1.3.72"repositories {google()jcenter()maven { url 'https://developer.huawei.com/repo/' } // HUAWEI Maven repository}dependencies {classpath "com.android.tools.build:gradle:4.0.0"classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"classpath 'com.huawei.agconnect:agcp:1.3.1.300'  // HUAWEI agcp plugin// NOTE: Do not place your application dependencies here; they belong// in the individual module build.gradle files}}allprojects {repositories {google()jcenter()maven { url 'https://developer.huawei.com/repo/' } // HUAWEI Maven repository}}task clean(type: Delete) {delete rootProject.buildDir}
```
2. 2.Agrega la dependencia del SDK al archivo build.gradle en el nivel de la aplicación.

Introduzca el SDK de reconocimiento facial y el SDK básico.

```
dependencies{implementation 'com.huawei.hms:ml-computer-vision-face-emotion-model:1.0.4.300'implementation 'com.huawei.hms:ml-computer-vision-face-feature-model:1.0.4.300'implementation 'com.huawei.hms:ml-computer-vision-face-shape-point-model:1.0.4.300'implementation 'com.huawei.hms:ml-computer-vision-face:1.0.4.300'}
```
3. El modelo se agrega al archivo AndroidManifest.xml en modo incremental para descarga automática.

Esto se usa principalmente para actualizar el modelo. Una vez que se optimiza el algoritmo, el modelo se puede descargar automáticamente al teléfono móvil para su actualización.
```
<applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/MaterialTheme"><activity android:name=".face.LiveFaceAnalyseActivity" /><activity android:name=".MainActivity"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity></application>
```
4. Solicita permisos de cámara y almacenamiento en el archivo AndroidManifest.xml.

```
<uses-feature android:name="android.hardware.camera" /><uses-permission android:name="android.permission.CAMERA" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
```
Desarrollo del código

    Creando un analizador facial y tomar fotos cuando se detecte una sonrisa.

Fotos tomadas después de la detección:

1)Configuración de parámetros del analizador

2) Envía la configuración de parámetros del analizador al analizador.

3) En analyzer.setTransaction, transactResult debera ser sobrescrito para procesar el contenido después del reconocimiento facial. Después del reconocimiento facial, se devuelve un nivel de confianza (probabilidad de sonrisa). Solo necesita establecer el nivel de confianza en un cierto valor.
```
private var analyzer: MLFaceAnalyzer? = null
 private fun createFaceAnalyzer() {
     // Create a face analyzer. You can create an analyzer using the provided customized face detection parameter
     // MLFaceAnalyzerSetting
     val setting = MLFaceAnalyzerSetting.Factory()
         .setFeatureType(MLFaceAnalyzerSetting.TYPE_FEATURES)
         .setKeyPointType(MLFaceAnalyzerSetting.TYPE_UNSUPPORT_KEYPOINTS)
         .setMinFaceProportion(0.1f)
         .setTracingAllowed(true)
         .create()
     analyzer = MLAnalyzerFactory.getInstance().getFaceAnalyzer(setting)
     if (detectMode == Constant.NEAREST_PEOPLE) {
         val transactor =
             MLMaxSizeFaceTransactor.Creator(analyzer, object : MLResultTrailer<MLFace?>() {
                 override fun objectCreateCallback(
                     itemId: Int,
                     obj: MLFace?
                 ) {
                     overlay!!.clear()
                     if (obj == null) {
                         return
                     }
                     val faceGraphic = LocalFaceGraphic(
                         overlay!!,
                         obj,
                         this@LiveFaceAnalyseActivity
                     )
                     overlay!!.addGraphic(faceGraphic)
                     val emotion = obj.emotions
                     if (emotion.smilingProbability > smilingPossibility) {
                         safeToTakePicture = false
                         mHandler.sendEmptyMessage(TAKE_PHOTO)
                     }
                 }
 
                 override fun objectUpdateCallback(
                     var1: MLAnalyzer.Result<MLFace?>,
                     obj: MLFace?
                 ) {
                     overlay!!.clear()
                     if (obj == null) {
                         return
                     }
                     val faceGraphic = LocalFaceGraphic(
                         overlay!!,
                         obj,
                         this@LiveFaceAnalyseActivity
                     )
                     overlay!!.addGraphic(faceGraphic)
                     val emotion = obj.emotions
                     if (emotion.smilingProbability > smilingPossibility && safeToTakePicture) {
                         safeToTakePicture = false
                         mHandler.sendEmptyMessage(TAKE_PHOTO)
                     }
                 }
 
                 override fun lostCallback(result: MLAnalyzer.Result<MLFace?>) {
                     overlay!!.clear()
                 }
 
                 override fun completeCallback() {
                     overlay!!.clear()
                 }
             }).create()
         analyzer!!.setTransactor(transactor)
     } else {
         analyzer!!.setTransactor(object : MLTransactor<MLFace> {
             override fun destroy() {}
             override fun transactResult(result: MLAnalyzer.Result<MLFace>) {
                 val faceSparseArray = result.analyseList
                 var flag = 0
                 for (i in 0 until faceSparseArray.size()) {
                     val emotion = faceSparseArray.valueAt(i).emotions
                     if (emotion.smilingProbability > smilingPossibility) {
                         flag++
                     }
                 }
                 if (flag > faceSparseArray.size() * smilingRate && safeToTakePicture) {
                     safeToTakePicture = false
                     mHandler.sendEmptyMessage(TAKE_PHOTO)
                 }
             }
         })
     }
 }
```
Fotografía y almacenamiento:
```
private fun takePhoto() {
     mLensEngine!!.photograph(null,
         PhotographListener { bytes ->
             mHandler.sendEmptyMessage(STOP_PREVIEW)
             val bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.size)
             saveBitmapToDisk(bitmap)
         })
 }
```
2. Creamos un motor visual para capturar transmisiones dinámicas de video desde cámaras y enviar las transmisiones al analizador.
```
private fun createLensEngine() {
     val context: Context = this.applicationContext
     // Create LensEngine
     mLensEngine = LensEngine.Creator(context, analyzer).setLensType(lensType)
         .applyDisplayDimension(640, 480)
         .applyFps(25.0f)
         .enableAutomaticFocus(true)
         .create()
 }
```
3. Aplicación de permisos dinámicos, adjuntando el analizador y el código de creación del motor visual
```
override fun onCreate(savedInstanceState: Bundle?) {
     super.onCreate(savedInstanceState)
     setContentView(R.layout.activity_main)
     if (!allPermissionsGranted()) {
         runtimePermissions
     }
 }
 
 private val runtimePermissions: Unit
     get() {
         val allNeededPermissions: MutableList<String?> = ArrayList()
         for (permission in requiredPermissions) {
             if (!isPermissionGranted(this, permission)) {
                 allNeededPermissions.add(permission)
             }
         }
         if (!allNeededPermissions.isEmpty()) {
             ActivityCompat.requestPermissions(
                 this,
                 allNeededPermissions.toTypedArray(),
                 PERMISSION_REQUESTS
             )
         }
     }
 
 private fun allPermissionsGranted(): Boolean {
     for (permission in requiredPermissions) {
         if (!isPermissionGranted(this, permission)) {
             return false
         }
     }
     return true
 }
 
 private val requiredPermissions: Array<String?>
     get() = try {
         val info = this.packageManager
             .getPackageInfo(this.packageName, PackageManager.GET_PERMISSIONS)
         val ps = info.requestedPermissions
         if (ps != null && ps.size > 0) {
             ps
         } else {
             arrayOfNulls(0)
         }
     } catch (e: RuntimeException) {
         throw e
     } catch (e: Exception) {
         arrayOfNulls(0)
     }
 
 override fun onRequestPermissionsResult(
     requestCode: Int, permissions: Array<String>,
     grantResults: IntArray
 ) {
     super.onRequestPermissionsResult(requestCode, permissions, grantResults)
     if (requestCode != PERMISSION_REQUESTS) {
         return
     }
     var isNeedShowDiag = false
     for (i in permissions.indices) {
         if (permissions[i] == Manifest.permission.READ_EXTERNAL_STORAGE && grantResults[i] != PackageManager.PERMISSION_GRANTED
         ) {
             // If permissions aren't satisfied, show dialog.
             isNeedShowDiag = true
         }
     }
     if (isNeedShowDiag && !ActivityCompat.shouldShowRequestPermissionRationale(
             this,
             Manifest.permission.CALL_PHONE
         )
     ) {
         val dialog: AlertDialog = AlertDialog.Builder(this)
             .setMessage(getString(R.string.camera_permission_rationale))
             .setPositiveButton(
                 getString(R.string.settings)
             ) { dialog, which ->
                 val intent =
                     Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
                 intent.data = Uri.parse("package:$packageName")
                 startActivityForResult(intent, 200)
                 startActivity(intent)
             }
             .setNegativeButton(
                 getString(R.string.cancel),
                 DialogInterface.OnClickListener { dialog, which -> finish() }).create()
         dialog.show()
     }
 }
```
Conclusión

Experimentemos el efecto de la captura de sonrisa de múltiples caras.

Instantánea de una sola sonrisa:
![1 mAEAZtE-wr5TzCmhxAmMmA](https://dev-to-uploads.s3.amazonaws.com/i/gl3oa6yi912loowvy69s.gif)
 
Según la capacidad de detección de rostros, ¿qué funciones se pueden realizar? ¡Abre tu mente a nuevas ideas y características! Aquí hay algunos consejos:

1. Agrega efectos decorativos interesantes identificando la ubicación de los rasgos faciales, como orejas, ojos, nariz, boca y cejas.

2. Identifica los contornos faciales y estira los contornos para generar retratos interesantes o desarrolla funciones de embellecimiento facial para áreas de contornos.

3. Desarrollar algunas funciones de control parental basadas en la identificación de la edad.

4. Desarrolle la función de comodidad ocular detectando la duración de los ojos mirando la pantalla.

5. Implementa la detección de patrones a través de comandos aleatorios (como sacudir la cabeza, parpadear y abrir la boca).

6. Recomendar ofertas a los usuarios en función de su edad y sexo.

Para obtener detalles sobre la guía de desarrollo, visita el sitio web oficial del desarrollador de HUAWEI:
[Link](https://developer.huawei.com/consumer/en/hms/huawei-mlkit)

O puedes visitarnos también en el foro de desarrolladores
[Dev Forum](https://forums.developer.huawei.com/forumPortal/en/home)