使用 mtcnn 和 facenet 进行人脸识别

一、前言

人脸识别目前有比较多的应用了,比如门禁系统,手机的人脸解锁等等,今天,我们也来实现一个简单的人脸识别。

二、思维导图

三、详细步骤

3.1 准备

3.1.1 facenet 权重文件下载

下载地址:https://drive.google.com/drive/folders/1pwQ3H4aJ8a6yyJHZkTwtjcL4wYWQb7bn,下载 facenet_keras_weights.h5权重文件到本地。

3.1.2 依赖库安装

pip 安装库的时候如果太慢,设置软件源的地址为清华源,设置命令:

pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
依赖库作用安装命令
OpenCV一个用于计算机视觉和图像处理的开源库。用于处理图像和视频。pip install opencv-python
mtcnn人脸检测的深度学习模型pip install mtcnn
tensorflow开源的机器学习框架pip install tensorflow
mysql-connector-python连接 mysql 数据库pip install mysql-connector-python
3.1.3 目录结构说明
├─docs 存放文档
├─encodings 存放本地图像特征值
├─facenet_model 存放 facenet 权重文件
├─font 存放简体字体
├─test_faces 测试集
├─train_faces 训练集
├─src 存放代码

3.2 训练人脸

3.2.1 人脸训练集准备

train_faces 文件夹下新建 hu_ge文件夹,然后从社交网络上获取胡歌图片放进去,作为训练集。

一张人脸生成的特征值显然是不够的,因此我们需要多张人脸,不考虑过拟合的情况下,人脸越多越精确。

3.2.2 加载模型

这边加载模型是 ResNetV2,没有引用库,而是手动去构建神经网络的,我尝试去直接使用 ResNet 库没成功,部分构建代码:

def inception_resnet_v2():inputs = Input(shape=(160, 160, 3))# 第一层是一个卷积层,应用了 32 个大小为 3x3 的滤波器x = Conv2D(32, 3, strides=2, padding='valid', use_bias=False, name= 'Conv2d_1a_3x3') (inputs)# 对输入进行批量归一化x = BatchNormalization(axis=3, momentum=0.995, epsilon=0.001, scale=False, name='Conv2d_1a_3x3_BatchNorm')(x)# 应用 ReLU 激活函数x = Activation('relu', name='Conv2d_1a_3x3_Activation')(x)x = Conv2D(32, 3, strides=1, padding='valid', use_bias=False, name= 'Conv2d_2a_3x3') (x)x = BatchNormalization(axis=3, momentum=0.995, epsilon=0.001, scale=False, name='Conv2d_2a_3x3_BatchNorm')(x)x = Activation('relu', name='Conv2d_2a_3x3_Activation')(x)x = Conv2D(64, 3, strides=1, padding='same', use_bias=False, name= 'Conv2d_2b_3x3') (x)x = BatchNormalization(axis=3, momentum=0.995, epsilon=0.001, scale=False, name='Conv2d_2b_3x3_BatchNorm')(x)x = Activation('relu', name='Conv2d_2b_3x3_Activation')(x)x = MaxPooling2D(3, strides=2, name='MaxPool_3a_3x3')(x)x = Conv2D(80, 1, strides=1, padding='valid', use_bias=False, name= 'Conv2d_3b_1x1') (x)x = BatchNormalization(axis=3, momentum=0.995, epsilon=0.001, scale=False, name='Conv2d_3b_1x1_BatchNorm')(x)x = Activation('relu', name='Conv2d_3b_1x1_Activation')(x)x = Conv2D(192, 3, strides=1, padding='valid', use_bias=False, name= 'Conv2d_4a_3x3') (x)x = BatchNormalization(axis=3, momentum=0.995, epsilon=0.001, scale=False, name='Conv2d_4a_3x3_BatchNorm')(x)x = Activation('relu', name='Conv2d_4a_3x3_Activation')(x)x = Conv2D(256, 3, strides=2, padding='valid', use_bias=False, name= 'Conv2d_4b_3x3') (x)x = BatchNormalization(axis=3, momentum=0.995, epsilon=0.001, scale=False, name='Conv2d_4b_3x3_BatchNorm')(x)x = Activation('relu', name='Conv2d_4b_3x3_Activation')(x)

