Explore MediaPipe para detectar puntos clave de la cara

MediaPipe es el marco de procesamiento de visión artificial de código abierto de Google. Se basa en TensorFlow para entrenar modelos y admite reconocimiento facial, puntos clave faciales, detección y seguimiento de objetivos, clasificación de imágenes, segmentación de retratos, reconocimiento de gestos, clasificación de texto, clasificación de voz, etc. Podemos usar la CPU para la inferencia o podemos elegir la GPU para acelerar la inferencia. En la escena de efectos especiales de filtro, a menudo es necesario utilizar los puntos clave de la cara.

 

Tabla de contenido

1. Parámetros y modelos de configuración

1. Parámetros de configuración

2. Modelo de detección 

2. Configuración de ingeniería

3. Trabajo de inicialización

1. Inicializar el modelo

2. Inicializar cámara

4. Detectar transmisión en tiempo real

1. Detectar puntos clave de la cara

2. Dibuja los puntos clave de la cara

5. Resultados

1. Parámetros y modelos de configuración

1. Parámetros de configuración

Los parámetros de configuración para la detección de puntos clave de rostros incluyen el modo de funcionamiento, la cantidad de rostros, la confianza mínima de detección de rostros, la confianza mínima de rostros de visualización, la confianza mínima de rostros de seguimiento y la devolución de llamada de resultado, como se muestra en la siguiente tabla:

opciones describir Rangos valores predeterminados
modo_ejecutando

IMAGEN: imagen única 

VÍDEO: cuadro de vídeo

LIVE_STREAM: transmisión en vivo

{IMAGEN, VÍDEO,

LIVE_STREAM}

IMAGEN
num_caras El número máximo de caras detectadas mayor que 0 1

min_face_detection

_confianza

Confianza mínima de detección de rostros [0.0, 1.0] 0.5

min_face_presence

_confianza

Cara que muestra confianza mínima [0.0, 1.0] 0.5
min_tracking_confidence Confianza mínima de seguimiento facial [0.0, 1.0] 0.5
salida_face_blendshapes Ya sea para generar formas de mezcla (para modelos de rostros en 3D) booleano FALSO

salida_facial_transformación

_matrices

Ya sea para generar la matriz de transformación (para efectos de filtro) booleano FALSO
resultado_devolución de llamada Resultado de devolución de llamada asincrónica (modo LIVE_STREAM) ResultListener    /

2. Modelo de detección 

La detección de los puntos clave de la cara se divide en tres pasos: primero detectar la cara, luego ubicar los puntos clave y finalmente identificar las características faciales. Los modelos utilizados son los siguientes:

  • Modelo de detección de rostros: detecta rostros de acuerdo con las características clave del rostro;
  • Modelo de cuadrícula facial: identificación facial 3D con 478 puntos de coordenadas;
  • Modelo de formas mixtas: predice puntajes para 52 formas mixtas que representan coeficientes para diferentes expresiones; 

2. Configuración de ingeniería

Tomando la plataforma Android como ejemplo, importe paquetes relacionados con MediaPipe en gradle:

implementation 'com.google.mediapipe:tasks-vision:0.10.0'

Luego ejecute la tarea de descargar el modelo y especifique la ruta para guardar el modelo:

project.ext.ASSET_DIR = projectDir.toString() + '/src/main/assets'
apply from: 'download_tasks.gradle'

El modelo utilizado aquí es face_landmarker, establece src y dest:

task downloadTaskFile(type: Download) {
    src 'https://storage.googleapis.com/mediapipe-models/face_landmarker/face_landmarker/float16/1/face_landmarker.task'
    dest project.ext.ASSET_DIR + '/face_landmarker.task'
    overwrite false
}

preBuild.dependsOn downloadTaskFile

3. Trabajo de inicialización

1. Inicializar el modelo

