简单介绍
本代码分成三块:
- 人脸录入模块:识别前得录入吧,就在这里录入
- 人脸识别模块:录入之后识别就完事了
- 公共函数模块:把1和2模块之中的共用模块拿下来放到一起
代码之外的一些轶事(anecdote)
中期检查的时候,我用的外部人脸库,答辩组说:你这没有自己的人脸库,有什么实用价值?
毕业答辩的时候,我用的自己的人脸库,答辩组说:你这没有外部的人脸库,你怎么证明你代码标准?
我:????
你是故意找茬是不是?你看不看吧?(哈哈哈)
上代码!!!
1,人脸录入
import common_function as cf
import cv2
import os
import sys
import numpy
MAX = 10 #设置保存照片的数量
def set_save_path(save_path):#设置保存图片的路径
return save_path
save_path = set_save_path("C:/imgs")
def save():#主函数
#获取要保存人脸的名字
name = get_name()
#保存图片
save_pic(save_path,name)
def save_pic(filepath,name): #本代码实现保存1个人的MAX个脸
num_face = 0 # 用来停止循环的标志
cap = cv2.VideoCapture(0)#打开相机
print("已打开相机,请切到相机界面")
print("拍摄比较多的照片时(比如大于100张),请一定要保证面部一直在摄像头内")
while cap.isOpened():
if num_face > 0:#第一个人拍完之后,就结束(一次只拍一个人)
print("共"+(str)(MAX)+"张照片,"+"已拍摄完毕")
cv2.destroyWindow("take pictures")
cv2.destroyAllWindows()
return True
ret,pic =cap.read()
cv2.putText(pic,"press 'Enter' to take pictures or 'Esc' to exit",
(25,25),
cv2.FONT_HERSHEY_SIMPLEX,
0.75,
(0,0,255),2)
cv2.namedWindow("take pictures")#建立拍照窗口
cv2.imshow("take pictures",pic)
flag = cv2.waitKey(1)
gray = pic #保存照片
#(其实不需要保存为灰度图片,
# 因为读取的时候可以以灰度图片格式读取)
if flag == 27:#ESC
cv2.destroyWindow("take prictures")
cv2.destroyAllWindows()
print("exit!")
sys.exit(0)
elif flag == 13:#ENTER
num_pic=0
while num_pic < MAX:#截取和保存MAX个人脸照片
ret,pic =cap.read()
gray = pic
face = cf.face_model_cas.detectMultiScale(gray,#检测人脸
scaleFactor = 1.2,
minNeighbors = 3,
minSize = (128,128)) #返回[[x,y,w,h]]
x,y,w,h = face[0]
image = gray[y : y + h , x : x + w ]#截取
cv2.imwrite(filepath+"/"+name+"_"+(str)(num_pic)+".jpg",image)#进行保存
#保存一个照片就+1
num_pic+=1
#画出矩形框
face = cf.face_model_cas.detectMultiScale(gray,#return [[x,y,w,h]]
scaleFactor = 1.2,
minNeighbors = 3,
minSize = (128,128))
x,y,w,h=face[0]
cv2.rectangle(pic, (x - 10, y - 10), (x + w + 10, y + h + 10), (255,0,0), 2)
#显示当前捕捉到了多少人脸图片
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(pic,'num:%d' % (num_pic),(x + 30, y + 30), font, 1, (255,0,255),4)
cv2.imshow("take pictures",pic)
cv2.waitKey(1)
else :#如果输入的不是ESC或ENTER,就继续循环
continue
num_face+=1#结束循环
def get_name():#读取保存的名字
print("请输入保存的名字(只能用英文,不然会出错)")
name = input()
cv2.namedWindow("take pictures")
return name
if __name__ == '__main__':
try:
#调用save函数,保存图片
save()
#调用训练模块,训练图片
cf.train(cf.set_fp(save_path),
cf.set_yml_path("C:/feature_victor/train.yml"))
except(IndexError):
print("IndexError!!!")
print("人脸没有完整进入摄像头内,请重新运行")
except(BaseException):
print("出现异常")
如果有什么不懂的地方,最好先去自己查,弄懂后会收获很多。
但如果实在不懂,欢迎留言!
2,人脸识别
import cv2
import os
import numpy
import common_function as cf
import sys
import save
fp = "C:/imgs/"#图片地址
yml_path ="C:/feature_victor/train.yml"#训练文件地址
labels_name = cf.get_name(fp)
labels_number = cf.get_number(fp,labels_name)
recognizer = cv2.face.LBPHFaceRecognizer_create()
recognizer.read(yml_path)
def get_num_of_name():#获取人员数量
name_num_array = []
len_of_name = len(labels_name)
j = 0
while j < len_of_name:
count = 0
for i in labels_number:
if i == j:
count +=1
elif i > j:
break
j+=1
name_num_array.append(count)
return name_num_array
def add_img(add_name,save_img):#新增数据库
if add_name in labels_name:
count=0
for name in labels_name:
count+=1
if name == add_name:
cv2.imwrite(fp+"/"+add_name+"_"+(str)(get_num_of_name()[count-1])+".jpg",save_img)
else:
cv2.imwrite(fp+"/"+add_name+"_0.jpg",save_img)
def face_recog():#主函数
shoot_img = cf.catch_pic()
gray = cf.bgr2gray(shoot_img)
gray = cv2.equalizeHist(gray)
face = cf.face_model_cas.detectMultiScale(gray,
scaleFactor = 1.2,
minNeighbors = 3,
minSize = (128,128))
face = face[0]
print("发现人脸")
x,y,w,h = face
shoot_img = shoot_img[y : y + h ,x : x + w ]
gray = cv2.equalizeHist(cf.bgr2gray(shoot_img))
label,confidence= recognizer.predict(gray)
print("name = ",labels_name[label])
print("confidence = ",confidence,"(越小代表越相似)")
#optimization
print("本次识别是否正确?y/n/q")
while 1 :
flag = input()
if flag == "y":
add_img(labels_name[label],shoot_img)
break
elif flag == "n":
print("请输入本次被识别人员的名字:")
add_name = input()
add_img(add_name,shoot_img)
break
elif flag == "q":
sys.exit(0)
else:
print("您输入字母的有误,请重新输入:y/n")
cf.train(fp,yml_path)
if __name__ == "__main__":#用于测试
try:
face_recog()
except(IndexError):
print("人脸没有完整进入摄像头内,请重新运行")
print("异常类型为:IndexError!")
except(BaseException):
print("发生了异常")
print("异常类型为:BaseException!")
3,公共函数模块
import cv2
import numpy
import os
import sys
path="C://Users//dongdong//AppData//Roaming//Python//Python39//site-packages//cv2//data//haarcascade_frontalface_alt.xml"
face_model_cas=cv2.CascadeClassifier(path)
#拍摄一张照片并返回
def catch_pic():
cap = cv2.VideoCapture(0)
print("已打开相机,请切到相机界面")
while cap.isOpened():
ret, frame = cap.read(5)
cv2.namedWindow("face recognition")#建立拍照窗口
cv2.putText(frame,"press 'Enter' to take pictures or 'Esc' to exit",
(25,25),
cv2.FONT_HERSHEY_SIMPLEX,
0.75,
(0,0,255),2)
faces = face_model_cas.detectMultiScale(frame,#return [[x,y,w,h]]
scaleFactor = 1.2,
minNeighbors = 3,
minSize = (128,128))
for face in faces:
#x,y,w,h=face[0]
x,y,w,h=face
cv2.rectangle(frame, (x - 10, y - 10), (x + w + 10, y + h + 10), (255,0,0), 2)
#cv2.rectangle(frame, (x , y ), (x + w , y + h), (0,255,0), 2)
cv2.imshow('face recognition', frame)
flag = cv2.waitKey(1)
if flag == 27:#按ESC键推出
print('系统未成功获取照片,结束识别系统')
print("将抛出BaseException异常~")
cap.release()
cv2.destroyAllWindows()
sys.exit(0)
elif flag == 13:#按回车键拍照
print('系统已获取照片,准备进行处理')
cap.release()
cv2.destroyAllWindows()
return frame
#将图片从BGR转为RGB
def bgr2rgb(img):
return cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
#将图片从BGR转为灰度(灰度≠黑白)
def bgr2gray(img):
return cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
#--------------------------------------------------------------------------------
face_imgs = []
labels_name = []
labels_number = [] #name ->number,1 for 1
def set_fp(fp_set):#设置保存yml文件的路径
fp = fp_set
return fp
def get_imgpaths(filepath):#获取jpg图片的文件地址,去除其他的类型文件或文件夹的地址
imgpaths = []
imgpaths_temp = [os.path.join(filepath,f) for f in os.listdir(filepath)]
for imgpath in imgpaths_temp:
if imgpath.endswith(".jpg"):
imgpaths.append(imgpath)
return imgpaths
def get_name(filepath):#获得名字并返回保存数组
imgpaths = get_imgpaths(filepath)
name_temp = []
for imgpath in imgpaths:
if imgpath.endswith(".jpg"): #如果路径有非.jpg的文件,跳过
name = os.path.split(imgpath)[1].split(".")[0].split("_")[0]
#print(name)
if name not in name_temp:
name_temp.append(name)
else:
continue
return name_temp
def get_number(filepath,labels_name):#不同人以不同的整数保存在数组,用于训练
imgpaths = get_imgpaths(filepath)
number_temp = []
name_number = 0
for label_name in labels_name:
for imgpath in imgpaths:
name = os.path.split(imgpath)[1].split(".")[0].split("_")[0]
if name == label_name :
number_temp.append(name_number)
name_number+=1
return number_temp
def get_img(filepath):#获取图片,存为图片数组
img_temp = []
imgpaths = get_imgpaths(filepath)
for imgpath in imgpaths:
#新增了直方图均衡化处理
#直方图均衡本身就已经具有亮度均衡
img_temp.append(cv2.equalizeHist(cv2.imread(imgpath,cv2.IMREAD_GRAYSCALE)))
return img_temp
def set_yml_path(yml_path):#设置训练文件的保存路径
return yml_path
def train(filepath,yml_path):#主函数
labels_name = get_name(filepath) #right
labels_number = get_number(filepath,labels_name) #right
face_imgs = get_img(filepath) #right
recognizer = cv2.face.LBPHFaceRecognizer_create()
recognizer.train(face_imgs, numpy.array(labels_number))
recognizer.write(yml_path)
print("训练完成!")
print("训练文件已经成功保存在了:"+yml_path)
if __name__ == "__main__":#用于测试
train(set_fp("C:/imgs"),set_yml_path("C:/feature_victor/train.yml"))