这边就涉及到神经网络比较底层的知识,我也不太懂,我就直接使用了。
加载完模型后,加载 facenet 权重文件。
最后再加载 mtcnn 来识别人脸。

face_encoder = inception_resnet_v2()
facenet_weight_path = "../facenet_model/facenet_keras_weights.h5"
face_encoder.load_weights(facenet_weight_path)face_detector = mtcnn.MTCNN()
3.2.3 读取图片、转换颜色空间

OpenCV 读取图片默认是以 BGR 颜色空间,如果我们要给 mtcnn识别人脸,要先转为 RGB 颜色空间。

# 读取图片
img_BGR = cv2.imread(image_path)
# 将一幅图像从 BGR(蓝绿红)颜色空间转换为 RGB(红绿蓝)颜色空间
img_RGB = cv2.cvtColor(img_BGR, cv2.COLOR_BGR2RGB)
3.2.4 mtcnn 识别人脸具体位置

MTCNN 是一种检测图像上的人脸和面部标志的神经网络。

x = face_detector.detect_faces(img_RGB)
print(x)

mtcnn 会生成人脸框的坐标和人脸上五个关键点的坐标,分别是左眼,右眼,鼻子,嘴唇的左边界,嘴唇的右边界。

{'box': [468, 98, 195, 249],'confidence': 0.9999933242797852,'keypoints': {'left_eye': (534, 190),'right_eye': (624, 186),'nose': (590, 236),'mouth_left': (549, 294),'mouth_right': (620, 291)}
}

显示一下:

# 人脸的框的左上角坐标和宽高
x1, y1, width, height = x[0]['box']
x1, y1 = abs(x1), abs(y1)
x2, y2 = x1 + width, y1 + height
# 绘制人脸框
cv2.rectangle(img_BGR, (x1, y1), (x2, y2), (0, 255, 0), 2)
# 绘制人脸关键点
for keypoint, coordinates in x[0]['keypoints'].items():cv2.circle(img_BGR, coordinates, 2, (0, 0, 255), -1)
# 显示
cv2.imshow('Detected Face', img_BGR)
cv2.waitKey(0)
cv2.destroyAllWindows()

# 裁剪出人脸部分
face = img_RGB[y1:y2, x1:x2]
3.2.5 归一化、设置图片大小、生成图像特征值

归一化,将像素值从 [0, 255] 归一化到 [0, 1],如果训练的特征分布和测试的差异很大,那么对输入数据进行归一化,可以在训练和测试过程中保持一致的特征分布。

def normalize(img):"""归一化处理:将数据缩放到均值为 0,标准差为 1 的标准正态分布像素值通常是在 0 到 255 的范围内。例如,将像素值从 [0, 255] 归一化到 [0, 1]。:param img::return: 归一化结果"""# 获取所有像素的平均值,标准差mean, std = img.mean(), img.std()return (img - mean) / std

face_encoder.predict(face_d)[0]这个函数可以对输入的人脸图像进行特征提取,我们这边只获取单张人脸的特征,所以取下标 0。

face = normalize(face)# 重新设置大小
face = cv2.resize(face, required_shape)
# 扩展(增加)数组的维度
face_d = np.expand_dims(face, axis=0)
encode = face_encoder.predict(face_d)[0]
encodes.append(encode)

encode 只是一张图像的特征值,我们要训练很多张才能实现泛化效果比较好的模型,因此用 encodes 存放每一张图像的特征值。

3.2.6 特征求和、存放到数据库中
if encodes:# 特征求和# 计算每一列的总和encode = np.sum(encodes, axis=0)# 将特征向量标准化为单位向量encode = l2_normalizer.transform(np.expand_dims(encode, axis=0))[0]image_feature = base64.b64encode(encode).decode('utf-8')# 获取标签中文名 hu_ge -> 胡歌label_chinese_name = get_label_chinese_name(face_names)encoding_dict[face_names] = encodesave_image_feature(face_names, label_chinese_name, image_feature)

3.3 测试人脸

将需要测试的人脸图片放在 test_faces 文件夹下,这四张都是全新的图片,模型不知道的,这样才可以进行预测。

