Update README.md
import cv2
import os
import numpy as np
import random
import joblib
from sklearn import svm
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
class FaceRecognizer:
def init(self, imgdir='./test_img/', grayfacedir='./test_img_gray', model_path='./svm_model.pkl'):
self.imgdir = imgdir
self.grayfacedir = grayfacedir
self.model_path = model_path
self.svm_model = svm.SVC(kernel='linear', probability=True)
self.face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
self.label_map = {}
self.pca_model = None # 初始化 pca_model 为 None
def collect_data(self, someone, picturenum=50):
"""
收集人脸数据并保存图像,同时进行数据增强
"""
person_dir = self._create_person_directory(someone)
capture = cv2.VideoCapture(0)
cv2.waitKey(1)
count = 0
while count < picturenum:
ret, img = capture.read()
if not ret:
print("无法获取图像")
break
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = self.detect_faces(gray)
for (x, y, w, h) in faces:
face_img = gray[y:y + h, x:x + w]
augmented_faces = self.augment_face(face_img)
for augmented_face in augmented_faces:
picturepath = os.path.join(person_dir, f'{count + 1}.jpg')
cv2.imwrite(picturepath, augmented_face)
count += 1
if count >= picturenum:
break
cv2.imshow(f'Capturing Face - {someone}', img)
if cv2.waitKey(100) == ord('q'):
break
capture.release()
cv2.destroyAllWindows()
def _create_person_directory(self, someone):
"""
创建人物名称的子文件夹
"""
person_dir = os.path.join(self.imgdir, someone)
if not os.path.exists(person_dir):
os.makedirs(person_dir)
return person_dir
def detect_faces(self, gray):
"""
检测图像中的人脸
"""
faces = self.face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))
return faces
def augment_face(self, face_img):
"""
对人脸图像进行数据增强,包括旋转、镜像、平移等
"""
augmented_faces = [cv2.flip(face_img, 1)] # 镜像(水平翻转)
angle = random.uniform(-10, 10) # 随机旋转
augmented_faces.append(self.rotate_image(face_img, angle))
translation = random.randint(-5, 5) # 随机平移
augmented_faces.append(self.translate_image(face_img, translation))
return augmented_faces
def rotate_image(self, image, angle):
"""
旋转图像指定角度
"""
height, width = image.shape
center = (width // 2, height // 2)
rotation_matrix = cv2.getRotationMatrix2D(center, angle, 1.0)
return cv2.warpAffine(image, rotation_matrix, (width, height))
def translate_image(self, image, tx):
"""
图像平移
"""
height, width = image.shape
translation_matrix = np.float32([[1, 0, tx], [0, 1, 0]])
return cv2.warpAffine(image, translation_matrix, (width, height))
def prepare_data(self):
"""
准备训练数据并进行标准化处理
"""
faces = []
labels = []
person_id = 0
for person_name in os.listdir(self.imgdir):
person_dir = os.path.join(self.imgdir, person_name)
if not os.path.isdir(person_dir):
continue
if person_name not in self.label_map:
self.label_map[person_id] = person_name # 新人物,分配新的ID
person_id += 1
for img_name in os.listdir(person_dir):
img_path = os.path.join(person_dir, img_name)
if img_name.lower().endswith(('.png', '.jpg', '.jpeg')):
img = cv2.imread(img_path)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces_detected = self.detect_faces(gray)
for (x, y, w, h) in faces_detected:
face = gray[y:y + h, x:x + w]
face_resized = cv2.resize(face, (100, 100))
faces.append(face_resized)
labels.append(self.get_person_id(person_name))
faces = np.array(faces)
faces = faces.reshape(faces.shape[0], -1) # 展平图像数据
faces = StandardScaler().fit_transform(faces) # 进行标准化处理
return faces, labels
def train_svm(self, n_components=50):
"""
使用 PCA 进行降维后,使用 SVM 训练模型
"""
faces, labels = self.prepare_data()
self.pca = PCA(n_components=n_components, whiten=True)
faces_pca = self.pca.fit_transform(faces)
self.svm_model.fit(faces_pca, labels)
self.save_model()
joblib.dump(self.pca, './pca_model.pkl')
print("SVM 模型和 PCA 降维模型训练完成!")
def get_person_id(self, person_name):
"""
根据人物名称获取对应的ID,如果没有,则让用户命名
"""
if person_name not in self.label_map.values():
new_name = input(f"请输入 {person_name} 的名称:")
person_id = len(self.label_map)
self.label_map[person_id] = new_name
print(f"已将 {person_name} 命名为 {new_name}")
return person_id
return list(self.label_map.values()).index(person_name)
def save_model(self):
"""
保存训练好的SVM模型
"""
joblib.dump(self.svm_model, self.model_path)
print(f"模型已保存至 {self.model_path}")
def load_model(self):
"""
加载已保存的SVM模型和PCA模型
"""
self.svm_model = joblib.load(self.model_path)
self.pca_model = joblib.load('./pca_model.pkl') # 加载PCA模型
print(f"模型已加载:{self.model_path} 和 ./pca_model.pkl")
def predict(self, img):
"""
使用训练好的SVM模型进行人脸识别,并应用PCA降维
"""
if self.pca_model is None: # 检查 pca_model 是否已加载
print("PCA模型尚未加载,请先加载模型。")
return
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces_detected = self.face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))
for (x, y, w, h) in faces_detected:
face = gray[y:y + h, x:x + w]
face_resized = cv2.resize(face, (100, 100)) # 调整大小
face_flattened = face_resized.flatten().reshape(1, -1)
face_flattened = StandardScaler().fit_transform(face_flattened)
face_pca = self.pca_model.transform(face_flattened) # 使用训练时的PCA进行降维
label = self.svm_model.predict(face_pca)
confidence = self.svm_model.decision_function(face_pca)
person_name = self.label_map.get(label[0], 'Unknown')
print(f"预测标签:{person_name}, 置信度:{confidence}")
cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)
cv2.putText(img, person_name, (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 255, 0), 2)
def prepare_data(self):
"""
准备训练数据并进行标准化处理
"""
faces = []
labels = []
person_id = 0
for person_name in os.listdir(self.imgdir):
person_dir = os.path.join(self.imgdir, person_name)
if not os.path.isdir(person_dir):
continue
if person_name not in self.label_map:
self.label_map[person_id] = person_name # 新人物,分配新的ID
person_id += 1
# 处理每个人物的图像
for img_name in os.listdir(person_dir):
img_path = os.path.join(person_dir, img_name)
if img_name.lower().endswith(('.png', '.jpg', '.jpeg')):
img = cv2.imread(img_path)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 进行人脸检测
faces_detected = self.face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5,
minSize=(30, 30))
for (x, y, w, h) in faces_detected:
face = gray[y:y + h, x:x + w]
face_resized = cv2.resize(face, (100, 100)) # 统一调整大小
faces.append(face_resized)
labels.append(self.get_person_id(person_name))
# 标准化
faces = np.array(faces)
faces = faces.reshape(faces.shape[0], -1) # 展平图像数据
faces = StandardScaler().fit_transform(faces) # 进行标准化处理
return faces, labels
def train_svm(self, n_components=50):
"""
使用 PCA 进行降维后,使用 SVM 训练模型
"""
faces, labels = self.prepare_data()
# 使用 PCA 进行降维
self.pca = PCA(n_components=n_components, whiten=True)
faces_pca = self.pca.fit_transform(faces)
# 使用 SVM 进行训练
self.svm_model.fit(faces_pca, labels)
# 保存模型和 PCA 对象
self.save_model()
joblib.dump(self.pca, './pca_model.pkl')
print("SVM 模型和 PCA 降维模型训练完成!")
def get_person_id(self, person_name):
"""
根据人物名称获取对应的ID,如果没有,则让用户命名
"""
# 如果人物名称不存在,提示用户输入新的名称
if person_name not in self.label_map.values():
new_name = input(f"请输入 {person_name} 的名称:")
# 确保该名字是唯一的
person_id = len(self.label_map)
self.label_map[person_id] = new_name
print(f"已将 {person_name} 命名为 {new_name}")
return person_id
else:
# 如果人物名称已经命名,返回已有ID
return list(self.label_map.values()).index(person_name)
def save_model(self):
"""
保存训练好的SVM模型
"""
joblib.dump(self.svm_model, self.model_path)
print(f"模型已保存至 {self.model_path}")
def load_model(self):
"""
加载已保存的SVM模型和PCA模型
"""
self.svm_model = joblib.load(self.model_path)
# 加载PCA模型
self.pca_model = joblib.load('./pca_model.pkl')
print(f"模型已加载:{self.model_path} 和 ./pca_model.pkl")
def predict(self, img):
"""
使用训练好的SVM模型进行人脸识别,并应用PCA降维
"""
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces_detected = self.face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))
for (x, y, w, h) in faces_detected:
face = gray[y:y + h, x:x + w]
face_resized = cv2.resize(face, (100, 100)) # 调整大小
face_flattened = face_resized.flatten().reshape(1, -1)
# 标准化
face_flattened = StandardScaler().fit_transform(face_flattened)
# 使用PCA降维
face_pca = self.pca_model.transform(face_flattened) # 使用训练时的PCA进行降维
# 预测结果
label = self.svm_model.predict(face_pca)
confidence = self.svm_model.decision_function(face_pca)
# 获取预测标签
person_name = self.label_map.get(label[0], 'Unknown')
# 显示识别结果
print(f"预测标签:{person_name}, 置信度:{confidence}")
cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)
cv2.putText(img, person_name, (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.9,
(0, 255, 0), 2)
# 收集数据和训练方法与之前保持一致
def display_menu(self):
"""
显示菜单并处理用户输入
"""
while True:
print("\n--- 人脸识别菜单 ---")
print("1. 收集数据")
print("2. 训练模型")
print("3. 预测人脸")
print("4. 加载模型")
print("5. 保存模型")
print("6. 退出")
choice = input("请输入选择(1-6):")
if choice == '1':
self.collect_data_menu()
elif choice == '2':
self.train_model_menu()
elif choice == '3':
self.predict_face_menu()
elif choice == '4':
self.load_model()
elif choice == '5':
self.save_model()
elif choice == '6':
print("退出程序")
break
else:
print("无效输入,请重新选择")
def collect_data_menu(self):
"""
提供用户选择进行数据收集
"""
someone = input("请输入要收集数据的人物名称:")
picturenum = int(input("请输入要收集的图像数量:"))
self.collect_data(someone, picturenum)
def train_model_menu(self):
"""
训练模型菜单
"""
try:
# 获取PCA降维的组件数量
n_components_input = input("请输入PCA降维的组件数量(整数或浮动值,0到1之间):")
if '.' in n_components_input: # 如果是浮动值
n_components = float(n_components_input)
else: # 如果是整数
n_components = int(n_components_input)
if n_components <= 0 or n_components > 1:
print("请输入一个介于0和1之间的浮动值,或大于0的整数!")
return
# 调用训练方法
self.train_svm(n_components=n_components)
except ValueError:
print("输入无效,请输入一个数字(整数或浮动值)!")
def predict_face_menu(self):
"""
提供用户选择进行人脸预测
"""
capture = cv2.VideoCapture(0)
print("正在进行人脸识别,按 'q' 键退出")
while True:
ret, img = capture.read()
if not ret:
print("无法获取图像")
break
self.predict(img)
cv2.imshow("Face Recognition", img)
if cv2.waitKey(1) == ord('q'):
break
capture.release()
cv2.destroyAllWindows()
在主程序中调用菜单
if name == "main":
face_recognizer = FaceRecognizer()
face_recognizer.display_menu()
以下是运行
C:\Users\32686\venv\Scripts\python.exe C:\Users\32686\PycharmProjects\实训人脸识别第五组\cs.py
--- 人脸识别菜单 ---
- 收集数据
- 训练模型
- 预测人脸
- 加载模型
- 保存模型
- 退出
请输入选择(1-6):3
正在进行人脸识别,按 'q' 键退出
Traceback (most recent call last):
File "C:\Users\32686\PycharmProjects\实训人脸识别第五组\cs.py", line 420, in
face_recognizer.display_menu()
File "C:\Users\32686\PycharmProjects\实训人脸识别第五组\cs.py", line 351, in display_menu
self.predict_face_menu()
File "C:\Users\32686\PycharmProjects\实训人脸识别第五组\cs.py", line 406, in predict_face_menu
self.predict(img)
File "C:\Users\32686\PycharmProjects\实训人脸识别第五组\cs.py", line 314, in predict
face_pca = self.pca_model.transform(face_flattened) # 使用训练时的PCA进行降维
^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'transform'
进程已结束,退出代码为 1