基于FaceNet的实时人脸识别训练
FaceNet人脸特征提取
FaceNet是一种用于提取人脸图像特征的深度神经网络。它由谷歌研究人员 Schroff 等人提出。
论文地址:https://arxiv.org/abs/1503.03832
FaceNet 的工作原理是,输入一张人脸图像,将其压缩并输出为一个由128 位数组成的向量,表示人脸的基本特征。这个向量被称为嵌入,(来自面部图像的所有相关信息都嵌入到向量中)。
那么,如何通过FaceNet实现人脸识别呢?
通常的做法是,获取图像嵌入并计算与已知人脸的图片的距离。通常使用余弦定理或欧几里得距离公式计算。如果计算出的人脸距离与已知人脸的嵌入足够接近,我们就假设这张脸是同一个人的。
那么问题就是,FaceNet 如何知道需要从人脸图像中提取什么东西?
为了训练一个人脸识别器,我们需要很多人脸图像。像每个机器学习问题一样,训练通常需要数千张不同的图像。当我们开始训练过程时,模型会为每张图像生成随机向量,这意味着图像是随机分布的。
学习步骤:
- 随机选择一个锚点图像;
- 随机选择同一个人的正样本图像作为基础图像;
- 随机选择与主图像不同的人的负样本图像;
- 调整 FaceNet 神经网络参数,使正样本比负样本更靠近锚点。
我们重复这四个步骤,直到不再需要更改或这些更改非常小以至于没有影响。训练完成后,同一个人的所有面孔在距离上都彼此靠近,而与不同的面孔相距很远。
faceNet.py
完整的对象代码:
# faceNet.py
import cv2import cv2
import stow
import typing
import numpy as np
import onnxruntime as ortclass FaceNet:"""FaceNet class object, which can be used for simplified face recognition"""def __init__(self, detector: object,onnx_model_path: str = "models/faceNet.onnx", anchors: typing.Union[str, dict] = 'faces',force_cpu: bool = False,threshold: float = 0.5,color: tuple = (255, 255, 255),thickness: int = 2,) -> None:"""Object for face recognitionParams:detector: (object) - detector object to detect faces in imageonnx_model_path: (str) - path to onnx modelforce_cpu: (bool) - if True, onnx model will be run on CPUanchors: (str or dict) - path to directory with faces or dictionary with anchor names as keys and anchor encodings as valuesthreshold: (float) - threshold for face recognitioncolor: (tuple) - color of bounding box and textthickness: (int) - thickness of bounding box and text"""if not stow.exists(onnx_model_path):raise Exception(f"Model doesn't exists in {onnx_model_path}")self.detector = detectorself.threshold = thresholdself.color = colorself.thickness = thicknessproviders = ['CUDAExecutionProvider', 'CPUExecutionProvider']providers = providers if ort.get_device() == "GPU" and not force_cpu else providers[::-1]self.ort_sess = ort.InferenceSession(onnx_model_path, providers=providers)self.input_shape = self.ort_sess._inputs_meta[0].shape[1:3]self.anchors = self.load_anchors(anchors) if isinstance(anchors, str) else anchorsdef normalize(self, img: np.ndarray) -> np.ndarray:"""Normalize imageArgs:img: (np.ndarray) - image to be normalizedReturns:img: (np.ndarray) - normalized image"""mean, std = img.mean(), img.std()return (img - mean) / stddef l2_normalize(self, x: np.ndarray, axis: int = -1, epsilon: float = 1e-10) -> np.ndarray:"""l2 normalization functionArgs:x: (np.ndarray) - input arrayaxis: (int) - axis to normalizeepsilon: (float) - epsilon to avoid division by zeroReturns:x: (np.ndarray) - normalized array"""output = x / np.sqrt(np.maximum(np.sum(np.square(x), axis=axis, keepdims=True), epsilon))return outputdef detect_save_faces(self, image: np.ndarray, output_dir: str = "faces"):"""Detect faces in given image and save them to output_dirArgs:image: (np.ndarray) - image to be processedoutput_dir: (str) - directory where faces will be savedReturns:bool: (bool) - True if faces were detected and saved"""face_crops = [image[t:b, l:r] for t, l, b, r in self.detector(image, return_tlbr=True)]if face_crops == []: return Falsestow.mkdir(output_dir)for index, crop in enumerate(face_crops):output_path = stow.join(output_dir, f"face_{str(index)}.png")cv2.imwrite(output_path, crop)print("Crop saved to:", output_path)self.anchors = self.load_anchors(output_dir)return Truedef load_anchors(self, faces_path: str):"""Generate anchors for given faces pathArgs:faces_path: (str) - path to directory with facesReturns:anchors: (dict) - dictionary with anchor names as keys and anchor encodings as values"""anchors = {}if not stow.exists(faces_path):return {}for face_path in stow.ls(faces_path):anchors[stow.basename(face_path)] = self.encode(cv2.imread(face_path.path))return anchorsdef encode(self, face_image: np.ndarray) -> np.ndarray:"""Encode face image with FaceNet modelArgs face_image: (np.ndarray) - face image to be encodedReturns:face_encoding: (np.ndarray) - face encoding"""face = self.normalize(face_image)face = cv2.resize(face, self.input_shape).astype(np.float32)encode = self.ort_sess.run(None, {self.ort_sess._inputs_meta[0].name: np.expand_dims(face, axis=0)})[0][0]normalized_encode = self.l2_normalize(encode)return normalized_encodedef cosine_distance(self, a: np.ndarray, b: typing.Union[np.ndarray, list]) -> np.ndarray:"""Cosine distance between wectors a and bArgs:a: (np.ndarray) - first vectorb: (np.ndarray) - second list of vectorsReturns:distance: (float) - cosine distance"""if isinstance(a, list):a = np.array(a)if isinstance(b, list):b = np.array(b)return np.dot(a, b.T) / (np.linalg.norm(a) * np.linalg.norm(b))def draw(self, image: np.ndarray, face_crops: dict):"""Draw face crops on imageArgs:image: (np.ndarray) - image to be drawn onface_crops: (dict) - dictionary with face crops as values and face names as keysReturns:image: (np.ndarray) - image with drawn face crops"""for value in face_crops.values():t, l, b, r = value["tlbr"]cv2.rectangle(image, (l, t), (r, b), self.color, self.thickness)cv2.putText(image, stow.name(value['name']), (l, t - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, self.color, self.thickness)return imagedef __call__(self, frame: np.ndarray) -> np.ndarray:"""Face recognition pipelineArgs:frame: (np.ndarray) - image to be processedReturns:frame: (np.ndarray) - image with drawn face recognition results"""face_crops = {index: {"name": "Unknown", "tlbr": tlbr} for index, tlbr in enumerate(self.detector(frame, return_tlbr=True))}for key, value in face_crops.items():t, l, b, r = value["tlbr"]face_encoding = self.encode(frame[t:b, l:r])distances = self.cosine_distance(face_encoding, list(self.anchors.values()))if np.max(distances) > self.threshold:face_crops[key]["name"] = list(self.anchors.keys())[np.argmax(distances)]frame = self.draw(frame, face_crops)return frame
我们可以使用faceNet/convert_to_onnx.py
脚本进行转换:
# faceNet/convert_to_onnx.py
import os
import tensorflow as tf
import tf2onnx
from architecture import InceptionResNetV2if __name__ == '__main__':""" weights can be downloaded from https://drive.google.com/drive/folders/1scGoVCQp-cNwKTKOUqevCP1N2LlyXU3l?usp=sharingPut facenet_keras_weights.h5 file in model folder"""facenet_weights_path = "models/facenet_keras_weights.h5"onnx_model_output_path = "models/faceNet.onnx"if not os.path.exists(facenet_weights_path):raise Exception(f"Model doesn't exists in {facenet_weights_path}, download weights from \https://drive.google.com/drive/folders/1scGoVCQp-cNwKTKOUqevCP1N2LlyXU3l?usp=sharing")faceNet = InceptionResNetV2()faceNet.load_weights(facenet_weights_path) spec = (tf.TensorSpec(faceNet.inputs[0].shape, tf.float32, name="image_input"),)tf2onnx.convert.from_keras(faceNet, output_path=onnx_model_output_path, input_signature=spec)
view raw
首先,从代码中的给定链接下载权重并将它们放在模型文件夹中。然后使用python 运行 faceNet/convert_to_onnx.py
代码,它能够将模型转换为.onnx
格式。
有了模型后,我们可以打开main.py
脚本并使用以下代码运行网络摄像头实时人脸识别:
# main.py
from utils import FPSmetric
from engine import Engine
from faceDetection import MPFaceDetection
from faceNet.faceNet import FaceNetif __name__ == '__main__':facenet = FaceNet(detector = MPFaceDetection(),onnx_model_path = "models/faceNet.onnx", anchors = "faces",force_cpu = True,)engine = Engine(webcam_id=0, show=True, custom_objects=[facenet, FPSmetric()])# save first face crop as anchor, otherwise don't usewhile not facenet.detect_save_faces(engine.process_webcam(return_frame=True), output_dir="faces"):continueengine.run()
给定模型的存储路径时。我们给它保存anchors的路径;它必须是带有面部裁剪的图像。保证模型将加载此锚点并在找到匹配项时显示对应的名字。
接下来,我们需要创建一个引擎对象,负责处理图像、视频或网络摄像头流;可以选择处理网络摄像头。使用“show”参数。
另外,我们可以添加一个 FPSmetric 来了解人脸识别的工作速度。
最后,我们需要将“facenet”对象传递给“custom_objects”参数。在这里,我们可以添加更多,“pencil sketch”、“background removal”或其他我们想要的实体。
我们还可以创建一个函数来抓取第一个网络摄像头帧,如果它在其中找到一张人脸,它就会裁剪并保存它:
while not facenet.detect_save_faces(engine.process_webcam(return_frame=True), output_dir="faces"):continue
这样我们就创建了一个可以在我们的 CPU 上进行实时人脸识别的系统,它的运行速度在 30 fps 左右,这对我们来说已经足够了!
来源:
GitHub地址:https://github.com/pythonlessons/background_removal
基于FaceNet的实时人脸识别训练相关推荐
- python人脸识别库_基于facenet的实时人脸识别系统
facenet_facerecognition opencv+mtcnn+facenet+python+tensorflow 实现实时人脸识别 Abstract:本文记录了在学习深度学习过程中,使用o ...
- 基于facenet的实时人脸检测
参考自https://github.com/shanren7/real_time_face_recognition 本人的项目代码https://github.com/zouzhen/real_tim ...
- 视觉识别入门之人脸识别——基于FACENET的高精度人脸识别
视觉识别入门之人脸识别---- 基于FACENET的高精度人脸识别 一:项目展示: - 这是实时视频读取的展示,是可以读单张图片,或者本地视频流,抑或是实时人脸检测与分类的,至于我为什么不展示我的自拍 ...
- 基于视频的实时人脸识别(含代码)
文章目录 介绍 思路介绍 运行环境介绍 模型介绍 人脸关键点预测器 人脸识别模型 效果展示 识别过程 代码 建立本地人脸库 人脸识别 介绍 思路介绍 无论是基于视频或者调用摄像头来完成人脸识别,其实是 ...
- 基于MTCNN和FaceNet的实时人脸检测识别系统
文章目录 模型介绍 MTCNN FaceNet 基于MTCNN和FaceNet的实时人脸检测识别系统 在LFW数据集上测试 参考文献 GitHub项目地址:https://github.com/Har ...
- gpu训练cnn人脸识别准确率_opencv+mtcnn+facenet+python+tensorflow 实现实时人脸识别
opencv+mtcnn+facenet+python+tensorflow 实现实时人脸识别 Abstract:本文记录了在学习深度学习过程中,使用opencv+mtcnn+facenet+pyth ...
- mtcnn人脸检测python_基于mtcnn和facenet的实时人脸检测与识别系统开发
简介:本文主要介绍了实时人脸检测与识别系统的详细方法.该系统基于python/opencv2/tensorflow环境,实现了从摄像头读取视频,检测人脸,识别人脸的功能.本系统代码地址:real ti ...
- Keras之CNN:基于Keras利用cv2建立训练存储卷积神经网络模型(2+1)并调用摄像头进行实时人脸识别
Keras之CNN:基于Keras利用cv2建立训练存储卷积神经网络模型(2+1)并调用摄像头进行实时人脸识别 目录 输出结果 设计思路 核心代码 输出结果 设计思路 核心代码 # -*- codin ...
- mtcnn人脸检测python_opencv+mtcnn+facenet+python+tensorflow 实现实时人脸识别
Abstract:本文记录了在学习深度学习过程中,使用opencv+mtcnn+facenet+python+tensorflow,开发环境为ubuntu18.04,实现局域网连接手机摄像头,对目标人 ...
最新文章
- [问题解决] Python中 == 与 is 的区别
- 播放视频android学习笔记---44_在线视频播放器,网络视频解析器,SurfaceView 控件使用方法...
- 嵌入式linux系统,给WIFI模块增加一个开关
- 三大主流软件负载均衡器(LVS、Nginx、HAproxy) 与商业SLB比较
- 产品经理的四个重要阶段
- BZOJ3743 : [Coci2014]Kamp
- 选择排序:简单选择排序
- poj 2153 Rank List
- STL中的所有算法(70个)
- 增强型绿植植被指数_植被指数--数据产品-国家青藏高原科学数据中心
- 百兆1光4电工业级光纤收发器4口百兆光纤收发器工业导轨式发送机导轨式以太网光电转换器
- 微信小程序上传并设置为体验版的办法(解决了没有上传按钮,体验版拉取不到数据的问题)
- VOT竞赛paper阅读笔记
- Matlab中regress函数各参数解释
- 牛逼!java只能输入数字的正则
- 深入浅出pytorch笔记——第一章
- 全栈工程师必备技能栈,聊聊月薪2W以内都该会点啥?
- 双硫脲改性Zr-MOF吸附材料|聚多巴胺(PDA)改性MOF-5|羧酸改性的UiO-66(Zr)膜|有机骨架材料的定制技术
- 细数Mac上那些好用且免费的软件(四)
- 黑马程序员训练营十道满分题解
热门文章
- Zookeeper 原理与优化
- 2020.11.9--AE--文字的文本属性、文字动画效果、内置动画预设
- 2021年12月中国A股石油加工贸易行业上市企业市值排行榜:中国石油位居榜首,宇新股份股价最高(附月榜TOP24详单)
- centos下Intel核显应用ffmpeg的qsv插件编解码
- 手机党心声:“离开手机生活”这是不可能的!
- Spark程序使用Scala进行单元测试
- Java多线程实现的两种方式
- i5 12490f和i5 12600kf差距 i512490f和i512600kf对比
- webstorm 常用插件集合
- shell脚本中实现远程和其他用户的子shell执行