该代码包含人脸数据采集和人脸识别两部分。
import face_recognition
import cv2 as cv
import numpy as np
import time
import os
class Rec_frg(object):
#定义全局变量
def __init__(self):
self.video_path = r"D:\pythonItems\opencv1\vodeo"
self.image_data_path = r"D:\pythonItems\opencv1\reg_facedata"
self.nums = 40
self.name = []
self.face_encodings = []
# 定义函数:用于计算视屏时长
def video_duration(self,filename):
cap = cv.VideoCapture(filename)
if cap.isOpened():
rate = cap.get(5)
frame_num = cap.get(7)
duration = frame_num // rate * 30
times = duration // 60
return times
return -1
#定义方法:用于收集数据
def image_datacolloct(self):
waitKey_count = 0
#显示该文件夹下的所有内容
video_path = os.listdir(self.video_path)
#分别显示每一个视屏
for path_v in video_path:
img_num = 1
# 找到每个视屏的绝对路径
p = r"{}".format(os.path.join(self.video_path,path_v))
#调用函数计算视屏时长
all_times = self.video_duration(p)
#打开视屏
capture = cv.VideoCapture(p)
while True:
have_landmasks = True
# 构造保存图片时图片的名称
name = path_v.split(".")[0] +"_"+ str(img_num)
# 通过视屏名称,找出每个人的名字
label_name = path_v.split(".")[0]
#显示时频每一帧
ret, frame = capture.read()
#缩小视屏宽、高为原来的一般
frame = cv.resize(frame, (0, 0), fx=0.5, fy=0.5)
#将每一帧的BGR格式转换为RGB格式
rgb_small_frame_data = frame[:, :, ::-1]
if ret == False:
break
#找出每一帧中人脸的位置
face_location = face_recognition.face_locations(rgb_small_frame_data)
#训练集面部特征编码
if waitKey_count == 0:
face_encoding = face_recognition.face_encodings(rgb_small_frame_data,model= "large")
if len(face_encoding) == 0:
have_landmasks = False
else:
have_landmasks = True
#将np.array()类型转换为list类型
fs = face_encoding[0].tolist()
#将数据和标签添加到列表中
self.face_encodings.append(fs)
self.name.append(label_name)
#保存图片
cv.imwrite("D:/pythonItems/opencv1/reg_facedata/"+name+".jpg",frame)
img_num += 1
#设置退出条件
if img_num > self.nums:
break
c = cv.waitKey(1)
if c == 27:
break
#设置人脸数据获取条件
if len(face_location) > 0 and have_landmasks == True:
waitKey_count += 1
print("wait",waitKey_count)
if waitKey_count == all_times - 1:
waitKey_count = 0
cv.imshow("face", frame)
#释放资源
capture.release()
#显示收集好的数据及标签
print("location", self.face_encodings)
print("name", self.name)
#将数据和标签存入文件中用于识别时使用
f_data = open("data.txt", "w")
f_name = open("name.txt","w")
f_data.write(str(self.face_encodings))
f_name.write(str(self.name))
#关闭文件
f_data.close()
f_name.close()
#关闭所有窗口
cv.destroyAllWindows()
#定义方法:用于识别
def face_dances(self,video_name):
success = 0
fail = 0
known_face_encodings = []
video_capture = cv.VideoCapture(video_name)
#读取人脸编码数据和标签
data_file = open("data.txt", "r")
label_file = open("name.txt","r")
data = eval(data_file.read())
#将从文件中读取出的每一张人脸数据的类型转化为 np.array()类型
for i in data:
list_to_array = np.array(i)
known_face_encodings.append(list_to_array)
known_face_names = eval(label_file.read())
#关闭文件
data_file.close()
label_file.close()
# 初始化变量
process_this_frame = True
time1 = time.time()
while True:
face_names = []
name_str = ""
# 读取视屏每一帧
ret, frame = video_capture.read()
if ret == False:
break
# 将视屏款、高缩小一半
frame = cv.resize(frame, (0, 0), fx=0.5, fy=0.5)
# 将BGR格式转化为RGB
rgb_small_frame = frame[:, :, ::-1]
# 只处理每隔一帧的视频以节省时间
if process_this_frame:
# 定位所找到的人脸的位置
face_locations = face_recognition.face_locations(rgb_small_frame)
# 对面部特征进行编码
face_encodings = face_recognition.face_encodings(rgb_small_frame, face_locations,model= "large")
#循环每一个编码好的人脸
for face_encoding in face_encodings:
# 由面部编码匹配人脸
matches = face_recognition.compare_faces(known_face_encodings, face_encoding,tolerance=0.5)
#计算 "Ture" 的个数
true_count = matches.count(True)
# print(matches)
# print(true_count)
#计算要识别的人脸和每个已知人脸之间的距离
face_distances = face_recognition.face_distance(known_face_encodings, face_encoding)
#找出最小距离的索引
best_match_index = np.argmin(face_distances)
#判断条件
if matches[best_match_index] == False or true_count < self.nums:
name = "Unknown"
#循环每一张人脸
for top, right, bottom, left in face_locations:
#画出人脸框
cv.rectangle(frame, (left, top), (right, bottom), (0, 0, 255), 2)
fail += 1
# 画出标签背景框
cv.rectangle(frame, (left, bottom - 35), (right, bottom), (0, 0, 255), cv.FILLED)
font = cv.FONT_HERSHEY_DUPLEX
#显示标签
cv.putText(frame, name, (left + 6, bottom - 6), font, 0.6, (255, 255, 255), 2)
if fail == 10:
print("识别失败!")
fail = 0
#计算时间
time2 = time.time()
spend = time2 - time1
print("花费时长:", spend)
time1 = time.time()
else:
#找出距离最小人脸的名字
name = known_face_names[best_match_index]
face_names.append(name)
#将人脸和相应的标签合并,并循环每一张人脸
for (top, right, bottom, left),name in zip(face_locations,face_names):
# 画出人脸框
cv.rectangle(frame, (left, top), (right, bottom), (0, 255, 0), 2)
success += 1
# 画出标签背景框
cv.rectangle(frame, (left, bottom - 35), (right, bottom), (0, 255, 0), cv.FILLED)
font = cv.FONT_HERSHEY_DUPLEX
#显示标签
cv.putText(frame, name, (left + 6, bottom - 6), font, 0.6, (255, 255, 255), 2)
if success == 10:
for name_one in face_names:
name_str += name_one+" "
print(" 识别成功!")
print(f"{name_str} 欢迎光临!")
time2 = time.time()
spend = time2 - time1
print("花费时长:", spend)
time1 = time.time()
success = 0
# 显示每一帧视屏
cv.imshow('Video', frame)
#按ESC键退出
key = cv.waitKey(1)
if key == 27:
break
# 释放视屏资源,并关闭所有窗口
video_capture.release()
cv.destroyAllWindows()
#程序入口
if __name__ == "__main__":
answer = input("人脸采集请输入0,输入其他进行识别!")
video1 = "test.mp4"
video2 = "girl_test.mp4"
#实例化类
Facerecognition = Rec_frg()
#判断采集还是识别
if answer == "0":
Facerecognition.image_datacolloct()
Facerecognition.face_dances(video1)
else:
Facerecognition.face_dances(video1)