La inicialización del modelo incluye: configurar el modo de ejecución, la ruta del modelo, detectar el número de caras, recuperar los resultados, etc. El código de ejemplo es el siguiente:

    fun setupFaceLandmark() {
        val baseOptionBuilder = BaseOptions.builder()

        // 设置运行模式,默认CPU
        when (currentDelegate) {
            DELEGATE_CPU -> {
                baseOptionBuilder.setDelegate(Delegate.CPU)
            }
            DELEGATE_GPU -> {
                baseOptionBuilder.setDelegate(Delegate.GPU)
            }
        }
        // 设置模型路径
        baseOptionBuilder.setModelAssetPath(MP_FACE_LANDMARKER_TASK)

        try {
            val baseOptions = baseOptionBuilder.build()
            // 设置检测的人脸数、最小的检测人脸置信度
            val optionsBuilder =
                FaceLandmarker.FaceLandmarkerOptions.builder()
                    .setBaseOptions(baseOptions)
                    .setMinFaceDetectionConfidence(minFaceDetectionConfidence)
                    .setMinTrackingConfidence(minFaceTrackingConfidence)
                    .setMinFacePresenceConfidence(minFacePresenceConfidence)
                    .setNumFaces(maxNumFaces)
                    .setRunningMode(runningMode)

            // LIVE_STREAM模式:设置回调结果
            if (runningMode == RunningMode.LIVE_STREAM) {
                optionsBuilder
                    .setResultListener(this::returnLivestreamResult)
                    .setErrorListener(this::returnLivestreamError)
            }

            val options = optionsBuilder.build()
            faceLandmarker =
                FaceLandmarker.createFromOptions(context, options)
        } catch (e: IllegalStateException) {
            faceLandmarkerHelperListener?.onError(
                "Face Landmark failed to initialize, error: " + e.message)
        } catch (e: RuntimeException) {
            faceLandmarkerHelperListener?.onError(
                "Face Landmark failed to initialize. See error logs for details", GPU_ERROR)
        }
    }

2. Inicializar cámara

Tomando el modo LIVE_STREAM como ejemplo, la inicialización de la cámara incluye: configuración del formato de píxeles, vista previa de la relación de aspecto, enlace del ciclo de vida y asociación de SurfaceProvider. El código de ejemplo es el siguiente:

    private fun bindCameraUseCases() {
        val cameraProvider = cameraProvider ?: throw IllegalStateException("Camera init failed.")

        val cameraSelector =
            CameraSelector.Builder().requireLensFacing(cameraFacing).build()

        // 预览的宽高比为4:3
        preview = Preview.Builder().setTargetAspectRatio(AspectRatio.RATIO_4_3)
            .setTargetRotation(fragmentCameraBinding.viewFinder.display.rotation)
            .build()

        // 设置像素格式为RGBA_8888,预览的旋转角度
        imageAnalyzer =
            ImageAnalysis.Builder().setTargetAspectRatio(AspectRatio.RATIO_4_3)
                .setTargetRotation(fragmentCameraBinding.viewFinder.display.rotation)
                .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
                .setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888)
                .build()
                .also {
                    it.setAnalyzer(backgroundExecutor) { image ->
                        // 执行检测人脸关键点
                        faceLandmarkerHelper.detectLiveStream(image, cameraFacing == CameraSelector.LENS_FACING_FRONT)
                    }
                }

        // 绑定之前,先解除绑定
        cameraProvider.unbindAll()

        try {
            // 绑定Lifecycle
            camera = cameraProvider.bindToLifecycle(
                this, cameraSelector, preview, imageAnalyzer)
            // 关联SurfaceProvider
            preview?.setSurfaceProvider(fragmentCameraBinding.viewFinder.surfaceProvider)
        } catch (exc: Exception) {
            Log.e(TAG, "bind lifecycle failed", exc)
        }
    }

4. Detectar transmisión en tiempo real

1. Detectar puntos clave de la cara

