人脸识别系统:基于PCA降维的Python实现
这个代码示例展示了如何使用Python和OpenCV库构建一个简单的人脸识别系统,并使用PCA降维技术来提高识别效率。
代码解释:
-
人脸检测:
detect_face函数使用cv2.CascadeClassifier加载一个预训练的人脸检测模型,用于检测图像中的人脸。- 它会返回检测到的人脸图像和其在原始图像中的位置信息。
-
数据准备:
prepare_training_data函数读取训练图像文件夹中的数据,并使用人脸检测模型提取每个图像中的人脸。- 它将提取的人脸转换为一维向量并存储在一个列表中,同时记录每个人的标签。
-
PCA降维:
- 使用
sklearn.decomposition.PCA类,将人脸向量进行降维处理。这能够减少特征数量,提高识别速度,并降低对内存的需求。
- 使用
-
识别测试:
- 代码使用摄像头获取实时图像,并进行人脸检测。
- 将检测到的人脸进行PCA降维,并与训练数据中的每个人的特征进行比较。
- 基于最小欧氏距离,代码识别出最匹配的人,并在图像上显示识别结果。
代码中的错误:
ValueError: not enough values to unpack (expected 4, got 1) 错误通常发生在 detect_face 函数中,当 face_cascade.detectMultiScale 函数无法检测到人脸,返回一个空列表时,就会发生这个错误。
解决办法:
- 在
detect_face函数中,检查rect列表是否为空,如果为空则返回None而不是尝试对其进行解包。
if (len(faces) == 0):
return None, None
- 在
prepare_training_data函数中,也应该添加类似的检查,以确保检测到的人脸数据不为空。
改进建议:
- 可以使用更强大的特征提取方法,例如深度学习模型,来提高人脸识别系统的准确率。
- 可以使用数据库存储人脸数据和标签,以提高系统可扩展性。
- 可以使用 GUI 界面,方便用户使用。
完整的代码:
import cv2
import os
import numpy as np
from sklearn.decomposition import PCA
def detect_face(img, face_cascade): #返回脸的图像和数值信息
#将测试图像转换为灰度图像,因为opencv人脸检测器需要灰度图像
gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
#检测多尺度图像,返回值是一张脸部区域信息的列表(x,y,宽,高)(输入图像,每次图像尺寸减小的比例,至少检测次数,目标的最小尺寸)
faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30), flags=cv2.CASCADE_SCALE_IMAGE) #检测人脸
# 如果未检测到面部,则返回原始图像
if (len(faces) == 0):
return None, None
#假设多张脸
for (x, y, w, h) in faces:
# 返回图像的正面部分
# cv2.imshow('face', img[y:y + w, x:x + h, :])
face = gray[y:y + w, x:x + h].astype(np.float32) # 数值转换
face = cv2.resize(face, (150,150))
return face, faces
def prepare_training_data(data_folder_path):
# 获取数据文件夹中的目录(每个主题的一个目录)
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_alt.xml') #训练一组数据
dirs = os.listdir(data_folder_path) #返回data_folder_path目录下的文件夹和文件
# 两个列表分别保存所有的脸部和标签
faces = []
labels = []
# 浏览每个目录并访问其中的图像
for dir_name in dirs:
# dir_name(str类型)即标签
label = int(dir_name)
# 建立包含当前主题主题图像的目录路径
subject_dir_path = data_folder_path + '/' + dir_name
# 获取给定主题目录内的图像名称
subject_images_names = os.listdir(subject_dir_path)
# 浏览每张图片并检测脸部,然后将脸部信息添加到脸部列表faces[]
for image_name in subject_images_names:
# 建立图像路径
image_path = subject_dir_path + '/' + image_name
# 读取图像
image = cv2.imread(image_path)
#确保图像正确加载
if image is None:
continue
# 显示图像0.1s
cv2.imshow('Training on image...', image)
cv2.waitKey(100)
# 检测脸部
gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
# 检测多尺度图像,返回值是一张脸部区域信息的列表(x,y,宽,高)(输入图像,每次图像尺寸减小的比例,至少检测次数,目标的最小尺寸)
rect = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30),flags=cv2.CASCADE_SCALE_IMAGE) # 检测人脸
# 假设多张脸
for (x, y, w, h) in rect:
# 返回图像的正面部分
# cv2.imshow('face', img[y:y + w, x:x + h, :])
face = gray[y:y + w, x:x + h].astype(np.float32) # 数值转换
face = cv2.resize(face, (150, 150))
# 我们忽略未检测到的脸部
if face is not None:
#将脸添加到脸部列表并添加相应的标签
#将每张面部图像转换为一维向量并添加到列表中
face_vector = np.reshape(face,(1,-1))[0]
print(face.shape)
faces.append(face_vector)
labels.append(label)
#将faces和labels转换为numpy数组,以备后续PCA操作
faces= np.array(faces)
labels= np.array(labels)
return faces, labels
cap = cv2.VideoCapture(0)
stop = False
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
if __name__ == '__main__':
pca = PCA(n_components=60, svd_solver='full')
faces, labels = prepare_training_data('raw1')
# 进行PCA降维处理,提取主要特征
faces = pca.fit_transform(faces)
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_alt.xml')
nofacenum = 0
error = 0
right = 0
while not stop:
success, img = cap.read()
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
face, rect = detect_face(img, face_cascade)
if not rect is None:
# 检测人脸
(x, y, w, h) = rect
cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)
c = cv2.waitKey(100)
subjects = ['xu', 'LU','ZHOU']
# 生成图像的副本,这样就能保留原始图像
img1 = img.copy()
# 将测试图像转换为灰度图像,因为opencv人脸检测器需要灰度图像
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 检测多尺度图像,返回值是一张脸部区域信息的列表(x,y,宽,高)
rect = face_cascade.detectMultiScale(img, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30),flags=cv2.CASCADE_SCALE_IMAGE)
# 如果未检测到面部
if len(rect) == 0:
txt = 'no face!'
cv2.putText(img1, txt, (10, 20), cv2.FONT_HERSHEY_COMPLEX, 1, (128, 128, 0), 2)
cv2.imshow('test', img1)
nofacenum += 1
print('nofacenum:%d' % nofacenum)
cv2.waitKey()
if not rect is None:
for (x, y, w, h) in rect:
face = gray[y:y + w, x:x + h].astype(np.float32) # 数值转换
face = cv2.resize(face, (150, 150))
# face_vector = np.reshape(face,(1,-1))[0]#转换成一维向量
# 如果传入了PCA模型,则将人脸图像降维
face_pca = pca.transform(face.reshape(1, -1))
# face_pca = np.reshape(face_pca,(1,-1))[0]
cv2.rectangle(img1, (x, y), (x + w, y + h), (0, 255, 0), 2) # 画出矩形框
min_d = 1000000000000
c = -1
for i, f in enumerate(faces): # i,f是训练数据的信息,遍历训练数据
d = ((face_pca - f) ** 2).sum() # 计算test和训练图片的欧氏距离
if d < min_d:
min_d = d
c = labels[i] # 获得最小欧式距离,即最近邻
cv2.putText(img1, subjects[c], (x, y), cv2.FONT_HERSHEY_COMPLEX, 1, (128, 128, 0), 2)
cv2.imshow('test', img1)
# 0.81
原文地址: https://www.cveoy.top/t/topic/mJzm 著作权归作者所有。请勿转载和采集!