探索MediaPipe检测人脸关键点

news/2024/12/29 2:20:42/

MediaPipe是Google开源的计算机视觉处理框架,基于TensorFlow来训练模型,支持人脸识别、人脸关键点、物体检测追踪、图像分类、人像分割、手势识别、文本分类、语音分类等。我们可以使用CPU来推理,也可以选择GPU加速推理。在滤镜特效场景,经常需要用到人脸关键点。

一、配置参数与模型

1、配置参数

检测人脸关键点的配置参数有运行模式、人脸数、最小的检测人脸置信度、最小的显示人脸置信度、最小的追踪人脸置信度、结果回调,具体如下表所示:

选项描述取值范围默认值
running_mode

图像:单个图像 

视频:解码的视频帧

实时流:实时视频数据

{IMAGE,VIDEO,

LIVE_STREAM}

IMAGE
num_faces最多检测的人脸数大于01

min_face_detection

_confidence

人脸检测最小置信度[0.0, 1.0]0.5

min_face_presence

_confidence

人脸显示最小置信度[0.0, 1.0]0.5
min_tracking_confidence人脸追踪最小置信度[0.0, 1.0]0.5
output_face_blendshapes是否输出混合形状(用于3D人脸模型)Booleanfalse

output_facial_transformation

_matrixes

是否输出变换矩阵(用于滤镜特效)Booleanfalse
result_callback异步回调结果(LIVE_STREAM模式)ResultListener   /

2、检测模型 

检测人间关键点分为三步:首先检测人脸,然后定位关键点,最后识别面部特征。使用到的模型如下:

  • 人脸检测模型:根据人脸关键点特征来检测人脸;
  • 人脸网格模型:包含478个坐标点的3D人脸标识;
  • 混合形状预测模型:预测52个混合形状的分数,表示不同表情的系数; 

二、工程配置

以Android平台为例,在gradle导入MediaPipe相关包:

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

然后运行下载模型的task,并且指定模型保存路径:

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

这里用到的模型是face_landmarker,设置src和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

三、初始化工作

1、初始化模型

模型的初始化包括:设置运行模式、模型路径、检测人脸数、回调结果等,示例代码如下:

    fun setupFaceLandmark() {val baseOptionBuilder = BaseOptions.builder()// 设置运行模式,默认CPUwhen (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、初始化Camera

这里以LIVE_STREAM模式为例,Camera的初始化包括:设置像素格式、预览宽高比、绑定生命周期、关联SurfaceProvider。示例代码如下:

    private fun bindCameraUseCases() {val cameraProvider = cameraProvider ?: throw IllegalStateException("Camera init failed.")val cameraSelector =CameraSelector.Builder().requireLensFacing(cameraFacing).build()// 预览的宽高比为4:3preview = 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 {// 绑定Lifecyclecamera = cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageAnalyzer)// 关联SurfaceProviderpreview?.setSurfaceProvider(fragmentCameraBinding.viewFinder.surfaceProvider)} catch (exc: Exception) {Log.e(TAG, "bind lifecycle failed", exc)}}

四、检测实时流

1、检测人脸关键点

在检测之前,先拷贝数据,图像帧预处理,然后执行检测:

    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为MPImageval mpImage = BitmapImageBuilder(rotatedBitmap).build()// 异步检测人脸关键点faceLandmarker?.detectAsync(mpImage, frameTime)}

2、绘制人脸关键点

检测到人脸关键点结果后,然后回调到主线程:

   override fun onResults(resultBundle: FaceLandmarkerHelper.ResultBundle) {activity?.runOnUiThread {if (_fragmentCameraBinding != null) {// 显示推理时长fragmentCameraBinding.bottomSheetLayout.inferenceTimeVal.text =String.format("%d ms", resultBundle.inferenceTime)// 传递结果给OverlayViewfragmentCameraBinding.overlay.setResults(resultBundle.result,resultBundle.inputImageHeight,resultBundle.inputImageWidth,RunningMode.LIVE_STREAM)// 主动触发渲染fragmentCameraBinding.overlay.invalidate()}}}

最后绘制人脸关键点,包括面部表情、轮廓:

   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)}}}

五、检测结果

输入数据可以是静态图像、实时视频流、文件视频帧。输出数据有人脸边界框、人脸网格、关键点坐标。其中,人脸关键点包括:脸部轮廓、嘴巴、鼻子、眼睛、眉毛、脸颊等,属于3D的landmark模型。如下图所示:

 在人脸识别、人脸关键点基础上,还支持换脸,变成可爱的卡通效果。眨眼睛、摇头、张嘴这些表情动作,都会有实时的卡通头像变化。如下图所示:


http://www.ppmy.cn/news/584058.html

相关文章

AI智能服务未来可能的场景

一、产业结构 ChatGPT大模型技术变革加速人工智能产业的变迁 1.投资热 2.产业结构:硬件-云平台-智能应用-应用提供 智能服务产业未来会是一个从算力到服务分发全流程的结构 二、Al智能无处不在的未来,产业将如何演变? 1.技术:…

Docker的“跳过更新”竟要付费;恶意软件用 Rust 重写后更难被发现;15 款输入法被指过多收集用户信息 | 架构视点...

点击上方 "编程技术圈"关注, 星标或置顶一起成长 后台回复“大礼包”有惊喜礼包! 每日英文 The best way to escape from the past is not to avoid or forget it, but to accept and forgive it. 摆脱过去并不是逃避或者忘记,只是学着去承受…

人工智能标记语言AIML聊天机器人:产生、种类、应用、实例、AIML概述、知识库、公司、业界(20k字经典收藏版)

人工智能标记语言AIML聊天机器人:产生、种类、应用、实例、AIML概述、知识库、公司、业界(20k字经典收藏版) 秦陇纪10译编 聊天机器人(chatterbot)是一个用来模拟人类对话或聊天的程序,试图建立程序让真人…

MySQL中ORDER BY的底层实现原理及示例详解

1. 引言 在MySQL数据库中,ORDER BY是一项常用的功能,用于对查询结果进行排序。本文将详细探讨MySQL中ORDER BY的底层实现原理,涵盖快速排序和归并排序两种排序算法,并包括示例和输出结果的解析。 2. ORDER BY的底层实现原理 OR…

2021年下半年软考信息安全工程师下午案例题及解析

软考信息安全工程师考试中,下午的案例分析是您能否通过考试的关键,案例能通过则整体通过概率就很高,因为从21年考试来看,上午的基础知识考得很简单,下午的案例很难。 和软考文科类考试不一样,信安的案例不是…

ChatGPT修炼指南和它的电力畅想

近期,ChatGPT刷屏各大社交平台,无疑成为人工智能界最靓的仔! 身为一款“会说话”的聊天机器人程序,它与前辈产品Siri、小度、微软小冰等有什么不同?先来听听小伙伴们怎么说。 ChatGPT何以修炼得这么强大?…

tcp,udp一些列问题

(tcp,udp基本介绍,三握四挥等)七层模型主要知识点等 OSI七层模型其功能简介 分层机制体现了分治的思想,每一层为上一层提供保障屏蔽异构。 物理层:规定了一系列的物理、电气、接口标准,传输的是比特流&…

14 个写 Java 的习惯

👇👇关注后回复 “进群” ,拉你进程序员交流群👇👇 来源丨java那些事 1、定义配置文件信息 有时候我们为了统一管理会把一些变量放到 yml 配置文件中 例如 用 ConfigurationProperties 代替 Value 使用方法 定义对应字…