识别效果图
依赖安装 opencv-python opencv-contrib-python tensorflow Pillow numpy
pip3 install opencv-python==4.5.1.48 -i https://pypi.tuna.tsinghua.edu.cn/simple --default-timeout=10000
pip3 install opencv-contrib-python==4.5.1.48 -i https://pypi.tuna.tsinghua.edu.cn/simple --default-timeout=10000
pip3 install tensorflow==2.4.1 -i https://pypi.tuna.tsinghua.edu.cn/simple --default-timeout=10000
pip3 install -U pillow==8.1.2
pip3 install numpy==1.19.4 -i https://pypi.tuna.tsinghua.edu.cn/simple --default-timeout=10000
头像目标锁定资源文件 haarcascade_frontalface_default.xml 如果觉得慢,可以从 csdn 资源中下载
项目结构
采集数据 collection.py 采集完成之后可以通过肉眼删除误差较大的数据
# 头像数据采集
import cv2 as cv
import uuid
# 数据集收集
def split_image(frame, set_path):
# 图片转灰度
frame_gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
# 加载人脸分类识别器
face_detector = cv.CascadeClassifier(r'../data/haarcascade_frontalface_default.xml')
faces = face_detector.detectMultiScale(frame_gray)
for x, y, w, h in faces:
# 头像标注
# cv.rectangle(frame, (x, y), (x + w, y + h), color=(0, 255, 0), thickness=1)
# 头像切割保存,分类型保存 frame_gray 为灰度图片 frame 为原始图片,选择灰度图片作为训练集
cv.imwrite(set_path + str(uuid.uuid1()) + '.jpg', frame_gray[y:y + h, x:x + w])
if __name__ == '__main__':
# 数据保存路径,不能有中文
set_path = "C:/Users/Administrator/Desktop/data"
label = 0 # 当前数据的标签
stream_address = "../data/one.mp4" # 读取视频文件
# stream_address = 0;//获取摄像头
stream = cv.VideoCapture(stream_address) # 转化为流
set_path = set_path + "/" + label
while True:
status, frame = stream.read() # 读取帧图片数据
if status:
print("获取到图片数据,规格为:", frame.shape)
else:
print('没有检查到图像数据')
break
split_image(frame, set_path) # 截取头部数据信息
cv.destroyAllWindows()
stream.release()
训练模型 train.py
# 训练模型
import numpy as np
from PIL import Image
import cv2 as cv
import os
# 加载训练数据
def get_train_data(data_path, image_width, image_high):
train_data_array = [] # 训练集,灰度图片
label_array = [] # 标签 必须是整数,数值型从0开始包括0,后续识别可以通过标签索引获取数组字典,数组从0开始
listdir = os.listdir(data_path)
for label in listdir:
label_path = data_path + "/" + label
files = os.listdir(label_path)
for file_name in files:
file_path = label_path + "/" + file_name
img_numpy = np.array(Image.open(file_path).convert('L'), 'uint8')
img_format = cv.resize(img_numpy, (image_width, image_high), interpolation=cv.INTER_CUBIC) # 图片大小格式化
train_data_array.append(img_format)
label_array.append(int(label))
return label_array, train_data_array
# 训练模型
def training():
print("人脸训练中 ...")
data_path = "C:/Users/Administrator/Desktop/data" # 训练数据路径
label_array, train_data_array = get_train_data(data_path, 128, 128) # 指定图片格式化大小
# 创建LBPH识别器并开始训练,当然也可以选择Eigen或者Fisher识别器
recognizer = cv.face.LBPHFaceRecognizer_create()
# 传入训练集与标签
recognizer.train(train_data_array, np.array(label_array))
# 保存训练信息
recognizer.write('../model/trainer.yml')
print("{0} 训练分类数为2,已完成".format(len(np.unique(label_array))))
if __name__ == '__main__':
training()
视频识别 distinguish.py
# 识别
import cv2 as cv
def distinguish():
# 加载算法 创建LBPH识别器并开始识别,当然也可以选择Eigen或者Fisher识别器
recognizer = cv.face.LBPHFaceRecognizer_create()
# 加载模型
recognizer.read('../model/trainer.yml')
face_detector = cv.CascadeClassifier(r"../data/haarcascade_frontalface_default.xml")
font = cv.FONT_HERSHEY_SIMPLEX
# 特征值对应的姓名映射
names = ['one', 'two']
cap = cv.VideoCapture("../data/one.mp4") # 加载视频文件数据
# cap = cv.VideoCapture(0) # 加载摄像头数据
while True:
status, frame = cap.read()
if status:
print("获取到图片数据,规格为:", frame.shape)
else:
print('没有检查到图像数据')
break
# 图片转灰度
frame_gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
faces = face_detector.detectMultiScale(frame_gray)
for x, y, w, h in faces:
cv.rectangle(frame, (x, y), (x + w, y + h), color=(0, 255, 0), thickness=1)
# 识别
feature_id, value = recognizer.predict(frame_gray[y:y + h, x:x + w])
print("当前识别分类为", feature_id, "得分为", value)
if value > 100:
feature_id = "unknown"
reliability = "100%"
else:
feature_id = names[feature_id] # 将识别的结果特征数值映射成姓名
reliability = "{0}%".format(round(100 - value, 2))
cv.putText(frame, str(feature_id), (x + 5, y - 5), font, 1, (0, 0, 255), 1)
cv.putText(frame, str(reliability), (x + 5, y + h - 5), font, 1, (0, 255, 0), 1)
cv.imshow("distinguish", frame)
if ord('q') == cv.waitKey(10):
break
cv.destroyAllWindows()
cap.release()
if __name__ == '__main__':
distinguish()
采集头像数据示例
训练完之后会在<project_home>mian/model目录下生成训练文件
校验模型的准确度 check.py
# 模型校验
import cv2 as cv
import os
# 数据结构
class CheckResult:
accuracy = 0 # 正确数
error = 0 # 正确数
unknown = 0 # 未知数
total = 0 # 总数
accuracy_list = [] # 正确详细数据
error_list = [] # 错误详细数据
unknown_list = [] # 未知详细数据
accuracy_rate = None # 正确率
error_rate = None # 错误率
unknown_rate = None # 未知率
accuracy_reliability = 0 # 正确平均可信度
error_reliability = 0 # 错误平均可信度
def msg(self):
return "正确识别数:{0},正确率:{1},错误识别数:{2},错误率:{3},未知识别数:{4},未知率:{5},正确可信度:{6},错误可信度:{7}".format(
self.accuracy,
self.accuracy_rate,
self.error,
self.error_rate, self.unknown,
self.unknown_rate,
self.accuracy_reliability,
self.error_reliability
)
# 加载校验数据
def get_test_data(data_path):
# 加载算法 创建LBPH识别器并开始校验,当然也可以选择Eigen或者Fisher识别器
recognizer = cv.face.LBPHFaceRecognizer_create()
# 加载模型
recognizer.read('../model/trainer.yml')
face_detector = cv.CascadeClassifier(r"../data/haarcascade_frontalface_default.xml")
test_data_array = [] # 校验集
listdir = os.listdir(data_path)
for label in listdir:
label_path = data_path + "/" + label
files = os.listdir(label_path)
for file_name in files:
file_path = label_path + "/" + file_name
frame = cv.imread(file_path, 3)
# 图片转灰度
frame_gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
faces = face_detector.detectMultiScale(frame_gray)
for x, y, w, h in faces:
cv.rectangle(frame, (x, y), (x + w, y + h), color=(0, 255, 0), thickness=1)
# 识别
feature_id, value = recognizer.predict(frame_gray[y:y + h, x:x + w])
if value > 100:
feature_id = "unknown"
reliability = 1
else:
reliability = 100 - value
test_data_array.append(
{"path": file_path, "feature": feature_id, "reliability": reliability, "label": int(label)})
return test_data_array
# 校验模型
def calc_result(test_data_array):
result = CheckResult()
for x in test_data_array:
if x["feature"] == x["label"]:
result.accuracy += 1
result.accuracy_list.append(x)
result.accuracy_reliability += x["reliability"]
elif x["feature"] == 'unknown':
result.unknown += 1
result.unknown_list.append(x)
else:
result.error += 1
result.error_list.append(x)
result.error_reliability += x["reliability"]
result.total = len(test_data_array)
if result.total == 0:
result.accuracy_rate = "0.00%"
result.error_rate = "0.00%"
result.unknown_rate = "0.00%"
else:
result.accuracy_rate = str(round(result.accuracy * 100 / result.total, 2)) + "%"
result.error_rate = str(round(result.error * 100 / result.total, 2)) + "%"
result.unknown_rate = str(round(result.unknown * 100 / result.total, 2)) + "%"
result.accuracy_reliability = str(round(result.accuracy_reliability / result.total, 2)) + "%"
result.error_reliability = str(round(result.error_reliability / result.total, 2)) + "%"
return result
def checking():
print("模型校验中 ...")
data_path = "C:/Users/Administrator/Desktop/data" # 校验数据路径
test_data_array = get_test_data(data_path)
result = calc_result(test_data_array)
print(result.msg())
# 校验模型准确度
if __name__ == '__main__':
checking()
校验结果