【OpenCV】人脸识别方法
代码已上传GitHub:plumqm/OpenCV-Projects at master
EigenFace、FisherFace、LBPHFace
这三种方法的代码区别不大所以就一段代码示例。
EigenFace与FisherFace
1. 将人脸图像展开为一维向量,组成训练数据集
2. PCA(EigenFace)或LDA(FisherFace)特征分解,得到一组特征向量,代表了训练集中人脸的主要特征,即特征脸
3. 将新的人脸展平为向量,减去训练数据的特征脸(即归一化)
4. 人脸向量与特征向量进行点积,得到在特征空间中的投影坐标
5. 投影得到的新坐标向量与数据库中已存的人脸投影坐标进行比较。通过计算距离(如欧氏距离),找到最相似的匹配,进行身份识别。
EigenFace和FisherFace的主要区别在于它们使用的特征分解方法不同:
FisherFace对光照、表情、姿态变化更具鲁棒性,因为它专注于区分类别,而不是仅仅关注图像的整体方差。
PCA只是从全局数据出发,而没有考虑类别之间的区分。这意味着,它虽然对所有人脸都有较好的重建能力,但可能对区分不同个体的表现较差,特别是当光照或姿态变化较大时。
- EigenFace(PCA)注重最大化数据的方差,它主要捕捉的是图像中的全局特征,不区分类别。
- FisherFace(LDA)则注重区分不同个体,最大化类间差异,因此在分类问题中通常表现得更好。
LBPH工作原理
LBPH算法通过将人脸图像分成多个小的局部区域,并计算每个区域的局部二值模式(Local Binary Patterns, LBP)直方图来描述这些区域的纹理特征。然后,它将这些局部直方图串联起来形成一个特征向量,这个特征向量就可以用来识别或分类人脸。
具体步骤:
灰度图转换:
- 首先,LBPH算法需要输入一张灰度图像。因为LBPH主要基于像素的纹理特征,所以不需要彩色信息,直接将人脸图像转换为灰度图即可。
计算局部二值模式(LBP):
- 对于每个像素点,LBP算法将以它为中心,比较它与周围8个像素的灰度值。根据灰度值的大小,将大于或等于中心像素的邻近像素标记为1,反之为0,得到一个8位二进制数。这个二进制数就是该像素的局部二值模式值。
- 例如,假设中心像素值为 50,周围的像素值为 [55, 60, 45, 30, 70, 40, 80, 90],根据规则将大于50的像素标记为1,小于的标记为0,得到的二进制模式可能是11010101,转换为十进制就是213。
划分区域:
- 将人脸图像分成若干个小的区域(通常是网格状,如10x10的网格),然后对每个区域计算该区域内所有像素的LBP直方图。
构建特征向量:
- 对于每个区域,LBPH都会计算局部二值模式的直方图,这些直方图包含了该区域内纹理的统计信息。然后,将所有区域的直方图连接起来,形成一个完整的特征向量。
特征匹配:
- 一旦提取了人脸的特征向量,就可以使用距离度量方法(如欧氏距离、卡方距离等)来比较新的人脸图像与数据库中已知的人脸特征向量。如果两个特征向量的距离足够小,则判定这两张人脸是同一个人。
准备阶段
导入包
import numpy as np
import cv2
import matplotlib.pyplot as plt
import dlib%matplotlib inline
读取gif格式
读取gif格式的文件,通过调用cv2的VideoCapture方法
# 读取gif格式img_path = './images/yalefaces/subject01.gif'
cap = cv2.VideoCapture(img_path)
ret,img = cap.read()
plt.imshow(cv2.cvtColor(img,cv2.COLOR_BGR2RGB))
Hog人脸检测器
#构造hog人脸检测器
hog_face_detector = dlib.get_frontal_face_detector()
图片预处理
用hog检测器检测出人脸部分,返回截取的人脸部分和标签
# 图片预处理
def getFaceImgLabel(filename):cap = cv2.VideoCapture(filename)ret,img = cap.read()# 转灰度图img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 检测人脸detections = hog_face_detector(img, 1)if len(detections) > 0:# 获取人脸区域坐标x = detections[0].left()y = detections[0].top()r = detections[0].right()b = detections[0].bottom()# 截取人脸img_crop = img[y:b,x:r]img_crop = cv2.resize(img_crop,(120,120))# 获取人脸labellabel_id = int(filename.split('/')[-1].split('.')[0].split('subject')[-1])return img_crop, label_idelse :return None, -1# img,label = getFaceImgLabel(img_path)
# plt.imshow(cv2.cvtColor(img,cv2.COLOR_BGR2RGB))
处理训练集
把训练集即train文件夹下的内容存入img_list,标签存入label_list,以便后面train函数直接训练
# 遍历训练文件夹
import glob
file_list = glob.glob('./images/yalefaces/*.gif')img_list =[]
label_list = []for file in file_list:img_crop, label_id = getFaceImgLabel(file)if img_crop is not None:img_list.append(img_crop)label_list.append(label_id)# print(len(img_list),len(label_list))
构造分类器
这个就包含三种方法,EigenFace、FisherFace、LBPHFace。
后面两种方法要求输入的图片大小一致,但是第一种没有要求,我们的代码就统一resize了。
# 构造分类器
face_cls = cv2.face.LBPHFaceRecognizer_create()
# cv2.face.EigenFaceRecognizer_create()
# cv2.face.FisherFaceRecognizer_create()# 后面两个方法要求人脸大小一致
训练
# 训练
face_cls.train(img_list, np.array(label_list))
试验图片
# 预测图片
test_file = './images/test/subject06.sad.gif'img_crop, label_id = getFaceImgLabel(test_file)plt.imshow(cv2.cvtColor(img_crop,cv2.COLOR_BGR2RGB)) # 显示图片
# plt.imshow(img_crop)
if img_crop is not None:predict_id,distance = face_cls.predict(img_crop)print(predict_id)
评估模型
其实也就是在试验单张图片的基础上通过大量测试集来评估模型好坏。
# 评估模型import glob
file_list = glob.glob('./images/test/*.gif')true_list = []
predict_list = []for file in file_list:img_crop, label_id = getFaceImgLabel(file)if img_crop is not None:predict_id,distance = face_cls.predict(img_crop)predict_list.append(predict_id)true_list.append(label_id)print(predict_list)
print(true_list)
查看准确率
# 查看准确率
from sklearn.metrics import accuracy_score
accuracy_score(true_list,predict_list)
结果可视化
# 获取融合矩阵
from sklearn.metrics import confusion_matrix
cm = confusion_matrix(true_list,predict_list)
cm# 可视化
import seaborn
seaborn.heatmap(cm,annot=True)
热力图:
(因为我没找到好的测试集,test文件夹就直接放的训练集的图片,所以结果怪怪的)
保存模型
# 保存模型
path = './weights/LBPG.yml'
face_cls.save(path)# 调用模型
new_cls = cv2.face.LBPHFaceRecognizer_create()
new_cls.read(path)# 预测一张图片
test_file = './images/test/subject06.sad.gif'img_crop, label_id = getFaceImgLabel(test_file)# plt.imshow(cv2.cvtColor(img_crop,cv2.COLOR_BGR2RGB)) # 显示图片
# plt.imshow(img_crop)
if img_crop is not None:predict_id,distance = new_cls.predict(img_crop)print(predict_id)
Residual Network
导入包
import numpy as np
import cv2
import matplotlib.pyplot as plt
import dlib# %matplotlib inline
plt.rcParams['figure.dpi'] = 200
提取关键点
# 获取人脸68个关键点
hog_face_detector = dlib.get_frontal_face_detector()
# 关键点检测模型
shape_detector = dlib.shape_predictor('./weights/shape_predictor_68_face_landmarks.dat')
# 读取1张测试图片
img = cv2.imread('./images/others/Walid_Al-Awadi/Walid_Al-Awadi_0001.jpg')
# plt.imshow(img)
# 检测人脸
detections = hog_face_detector(img,1)for face in detections:l,t,r,b = face.left(),face.top(),face.right(),face.bottom()# 获取68个关键点points = shape_detector(img,face)# 绘制关键点for point in points.parts():cv2.circle(img,(point.x,point.y),2,(0,255,0),1)# 绘制矩形框cv2.rectangle(img,(l,t),(r,b),(255,0,0),2)plt.imshow(cv2.cvtColor(img,cv2.COLOR_BGR2RGB))
导入Resent模型
# resent模型
face_descriptor_extractor = dlib.face_recognition_model_v1('./weights/dlib_face_recognition_resnet_model_v1.dat')
提取单张图片的特征描述符和label
通过face_descriptor_extractor.compute_face_descriptor计算特征描述符
# 提取单张图片的特征描述符label
def getFaceFeatLabel(filename):label_id = int(filename.split('/')[-1].split('.')[0].split('subject')[-1])# 读取图片cap = cv2.VideoCapture(filename)ret,img = cap.read()img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)# 检测人脸detections = hog_face_detector(img, 1)face_decriptor = Nonefor face in detections:# 获取关键点points = shape_detector(img,face)# 获取特征描述符face_decriptor = face_descriptor_extractor.compute_face_descriptor(img,points)# 转为numpy格式数组face_decriptor = [f for f in face_decriptor]face_decriptor = np.asarray(face_decriptor,dtype=np.float64)face_decriptor = np.reshape(face_decriptor,(1,-1))return label_id,face_decriptor
# img,label = getFaceImgLabel(img_path)
# plt.imshow(cv2.cvtColor(img,cv2.COLOR_BGR2RGB))id1,fd1 = getFaceFeatLabel('./images/test/subject06.sad.gif')
fd1.shape
训练
# 遍历训练文件夹
import glob
file_list = glob.glob('./images/yalefaces/*.gif')
file_list = [file.replace('\\', '/') for file in file_list]label_list = []
feature_list = Nonename_list = {}
index = 0
for file in file_list:label, feature = getFaceFeatLabel(file)if feature is not None:# 文件名列表name_list[index] = file# label列表label_list.append(label)index += 1if feature_list is None:feature_list = featureelse: # 特征列表feature_list = np.concatenate((feature_list ,feature),axis=0)# feature_list = np.concatenate((feature_list, feature.reshape(1, -1)), axis=0)# print(len(img_list),len(label_list))
print(name_list)
评估模型
距离的计算
# 计算距离
np.linalg.norm((feature_list[20]-feature_list[100]))# 计算某个特征描述符与所有特征描述符的距离
np.linalg.norm((feature_list[100]-feature_list),axis=1)# 寻找最小值索引min_index = np.argmin(np.linalg.norm((feature_list[0]-feature_list[1:]),axis=1))
min_index
模型评估
# 评估模型import glob
file_list = glob.glob('./images/test/*.gif')
file_list = [file.replace('\\', '/') for file in file_list]label_list = []
predict_list = []# 距离阈值
threshold = 0.5for file in file_list:label, feat = getFaceFeatLabel(file)cap = cv2.VideoCapture(file)ret,img = cap.read()img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)if feat is not None:# 计算距离distances = np.linalg.norm((feat-feature_list),axis=1)# 找最短距离min_index = np.argmin(distances)min_distance = distances[min_index]if min_distance < threshold:# 同一个人predict_id = int(name_list[min_index].split('/')[-1].split('.')[0].split('subject')[-1])else:predict_id = -1predict_list.append(predict_id)label_list.append(label)cv2.putText(img,'True:'+str(label),(10,30),cv2.FONT_HERSHEY_COMPLEX_SMALL,1,(0,255,0))cv2.putText(img,'Pred:'+str(predict_id),(10,50),cv2.FONT_HERSHEY_COMPLEX_SMALL,1,(0,255,0))cv2.putText(img,'Dist:'+str(min_distance),(10,70),cv2.FONT_HERSHEY_COMPLEX_SMALL,1,(0,255,0))plt.figure()plt.imshow(img)print(len(label_list))
print(len(predict_list))
准确率
# 公式评估
from sklearn.metrics import accuracy_score
accuracy_score(label_list,predict_list)
相关文章:

【OpenCV】人脸识别方法
代码已上传GitHub:plumqm/OpenCV-Projects at master EigenFace、FisherFace、LBPHFace 这三种方法的代码区别不大所以就一段代码示例。 EigenFace与FisherFace 1. 将人脸图像展开为一维向量,组成训练数据集 2. PCA(EigenFace)或…...

xxl-job定时任务
学习中心 清理Redis中的历史榜单: 持久化榜单数据: 创建历史榜单表: 支付服务 待退款订单检查: 未支付订单检查: 交易服务 退款单处理: 促销中心 优惠券发放状态处理:...

C#从零开始学习(如何构建应用)(1)
开始使用 C# 本章所有的代码都放在 https://github.com/hikinazimi/head-first-Csharp 创建一个控制台应用 打开Visual Studio 2019 创建项目 选择控制台应用程序 创建后点击运行,就可以在控制台打印Hello World 构建一个游戏(创建WPF项目) 构建游戏的步骤 首先创建WPF项…...

OpenCV高级图形用户界面(7)获取指定窗口的属性值函数getWindowProperty()的使用
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 提供窗口的参数。 函数 getWindowProperty 返回窗口的属性。 cv::getWindowProperty() 函数用于获取指定窗口的属性值。这个函数允许你查询窗口…...

