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. Configuración de ingeniería
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: