赞
踩
MediaPipe
是一款由 Google Research 开发并开源的多媒体机器学习模型应用框架
。谷歌的一系列重要产品,如Google Lens、ARCore、Google Home等都已深度整合了 MediaPipe。
MediaPipe
目前支持的解决方案(Solution)及支持的平台如下图所示,除了视觉任务,还支持文本、语音及生成式AI任务(实验中)。作为一款跨平台框架,MediaPipe 不仅可以被部署在Web端,更可以在多个移动端 (Android和苹果 iOS)和嵌入式平台(Google Coral 和树莓派)中作为设备端机器学习推理框架。
MediaPipe
的每个解决方案(Solution)包括一个或多个模型,一些解决方案还可以自定义模型(使用Model Maker)。
今天,我们主要来了解下人脸检测(Face Detection)
。
官网地址(需魔法流量): MediaPipe | Google for Developers
Mediapipe框架的核心概念可以参考:Mediapipe框架(一)人手关键点检测
MediaPipe人脸检测是一种超快速的人脸检测解决方案,除了提供面部边界框
外,还可以输出6个特征点的坐标:双眼中央、耳垂、嘴部中央与鼻尖
。
MediaPipe人脸检测所用模型是BlazeFace的变体,BlazeFace 是谷歌19年提出的一种针对移动 GPU 推断进行优化的轻量级且精确的人脸检测器。
200-1000 + FPS
的速度运行。 这种超实时性能使其能够应用于任何对性能要求极高的增强现实应用中。该检测器的超实时性能使其可应用于其他需要准确地关注面部区域的模型:
例如
1、3D面部关键点检测
2、面部特征或表情分类,以及面部区域分割等
只有此模型提供了预训练权重
。一种轻量级模型,用于在智能手机相机或网络摄像头的自拍式图像中检测单个或多个面部。该模型针对短距离的前置手机摄像头图像进行了优化。模型架构使用了一种带有自定义编码器的Single Shot Detector (SSD)卷积网络技术。BlazeFace已经被谷歌用于实际的工程中,因此这篇文章非常值得参考。
论文地址:https://arxiv.org/abs/1907.05047
BlazeFace是Google专为移动端GPU定制的人脸检测方案。主要创新点如下:
我们知道深度可分离卷积
是轻量网络经常采用的卷积形式。它使用两步卷积运算,即Depthwise卷积与Pointwise卷积替代常规的单次卷积。
作者在iPhone上实测后发现,一个56×56×128大小、16-bit张量的Depthwise卷积运算耗时0.07ms,而伴随其后128-128通道的Pointwise卷积运算耗时0.3ms,是前者的4倍以上(作者认为是内存存取的固定开销造成)。因此作者提出在Depthwise卷积中使用较大的卷积核(即使用5*5卷积核代替3*3卷积核,扩大感受野)
,这样只需要较少的bottleneck数量就可以获得指定大小的感受野范围。作者将该结构命名为 BlazeBlock。
另外为了促进感受野Size的传递,提出了double BlazeBlock 模块。该模块在bottleneck的最前端又塞入了一层深度可分离卷积,并增加了Max Pooling与Channel Padding作为可选旁路。
对于前置摄像头这种人脸占图像很大面积、人脸尺度变化较小的场景,作者定义了更加轻量级的特征提取。
作者使用了128×128像素的RGB输入,后跟1个常规5×5卷积、5个BlazeBlock、6个Double BlazeBlock,其中通道数最大值为96(网络结构可以参考原文)。
BlazeFace最低的空间分辨率为8×8(SSD分辨率一直降低到1×1)。
该文重点说明在手机终端真实应用中,检测算法的加速,只是在谷歌的私有数据集上与MobileNetV2-SSD的比较。
配置项 | 描述 | 取值范围 | 默认值 |
---|---|---|---|
running_mode | 设置任务的运行模式。有三种模式:IMAGE:用于单张图像输入。VIDEO:用于视频解码帧。LIVE_STREAM:用于输入数据的实时流模式,例如来自摄像机的数据。在此模式下,必须调用resultListener来设置一个监听器以异步接收结果。 | {IMAGE, VIDEO, LIVE_STREAM } | IMAGE |
min_detection_confidence | 脸部检测被视为成功所需的最低置信度分数。 | Float [0,1] | 0.5 |
min_suppression_threshold | 非极大值抑制阈值 | Float [0,1] | 0.3 |
result_callback | 异步回调结果(仅用于LIVE_STREAM模式) | N/A | Not set |
1、安装mediapipe包
pip install mediapipe
2、下载预训练模型:
下载地址:
3、检测结果
人脸检测器返回一个FaceDetectorResult对象来表示每次检测运行的结果。该结果对象包含检测到的人脸的边界框和每个检测到的人脸的置信度分数等信息。
检测到的面部的集合,其中包含边界框和6个关键点。边界框未标准化,不过每个关键点(由x和y组成)通过图像的宽度和高度进行了标准化。
以下是此任务输出数据的示例。
FaceDetectionResult: Detections: Detection #0: BoundingBox: #人脸的bbox origin_x: 126 origin_y: 100 width: 463 height: 463 Categories: Category #0: index: 0 score: 0.9729152917861938 # 人脸检测的置信度 NormalizedKeypoints: # 每张人脸所含的6个关键点 NormalizedKeypoint #0: x: 0.18298381567001343 y: 0.2961040139198303 NormalizedKeypoint #1: x: 0.3302789330482483 y: 0.29289937019348145 ... (6 keypoints for each face) Detection #1: BoundingBox: origin_x: 616 origin_y: 193 width: 430 height: 430 Categories: Category #0: index: 0 score: 0.9251380562782288 NormalizedKeypoints: NormalizedKeypoint #0: x: 0.6151331663131714 y: 0.3713381886482239 NormalizedKeypoint #1: x: 0.7460576295852661 y: 0.38825345039367676 ... (6 keypoints for each face)
4、检测速度
import numpy as np import mediapipe as mp from mediapipe.tasks import python from mediapipe.tasks.python import vision import cv2 from utils import visualize def detect_face_from_image(img_path): # 1、创建人脸检测器 # 需要先下载预训练模型 base_options = python.BaseOptions(model_asset_path='blaze_face_short_range.tflite') options = vision.FaceDetectorOptions(base_options=base_options) detector = vision.FaceDetector.create_from_options(options) # 2、加载输入图片 image = mp.Image.create_from_file(img_path) # 3、使用下载好的模型进行人脸检测 detection_result = detector.detect(image) print(detection_result) # 4、 可视化 image_copy = np.copy(image.numpy_view()) annotated_image = visualize(image_copy, detection_result) rgb_annotated_image = cv2.cvtColor(annotated_image, cv2.COLOR_BGR2RGB) # 在使用OpenCV的cv2.imshow函数显示图像时,它会默认将传入的图像数据解释为BGR格式 # 如果你传入的是RGB格式的图像数据,OpenCV会在显示时进行颜色通道的调整,使图像以BGR格式进行显示。 cv2.imshow('face detection', rgb_annotated_image) # 输入esc结束捕获 if cv2.waitKey(0) == 27: cv2.destroyAllWindows() if __name__ == '__main__': detect_face_from_image(img_path='face_image.jpg')
检测结果如下:
import time
from utils import visualize
import mediapipe as mp
from mediapipe.tasks import python
from mediapipe.tasks.python import vision
import cv2
from PySide6 import QtWidgets, QtCore, QtGui
from threading import Thread
# 通过pyside6实现一个简单的界面
class MWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
# 设置界面
self.setupUI()
# 给按钮绑定事件
self.videoBtn.clicked.connect(self.startVideo)
self.camBtn.clicked.connect(self.startCamera)
self.stopBtn.clicked.connect(self.stop)
# 定义定时器,用于控制显示视频的帧率
self.timer_camera = QtCore.QTimer()
# 定时到了,回调 self.show_image
self.timer_camera.timeout.connect(self.show_image)
# 初始化模型
self.initialize_model()
# 要处理的视频帧图片队列,目前就放1帧图片
self.frameToAnalyze = []
self.frame_timestamp_ms = int(time.time())
# 启动处理视频帧独立线程(设置未守护线程)
Thread(target=self.frameAnalyzeThreadFunc, daemon=True).start()
def initialize_model(self):
# 创建人脸检测器,注意running_mode设置为VIDEO模式
VisionRunningMode = mp.tasks.vision.RunningMode
base_options = python.BaseOptions(model_asset_path='blaze_face_short_range.tflite')
options = vision.FaceDetectorOptions(base_options=base_options, running_mode=VisionRunningMode.VIDEO)
self.detector = vision.FaceDetector.create_from_options(options)
def setupUI(self):
self.resize(1200, 800)
self.setWindowTitle('人脸检测系统')
# 设置窗口在屏幕中间
availableGeometry = QtGui.QGuiApplication.primaryScreen().availableGeometry()
window = self.frameGeometry()
window.moveCenter(availableGeometry.center())
self.move(window.topLeft())
# central Widget
centralWidget = QtWidgets.QWidget(self)
self.setCentralWidget(centralWidget)
# central Widget 里面的 主 layout
mainLayout = QtWidgets.QVBoxLayout(centralWidget)
# 界面的上半部分 : 图形展示部分
topLayout = QtWidgets.QHBoxLayout()
self.label_ori_video = QtWidgets.QLabel(self)
self.label_treated = QtWidgets.QLabel(self)
self.label_ori_video.setMinimumSize(520, 400)
self.label_treated.setMinimumSize(520, 400)
self.label_ori_video.setStyleSheet('border:1px solid #D7E2F9;')
self.label_treated.setStyleSheet('border:1px solid #D7E2F9;')
topLayout.addWidget(self.label_ori_video)
topLayout.addWidget(self.label_treated)
mainLayout.addLayout(topLayout)
# 界面下半部分: 输出框 和 按钮
groupBox = QtWidgets.QGroupBox(self)
bottomLayout = QtWidgets.QHBoxLayout(groupBox)
self.textLog = QtWidgets.QTextBrowser()
bottomLayout.addWidget(self.textLog)
mainLayout.addWidget(groupBox)
btnLayout = QtWidgets.QVBoxLayout()
self.videoBtn = QtWidgets.QPushButton('声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/749668
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。