Antes de la detección, primero copie los datos, preprocese el marco de la imagen y luego realice la detección:

    fun detectLiveStream(
        imageProxy: ImageProxy,
        isFrontCamera: Boolean) {
        val frameTime = SystemClock.uptimeMillis()

        // 拷贝RGB数据到缓冲区
        val bitmapBuffer =
            Bitmap.createBitmap(
                imageProxy.width,
                imageProxy.height,
                Bitmap.Config.ARGB_8888
            )
        imageProxy.use { bitmapBuffer.copyPixelsFromBuffer(imageProxy.planes[0].buffer) }
        imageProxy.close()

        val matrix = Matrix().apply {
            // 图像旋转
            postRotate(imageProxy.imageInfo.rotationDegrees.toFloat())

            // 如果是前置摄像头,需要左右镜像
            if (isFrontCamera) {
                postScale(-1f, 1f, imageProxy.width.toFloat(), imageProxy.height.toFloat())
            }
        }
        val rotatedBitmap = Bitmap.createBitmap(
            bitmapBuffer, 0, 0, bitmapBuffer.width, bitmapBuffer.height,
            matrix, true)

        // 转换Bitmap为MPImage
        val mpImage = BitmapImageBuilder(rotatedBitmap).build()
        // 异步检测人脸关键点
        faceLandmarker?.detectAsync(mpImage, frameTime)
    }

2. Dibuja los puntos clave de la cara

Después de detectar los puntos clave de la cara, se vuelve a llamar al hilo principal:

   override fun onResults(resultBundle: FaceLandmarkerHelper.ResultBundle) {
        activity?.runOnUiThread {
            if (_fragmentCameraBinding != null) {
                // 显示推理时长
                fragmentCameraBinding.bottomSheetLayout.inferenceTimeVal.text =
                    String.format("%d ms", resultBundle.inferenceTime)

                // 传递结果给OverlayView
                fragmentCameraBinding.overlay.setResults(
                    resultBundle.result,
                    resultBundle.inputImageHeight,
                    resultBundle.inputImageWidth,
                    RunningMode.LIVE_STREAM
                )

                // 主动触发渲染
                fragmentCameraBinding.overlay.invalidate()
            }
        }
    }

Finalmente, dibuje los puntos clave de la cara, incluidas las expresiones faciales y los contornos:

   override fun draw(canvas: Canvas) {
        super.draw(canvas)
        if(results == null || results!!.faceLandmarks().isEmpty()) {
            clear()
            return
        }

        results?.let { faceLandmarkResult ->
            // 绘制关键点
            for(landmark in faceLandmarkResult.faceLandmarks()) {
                for(normalizedLandmark in landmark) {
                    canvas.drawPoint(normalizedLandmark.x() * imageWidth * scaleFactor,
                        normalizedLandmark.y() * imageHeight * scaleFactor, pointPaint)
                }
            }
            // 绘制线条
            FaceLandmarker.FACE_LANDMARKS_CONNECTORS.forEach {
                canvas.drawLine(
                    faceLandmarkResult.faceLandmarks()[0][it!!.start()].x() * imageWidth * scaleFactor,
                    faceLandmarkResult.faceLandmarks()[0][it.start()].y() * imageHeight * scaleFactor,
                    faceLandmarkResult.faceLandmarks()[0][it.end()].x() * imageWidth * scaleFactor,
                    faceLandmarkResult.faceLandmarks()[0][it.end()].y() * imageHeight * scaleFactor,
                    linePaint)
            }
        }
    }

5. Resultados de la prueba

Los datos de entrada pueden ser imágenes fijas, secuencias de video en vivo, cuadros de video de archivo. Los datos de salida tienen un cuadro delimitador de caras, una cuadrícula de caras y coordenadas de puntos clave. Entre ellos, los puntos clave del rostro incluyen: contorno facial, boca, nariz, ojos, cejas, mejillas, etc., que pertenecen al modelo 3D de hitos. Como se muestra abajo:

 Sobre la base del reconocimiento facial y los puntos clave de la cara, también admite el cambio de rostro, convirtiéndolo en un lindo efecto de dibujos animados. Parpadear, sacudir la cabeza, abrir la boca y otras expresiones faciales tendrán cambios de avatar de dibujos animados en tiempo real. Como se muestra abajo:

Supongo que te gusta

Origin blog.csdn.net/u011686167/article/details/131386486
Recomendado
Clasificación