¿Cómo configurar los métodos de verificación de rostro y selfie en Android?
Adentrarse en el mundo de la programación para Android te abre múltiples puertas, permitiéndote explorar herramientas avanzadas y técnicas para mejorar la experiencia del usuario. En esta lección, aprenderemos a establecer los métodos para verificar el rostro y lograr que se visualice en una cámara de selfies configurada desde nuestra aplicación. ¡Vamos allá!
¿Cómo establecer la comunicación entre botones y el tipo de detección?
Para iniciar, debemos configurar el código que nuestros botones enviarán para indicar el tipo de detección que deseamos utilizar.
Intent intent =newIntent();intent.putExtra("detect_mode",1002);// Código para un botónintent.putExtra("detect_mode",1003);// Código para otro botón
Este procedimiento ayuda a diferenciar qué acción debe tomar la aplicación con base en el botón presionado, facilitando la comunicación entre el botón y la lógica de detección.
¿Cómo almacenar el estado en Android?
Cuando trabajamos con orientación en las aplicaciones, es crucial guardar el estado en ciertas ocasiones. Aquí es donde entra en juego saveInstanceState.
Este fragmento garantiza que el motor de lentes se inicialice correctamente, mientras se manejan excepciones que pueden surgir durante la sincronización con la cámara.
¿Cuál es el uso de los estados del ciclo de vida en la cámara?
Es indispensable gestionar los ciclos de vida de la cámara para asegurar que funcione adecuadamente. Aquí los eventos onResume, onPause y onDestroy son clave.
Estos métodos permiten que la cámara se detenga, libere recursos o inicie en función de los estados de la aplicación.
¿Cómo validar el modo de detección al crear la actividad?
Al crear la actividad, es importante asegurar que el modo de detección se reciba correctamente desde la actividad principal.
Intent intent =getIntent();try{ detectMode = intent.getIntExtra("detect_mode",1);}catch(RuntimeException e){Log.e("Error","No pude traer el código de detección");}
Esta comprobación preliminar es esencial para adaptarse a las necesidades de detección deseadas y evitar errores de ejecución.
¿Qué hacer si la visualización en cámara falla?
A veces, pueden surgir problemas de visualización que deben ser resueltos. Al estar configurados los callbacks del SurfaceHolder y ajustar proporciones, se mitigan estos inconvenientes.
Corregir la proporción de la imagen también es crucial para una sincronización visual adecuada.
¿Qué pasos seguir para probar la cámara?
Finalmente, después de realizar estas configuraciones, es hora de probar nuestra cámara:
Corre la aplicación.
Instala la aplicación en un dispositivo Android.
Al dar clic a uno de los botones y autorizar los permisos con Huawei ID, observa si el rostro aparece en la cámara.
Estos pasos te llevarán a ver tus resultados en acción y te permitirán hacer ajustes sobre la marcha.
En conclusión, esta clase te ha armado con las herramientas necesarias para visualizar rostros a través de una cámara de selfies configurada en Android. Prepárate para la próxima clase, donde incorporaremos la detección de sonrisa y más características que enriquecerán tu aplicación. ¡Adelante, sigue explorando y aprendiendo!
Ademas de detección de rostros ML Kit proporciona una amplia variedad de funciones tales como clasificacion de imagenes, traduccion de texto, generador de audio a partir de texto, identificacion de tarjetas bancarias, etc
Hola
Mi código ha tirado un error .. Básicamente es un NullPointerException XD:
E/SurfaceView:Exception configuring surface
kotlin.KotlinNullPointerException at com.pirris.hselfiecamera.camera.LensEnginePreview.startIfReady(LensEnginePreview.kt:139) at com.pirris.hselfiecamera.camera.LensEnginePreview$SurfaceCallback.surfaceCreated(LensEnginePreview.kt:164) at android.view.SurfaceView.updateSurface(SurfaceView.java:728) at android.view.SurfaceView$2.onPreDraw(SurfaceView.java:151) at android.view.ViewTreeObserver.dispatchOnPreDraw(ViewTreeObserver.java:977) at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2573) at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1558) at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7463) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1041) at android.view.Choreographer.doCallbacks(Choreographer.java:847) at android.view.Choreographer.doFrame(Choreographer.java:774) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1027) at android.os.Handler.handleCallback(Handler.java:809) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:166) at android.app.ActivityThread.main(ActivityThread.java:7555) at java.lang.reflect.Method.invoke(NativeMethod) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:469) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:963)
Al parecer el error se encuentra en las líneas 139 y 164 de la clase LensEnginePreview, acá el código del método startIfReady():
//Función para verificar que la cámara se encuentra lista para funcionar @Throws(IOException::class) fun startIfReady(){if(mStartRequested && mSurfaceAvailable){ mLensEngine!!.run(mSurfaceView.holder)if(overlay !=null){ val size:Size= mLensEngine!!.displayDimension val min:Int= size.width.coerceAtMost(size.height) val max:Int= size.width.coerceAtLeast((size.height))if(Configuration.ORIENTATION_PORTRAIT== mContext.resources.configuration.orientation){ mOverlay!!.setCameraInfo(min, max, mLensEngine!!.lensType)// ESTA ES LA LÍNEA 139}else{ mOverlay!!.setCameraInfo(max, min, mLensEngine!!.lensType)} mOverlay!!.clear()} mStartRequested =false}}
Como dato interesante, revisando el código, detecté que al crear el inner class SurfaceCallback, la clase padre SurfaceHolder,Callback no me permite declarar los parámetros tipo SurfaceHolder como nullsafety... Ver a continuación:
private inner classSurfaceCallback:SurfaceHolder.Callback{ override fun surfaceChanged(p0:SurfaceHolder,p1:Int,p2:Int,p3:Int){} override fun surfaceDestroyed(p0:SurfaceHolder){ mSurfaceAvailable =false} override fun surfaceCreated(p0:SurfaceHolder){ mSurfaceAvailable =truetry{startIfReady()}catch(e:IOException){Log.e("Error:","No pudimos iniciar la camara $e")}}}}
En el código ejemplo de la clase, cuando el profesor implementa los miembros de la clase, los mismos se incorporan automáticamente como nullsafety para los parámetros tipo SurfaceHolder, no obstante en mi caso si los intento declarar como nullsafety(?) me marca un error.. es como si se tratase de clases completamente diferentes...
Agradezco de antemanos cualquier ayuda.
Hola
Para agregar más información acerca de este error... el mismo se da al presionar el botón mostPeople, es decir con el detectMode == 1002 ... Acorde al código, por el momento solo se ha programado para el código "1003" proveniente del segundo botón.
Revisando el código desarrollado para la clase LiveFaceActivityCamera.kt, encontré el posible error que impedía el buen funcionamiento del botón mostPeople.
Básicamente en el siguiente segmento:
private fun startLensEngine(){ restartButton!!.visibility=View.GONEif(mLensEngine !=null){try{//Al traer la cámara debemos de manejar todas las excepciones posiblesif(detectMode ==1003){ mPreview!!.start(mLensEngine, overlay)}else{ mPreview!!.start(mLensEngine)}}catch(e:IOException){ mLensEngine!!.release() mLensEngine =null}}}
Nótese que en la sentencia else{}, al método "mPreview!!.start()" solo se le está pasando 1 parámetro, el cual es mLensEngine, sin embargo no se le asigna el parámetro overlay.
Esto, desde mi punto de vista hace que el método start() de la clase LensEnginePreview detenga la aplicación, ya que existen 2 métodos start, los cuales difieren en los parámetros que reciben, y curiosamente el método que solo recibe un parámetro tipo LensEngine está incompleto (acorde a las notas del profesor en la clase):
@Throws(IOException::class) fun start(lensEngine:LensEngine?,overlay:GraphicOverlay?){ mOverlay = overlay
start(lensEngine)}//Función para inicializar la cámara, esta función es una sobreescritura de la función start anterior @Throws(IOException::class) fun start(lensEngine:LensEngine?){if(lensEngine ==null){stop()} mLensEngine = lensEngine
if(mLensEngine !=null){ mStartRequested =true//Vamos a crear una función que nos va a decir si la cámara está lista}}
Dejo esto por acá en caso de que alguien experimente una situación similar.
Por otro lado, si desean ver ambos botones funcionar, comparto el siguiente código temporal:
private fun startLensEngine(){ restartButton!!.visibility=View.GONEif(mLensEngine !=null){try{//Al traer la cámara debemos de manejar todas las excepciones posiblesif(detectMode ==1003){ mPreview!!.start(mLensEngine, overlay)}else{ mPreview!!.start(mLensEngine, overlay)}}catch(e:IOException){ mLensEngine!!.release() mLensEngine =null}}}
Otra alternativa:
private fun startLensEngine(){ restartButton!!.visibility=View.GONEif(mLensEngine !=null){try{//Al traer la cámara debemos de manejar todas las excepciones posiblesif(detectMode ==1003|| detectMode ==1002){ mPreview!!.start(mLensEngine, overlay)}else{ mPreview!!.start(mLensEngine)}}catch(e:IOException){ mLensEngine!!.release() mLensEngine =null}}}