也是对每一张图像生成人脸的特征值,然后和数据库中的特征值进行比较。

dist = cosine(input_feature, image_feature)

**在机器学习中,欧氏距离用于特征空间中样本之间的相似性度量,通过 ****cosine**函数计算相似度,只要小于相似度阈值,我们就认为属于同一张人脸。

原来我是设置成 0.5,可能由于训练的样本数太少,不是冯提莫的图片也会被认为是冯提莫,造成错误识别,它的值是 0.480.49 这样,后面我改成 0.4 就好了。
冯提莫和胡歌的人脸特征我提前训练好了,因此这边可以识别到,杨幂和宋轶没有训练,所以识别不到,显示未知。

四、参考资料

  • facenet
  • mtcnn
  • Face Detection using MTCNN

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/212971.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

luceda ipkiss教程 42:获取版图所有的电端口

通过判断版图端口的domain.name,可以知道端口是电端口还是光端口: 如: 可以通过如下代码获取两个电端口(anode和cathode)的信息: from si_fab import all as pdkdef get_electrical_ports(layout):ports …

题目:挑选子串(蓝桥OJ 1621)

题目描述&#xff1a; 解题思路&#xff1a; 采用双指针的快慢指针。与蓝桥OJ1372类似。 图解 题解&#xff1a; #include <bits/stdc.h> using namespace std;const int N 1e5 9; int a[N];int main() {ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);int n, m…

基于Java技术的选课管理系统设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

SQL自学通之表达式条件语句与运算

目录 一、目标 二、表达式条件语句 1、表达式&#xff1a; 2、条件 2.1、WHERE 子句 三、运算 1、数值型运算: 1.1、加法() 1.2、减法 (-) 1.3、除法&#xff08;/&#xff09; 1.4、乘法 &#xff08;*&#xff09; 1.5、取模 &#xff08;%&#xff09; 优先级别…

.Net6支持的操作系统版本(.net8已来,你还在用.netframework4.5吗)

机缘 不知不觉,.NET8都已经面世,而我们一直还停留在.netframework4.5开发阶段,最近准备抽空研究一下.Net6,一是为了提高技术积累,一方面想着通过这次的学习,看有没有可能将老的FX版本替换到.Net6开发上,经过查找官方资料,对.Net6支持的系统版本做一个分享,方便大家后期…

python圣诞树代码编程

以下是一个简单的Python圣诞树代码&#xff1a; def draw_tree(height): for i in range(height): print( * (height - i - 1) * * (2 * i 1)) print( * (height - 1) |)draw_tree(10) 这个函数会绘制一个等腰三角形&#xff0c;其中每一行的星号数量从1开…

分享 | 顶刊高质量论文插图配色(含RGB值及16进制HEX码)(第一期)

我在很早之前出过一期高质量论文绘图配色&#xff0c;但当时觉得搜集太麻烦于是就没继续做&#xff0c;后来用MATLAB爬了上万张顶刊绘图&#xff0c;于是又想起来做这么一个系列&#xff0c;拿了一个多小时写了个提取论文图片颜色并得出RGB值和16进制码并标注在原图的代码&…

[RK-Linux] 移植Linux-5.10到RK3399(三)| 检查eMMC与SD卡配置

这个专题主要记录把 RK Linux-5.10 移植到 ROC-RK3399-PC Pro 的过程。 文章目录 一、eMMC二、SD 卡三、两个接口的区别一、eMMC RK3399 的 eMMC 接口如图: datasheet 介绍: 实际上,连接 eMMC 存储器用的是 SDHCI 接口。SDHCI(Secure Digital Host Controller Interface)…

12v转48v升压电源芯片:参数、特点及应用领域

12v转48v升压电源芯片&#xff1a;参数、特点及应用领域 随着电子设备的日益普及&#xff0c;电源芯片的需求也在不断增长。今天我们将介绍一款具有广泛应用前景的升压电源芯片——12v转48v升压电源芯片。该芯片具有宽输入电压范围、高效率、固定工作频率等特点&#xff0c;适…

Numpy数组的运算(第7讲)

Numpy数组的运算(第7讲)         🍹博主 侯小啾 感谢您的支持与信赖。☀️ 🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ…

python使用记录

