【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)直方图来描述这些区域的纹理特征。然后,它将这些局部直方图串联起来形成一个特征向量,这个特征向量就可以用来识别或分类人脸。

具体步骤:

  1. 灰度图转换

    • 首先,LBPH算法需要输入一张灰度图像。因为LBPH主要基于像素的纹理特征,所以不需要彩色信息,直接将人脸图像转换为灰度图即可。
  2. 计算局部二值模式(LBP)

    • 对于每个像素点,LBP算法将以它为中心,比较它与周围8个像素的灰度值。根据灰度值的大小,将大于或等于中心像素的邻近像素标记为1,反之为0,得到一个8位二进制数。这个二进制数就是该像素的局部二值模式值。
    • 例如,假设中心像素值为 50,周围的像素值为 [55, 60, 45, 30, 70, 40, 80, 90],根据规则将大于50的像素标记为1,小于的标记为0,得到的二进制模式可能是11010101,转换为十进制就是213。
  3. 划分区域

    • 将人脸图像分成若干个小的区域(通常是网格状,如10x10的网格),然后对每个区域计算该区域内所有像素的LBP直方图。
  4. 构建特征向量

    • 对于每个区域,LBPH都会计算局部二值模式的直方图,这些直方图包含了该区域内纹理的统计信息。然后,将所有区域的直方图连接起来,形成一个完整的特征向量。
  5. 特征匹配

    • 一旦提取了人脸的特征向量,就可以使用距离度量方法(如欧氏距离、卡方距离等)来比较新的人脸图像与数据库中已知的人脸特征向量。如果两个特征向量的距离足够小,则判定这两张人脸是同一个人。

准备阶段

导入包

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))
        
        # 获取人脸label
        label_id = int(filename.split('/')[-1].split('.')[0].split('subject')[-1])

        return img_crop, label_id
    else :
        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 = None
    for 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 = None

name_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 += 1

        if feature_list is None:
            feature_list = feature
        else:    
            # 特征列表
            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.5

for 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 = -1
    
        predict_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)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Spring MVC 原理与源码

Spring MVC 整体代码量有 5w 行&#xff0c;通过本专栏&#xff0c;可以快速的研读核心部分的代码&#xff0c;节省你的时间。 DispatcherServlet 的流程处理如下图&#xff1a; 但是随着前后端分离&#xff0c;后端大多提供 Restful API &#xff0c;里面的 ViewResolver 和 …

word怎么清除格式,Word一键清除所有格式教程

你是否曾在编辑Word文档时遇到过复制内容时格式混乱的情况?别担心&#xff0c;这只需要清除一下格式就可以了&#xff0c;很多朋友还不知道word怎么清除格式&#xff0c;下面小编就来给大家讲一讲word一键清除所有格式的方法教程&#xff0c;操作非常简单&#xff0c;有需要的…

02电力电子技术简介

电力电子技术简介 第一章主要是做通识性的介绍&#xff0c;介绍电力电子涉及的基本概念、学习方法和关联学科。最重要的是希望大家能理解电力电子在现实生活中的广泛应用。这一章简介主要分三部分来介绍。首先是概要性的通盘介绍。然后会通过力电子技术性的内容来了解一些拓扑…

用Python将Office文档(Word、Excel、PowerPoint)批量转换为PDF

在处理不同格式的Office文档&#xff08;如Word、Excel和PowerPoint&#xff09;时&#xff0c;将其转换为PDF格式是常见的需求。这种转换不仅确保了文件在不同设备和操作系统间的一致性显示&#xff0c;而且有助于保护原始内容不被轻易修改&#xff0c;非常适合于正式报告、提…

InnoDB引擎(架构,事务原理,MVCC详细解读)

