人脸识别实战之基于开源模型搭建实时人脸识别系统(二):人脸检测概览与模型选型

这篇具有很好参考价值的文章主要介绍了人脸识别实战之基于开源模型搭建实时人脸识别系统(二):人脸检测概览与模型选型。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

进行人脸识别首要的任务就是要定位出画面中的人脸,这个任务就是人脸检测。人脸检测总体上算是目标检测的一个特殊情况,但也有自身的特点,比如角度多变,表情多变,可能存在各类遮挡。早期传统的方法有Haar Cascade、HOG等,基本做法就是特征描述子+滑窗+分类器,随着2012年Alexnet的出现,慢慢深度学习在这一领域开始崛起。算法和硬件性能的发展,也让基于深度学习的人脸识别不仅性能取得了很大的提升,速度也能达到实时,使得人脸技术真正进入了实用。
开源人脸识别,人脸识别,深度学习,目标检测,人工智能,python
人脸检测大体上跟随目标检测技术的发展,不过也有些自己的方法,主要可以分为一下几类方法.
开源人脸识别,人脸识别,深度学习,目标检测,人工智能,python

人脸检测算法概览

由于这个系列重点并不在于算法细节本身,因而对于一些算法只是提及,有兴趣可以自己精读。

Cascade-CNN Based Models

这类方法通过级联几个网络来逐步提高准确率,比较有代表性的是MTCNN方法。
开源人脸识别,人脸识别,深度学习,目标检测,人工智能,python
MTCNN通过级联PNet, RNet, ONet,层层过滤来提高整个检测的精度。这个方法更适合CPU,那个时期的嵌入式设备使用比较多。 由于有3个网络,训练起来比较麻烦。

R-CNN

这一块主要来源于目标检测中的RCNN, Fast RCNN, Faster RCNN
开源人脸识别,人脸识别,深度学习,目标检测,人工智能,python

这类方法精度高,但速度相对较慢。

Single Shot Detection Models

SSD是目标检测领域比较有代表性的一个算法,与RCNN系列相比,它是one stage方法,速度比较快。基于它的用于人脸检测的代表性方法是SSH.

Feature Pyramid Network Based Models

开源人脸识别,人脸识别,深度学习,目标检测,人工智能,python

YOLO系列

YOLO系列在目标检测领域比较成功,自然的也会用在人脸检测领域,比如tiny yolo face,yolov5face, yolov8face等,基本上每一代都会应用于人脸。

开源模型的选型

为了能够达到实时,同时也要有较好的效果,我们将目光锁定在yolo系列上,yolo在精度和速度的平衡上做的比较好,也比较易用。目前最新的是yolov8, 经过搜索,也已经有人将其用在人脸检测上了:derronqi/yolov8-face: yolov8 face detection with landmark (github.com),
开源人脸识别,人脸识别,深度学习,目标检测,人工智能,python

推理框架的选择

简单起见,我们选择onnxruntime,该框架既支持CPU也支持GPU, 基本满足了我们的开发要求。

yolov8-face的使用

为了减少重复工作,我们可以定义一个模型的基类, 对模型载入、推理的操作进行封装,这样就不需要每个模型都实现一遍了:

from easydict import EasyDict as edict
import onnxruntime
import threading

class BaseModel:
    def __init__(self, model_path, device='cpu', **kwargs) -> None:
        self.model = self.load_model(model_path, device)
        self.input_layer = self.model.get_inputs()[0].name
        self.output_layers = [output.name for output in self.model.get_outputs()]
        self.lock = threading.Lock()

    def load_model(self, model_path:str, device:str='cpu'):
        available_providers = onnxruntime.get_available_providers()
        if device == "gpu" and "CUDAExecutionProvider" not in available_providers:
            print("CUDAExecutionProvider is not available, use CPUExecutionProvider instead")
            device = "cpu"

        if device == 'cpu':
            self.model = onnxruntime.InferenceSession(model_path, providers=['CPUExecutionProvider'])
        else:
            self.model = onnxruntime.InferenceSession(model_path,providers=['CUDAExecutionProvider'])
            
        return self.model
        
    def inference(self, input):
        with self.lock:
            outputs = self.model.run(self.output_layers, {self.input_layer: input})
        return outputs
        
    def preprocess(self, **kwargs):
        pass

    def postprocess(self, **kwargs):
        pass

    def run(self, **kwargs):
        pass

