目录
摘要
-
一、 需求分析
-
二、 概要设计
- 总功能模块
- 录入人脸模块
- 实时检测模块
- 三、 详细设计
- 第三方库导入
- 建立相关储存文件
- 对照人脸获取
- 通过算法建立对照模型
- 人脸检测识别
- 日志返回
-
四、 执行结果
-
五、 附录(程序清单)
-
六、 运行过程遇到的问题
-
摘要
在20世纪末,计算机的发展催生了人们对人工智能的研究,为了实现这一技术,那么,对人脸识别技术的研究就显得非常重要而且也是必不可少的。因为计算机的发展,所以近十年来对人脸识别的研究飞速发展,如今已经产生了很多进行人脸识别的方法。但是我们不能满足于现状,伴随着Python这一电脑编程语言的深入开发,Python编程语言相对于C或C++等编程语言的优点也凸显出来。根据Python的优点,我采用了一种以Python编程语言及其图像处理库为基础的人脸识别的方法,通过对人脸图像对比库进行人脸检测、捕获人脸、提取人脸关键部位特征参数、生成特征参数描述文件等一些列步骤,并计算欧氏距离,把人脸图像对比库的人脸图像的欧氏距离与对照组人脸图像的欧氏距离进行对比并判定等得出识别结果。结果表明,该系统对于对照组的人脸图像的识别准确率可达70%,因此,以Python编程语言及其图像处理库为基础的人脸识别方法不仅具有比较高效的识别率,而且也降低了设备的要求,具有一定的实用价值。
关键词:人脸识别;Python;opencv-python qt5库
- 一、 需求分析
本课题主要目的是设计一个实时监控的人脸识别系统,将摄像头部署在需要进行监控的场合,系统初始化完毕后便于自动检测录入人脸和识别并显示个人信息,并实时记录人脸打卡的日志,并将不能识别的人脸标记为“UNKOWN”,系统只能识别预先经过信息采集的人物,在采集阶段,记录人物ID与姓名
- 二、 概要设计
- 总功能模块
整个系统分为三个功能模块,一个是人脸信息采集模块,一个是实时打卡模块,另一个是将打卡时间写入日志文件
- 录入人脸模块
- 实时检测模块
- 三、 详细设计
-
第三方库导入
安装好程序所设计的库:opencv-python ; numpy ; image ; opencv-contrib-python -
建立相关储存文件
在项目工程opencv-人脸识别下建立:
facedata文件夹:用于储存人脸识别录入的信息
Haarcascade-frontalface-default : CV2库本身data文件夹中所带的安装包,可以一并放在这个项目目录下,后面可以避免很多因它出现的问题
*Log.csv:*用于返回实时打开日志文件,记录打卡时间 Maxmenber.csv : 导入录入人脸信息,字段为 “编号,姓名”
- 对照人脸获取
import cv2
#调用笔记本内置摄像头,参数为0,如果有其他的摄像头可以调整参数为1,2
cap = cv2.VideoCapture(0)
#调用人脸分类器,要根据实际路径调整3
face_detector = cv2.CascadeClassifier(‘haarcascade_frontalface_default.xml')
#待更改为即将录入的脸标记一个id
face_id = input('\n User data input,Look at the camera and wait ...')
#sampleNum用来计数样本数目
count = 0
while True:
#从摄像头读取图片
success,img = cap.read()
#转为灰度图片,减少程序符合,提高识别度
if success is True:
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
else:
break
#检测人脸,将每一帧摄像头记录的数据带入OpenCv中,让Classifier判断人脸
#其中gray为要检测的灰度图像,1.3为每次图像尺寸减小的比例,5为minNeighbors
faces = face_detector.detectMultiScale(gray, 1.3, 5)
#框选人脸,for循环保证一个能检测的实时动态视频流
for (x, y, w, h) in faces:
#xy为左上角的坐标,w为宽,h为高,用rectangle为人脸标记画框
cv2.rectangle(img, (x, y), (x+w, y+w), (255, 0, 0))
#成功框选则样本数增加
count += 1
#保存图像,把灰度图片看成二维数组来检测人脸区域
#(这里是建立了data的文件夹,当然也可以设置为其他路径或者调用数据库)
cv2.imwrite("data/User."+str(face_id)+'.'+str(count)+'.jpg',gray[y:y+h,x:x+w])
#显示图片
cv2.imshow('image',img)
#保持画面的连续。waitkey方法可以绑定按键保证画面的收放,通过q键退出摄像
k = cv2.waitKey(1)
if k == '27':
break
#或者得到80个样本后退出摄像,这里可以根据实际情况修改数据量,实际测试后80张的效果是比较理想的
elif count >= 80:
break
#关闭摄像头,释放资源
cap.realease()
cv2.destroyAllWindows()
人脸录入成功后将会在facedata文件目录下看到如下(这里录入了三个人的人脸) 在项目下可以看到,在路径文件下也可以看到
LBP是一种特征提取方式,能提取出图像的局部的纹理特征,最开始的LBP算子是在3X3窗口中,取中心像素的像素值为阀值,与其周围八个像素点的像素值比较,若像素点的像素值大于阀值,则此像素点被标记为1,否则标记为0。这样就能得到一个八位二进制的码,转换为十进制即LBP码,于是得到了这个窗口的LBP值,用这个值来反映这个窗口内的纹理信息。
LBPH是在原始LBP上的一个改进,在opencv支持下我们可以直接调用函数直接创建一个LBPH人脸识别的模型。
import os
import cv2
import numpy as np
from PIL import Image
#导入pillow库,用于处理图像
#设置之前收集好的数据文件路径
path = 'data'
#初始化识别的方法
recog = cv2.face.LBPHFaceRecognizer_create()
#调用熟悉的人脸分类器
detector = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
#创建一个函数,用于从数据集文件夹中获取训练图片,并获取id
#注意图片的命名格式为User.id.sampleNum
def get_images_and_labels(path):
image_paths = [os.path.join(path,f) for f in os.listdir(path)]
#新建连个list用于存放
face_samples = []
ids = []
#遍历图片路径,导入图片和id添加到list中
for image_path in image_paths:
#通过图片路径将其转换为灰度图片
img = Image.open(image_path).convert('L')
#将图片转化为数组
img_np = np.array(img,'uint8')
if os.path.split(image_path)[-1].split(".")[-1] != 'jpg':
continue
#为了获取id,将图片和路径分裂并获取
id = int(os.path.split(image_path)[-1].split(".")[1])
faces = detector.detectMultiScale(img_np)
#将获取的图片和id添加到list中
for(x,y,w,h) in faces:
face_samples.append(img_np[y:y+h,x:x+w])
ids.append(id)
return face_samples,ids
#调用函数并将数据喂给识别器训练
print('Training...')
faces,ids = get_images_and_labels(path)
#训练模型
recog.train(faces,np.array(ids))
#保存模型
recog.save('trainner/trainner.yml')
- 人脸检测识别
import cv2
#准备好识别方法
recognizer = cv2.face.LBPHFaceRecognizer_create()
#使用之前训练好的模型
recognizer.read('trainner/trainner.yml')
#再次调用人脸分类器
cascade_path = "haarcascade_frontalface_default.xml"
face_cascade = cv2.CascadeClassifier(cascade_path)
#加载一个字体,用于识别后,在图片上标注出对象的名字
font = cv2.FONT_HERSHEY_SIMPLEX
idnum = 0
#设置好与ID号码对应的用户名,如下,如0对应的就是初始
names = ['初始','admin','user1','user2','user3']
#调用摄像头
cam = cv2.VideoCapture(0)
minW = 0.1*cam.get(3)
minH = 0.1*cam.get(4)
while True:
ret,img = cam.read()
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
#识别人脸
faces = face_cascade.detectMultiScale(
gray,
scaleFactor = 1.2,
minNeighbors = 5,
minSize = (int(minW),int(minH))
)
#进行校验
for(x,y,w,h) in faces:
cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)
idnum,confidence = recognizer.predict(gray[y:y+h,x:x+w])
#计算出一个检验结果
if confidence < 100:
idum = names[idnum]
confidence = "{0}%",format(round(100-confidence))
else:
idum = "unknown"
confidence = "{0}%",format(round(100-confidence))
#输出检验结果以及用户名
cv2.putText(img,str(idum),(x+5,y-5),font,1,(0,0,255),1)
cv2.putText(img,str(confidence),(x+5,y+h-5),font,1,(0,0,0),1)
#展示结果
cv2.imshow('camera',img)
k = cv2.waitKey(20)
if k == 27:
break
#释放资源
cam.release()
cv2.destroyAllWindows()
- 日志返回
所有的打卡记录将会返回到日志文件中,这有利于管理者查看
- 四、 执行结果
程序运行:
- 五、 附录(程序清单)
import cv2
import os
import numpy as np
from PIL import Image
import datetime
import csv
# 调用笔记本内置摄像头,所以参数为0,如果有其他的摄像头可以调整参数为1,2
Path = r"D:\python install\Lib\site-packages\cv2\data\haarcascade_frontalface_default.xml"
# 人脸识别器分类
face_detector = cv2.CascadeClassifier(Path)
names = []
zh_name = []
with open("maxmember.csv", "r", encoding='UTF-8') as csv_file:
reader = csv.reader(csv_file)
for item in reader:
# print(item)
names.append(item[2])
zh_name.append(item[1])
# print (zh_name)
def data_collection():
# cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
videoSourceIndex = 0
cap = cv2.VideoCapture(cv2.CAP_DSHOW + videoSourceIndex)
# cv2.CAP_DSHOW是作为open调用的一部分传递标志,
# 还有许多其它的参数,而这个CAP_DSHOW是微软特有的。
face_id = input('\n 请输入你的ID:')
print('\n 数据初始化中,请直视摄像机录入数据....')
count = 0
while True:
# 从摄像头读取图片
sucess, img = cap.read()
# 转为灰度图片
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 检测人脸
faces = face_detector.detectMultiScale(gray, 1.3, 5)
for (x, y, w, h) in faces:
cv2.rectangle(img, (x, y), (x + w, y + w), (255, 0, 0))
count += 1
# 保存图像
cv2.imwrite("facedata/Member." + str(face_id) + '.' + str(count) + '.jpg', gray[y: y + h, x: x + w])
cv2.imshow('data collection', img)
# 保持画面的持续。
k = cv2.waitKey(1)
if k == 27: # 通过esc键退出摄像
break
elif count >= 30: # 得到n个样本后退出摄像
break
cap.release()
cv2.destroyAllWindows()
# 人脸数据训练
def face_training():
# 人脸数据路径
path = './facedata'
recognizer = cv2.face.LBPHFaceRecognizer_create()
# FaceRecognizer 人脸识别类内的接口函数也是异常简单,
# 人脸识别的任务也就是两大部分,训练和预测
'''
LBP,参数包括半径radius,邻域大小即采样点个数neighbors,
x和y方向的单元格数目grid_x, grid_y,
还有两个参数histograms为训练数据得到的直方图,
labels为直方图对应的标签。
这个方法也要求训练和测试的图像是灰度图
'''
def getImagesAndLabels(path):
imagePaths = [os.path.join(path, f) for f in os.listdir(path)]
# join函数将多个路径组合后返回
faceSamples = []
ids = []
for imagePath in imagePaths:
# 把它转换成灰度
PIL_img = Image.open(imagePath).convert('L')
img_numpy = np.array(PIL_img, 'uint8')
id = int(os.path.split(imagePath)[-1].split(".")[1])
faces = face_detector.detectMultiScale(img_numpy)
for (x, y, w, h) in faces:
faceSamples.append(img_numpy[y:y + h, x: x + w])
ids.append(id)
return faceSamples, ids
print('数据训练中')
faces, ids = getImagesAndLabels(path)
recognizer.train(faces, np.array(ids))
recognizer.write(r'.\trainer.yml')
# print("{0} faces trained. Exiting Program".format(len(np.unique(ids))))
def face_ientification():
# 开启摄像头
cap = cv2.VideoCapture(0)
recognizer = cv2.face.LBPHFaceRecognizer_create()
recognizer.read('./trainer.yml')
faceCascade = cv2.CascadeClassifier(Path)
font = cv2.FONT_HERSHEY_SIMPLEX
idnum = 0
names = ['汪涵', 'Allen', 'zouxuan']
global namess
cam = cv2.VideoCapture(0)
# 设置大小
minW = 0.1 * cam.get(3)
minH = 0.1 * cam.get(4)
while True:
ret, img = cam.read()
# 图像灰度处理
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 将人脸用vector保存各个人脸的坐标、大小(用矩形表示)
faces = faceCascade.detectMultiScale(
gray,
scaleFactor=1.2, # 表示在前后两次相继的扫描中,搜索窗口的比例系数
minNeighbors=5, # 表示构成检测目标的相邻矩形的最小个数(默认为3个)
minSize=(int(minW), int(minH)) # minSize和maxSize用来限制得到的目标区域的范围
)
for (x, y, w, h) in faces:
cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)
idnum, confidence = recognizer.predict(gray[y:y + h, x:x + w])
if confidence < 100:
namess = names[idnum]
confidence = "{0}%".format(round(100 - confidence))
else:
namess = "unknown"
confidence = "{0}%".format(round(100 - confidence))
cv2.putText(img, str(namess), (x + 5, y - 5), font, 1, (0, 0, 255), 1)
cv2.putText(img, str(confidence), (x + 5, y + h - 5), font, 1, (0, 0, 0), 1) # 输出置信度
cv2.imshow(u'Identification punch', img)
k = cv2.waitKey(10)
if k == 13:
theTime = datetime.datetime.now()
# print(zh_name[idnum])
strings = [str(zh_name[idnum]), str(theTime)]
print(strings)
# 将获取到的打卡时间重新做一个表格
with open("log.csv", "a", newline="") as csvFile:
writer = csv.writer(csvFile)
writer.writerow([str(zh_name[idnum]), str(theTime)])
elif k == 27:
cap.release()
cv2.destroyAllWindows()
break
while True:
a = int(input("输入1,录入脸部,输入2进行识别打卡:"))
if a == 1:
data_collection()
face_training()
elif a == 2:
face_ientification()
- 六、 运行过程遇到的问题
见这个连接:报错问题