目录 架构分析 逻辑存储结构​ 内存结构​ Buffer Pool​ ChaneBuffer 自适应哈希​ LogBuffer​ 磁盘结构​ 后台线程​ 事务原理​ redolog日志 undolog日志​ MVCC​ 三个隐藏字段​ undolog版本链 readview​ RC(读已提交原理分析)​ RR(可重复读原理分析…

yolov8-ultralytics-利用TP、TN、FP、FN添加mIoU指标

在文件ultralytics/utils/metrics.py中的ConfusionMatrix类里 tp_fp 函数下方添加函数tp_fp_fn&#xff1a; def tp_fp_fn(self):"""Returns true positives, false positives and false negative."""tp self.matrix.diagonal()fp self.matri…

深入理解计算机系统--计算机系统漫游

对于一段最基础代码的文件hello.c&#xff0c;解释程序的运行 #include <stdio.h>int main() {printf ( "Hello, world\n") ;return 0; }1.1、信息就是位上下文 源程序是由值 0 和 1 组成的位&#xff08;比特&#xff09;序列&#xff0c;8 个位被组织成一组…

HCIA复习实验

实验要求 实验拓扑以及实验分析 第一步先划分网段 先对内网划分 192.168.1.0/24划分 192.168.1.0/26---骨干主线路 192.168.1.64/26---骨干备线路 ---192.168.1.128/25--vlan2 3汇总---便于减少路由表条目---在大型网络方便 192.168.1.128/26---vlan2 192.168.1.192/26---vla…

OpenCV视觉分析之运动分析(2)背景减除类:BackgroundSubtractorKNN的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 K-最近邻&#xff08;K-nearest neighbours, KNN&#xff09;基于的背景/前景分割算法。 该类实现了如 319中所述的 K-最近邻背景减除。如果前景…

-webkit-box-orient属性丢失?

在实际项目场景当中&#xff0c;我们经常会遇到需要对超长文本溢出省略的场景&#xff1a; 我们经常会这样写—— 单行省略&#xff1a; overflow: hidden; //文本溢出隐藏text-overflow: ellipsis; //文本溢出显示省略号white-space: nowrap; //不换行 多行省略&#xff1a…

VUE3.0基础入门笔记

一、响应式基础 1.ref()&#xff1a;声明基本类型,引用类型&#xff0c;函数需接收参数&#xff0c;并将其包裹在一个带有 .value 属性的对象中&#xff0c;在模板中使用 ref 时&#xff0c;我们不需要附加 .value,当在模板中使用时&#xff0c;ref 会自动解包。 <templat…

计算机毕业设计 基于 Python的考研学习系统的设计与实现 Python毕业设计选题 前后端分离 附源码 讲解 文档

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

CISP/NISP二级练习题-第一卷

目录 另外免费为大家准备了刷题小程序和docx文档&#xff0c;有需要的可以私信获取 1&#xff0e;不同的信息安全风险评估方法可能得到不同的风险评估结果&#xff0c;所以组织 机构应当根据各自的实际情况选择适当的风险评估方法。下面的描述中错误的是 &#xff08;&#…

【Linux】进程的挂起状态

挂起状态的前提条件 当 内存资源严重不足 时&#xff0c;操作系统会考虑将部分进程换出到磁盘上的交换空间&#xff08;swap 分区&#xff09;。这通常发生在以下几种情况下&#xff1a; 内存不足&#xff1a; 当物理内存接近耗尽时&#xff0c;操作系统会选择将一部分暂时不需…

明源云ERP报表服务GetErpConfig.aspx接口存在敏感信息泄露

一、漏洞简介 在访问 /service/Mysoft.Report.Web.Service.Base/GetErpConfig.aspx?erpKeyerp60 路径时&#xff0c;返回了包含敏感信息的响应。这些信息包括但不限于数据库连接字符串、用户名、密码、加密密钥等。这些敏感信息的暴露可能导致以下风险&#xff1a;数据库访问…

Linux 常用命令(一)

目录 ll命令&#xff1a;显示指定文件的详细属性信息 ls&#xff1a;显示目录中文件及其属性信息 mkdir命令&#xff1a;创建目录文件 touch&#xff1a;创建空文件与修改时间戳 rm命令&#xff1a;删除文件或目录 cd命令&#xff1a;切换目录 chmod命令&#xff1a;改变…

llama.cpp 去掉打印,只显示推理结果

llama.cpp 去掉打印&#xff0c;只显示推理结果 1 llama.cpp/common/log.h #define LOG_INF(...) LOG_TMPL(GGML_LOG_LEVEL_INFO, 0, __VA_ARGS__) #define LOG_WRN(...) LOG_TMPL(GGML_LOG_LEVEL_WARN, 0, __VA_ARGS__) #define LOG_ERR(…

docker部署es与kibana Mac

1. 创建网络 神一样的链接&#xff0c;不用谢&#xff1a; 1.Docker命令链接&#xff1a;黑马整理的docker速成链接 2.jdk11链接&#xff1a;jdk11 3.神资源链接&#xff1a;别点&#xff0c;要脸 注意&#xff1a;es需要先安装jdk环境&#xff0c;推荐jdk11&#xff0c;否则…

MySQL企业常见架构与调优经验分享

文章目录 一、选择 PerconaServer、MariaDB 还是 MYSQL二、常用的 MYSQL 调优策略三、MYSOL 常见的应用架构分享四、MYSOL 经典应用架构 观看学习课程的笔记&#xff0c;分享于此~ 课程&#xff1a;MySQL企业常见架构与调优经验分享 mysql官方优化文档 一、选择 PerconaServer、…

基于SSM的的水电管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…