继承BaseModel, 实现模型的前处理和后处理:

class Yolov8Face(BaseModel):
    def __init__(self, model_path, device='cpu',**kwargs) -> None:
        super().__init__(model_path, device, **kwargs)
        self.conf_threshold = kwargs.get('conf_threshold', 0.5)
        self.iou_threshold = kwargs.get('iou_threshold', 0.4)
        self.input_size = kwargs.get('input_size', 640)
        self.input_width, self.input_height = self.input_size, self.input_size
        self.reg_max=16
        self.project = np.arange(self.reg_max)
        self.strides=[8, 16, 32]

        self.feats_hw = [(math.ceil(self.input_height / self.strides[i]), math.ceil(self.input_width / self.strides[i])) for i in range(len(self.strides))]
        self.anchors = self.make_anchors(self.feats_hw)

    def make_anchors(self, feats_hw, grid_cell_offset=0.5):
        """Generate anchors from features."""
        anchor_points = {}
        for i, stride in enumerate(self.strides):
            h,w = feats_hw[i]
            x = np.arange(0, w) + grid_cell_offset  # shift x
            y = np.arange(0, h) + grid_cell_offset  # shift y
            sx, sy = np.meshgrid(x, y)
            # sy, sx = np.meshgrid(y, x)
            anchor_points[stride] = np.stack((sx, sy), axis=-1).reshape(-1, 2)
        return anchor_points
    
    def preprocess(self, image, **kwargs):
        return resize_image(image, keep_ratio=True, dst_width=self.input_width, dst_height=self.input_height)
    
    def distance2bbox(self, points, distance, max_shape=None):
        x1 = points[:, 0] - distance[:, 0]
        y1 = points[:, 1] - distance[:, 1]
        x2 = points[:, 0] + distance[:, 2]
        y2 = points[:, 1] + distance[:, 3]
        if max_shape is not None:
            x1 = np.clip(x1, 0, max_shape[1])
            y1 = np.clip(y1, 0, max_shape[0])
            x2 = np.clip(x2, 0, max_shape[1])
            y2 = np.clip(y2, 0, max_shape[0])
        return np.stack([x1, y1, x2, y2], axis=-1)

    def postprocess(self, preds, scale_h, scale_w, top, left, **kwargs):
        bboxes, scores, landmarks = [], [], []
        for i, pred in enumerate(preds):
            stride = int(self.input_height/pred.shape[2])
            pred = pred.transpose((0, 2, 3, 1))
            
            box = pred[..., :self.reg_max * 4]
            cls = 1 / (1 + np.exp(-pred[..., self.reg_max * 4:-15])).reshape((-1,1))
            kpts = pred[..., -15:].reshape((-1,15)) ### x1,y1,score1, ..., x5,y5,score5

            # tmp = box.reshape(self.feats_hw[i][0], self.feats_hw[i][1], 4, self.reg_max)
            tmp = box.reshape(-1, 4, self.reg_max)
            bbox_pred = softmax(tmp, axis=-1)
            bbox_pred = np.dot(bbox_pred, self.project).reshape((-1,4))

            bbox = self.distance2bbox(self.anchors[stride], bbox_pred, max_shape=(self.input_height, self.input_width)) * stride
            kpts[:, 0::3] = (kpts[:, 0::3] * 2.0 + (self.anchors[stride][:, 0].reshape((-1,1)) - 0.5)) * stride
            kpts[:, 1::3] = (kpts[:, 1::3] * 2.0 + (self.anchors[stride][:, 1].reshape((-1,1)) - 0.5)) * stride
            kpts[:, 2::3] = 1 / (1+np.exp(-kpts[:, 2::3]))

            bbox -= np.array([[left, top, left, top]])  ###合理使用广播法则
            bbox *= np.array([[scale_w, scale_h, scale_w, scale_h]])
            kpts -= np.tile(np.array([left, top, 0]), 5).reshape((1,15))
            kpts *= np.tile(np.array([scale_w, scale_h, 1]), 5).reshape((1,15))

            bboxes.append(bbox)
            scores.append(cls)
            landmarks.append(kpts)

        bboxes = np.concatenate(bboxes, axis=0)
        scores = np.concatenate(scores, axis=0)
        landmarks = np.concatenate(landmarks, axis=0)
    
        bboxes_wh = bboxes.copy()
        bboxes_wh[:, 2:4] = bboxes[:, 2:4] - bboxes[:, 0:2]  ####xywh
        classIds = np.argmax(scores, axis=1)
        confidences = np.max(scores, axis=1)  ####max_class_confidence
        
        mask = confidences>self.conf_threshold
        bboxes_wh = bboxes_wh[mask]  ###合理使用广播法则
        confidences = confidences[mask]
        classIds = classIds[mask]
        landmarks = landmarks[mask]

        if len(bboxes_wh) == 0:
            return np.empty((0, 5)), np.empty((0, 5))
        
        indices = cv2.dnn.NMSBoxes(bboxes_wh.tolist(), confidences.tolist(), self.conf_threshold,
                                   self.iou_threshold).flatten()
        if len(indices) > 0:
            mlvl_bboxes = bboxes_wh[indices]
            confidences = confidences[indices]
            classIds = classIds[indices]
            ## convert box to x1,y1,x2,y2
            mlvl_bboxes[:, 2:4] = mlvl_bboxes[:, 2:4] + mlvl_bboxes[:, 0:2]

            # concat box, confidence, classId
            mlvl_bboxes = np.concatenate((mlvl_bboxes, confidences.reshape(-1, 1), classIds.reshape(-1, 1)), axis=1)
            
            landmarks = landmarks[indices]
            return mlvl_bboxes, landmarks.reshape(-1, 5, 3)[..., :2]
        else:
            return np.empty((0, 5)), np.empty((0, 5))

    
    def run(self, image, **kwargs):
        img, newh, neww, top, left = self.preprocess(image)
        scale_h, scale_w = image.shape[0]/newh, image.shape[1]/neww
        # convert to RGB
        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        img = img.astype(np.float32)
        img = img / 255.0
        img = np.transpose(img, (2, 0, 1))
        img = np.expand_dims(img, axis=0)
        output = self.inference(img)
        bboxes, landmarks = self.postprocess(output, scale_h, scale_w, top, left)
        # limit box in image
        bboxes[:, 0] = np.clip(bboxes[:, 0], 0, image.shape[1])
        bboxes[:, 1] = np.clip(bboxes[:, 1], 0, image.shape[0])
        
        return bboxes, landmarks

