【DigiKey“智造万物,快乐不停”创意大赛】基于树莓派的智能考勤机+人脸识别
[复制链接]
前面测试了open cv调用摄像头的基础功能,下面开始进阶。
首先识别人脸的第一步是获取人脸,所以使用open cv自带的人脸检测器来检测人脸。
首先需要知道分类器的地址所以在终端输入:
python3
>>import cv2
>>print(cv2.__flie__)
>>/home/lalala/.local/lib/python3.7/site-packages/cv2/__init__.py
>>quit()
其中,下面这个路径很重要,
/home/lalala/.local/lib/python3.7/site-packages/cv2/
贴换到这个路径:
cd /home/lalala/.local/lib/python3.7/site-packages/cv2/
可以看到,文件下有这些文件
cd data
我们可以看到open cv 已经有了很多的分类器,所以我们只需要来就进行使用就可以了,
其中人脸识别的分类器为 haarcascade_frontalface_alt2.xml
先加载分类器,这里使用绝对路径
facecascade=cv2.CascadeClassifier(cv2.data.haarcascades+'haarcascade_frontalface_alt2.xml')
在检测人脸时,先输入人脸ID,然后在进行就可以使用相机来获取视频中的人脸新建脚本 vim face_collect.py
然后键入如下代码:
import cv2
import os
if __name__ == "__main__":
str_face_id = ""
index_photo=0
# 加载训练好的人脸检测器
faceCascade=cv2.CascadeClassifier(cv2.data.haarcascades+'haarcascade_frontalface_alt2.xml')
# 打开摄像头
cap = cv2.VideoCapture(0)
while True:
# 判断人脸id 是否为空,空的话创建face_id
if str_face_id.strip()=="":
str_face_id = input('Enter your face ID:')
index_photo=0
if not os.path.exists(str_face_id):
os.makedirs(str_face_id)
# 读取一帧图像
success, img = cap.read()
if not success:
continue
# 转换为灰度
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 进行人脸检测
faces = faceCascade.detectMultiScale(gray, scaleFactor=1.3, minNeighbors=4)
# 画框
for (x, y, w, h) in faces:
cv2.rectangle(img, (x, y), (x+w, y+h), (255, 0, 0), 3)
# 显示检测结果
cv2.imshow("FACE",img)
cap.release()
然后运行,键入:
python3 face_collect.py
按照终端提示输入name :xiao_zhang
###################可以看到显示结果###################
此时已经可以看到调用分类器以后已经可以识别到人脸,同时把识别到的人脸框起来。
然后键入C,保存采集到的人脸数据,此时输入命令:ls
可以看到多了一个文件夹xiao_zhang,存放识别到的人脸数据图片,
在VNC桌面中可以看到对应的图片
##################人脸标注和训练#####################
当人脸数据得到以后,需要对人脸进行标注然后进行训练。
首先新建文件夹dataset存放人脸数据,在dataset下新建四个文件夹,每个文件夹下放不同人物的头像,可以看到
文件夹Nicholas为:
文件夹Statham
文件夹 Vin_Diesel
然后进行人物训练,新建脚本:
vim face_train.py
键入代码
#导入库
import os
import cv2
import numpy as np
import pickle
curid=0
#设置字典,意图将目标文件内的图片排序{'gzy':5,..}
labelids={}
xtrain=[]
ylabels=[]
#指定文件路径以读取训练
BASE_DIR =os.path.dirname(os.path.abspath(__file__))
image_dir=os.path.join(BASE_DIR,"dataset")
#导入训练和分类器
recognizer=cv2.face.LBPHFaceRecognizer_create()
classifier=cv2.CascadeClassifier(cv2.data.haarcascades+'haarcascade_frontalface_alt2.xml')
#训练过程
for root,dirs,files in os.walk(image_dir):
for file in files:
path=os.path.join(root,file)
image=cv2.imread(path)
gray=cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
#将灰度图转换成 Numpy 数组,存储在 xtrain 中。
imagearray=np.array(gray,"uint8")
label=os.path.basename(root)
#同时,将人物的标识(label)存储在 ylabels 中。
if not label in labelids:
labelids[label]=curid
curid+=1
id_=labelids[label]
faces=classifier.detectMultiScale(imagearray,scaleFactor=1.5,minNeighbors=5)
for(x,y,w,h)in faces:
#添加置信区域
roi=imagearray[y:y+h,x:x+w]
xtrain.append(roi)
ylabels.append(id_)
#将训练数据标签用pickle库存放,用于将标签与人物名称相互映射
with open("label.pickle","wb") as f:
pickle.dump(labelids,f)
#通过LBPH脸部模型训练
recognizer.train(xtrain,np.array(ylabels))
#将我们训练好的模型保存为指定的xml
recognizer.save("myfacialtrainer.xml")
#############
训练完毕以后可以使用命令ls可以看到多了两个文件 label.pickle、myfacialtrainer.xml
EEWORLDIMGTK11
使用命令可以查看训练好的数据集
cat myfacialtrainer.xml
EEWORLDIMGTK12
当数据集训练好以后,就可以用来识别了。
新建脚本: vim face_recogn.py
下面是用到的代码
#导入库
import cv2
import numpy as np
import pickle
import os
import tkinter as tk
from PIL import Image, ImageTk
#加载模型
face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_alt2.xml')
face_cascade.load('/home/pi/.local/lib/python3.9/site-packages/cv2/data/haarcascade_frontalface_alt2.xml')
recognizer = cv2.face.LBPHFaceRecognizer_create()
recognizer.read("./myfacialtrainer.xml")
#窗体和按钮设置
root = tk.Tk()
root.geometry("430x310") # 设置窗体初始大小为宽度 800 像素,高度 600 像素i
root.config(bg="white")
root.title("Face Recognition")
label = tk.Label(root)
label.pack()
label.config(bg="white")
labels = {}
button_frame = tk.Frame(root)
button_frame.pack(side="bottom", anchor="s", pady=10)
button_frame.configure(bg="white")
exit_button = tk.Button(button_frame, text="Exit", command=root.destroy)
exit_button.pack(side="right", anchor="se", padx=10)
#打开已有的pickle库,导入数据和标签
with open("label.pickle", "rb") as f:
origin_labels = pickle.load(f)
labels = {v: k for k, v in origin_labels.items()} # 交换名字和值的位置
#初始摄像头窗口设置
cap = cv2.VideoCapture(0)
desired_width = 400
desired_height = 310
cap.set(cv2.CAP_PROP_FRAME_WIDTH, desired_width)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, desired_height)
#识别过程
def recognition():
ret, frame = cap.read()
if ret:
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray, scaleFactor=1.3, minNeighbors=5)
image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
for (x, y, w, h) in faces:
gray_roi = gray[y:y + h, x:x + w]
#预测识别,置信值如果大于70则判定符合人脸
id_, conf = recognizer.predict(gray_roi)
if conf >= 70:
name = labels[id_]
elif conf<70:
name = "NOBODY"
#显示人脸信息到摄像头画面
cv2.putText(image, str(name), (x, y - 15), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2)
cv2.rectangle(image, (x, y), (x + w, y + h), (255, 0, 0), 2)
imgtk = ImageTk.PhotoImage(image=Image.fromarray(image))
label.imgtk = imgtk
label.config(image=imgtk)
if cv2.waitKey(1) & 0xFF == ord('q'):
cap.release()
cv2.destroyAllWindows()
else:
root.after(10, recognition)
#主体
recognition()
root.mainloop()
cap.release()
cv2.destroyAllWindows()
os._exit(0)
##############
输入命令运行:
python3 face_recogn.py
此时报错,缺少PIL库
这里安装PIL库,键入命令:
pip install pillow
再次运行,仍然提示报错
Traceback (most recent call last):
File "face_recogn.py", line 7, in <module>
from PIL import Image, ImageTk
ImportError: cannot import name 'ImageTk' from 'PIL' (/usr/lib/python3/dist-packages/PIL/__init__.py)
使用命令安装pil.imagetk
sudo apt-get install python3-pil python3-pil.imagetk
可以看到安装成功
然后再次运行:
python3 face_recogn.py
但是识别结果有时候不正确,哈哈
这个问题后面再调整调整,不知道是哪里的问题,有可能是数据有点少。
|