1、VSCode添加多个python解释器 只需要将对应的python.exe的目录&#xff0c;添加到系统环境变量的Path中即可&#xff0c;VSCode会自动识别及添加 2、pip 使用 pip常用命令和一些坑 查看已安装库的版本号 pip show 库名称 通过git 仓库安装第三方库 pip install git仓库地…

人工智能基础创新的第二增长曲线

编者按&#xff1a;2023年是微软亚洲研究院建院25周年。借此机会&#xff0c;我们特别策划了“智启未来”系列文章&#xff0c;邀请到微软亚洲研究院不同研究领域的领军人物&#xff0c;以署名文章的形式分享他们对人工智能、计算机及其交叉学科领域的观点洞察及前沿展望。希望…

深入了解Java 8日期时间新玩法:DateTimeFormatter与ZoneOffset的使用

推荐语 在这篇文章中&#xff0c;我们将深入探讨Java中的DateTimeFormatter和ZoneOffset类的功能和使用方法。这些类是在Java 8中引入的新的日期时间API的一部分&#xff0c;它们为我们提供了更灵活、更易用的日期和时间处理能力。尽管这些类在Java 8中已经出现&#xff0c;但…

【Docker二】docker网络模式、网络通信、数据管理、资源控制

目录 一、docker网络模式&#xff1a; 1、概述 2、docker网络实现原理&#xff1a; 3、docker的网络模式&#xff1a; 3.1、bridge模式&#xff1a; 3.2、host模式&#xff1a; 3.3、container模式&#xff1a; 3.4、none模式&#xff1a; 3.5、自定义网络模式&#xf…

DTS认证

一、什么叫DTS DTS 是“Digital Theatre System“的缩写&#xff0c;是”数字化影院系统“的意思。是一种音频格式&#xff0c;从技术上讲&#xff0c;把音效数据存储到另外的CD-ROM中&#xff0c;使其与影像数据同步。这样不但空间得到增加&#xff0c;而且数据流量也可以相对…

RPG项目01_UI面板Game

基于“RPG项目01_技能释放”&#xff0c;将UI包导入Unity场景中&#xff0c; 将图片放置 拖拽 取消勾选&#xff08;隐藏攻击切片&#xff09; 对技能添加蒙版 调节父子物体大小一致 将子类蒙版复制 执行5次 运行即可看到技能使用完的冷却条 在Scripts下创建UI文件夹 写代码&am…

玩转大数据7:数据湖与数据仓库的比较与选择

1. 引言 在当今数字化的世界中&#xff0c;数据被视为一种宝贵的资源&#xff0c;而数据湖和数据仓库则是两种重要的数据处理工具。本文将详细介绍这两种工具的概念、作用以及它们之间的区别和联系。 1.1. 数据湖的概念和作用 数据湖是一个集中式存储和处理大量数据的平台&a…

3.5毫米音频连接器接线方式

3.5毫米音频连接器接线方式 耳机插头麦克风插头 绘制电路图注意事项 3.5毫米音频连接器分为单声道开关型和无开关型如下图&#xff1a; sleeve&#xff08;套筒&#xff09; tip&#xff08;尖端&#xff09; ring&#xff08;环&#xff09; 耳机插头 麦克风插头 绘制电路图…

【微服务】springboot整合quartz使用详解

目录 一、前言 二、quartz介绍 2.1 quartz概述 2.2 quartz优缺点 2.3 quartz核心概念 2.3.1 Scheduler 2.3.2 Trigger 2.3.3 Job 2.3.4 JobDetail 2.4 Quartz作业存储类型 2.5 适用场景 三、Cron表达式 3.1 Cron表达式语法 3.2 Cron表达式各元素说明 3.3 Cron表达…

北邮22级信通院数电:Verilog-FPGA(12)第十二周实验(2)彩虹呼吸灯(bug已解决 更新至3.0)

北邮22信通一枚~ 跟随课程进度更新北邮信通院数字系统设计的笔记、代码和文章 持续关注作者 迎接数电实验学习~ 获取更多文章&#xff0c;请访问专栏&#xff1a; 北邮22级信通院数电实验_青山如墨雨如画的博客-CSDN博客 目录 一.代码部分 1.1一些更新和讲解 1.2改正后的…