目录
一、Haar特征的级联分类器(Cascade Classifier)
一、Haar特征的级联分类器(Cascade Classifier)
Haar特征的级联分类器(Cascade Classifier)是一种用于对象检测的机器学习算法,特别是在计算机视觉领域中用于人脸检测。这种方法由Paul Viola和Michael Jones在2001年提出,因此也被称为Viola-Jones人脸检测算法。
(1)关键特点:
快速高效:Haar级联分类器能够在视频流中实时检测人脸,因为它的设计允许快速排除非人脸区域。
使用Haar特征:Haar特征是基于图像的灰度变化,可以捕捉到图像中的亮区域和暗区域。这些特征可以是简单的(如边缘、线条、斑点)或复杂的(如多个区域的组合)。
AdaBoost训练:使用AdaBoost算法从大量弱分类器(基于Haar特征的分类器)中训练出一个强分类器。每个弱分类器都能识别出人脸的某些特征,而AdaBoost算法则确定这些弱分类器的最优组合。
级联结构:分类器被组织成一个级联,通常包括多个阶段。每个阶段由多个弱分类器组成,只有当一个候选区域通过了前一个阶段的所有弱分类器后,它才会进入下一个阶段。
多尺度检测:通过在不同的尺度上应用分类器,可以检测到不同大小的人脸。
(2)工作原理:
图像预处理:输入图像通常被转换为灰度图,因为Haar特征是基于灰度变化的。
Haar特征提取:在图像中提取Haar特征,这些特征可以是任意形状的矩形区域,通过计算这些区域内的像素值差异来形成特征。
级联分类:图像中的每个候选区域(如窗口)都会被送入级联分类器。级联的每个阶段都会尝试拒绝候选区域(即判断它是否不是人脸)。
阶段判断:如果候选区域通过了当前阶段的所有弱分类器,它将进入下一个阶段。如果它未能通过任何阶段,就会被标记为非人脸区域,并从进一步检测中排除。
最终检测:只有通过了所有阶段的候选区域才会被最终确定为人脸,并返回其位置和大小。
多尺度扫描:为了检测不同大小的人脸,这个过程会在不同的尺度上重复进行。
二、 人脸检测:
人脸检测是计算机视觉领域中的一个重要任务,它涉及到从图像或视频帧中识别和定位人脸的存在。通过使用Haar特征的级联分类器等先进的算法,人脸检测系统能够快速准确地从复杂的背景中提取出人脸,为后续的人脸识别、表情分析等任务提供基础。
(1)检测原理:
多尺度目标检测:detectMultiScale
函数能够检测图像中所有目标对象的实例,这些目标对象可以有不同的尺寸。这是通过在不同尺度上滑动窗口来实现的,即对图像进行多次扫描,每次扫描时窗口的尺寸都会按比例系数scaleFactor
进行缩放。
参数化检测:该函数允许用户通过参数调整检测过程,例如scaleFactor
控制窗口的缩放比例,minNeighbors
参数控制每个候选矩形应该保留的邻近元素个数,以减少误检。
特征提取与分类:在每个候选窗口中,detectMultiScale
会提取Haar特征,并使用预训练的级联分类器进行分类,以确定窗口是否包含目标对象。
候选框筛选与合并:根据分类器的结果,将分类为目标对象的候选框保留下来,其余的候选框被舍弃。对于相邻的被保留的候选框,算法还会进行合并,以确保每个目标对象只被检测一次。
输出结果:最终,函数输出被检测到的目标对象的位置和尺寸信息,通常以矩形框的形式表示。
灵活性与效率:通过级联分类器的使用,detectMultiScale
函数提高了检测的准确性和速度,同时,算法的可调整参数和模型的训练也为人脸检测的精度和性能提供了灵活性。
(2)导入人脸和眼睛分类器:
分类器使用:
# 人脸识别分类器
faceCascade = cv2.CascadeClassifier('C:/Users/86173/AppData/Roaming/Python/Python38/site-packages/cv2/data/haarcascade_frontalface_default.xml')
# 识别眼睛的分类器
eyeCascade = cv2.CascadeClassifier('C:/Users/86173/AppData/Roaming/Python/Python38/site-packages/cv2/data/haarcascade_eye.xml')
在OpenCV中,预训练的Haar特征分类器文件通常位于OpenCV的data
目录下。这些文件是XML格式的,包含了用于人脸、眼睛等对象检测的级联分类器。
路径示例:
- 在Windows系统上,路径可能类似于:
C:\Users\你的用户名\AppData\Roaming\Python\Python版本号\site-packages\cv2\data
分类器文件:
在data
目录下,可以找到多个XML文件,例如:
haarcascade_frontalface_default.xml
:用于人脸检测。haarcascade_eye.xml
:用于眼睛检测。haarcascade_smile.xml
:用于微笑检测。
还有其他用于不同对象检测的XML文件。
(3)detectMultiScale函数:
detectMultiScale函数是OpenCV中用于目标检测的函数,它可以用来检测图像中是否存在指定的目标,并返回目标位置的矩形边界框。
函数原型:
detectMultiScale(
image,
scaleFactor=1.1,
minNeighbors=3,
flags=None,
minSize=(0, 0),
maxSize=(0, 0)
)
参数说明:
mage
:输入的图像,必须是灰度图,因为Haar特征是基于灰度的。scaleFactor
:(可选)在图像尺寸减小的比例,即每次图像尺寸减小的比例。默认值为1.1,表示每次窗口尺寸减少10%。调整这个参数可以平衡检测的精度和速度:较小的scaleFactor
值能够提高检测的细致程度,但会增加计算负担;而较大的值则可以减少计算量,加快处理速度,但可能会降低检测的准确性,从而错过一些较小或较远的目标。minNeighbors
:(可选)构成检测目标的相邻矩形的最小个数。默认值为3,意味着有3个以上的检测标记存在时,才认为人脸存在。这个参数有助于减少误检,即非目标对象被错误地识别为目标的情况。设置一个较高的minNeighbors
值可以更严格地筛选出真正的目标,从而减少误检,但同时也有可能将一些真正的目标遗漏,因为它们可能没有足够的邻近矩形满足条件。flags
:(可选)这个参数通常被省略,flags参数用于定义检测模式,在使用低版本OpenCV时,它可能会被设置为cv2.CASCADE_SCALE_IMAGE
,表示在多尺度检测时调整图像尺寸。它可以是以下几个值的组合:- CASCADE_DO_ROUGH_SEARCH:快速搜索模式。
- CASCADE_FIND_BIGGEST_OBJECT:只检测最大的目标。
- CASCADE_SCALE_IMAGE:使用缩放图像进行检测(默认值)。
minSize
:(可选)目标的最小尺寸,小于这个尺寸的目标将被忽略。默认为(0, 0),表示没有限制。maxSize
:(可选)目标的最大尺寸,大于这个尺寸的目标将被忽略。默认为(0, 0),表示没有限制。
返回值:
rects
:一个矩形列表,其中每个矩形包含检测到的对象的坐标和尺寸,格式为(x, y, w, h)
。levels
:每个检测到的对象的金字塔层级。scores
:每个检测到的对象的置信度分数。
(3)完整代码:
import numpy as np
import cv2
# 人脸识别分类器
faceCascade = cv2.CascadeClassifier('C:/Users/86173/AppData/Roaming/Python/Python38/site-packages/cv2/data/haarcascade_frontalface_default.xml')
# 识别眼睛的分类器
eyeCascade = cv2.CascadeClassifier('C:/Users/86173/AppData/Roaming/Python/Python38/site-packages/cv2/data/haarcascade_eye.xml')
# 开启摄像头
cap = cv2.VideoCapture(0) # 0代表默认摄像头
Face = True # 用于控制循环的布尔变量
while Face: # 当Face为True时,循环继续
# 读取摄像头中的图像,Face为是否读取成功的判断参数
Face, img = cap.read()
# 转换成灰度图像
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 转换为灰度图像,Haar特征是基于灰度的
# 人脸检测
faces = faceCascade.detectMultiScale(
gray,
scaleFactor=1.2, # 每次图像尺寸减小的比例
minNeighbors=6, # 有6个以上的检测标记存在时,才认为人脸存在。
minSize=(32, 32) # 检测的最小尺寸
)
# 在检测人脸的基础上检测眼睛
for (x, y, w, h) in faces: # detectMultiScale返回值格式为(x, y, w, h)
fac_gray = gray[y: (y+h), x: (x+w)] # 截取人脸区域的灰度图像
result = [] # 用于存储眼睛检测结果的列表
eyes = eyeCascade.detectMultiScale(fac_gray, 1.3, 2) # 检测眼睛,eyeCascade为眼睛分类器
# 眼睛坐标的换算,将相对位置换成绝对位置
# ex和ew是眼睛区域在人脸区域图像中的宽度和高度
# x+ex和y+ey将眼睛的坐标从人脸区域的相对坐标转换为整个图像的绝对坐标
for (ex, ey, ew, eh) in eyes:
result.append((x+ex, y+ey, ew, eh)) # 将相对坐标转换为绝对坐标
# result.append()是一个列表方法,存储眼睛检测结果区域的列表。
# 画矩形
for (x, y, w, h) in faces:
cv2.rectangle(img, (x, y), (x+w, y+h), (255, 0, 0), 2) # 在人脸区域画蓝色矩形框
for (ex, ey, ew, eh) in result:
cv2.rectangle(img, (ex, ey), (ex+ew, ey+eh), (0, 255, 0), 2) # 在眼睛区域画绿色矩形框
cv2.imshow('Face', img) # 显示图像窗口
Exit = cv2.waitKey(1) # 等待键盘输入,参数1表示等待1毫秒
if Exit == 27: # 如果按下ESC键(ASCII码27),则退出循环
break
# 释放摄像头资源
cap.release()
# 关闭所有OpenCV窗口
cv2.destroyAllWindows()
三、收集人脸数据 :
收集人脸数据是人脸识别系统中的一个关键步骤,它涉及到捕获和保存用于训练和测试算法的人脸图像。这些图像通常需要从不同角度、不同光照条件下以及不同表情下的人脸中收集,以确保算法的鲁棒性和准确性。通过自动化的图像捕获工具和手动标注,可以构建一个多样化的人脸数据库,这对于训练出一个能够准确识别不同个体的人脸识别系统至关重要。此外,收集的数据还需要进行预处理,如调整大小、归一化和对齐,以适应特定的人脸识别模型。最终,这些经过处理的人脸图像将被用于训练人脸识别模型,使其能够识别和区分不同的人脸。
(1)图像保存初始化:
初始化人脸数据收集程序,通过打开默认摄像头、加载Haar特征的人脸识别分类器、获取用户ID以及初始化人脸捕获计数器,为后续捕获和保存特定用户的面部图像做好准备,以便用于人脸识别系统的训练或测试。
# 打开摄像头,参数0通常表示默认或第一个摄像头,自带的摄像头。
cap = cv2.VideoCapture(0)
# 加载Haar特征的人脸识别分类器
faceCascade = cv2.CascadeClassifier('C:/Users/86173/AppData/Roaming/Python/Python38/site-packages/cv2/data/haarcascade_frontalface_default.xml')
# 从用户那里获取ID,用于保存人脸数据
face_ID = input('\n Please enter the user ID:')
# 打印初始化信息
print('\n Capture the face...')
# 初始化计数器,用于记录捕获的人脸数量
count = 0
(2)捕获人像收集人脸数据:
使用循环从摄像头实时捕获图像,并使用Haar特征级联分类器检测图像中的人脸。对于每个检测到的人脸,程序会在图像上绘制一个蓝色的矩形框,并将其保存为灰度图像文件。这个过程会一直持续,直到捕获到1000个人脸图像或者用户按下ESC键(ASCII码27)为止。每次成功保存一个人脸图像后,计数器count
会增加。最后,程序会释放摄像头资源并关闭所有OpenCV创建的窗口,有效地收集了用于人脸识别训练的数据集。
# 开始无限循环,直到count >= 1000
while True:
# 从摄像头读取一帧图像
Read, img = cap.read()
# 如果读取失败,Read将为False
if not Read:
print("Image acquisition failed...")
break
# 将图像转换为灰度图,因为人脸识别通常在灰度图上进行
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 使用分类器检测图像中的人脸
faces = faceCascade.detectMultiScale(gray, 1.3, 5)
# 遍历检测到的每个人脸
for (x, y, w, h) in faces:
# 在原图上绘制矩形框,标记出人脸区域
cv2.rectangle(img, (x, y), (x+w, y+h), (255, 0, 0), 2)
# 增加计数器
count += 1
# 保存人脸图像到文件系统
# 文件名格式为 "C:/Users/86173/Desktop/Face/Face/Facedata/User.ID.Count.jpg"
# 这部分截取了灰度图像中的人脸区域,准备将其保存为文件
cv2.imwrite("C:/Users/86173/Desktop/Face/Face/Facedata/User." + str(face_ID) + '.' + str(count) + '.jpg', gray[y: y + h, x: x + w])
# 显示图像窗口
cv2.imshow('Face', img)
# 等待键盘事件,参数1表示等待1毫秒
Exit = cv2.waitKey(1)
# 如果按下ESC键(ASCII码27),则退出循环
if Exit == 27:
break
# 如果捕获到的人脸数量达到1000,也退出循环
elif count >= 1000:
break
# 释放摄像头资源
cap.release()
# 关闭所有OpenCV创建的窗口
cv2.destroyAllWindows()
保存的人脸图像是人脸识别系统中不可或缺的一部分,可以为训练、测试和部署人脸识别模型提供了必要的数据支持。
(3)完整代码:
import cv2
# 打开摄像头,参数0通常表示默认或第一个摄像头,自带的摄像头。
cap = cv2.VideoCapture(0)
# 加载Haar特征的人脸识别分类器
faceCascade = cv2.CascadeClassifier('C:/Users/86173/AppData/Roaming/Python/Python38/site-packages/cv2/data/haarcascade_frontalface_default.xml')
# 从用户那里获取ID,用于保存人脸数据
face_ID = input('\n Please enter the user ID:')
# 打印初始化信息
print('\n Capture the face...')
# 初始化计数器,用于记录捕获的人脸数量
count = 0
# 开始无限循环,直到count >= 1000
while True:
# 从摄像头读取一帧图像
Read, img = cap.read()
# 如果读取失败,Read将为False
if not Read:
print("Image acquisition failed...")
break
# 将图像转换为灰度图,因为人脸识别通常在灰度图上进行
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 使用分类器检测图像中的人脸
faces = faceCascade.detectMultiScale(gray, 1.3, 5)
# 遍历检测到的每个人脸
for (x, y, w, h) in faces:
# 在原图上绘制矩形框,标记出人脸区域
cv2.rectangle(img, (x, y), (x+w, y+h), (255, 0, 0), 2)
# 增加计数器
count += 1
# 保存人脸图像到文件系统
# 文件名格式为 "C:/Users/86173/Desktop/Face/Face/Facedata/User.ID.Count.jpg"
# 这部分截取了灰度图像中的人脸区域,准备将其保存为文件
cv2.imwrite("C:/Users/86173/Desktop/Face/Face/Facedata/User." + str(face_ID) + '.' + str(count) + '.jpg', gray[y: y + h, x: x + w])
# 显示图像窗口
cv2.imshow('Face', img)
# 等待键盘事件,参数1表示等待1毫秒
Exit = cv2.waitKey(1)
# 如果按下ESC键(ASCII码27),则退出循环
if Exit == 27:
break
# 如果捕获到的人脸数量达到1000,也退出循环
elif count >= 1000:
break
# 释放摄像头资源
cap.release()
# 关闭所有OpenCV创建的窗口
cv2.destroyAllWindows()
四、训练人脸数据:
加载人脸数据,使用Haar特征分类器检测人脸,提取人脸特征,训练LBPH人脸识别器,并将训练好的模型保存到文件中,以便后续用于人脸识别任务。
(1)原理及方法:
cv2.face.LBPHFaceRecognizer_create()
是 OpenCV 中用于创建局部二值模式直方图(Local Binary Patterns Histograms,简称 LBPH)人脸识别器的方法。LBPH是一种基于图像纹理特征的描述符,它通过比较每个像素与其周围邻域的像素值来生成二进制模式,然后将这些模式转换为直方图,用于描述图像的局部特征。
加载收集的人脸数据并创建LBPH人脸识别器和Haar特征的人脸识别分类器:
# 人脸数据路径
path = 'C:/Users/86173/Desktop/Face/Face/Facedata'
# 创建一个LBPH人脸识别器
recognizer = cv2.face.LBPHFaceRecognizer_create()
# 加载Haar特征的人脸识别分类器
faceCascade = cv2.CascadeClassifier('C:/Users/86173/AppData/Roaming/Python/Python38/site-packages/cv2/data/haarcascade_frontalface_default.xml')
定义获取图像和标签函数:
# 定义一个函数,用于获取图像和标签
def getImagesAndLabels(path):
# 使用os.path.join获取完整的文件路径,并列出path目录下的所有文件
imagePaths = [os.path.join(path, f) for f in os.listdir(path)]
faceSamples = [] # 用于存储人脸样本的列表
ids = [] # 用于存储每个人脸样本对应的ID
for imagePath in imagePaths:
# 使用PIL打开图像,并转换为灰度图
PIL_img = Image.open(imagePath).convert('L')
# 将PIL图像转换为NumPy数组
img_numpy = np.array(PIL_img, 'uint8')
# 从文件名中提取ID
id = int(os.path.split(imagePath)[-1].split(".")[1])
# 使用分类器检测图像中的人脸
faces = faceCascade.detectMultiScale(img_numpy)
# 遍历检测到的每个人脸
for (x, y, w, h) in faces:
# 截取人脸区域并添加到人脸样本列表中
faceSamples.append(img_numpy[y:y + h, x: x + w])
# 将ID添加到ID列表中
ids.append(id)
# 返回人脸样本和对应的ID列表
return faceSamples, ids
(2)函数介绍:
定义函数和参数:
getImagesAndLabels(path)
:这是一个自定义函数,path
是它的参数,表示包含人脸图像文件的目录路径。
获取文件列表:
imagePaths = [os.path.join(path, f) for f in os.listdir(path)]
:这行代码列出了指定目录下的所有文件,并使用os.path.join
构建每个文件的完整路径。结果是一个包含所有图像文件路径的列表。- 即该文件夹下所有图像文件的路径:
初始化样本和标签列表:
faceSamples = []
:创建一个空列表,用于存储转换为人脸样本的NumPy数组。ids = []
:创建一个空列表,用于存储每个样本对应的ID。
遍历图像文件:
for imagePath in imagePaths:
:这个循环遍历每个图像文件的路径。
打开和转换图像:
PIL_img = Image.open(imagePath).convert('L')
:使用PIL库打开图像文件,并将其转换为灰度图('L'模式)。img_numpy = np.array(PIL_img, 'uint8')
:将PIL图像对象转换为NumPy数组,这是OpenCV处理图像的常用格式。
提取ID:
id = int(os.path.split(imagePath)[-1].split(".")[1])
:从文件路径中提取文件名,然后根据文件名格式(假设为User.ID.Count.jpg
)提取ID部分,并将其转换为整数。
人脸检测:
faces = faceCascade.detectMultiScale(img_numpy)
:使用Haar特征分类器在灰度图像上检测人脸,返回值是一个包含人脸区域坐标的列表。
遍历检测到的人脸:
for (x, y, w, h) in faces:
:这个循环遍历每个检测到的人脸区域。
截取人脸区域:
faceSamples.append(img_numpy[y:y + h, x: x + w])
:根据人脸区域的坐标,从灰度图像的NumPy数组中截取人脸区域,并添加到faceSamples
列表中。
添加ID:
ids.append(id)
:对于每个截取的人脸样本,将对应的ID添加到ids
列表中。
返回结果:
return faceSamples, ids
:函数返回两个人脸样本列表,一个是包含人脸图像数据的faceSamples
,另一个是包含对应ID的ids
。
(3)训练人脸模型:
调用getImagesAndLabels
函数从指定路径加载人脸图像和对应的ID,使用这些数据训练一个LBPH人脸识别模型,然后将训练好的模型保存到文件中,以便后续使用。最后,代码打印出训练完成的消息和训练的人脸数量,标志着模型训练过程的结束。这个过程可以为人脸识别任务提供了一个预训练的模型,可以用于实时识别或验证个体身份。
# 训练人脸识别模型
print('Training a face recognition model...')
faces, ids = getImagesAndLabels(path)
recognizer.train(faces, np.array(ids))
# 将训练好的模型保存到文件
recognizer.write('C:/Users/86173/Desktop/Face/Face/face_trainer/trainer.yml')
# 打印训练完成的消息
print("{0} Model training over...".format(len(np.unique(ids))))
由于处理的图像较多,需要等待一会才能训练完成。
(4)完整代码:
import numpy as np
from PIL import Image
import os
import cv2
# 人脸数据路径
path = 'C:/Users/86173/Desktop/Face/Face/Facedata'
# 创建一个LBPH人脸识别器
recognizer = cv2.face.LBPHFaceRecognizer_create()
# 加载Haar特征的人脸识别分类器
faceCascade = cv2.CascadeClassifier('C:/Users/86173/AppData/Roaming/Python/Python38/site-packages/cv2/data/haarcascade_frontalface_default.xml')
# 定义一个函数,用于获取图像和标签
def getImagesAndLabels(path):
# 使用os.path.join获取完整的文件路径,并列出path目录下的所有文件
imagePaths = [os.path.join(path, f) for f in os.listdir(path)]
faceSamples = [] # 用于存储人脸样本的列表
ids = [] # 用于存储每个人脸样本对应的ID
for imagePath in imagePaths:
# 使用PIL打开图像,并转换为灰度图
PIL_img = Image.open(imagePath).convert('L')
# 将PIL图像转换为NumPy数组
img_numpy = np.array(PIL_img, 'uint8')
# 从文件名中提取ID
id = int(os.path.split(imagePath)[-1].split(".")[1])
# 使用分类器检测图像中的人脸
faces = faceCascade.detectMultiScale(img_numpy)
# 遍历检测到的每个人脸
for (x, y, w, h) in faces:
# 截取人脸区域并添加到人脸样本列表中
faceSamples.append(img_numpy[y:y + h, x: x + w])
# 将ID添加到ID列表中
ids.append(id)
# 返回人脸样本和对应的ID列表
return faceSamples, ids
# 训练人脸识别模型
print('Training a face recognition model...')
faces, ids = getImagesAndLabels(path)
recognizer.train(faces, np.array(ids))
# 将训练好的模型保存到文件
recognizer.write('C:/Users/86173/Desktop/Face/Face/face_trainer/trainer.yml')
# 打印训练完成的消息
print("{0} Model training over...".format(len(np.unique(ids))))
五、实现人脸检测:
(1)图像识别初始化:
初始化人脸识别系统,包括创建一个LBPH人脸识别器、加载预先训练好的模型、加载Haar特征分类器用于人脸检测、设置字体以在图像上显示文本、定义已知人脸的名称与ID的对应关系,并打开默认摄像头以实时捕获视频帧,从而准备进行实时人脸识别。此外,使用基于摄像头分辨率的人脸检测的最小宽度和高度,以优化检测过程。
# 创建一个LBPH人脸识别器
recognizer = cv2.face.LBPHFaceRecognizer_create()
# 从文件中读取之前训练好的模型
recognizer.read('C:/Users/86173/Desktop/Face/Face/face_trainer/trainer.yml')
# 加载Haar特征的人脸识别分类器
cascadePath = "C:/Users/86173/AppData/Roaming/Python/Python38/site-packages/cv2/data/haarcascade_frontalface_default.xml"
faceCascade = cv2.CascadeClassifier(cascadePath)
# 设置字体,用于在图像上显示文本
font = cv2.FONT_HERSHEY_SIMPLEX
# 初始化ID编号
idnum = 0
# 定义一个列表,用于存储已知人脸的名字对应ID:0,1
names = ['Allen', 'Demo']
# 打开默认摄像头
cam = cv2.VideoCapture(0)
# 根据摄像头的分辨率计算人脸检测的最小宽度和高度
minW = 0.1*cam.get(3) # 3对应于CV_CAP_PROP_FRAME_WIDTH
minH = 0.1*cam.get(4) # 4对应于CV_CAP_PROP_FRAME_HEIGHT
(2)人脸识别程序:
不断地从摄像头读取图像,检测图像中的人脸,并使用训练好的LBPH人脸识别模型来识别。 recognizer.predict
方法是OpenCV中LBPH人脸识别器的一个核心函数,用于对给定的人脸图像进行识别,预测其对应的标签(ID)和置信度。
使用方法:
idnum, confidence = recognizer.predict(gray[y:y+h, x:x+w])
:这行代码调用了LBPH人脸识别器的predict
方法,其中gray[y:y+h, x:x+w]
是检测到的人脸区域的灰度图像。该方法返回两个值:idnum
(识别出的人脸的标签或ID)和confidence
(置信度,表示识别结果的可信程度)。
函数说明:
recognizer.predict
方法接受一个灰度图像作为输入,并返回两个值:标签值和置信度。标签值对应于训练阶段给定的标签,而置信度是一个介于0到100之间的值,表示识别结果的可信程度,值越小表示匹配度越高,即置信度越高。
置信度解释:
- 置信度是识别器对于预测结果的一个评估,它表示待识别图像与训练集中某个标签对应的人脸之间的相似度或距离。在实际应用中,如果置信度低于某个阈值(例如100),则认为识别成功;如果高于该阈值,则可能表示识别失败或未知人脸。
# 开始无限循环,直到用户决定退出
while True:
# 从摄像头读取一帧图像
ret, img = cap.read()
# 将图像转换为灰度图,因为人脸识别通常在灰度图上进行
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 使用分类器检测图像中的人脸
faces = faceCascade.detectMultiScale(
gray,
scaleFactor=1.2, # 每次图像尺寸减小的比例
minNeighbors=5, # 每个候选矩形应该保留的邻近元素个数
minSize=(int(minW), int(minH)) # 检测的最小尺寸
)
# 遍历检测到的每个人脸
for (x, y, w, h) in faces:
# 在原图上绘制矩形框,标记出人脸区域
cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 2)
# 使用识别器预测人脸的ID和置信度
idnum, confidence = recognizer.predict(gray[y:y+h, x:x+w])
# 如果置信度小于100,表示识别成功,否则为未知
if confidence < 100:
idnum = names[idnum]
confidence = "{0}%".format(round(100 - confidence))
else:
idnum = "unknown"
confidence = "{0}%".format(round(100 - confidence))
# 在图像上显示ID和置信度
cv2.putText(img, str(idnum), (x+5, y-5), font, 1, (0, 0, 255), 1)
cv2.putText(img, str(confidence), (x+5, y+h-5), font, 1, (0, 0, 255), 1)
# 显示图像窗口
cv2.imshow('Face', img)
# 等待键盘事件,参数10表示等待10毫秒
Exit = cv2.waitKey(10)
# 如果按下ESC键(ASCII码27),则退出循环
if Exit == 27:
break
# 释放摄像头资源
cap.release()
# 关闭所有OpenCV创建的窗口
cv2.destroyAllWindows()
实时图像处理:
- 程序进入一个无限循环,不断从摄像头读取图像,并将其转换为灰度图,因为Haar特征是基于灰度变化的。
- 使用Haar分类器在灰度图像中检测人脸,并在检测到的人脸周围绘制矩形框。
人脸识别和显示:
- 对于每个检测到的人脸,使用LBPH人脸识别器预测人脸的ID和置信度。
- 根据置信度判断识别结果,如果置信度低于阈值,则认为识别成功,并显示对应的人名;否则,显示“unknown”。
- 在图像上显示识别到的人脸ID和置信度。
用户交互和资源管理:
- 显示处理后的图像,并等待用户输入。如果用户按下ESC键,则退出循环。
- 在退出前,释放摄像头资源并关闭所有OpenCV创建的窗口。
(3)完整代码:
import cv2
# 创建一个LBPH人脸识别器
recognizer = cv2.face.LBPHFaceRecognizer_create()
# 从文件中读取之前训练好的模型
recognizer.read('C:/Users/86173/Desktop/Face/Face/face_trainer/trainer.yml')
# 加载Haar特征的人脸识别分类器
cascadePath = "C:/Users/86173/AppData/Roaming/Python/Python38/site-packages/cv2/data/haarcascade_frontalface_default.xml"
faceCascade = cv2.CascadeClassifier(cascadePath)
# 设置字体,用于在图像上显示文本
font = cv2.FONT_HERSHEY_SIMPLEX
# 初始化ID编号
idnum = 0
# 定义一个列表,用于存储已知人脸的名字对应ID:0,1,2,3...
names = ['Not_Added', 'Demo']
# 打开默认摄像头
cap = cv2.VideoCapture(0)
# 根据摄像头的分辨率计算人脸检测的最小宽度和高度
minW = 0.1*cap.get(3) # 3对应于CV_CAP_PROP_FRAME_WIDTH
minH = 0.1*cap.get(4) # 4对应于CV_CAP_PROP_FRAME_HEIGHT
# 开始无限循环,直到用户决定退出
while True:
# 从摄像头读取一帧图像
ret, img = cap.read()
# 将图像转换为灰度图,因为人脸识别通常在灰度图上进行
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 使用分类器检测图像中的人脸
faces = faceCascade.detectMultiScale(
gray,
scaleFactor=1.2, # 每次图像尺寸减小的比例
minNeighbors=5, # 每个候选矩形应该保留的邻近元素个数
minSize=(int(minW), int(minH)) # 检测的最小尺寸
)
# 遍历检测到的每个人脸
for (x, y, w, h) in faces:
# 在原图上绘制矩形框,标记出人脸区域
cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 2)
# 使用识别器预测人脸的ID和置信度
idnum, confidence = recognizer.predict(gray[y:y+h, x:x+w])
# 如果置信度小于100,表示识别成功,否则为未知
if confidence < 100:
idnum = names[idnum]
confidence = "{0}%".format(round(100 - confidence))
else:
idnum = "unknown"
confidence = "{0}%".format(round(100 - confidence))
# 在图像上显示ID和置信度
cv2.putText(img, str(idnum), (x+5, y-5), font, 1, (0, 0, 255), 1)
cv2.putText(img, str(confidence), (x+5, y+h-5), font, 1, (0, 0, 255), 1)
# 显示图像窗口
cv2.imshow('Face', img)
# 等待键盘事件,参数10表示等待10毫秒
Exit = cv2.waitKey(10)
# 如果按下ESC键(ASCII码27),则退出循环
if Exit == 27:
break
# 释放摄像头资源
cap.release()
# 关闭所有OpenCV创建的窗口
cv2.destroyAllWindows()
六、局限性:
Haar特征的级联分类器(Cascade Classifier):
过时的方法:
- Haar特征级联分类器是一种较早的方法,随着深度学习技术的发展,它在某些方面已经显得过时。
视角和姿态变化的鲁棒性不足:
- Haar级联分类器对于人脸的姿态和视角变化不够鲁棒,轻微的旋转或侧脸可能无法被有效检测。
训练时间长:
- 使用Haar特征进行训练的时间较长,特别是对于复杂的分类器。
尺寸比例敏感性不足:
- Haar级联分类器对于目标对象的尺寸比例不够敏感,这可能导致在不同尺寸的目标检测中表现不佳。
检测性能有限:
- 在没有大量样本和丰富经验的情况下,Haar级联分类器很难获得高的检测精度。
误检率较高:
- Haar级联分类器在复杂背景或目标检测中,误检率较高,尤其是在背景中存在与目标相似特征的物体时。
对光照变化敏感:
- Haar级联分类器对光照变化较为敏感,不同的光照条件可能会影响检测结果。
对遮挡的鲁棒性不足:
- 在目标被遮挡的情况下,Haar级联分类器的检测性能会下降。
需要大量样本:
- 为了获得较好的检测效果,需要大量的正负样本进行训练,这对于数据收集和处理是一个挑战。
LBPH(Local Binary Patterns Histograms)算法:
对训练数据要求较高:
LBPH算法需要大量的训练数据来学习人脸的特征分布,这可能导致在实际应用中需要采集大量的人脸图像来进行训练,增加了数据采集和处理的成本。
对复杂表情和姿态的识别效果不佳:
LBPH方法主要关注图像的局部特征,因此在面对复杂表情和姿态时,其识别效果可能会受到影响。此外,该方法对光照和角度的敏感性也可能限制其在某些场景下的应用。
对噪声和模糊敏感:
LBPH算法对图像质量的要求较高,对噪声和模糊等因素比较敏感,这可能导致在图像质量不佳时识别的准确性下降。
分类效果相对较差:
相对于其他的人脸识别算法而言,LBPH算法的分类效果可能较差。部分原因是因为LBPH算法仅从局部图像维度来表示人脸特征,因此容易受局部区域的噪声影响而与全局特征差异大。
对图像旋转、缩放等变化的适应性较差:
LBPH算法在处理图像旋转、缩放等变化时的适应性不如一些更先进的算法。
可能忽略重要的纹理信息:
当人脸尺寸较小时,一些重要的纹理信息可能会被忽略而导致人脸识别效果较差
七、程序源码:
链接:
https://pan.baidu.com/s/1fm_tYG71pnjgWyhgAY0P4Q
提取码:wpsc