Java实现文件上传功能
目录 1、准备工作 2、注意事项 3、jsp页面代码 4、Servlet 5、注册Servlet 1、准备工作 导入依赖:commons-fileupload和commons-io 2、注意事项 ①为保证服务器安全,上传文件应该放在外界无法直接访问的目录下,比如WEB-INF目录下 ②为…...

Leetcode|24. 两两交换链表中的节点 ● 19.删除链表的倒数第N个节点 ● 面试题 02.07. 链表相交 ● 142.环形链表II
24. 注意:涉及头节点的修改或者删除时,最好设置一个虚拟的头结点,方便简化代码,不必进行是否为头节点的的判断,简化code class Solution { public:ListNode* swapPairs(ListNode* head) {ListNode* dummyHead new Li…...

OpenCV学习笔记5——图像的数值计算
目录 一、简单数值计算 二、opencv中提供函数进行计算 三、cv2.addWeighted 一、简单数值计算 在opencv中,我们有许多可以获取图像各类数值的办法,许多函数能获得各种方面的数据。但如果我们什么都不用,仅仅对图像上每一个点做加法运算会…...

P3137 [USACO16FEB] Circular Barn S
P3137 [USACO16FEB] Circular Barn S 思路:数据范围为O(n^2)那么因此我们可以暴力,那么如何进行构造呢?首先假设一头奶牛在a,一头在b,如果要使一个到b,另一个到c,(a<b<c)&…...

yocto编辑软件包-devtool的使用方法
之前用了很多次devtool,总是忘记用法,故此记录一下。 假设你有一个软件包名叫foo,并且已经下载编译过,需要修改它的源码并生成patch 生成修改工作区 devtool modify foo modify命令会将foo的源码压缩包解压到build/workspace/so…...

51单片机快速入门之 串行通信 2024/10/21
51单片机快速入门之 串行通信 并行通信: 好处:传输快 适合短距离通信弊端:占用大量io 接线形式为8对8 串行通信 异步通信: 数据一帧一帧传送,传输完一帧之后,可继续或者等待(等待时为高电平) 其帧细分为(图片来源) 起始位:数据帧开始,一定为 0 外部设备只有接受到 0 之后…...

webpack 老项目升级记录:node-sass 规定的 node v8 提升至支持 node v22
老项目简介 技术框架 vue 2.5.17webpack 4.16.5"webpack-cli": "3.1.0""node-sass": "^4.7.2" 几个阶段 第一步:vue2 升级到最新 第一步:升级 vue2 至最新版本,截止到目前(2024-10-…...

【wpf】08 xml文件的存取操作
在使用wpf编程过程中,会用到xml的配置文件,实现对其读取和存储的操作是必须的。 1 xml说明 可扩展标记语言 (Extensible Markup Language, XML) ,标准通用标记语言的子集,可以用来标记数据、定义数据类型,是一种允许…...

即时通讯代码优化
在线用户逻辑修复 在进行测试时,发现当前代码有个问题,如果test1在服务器进行连接,本地的test2给test1发消息,虽然test1能收到服务器上的信息,但是本地服务日志中会报teset1不在线,需要对该种情况进行修复…...

jmeter学习(8)界面的使用
1、新建test plan 3、 打开文件 4、保存 5、剪切 6、复制 7、粘贴 8、所有线程组展开 9、所有线程组收缩 10、置灰,操作后无法使用 11、执行 13、清空当前线程组结果 14、清空所有线程组结果 15、函数助手 搜索,可以用于搜索某个请求&#x…...

记录一次hiveserver2卡死(假死)问题
问题描述 给开发人员开通了个账号,连接hive进行查询,后来发现,hive服务有时候会卡死,查询不了,连不上(所有账号/客户端都连不上hive),但在chd里面看监控,服务器资源状态…...

【ios】在 SwiftUI 中实现可随时调用的加载框
在 SwiftUI 项目中实现一个自定义的加载框(loading)功能,可以在任意位置调用,以便显示加载动画或者进度条。下面的教程将详细讲解如何创建一个可复用的 Loading 组件,并通过通知机制控制其显示和隐藏。 先上效果&…...

字符、解释型语言、编程语言的互操作、输出
字符 同样是1,有人看到的是数字,有人看到的是字符,还有人看到的是一个小目标。 不同语言的字符 正则表达式把字符分成普通字符和元字符,元字符为了搭配匹配。比如.代表任意非换行字符,这对于通配很简便,用\…...

基于Python的自然语言处理系列(39):Huggingface中的解码策略
在自然语言生成任务中,如何选择下一步的单词或者词语对生成的文本质量影响巨大。Huggingface 提供了多种解码策略,可以在不同的场景下平衡流畅度、创造力以及生成效率。在这篇文章中,我们将逐步介绍 Huggingface 中的几种常见解码策略&#x…...

如何将视频格式转为mp4?好好看看下面这几个方法
如何将视频格式转为mp4?在数字化时代,视频已成为信息传播与娱乐消遣的重要载体。无论是学习、工作还是日常生活,我们几乎每天都会接触到各式各样的视频内容。然而,不同设备、平台或软件生成的视频文件往往采用不同的编码格式&…...

景区智慧公厕系统,监测公厕异味,自动清洁除臭
随着旅游业的快速发展,景区的公共厕所管理成为提升游客体验的重要环节。传统的公厕管理方式存在诸多不足,如卫生条件差、异味严重等问题。为了改善这些问题,许多景区开始采用智慧公厕系统。这种系统能够实时监测公厕内的异味,并自…...

GitLab CVE-2024-6389、CVE-2024-4472 漏洞解决方案
极狐GitLab 近日发布安全补丁版本17.3.2, 17.2.5, 17.1.7,修复了17个安全漏洞,本分分享其中两个漏洞 CVE-2024-6389、CVE-2024-4472 两个漏洞详情及解决方案。 极狐GitLab 正式推出面向 GitLab 老旧版本免费用户的专业升级服务,为 GitLab 老…...

hashCode的底层原理
HashCode是计算机科学中一个广泛使用的概念,特别是在Java等编程语言中,它扮演着重要的角色。为了详细解释hashCode的底层原理,以下从几个方面进行阐述: 一、hashCode的基本概念 HashCode,即哈希码,是一个将…...

hadoop_hdfs详解
HDFS秒懂 HDFS定义HDFS优缺点优点缺点 HDFS组成架构NameNodeDataNodeSecondary NameNodeClient NameNode工作机制元数据的存储启动流程工作流程 Secondary NameNode工作机制checkpoint工作流程 DataNode工作机制工作流程数据完整性 文件块大小块太小的缺点块太大的缺点 文件写入…...

【Linux】Linux命令行与环境变量
1.命令行 前⾯写C语⾔时,很少关注过 main 函数的参数,也没有考虑过 main 为什么会有参 数。 实际上在C语⾔中, main 函数⼀共有三个参数,在命令⾏部分先关注前两个参数: 1. argc:表示 main 函数接收到参…...

改变函数调用上下文:apply与call方法详解及实例
目录 改变函数调用上下文:apply与call方法详解及实例 一、什么是 apply 方法? 1、apply 语法 2、apply 示例 二、什么是 call 方法? 1、call 语法 2、call 示例 三、apply 和 call 的共同与差异 1、apply 和 call 的共同点 2、apply…...

k8s中的微服务
一、什么是微服务 用控制器来完成集群的工作负载,那么应用如何暴漏出去?需要通过微服务暴漏出去后才能被访问 Service是一组提供相同服务的Pod对外开放的接口。 借助Service,应用可以实现服务发现和负载均衡。 service默认只支持4层负载均…...

树莓派--AI视觉小车智能机器人--1.树莓派系统烧入及WiFi设置并进入jupyterlab
一、Raspberry Pi 系统烧入 使用树莓派,我们是需要有操作系统的。默认情况下,树莓派会在插入的SD卡上查找操作系统。这需要一台电脑将存储设备映像为引导设备,并将存储设备插入该电脑。大多数树莓派用户选择microSD卡作为引导设备。 1.1 下载…...

MacOS安装BurpSuite
文章目录 一、下载地址二、下载注册机三、安装教程四、启动burpsuit五、免责声明 一、下载地址 https://portswigger-cdn.net/burp/releases/download?productpro&version2024.7.1&typeMacOsx二、下载注册机 https://github.com/NepoloHebo/BurpSuite-BurpLoaderKey…...

【AI工具大全】《史上最全的AI工具合集》
一.AI编程类工具 1.CodeArts Snap CodeArts Snap是华为云研发的智能开发助手,覆盖软件开发全生命周期,提供代码生成、研发知识问答、智能协同等功能。通过自然语言编程,它能自动生成代码、解释代码逻辑、提供调试与检查,提升开发效率和软件质量。 2.ModelArts ModelArt…...

qt继承结构
一、 继承结构 所有的窗口类均继承自QWidget类,因此QWidget类本身包含窗口的特性。QWidget对象本身既可以作为独立窗口,又可以作为组件(子窗口)。 通过构造函数可以创建以上两种形态的QWidget: // 参数1:使…...