测试

在Intel® Core™ i5-10210U上,yolov8-lite-t耗时50ms, 基本可以达到实时的需求。
开源人脸识别,人脸识别,深度学习,目标检测,人工智能,python

参考文献:
ZOU, Zhengxia, et al. Object detection in 20 years: A survey. Proceedings of the IEEE, 2023.
MINAEE, Shervin, et al. Going deeper into face detection: A survey. arXiv preprint arXiv:2103.14983, 2021.文章来源地址https://www.toymoban.com/news/detail-767169.html

到了这里,关于人脸识别实战之基于开源模型搭建实时人脸识别系统(二):人脸检测概览与模型选型的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 基于OpenCV的人脸识别和模型训练系统(万字详解)

    我们身边的人脸识别有车站检票,监控人脸,无人超市,支付宝人脸支付,上班打卡,人脸解锁手机。  人脸检测是人脸识别系统组成的关键部分之一,其目的是检测出任意给定图片中的包含的一个或多个人脸,是人脸识别、表情识别等下游任务的基础。人脸识别是通过采集

    2024年02月12日
    浏览(25)
  • 基于OpenCV进行ESP32 CAM 的人脸和眼睛识别系统搭建

    在这个项目中,我们将构建一个 基于 ESP32 CAM 的人脸和眼睛识别系统 。本教程向大家介绍一种高效的无线 视频串流 方式。这里我们使用了 ESP32-CAM 模组,它是一个带有 ESP32-S 芯片的 小型摄像头模组。除了 OV2640 相机和多个用于连接外围设备的 GPIO 外,它还具有一个 microSD 卡

    2024年02月14日
    浏览(34)
  • 【实战项目】网络编程:在Linux环境下基于opencv和socket的人脸识别系统--C++实现

    这里我们会实现一个项目:在linux操作系统下基于OpenCV和Socket的人脸识别系统。 目录 🌞前言 🌞一、项目介绍 🌞二、项目分工 🌞三、项目难题 🌞四、实现细节 🌼4.1 关键程序 🌼4.2 运行结果 🌞五、程序分析 🌷5.1 wkcv.link 🌷5.2 客户端client.cpp 🌷5.3 服务端server.cpp 项目

    2024年03月12日
    浏览(48)
  • 人脸情绪识别开源代码、模型以及说明文档

    队名:W03KFgNOc 排名:3 正确率: 0.75564 队员:yyMoming,xkwang,RichardoMu。 比赛链接:人脸情绪识别挑战赛 项目链接:link 该项目分别训练八个模型并生成csv文件,并进行融合 打开 train.sh ,可以看到训练的命令行,依次注释和解注释随后运行 train.sh 。 因为是训练八个模型,分别是

    2023年04月09日
    浏览(29)
  • 基于深度学习的高精度人脸口罩检测识别系统(PyTorch+Pyside6+YOLOv5模型)

    摘要:基于深度学习的高精度人脸口罩检测识别系统可用于日常生活中或野外来检测与定位人脸口罩目标,利用深度学习算法可实现图片、视频、摄像头等方式的人脸口罩目标检测识别,另外支持结果可视化与图片或视频检测结果的导出。本系统采用YOLOv5目标检测模型训练数

    2024年02月08日
    浏览(36)
  • 机器学习实战-SVM模型实现人脸识别

    首先进行导包 我们加载sklearn已经帮我们收集好的人脸数据 查看结果: 我们取出其中的数据进行查看: 运行结果: 我们随机选取一个人的图片并通过索引获取名字: 结果展示: 由于原来的数据很大,而且数据量多,我们首先对原始数据进行PCA降维 结果展示: 然后对降维后

    2024年02月04日
    浏览(30)
  • 开源人脸识别系统compareface介绍

    Exadel CompreFace是一种免费的open-source人脸识别服务,无需事先具备机器学习技能,即可轻松集成到任何系统中。CompreFace为人脸识别、人脸验证、人脸检测、里程碑检测、年龄和性别识别提供了REST API,并且易于与docker一起部署。 https://www.5axxw.com/wiki/content/cledeb 官网地址:Tech

    2023年04月09日
    浏览(30)
  • 项目实战解析:基于深度学习搭建卷积神经网络模型算法,实现图像识别分类

    随着人工智能的不断发展,深度学习这门技术也越来越重要,很多人都开启了学习机器学习,本文将通过项目开发实例,带领大家从零开始设计实现一款基于深度学习的图像识别算法。 学习本章内容, 你需要掌握以下基础知识: Python 基础语法 计算机视觉库(OpenCV) 深度学习

    2024年02月03日
    浏览(42)
  • 基于python-opencv,svm的开源人脸识别项目

      前言       本项目是我自己在学校里完成的一个小项目,本项目为基于python-opencv,svm的人脸识别开源项目,不同于其他的直接从kaggle等获取划分好的数据集,本项目致力于从无到有的完成机器学习的所有步骤,即: 目录 项目展示: 一、数据采集 1.创建爬虫项目 2.修改set

    2024年02月08日
    浏览(36)
  • Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单人脸检测/识别实战案例 之六 简单进行人脸训练与识别

    目录 Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单人脸检测/识别实战案例 之六 简单进行人脸训练与识别 一、简单介绍 二、简单进行人脸训练与识别 1、LBPH(Local Binary Patterns Histograms)算法进行人脸训练和识别 2、实现步骤: 3、判断是谁的人脸: 案例中涉及的关键函数说

    2024年04月26日
    浏览(62)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包