上一部分我们解决了环境问题,这一部分我们可以开始上代码,环境没有配好的可以参照上一篇博客:环境搭建解决:
下面先说一下原理:
一.原理部分
本文基于opencv来实现人脸识别,大致实现流程可以描述为:

当计算机拿到你输入的图片以后,首先对整个图片先进行灰度处理,即将图片拆解成一个矩阵,矩阵中的每个元素分别代表着图片中每个像素点的像素值,映射范围是0~255,再提取图片中人脸的部分将其框出,然后提取图片特征,即把人脸那一块数据提取出来,经过多个人脸的特征数据和图片的id进行对应,经过大量数据的训练后,计算机就可以生成人脸识别模型,然后再调用视频,图片或者摄像头就可以识别出来图片里的人是谁。
在opencv中筛选人脸的代码在刚刚下载好的opencv文件夹中,找到刚刚下载好的opencv文件夹,打开source—>data—>haarcascades,找到里面的haarcascade_frontalface_alt2.xml或者haarcascade_frontalface_default.xml
这两个代码的作用都是将图片中人脸的信息框选出来,以我自己的电脑为例

在写代码的时候调用这两个中的一个就好,就例如在这里我们调用的是_alt2,还有就是这个路径中不能出现中文,否则会报错,所以opencv最好不要安装到文件名中带有中文的文件夹里。
二.代码部分
首先安装必备的包

这几个包必须有,因为在中间做计算的时候会用到
数据训练的代码
import os
from os import listdir
import cv2
from PIL import Image # 如果这里报错了就下载Image,因为我用的是python3,PIL在python3里被Pillow取代了,但是Pillow里没有Image
import numpy as np
import contribdef getImageAndLabels(path):#存储人脸数据faceSamples = []#存储姓名数据ids = []imagePaths = [os.path.join(path,f) for f in listdir(path)]#加载分类器face_detector = cv2.CascadeClassifier('D:/OpenCV/opencv/sources/data/haarcascades/haarcascade_frontalface_alt2.xml') # 人脸检测文件#遍历列表中的图片for imagePaths in imagePaths: #要求每一张图片里只能有一张人脸#打开图片#灰度化PIL有九种不同模式:1,L,P,RGB,RGBA,CMYK,YCbCr,I,F, 1打开方式为是黑白,L是打开方式是灰度图像PIL_img = Image.open(imagePaths).convert('L') #灰度打开图像,相当于cv.imread然后再用cv.cvtColor对图像进行灰度转换,把像素范围界定在0~255#将图片转换为数组,以黑白深浅。就是将图片向量化,把图片的每一个像素点变成一个数值,用这个数值进行判别计算img_numpy = np.array(PIL_img,'uint8')#获取图片人脸特征faces = face_detector.detectMultiScale(img_numpy) #img_numpy是整张图片,然后将整张图片中人脸的那一块小数组提取出来存到faces里面#获取每张图片id和姓名id = int(os.path.split(imagePaths)[1].split('.')[0]) #把文件名”.“前面的文件名称提取出来,去掉文件扩展名,比如图片名称是“张三.jpg”,id就是”张三“#预防无面容照片for x,y,w,h in faces:ids.append(id)faceSamples.append(img_numpy[y:y+h,x:x+w])#打印面部特征和idprint('id:',id)print('fs:',faceSamples)return faceSamples,idsif __name__ == '__main__':#图片路径path = 'D:/深度学习/人脸识别项目/人脸信息'#获取图片数组和id数组faces,ids = getImageAndLabels(path)#加载识别器recognizer = cv2.face.LBPHFaceRecognizer_create()#训练recognizer.train(faces,np.array(ids))#保存文件recognizer.write('trainer/trainer.yml')#如果运行报cv2.cv2错的话,重新安装opencv-python和opencv-contrib-python,装之前先把之前的版本卸载掉
#如果3.7以上版本可能会出现cv2没有face命令,就pip opencv-python-handless和contrib的handless
如果运行报cv2.cv2错的话,重新安装opencv-python和opencv-contrib-python,装之前先把之前的版本卸载掉
如果3.7以上版本可能会出现cv2没有face命令,就pip opencv-python-handless和contrib的handless
需要注意的是需要在当下的文件夹下建立一个trainer文件夹,用于存放训练好的模型。同时也建立一个用来存放人脸信息的文件夹存放训练数据,就是所谓的训练集。训练集中的图片最好是一张图片中只有一张人脸,然后图片的命名规则是: 序号.图片名称.jpg
如下图中所示,这样做的目的在于便于分割id和图片名

人脸识别的代码
import cv2
import os
import urllib
import urllib.request#加载训练数据集文件
recognizer = cv2.face.LBPHFaceRecognizer_create() # 如果运行时报错module has no attribute 'face' 说明没有opencv-contrib-python
#加载数据
recognizer.read('trainer/trainer.yml')
#名称
names = []
#警报全局变量
warningtime = 0#md5加密
def md5(str):import hashlibm = hashlib.md5()m.update(str.encode("utf8"))return m.hexdigest()#短信反馈
statusStr = {#相当于一个数据字典,目的是把返回的代码翻译成相应的错误类型告诉你'0':'短信发送成功','-1':'参数不全','-2':'服务器空间不支持,请确认支持curl或者fsocket,联系您的空间商解决或更换空间','30':'密码错误','40':'账号不存在','41':'余额不足','42':'账户已过期','43':'IP地址限制','50':'内容含有敏感词'
}#警报模块
def warning():smsapi = "http://api.smsbao.com/"#短信平台账号user = '150********'#短信平台密码password = md5('*********') # 密码需要用md5加密#要发送短信的内容content = '【报警】\n原因:xxx\n时间:xxx\n地点:xxx\n'#要发送短信的手机号码phone = '150********'data = urllib.parse.urlencode({ 'u':user , 'p':password , 'm':phone , 'c':content})send_url = smsapi + 'sms?' + dataresponse = urllib.request.urlopen(send_url)the_page = response.read().decode('utf-8')print(statusStr[the_page]) # 输出短信反馈的具体信息#准备识别图片
def face_detect_demo(img):# 灰度转换gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)# 加载人脸检测文件face_detector = cv2.CascadeClassifier('D:/OpenCV/opencv/sources/data/haarcascades/haarcascade_frontalface_alt2.xml')#限定人脸大小100*100~300*300face = face_detector.detectMultiScale(gray,1.1,5,cv2.CASCADE_SCALE_IMAGE,(100,100),(300,300))#face = face_detector.detectMultiScale(gray)for x,y,w,h in face:cv2.rectangle(img,(x,y),(x+w,y+h),color=(0,0,255),thickness = 1)#人脸识别ids,confidence = recognizer.predict(gray[y : y+h , x : x+w]) # ids是名字,confidence是评分#print('标签id:',ids,'置信评分:',confidence)if(confidence > 80): # 如果评分很高就说明这个人不是我们认识的人,发出警报,调用报警函数global warningtimewarningtime += 1if warningtime > 100:warning() # 遇到不认识的人长时间在摄像头面前徘徊就调用报警模块warningtime = 0cv2.putText(img,'unkonw',( x+10 , y-10 ),cv2.FONT_HERSHEY_SIMPLEX,0.75,(0,255,0),1)else: # 如果评分比较小,那么说明是一个可信的人,那么久把他的姓名打到框图上面cv2.putText(img,str(names[ids-1]),( x+10 , y-10 ),cv2.FONT_HERSHEY_SIMPLEX,0.75,(0,255,0),1)cv2.imshow('result',img)#print('bug:',ids)def name():path = './人脸信息'#names = []imagePaths=[os.path.join(path,f) for f in os.listdir(path)]for imagePath in imagePaths:name = str(os.path.split(imagePath)[1].split('.',2)[1])names.append(name)cap=cv2.VideoCapture('1.mp4')
name()
while True:flag,frame=cap.read()if not flag:breakface_detect_demo(frame)if ord(' ') == cv2.waitKey(10): # 按空格结束break
cv2.destroyAllWindows()
cap.release()
#print(names)
这里使用了一个短信网站,其实完全可以删掉,加上这段代码的用处在于在进行人脸识别的时候可以附加一个功能:当摄像头前出现了不认识的人的时候,如果停留时间过长就会触发报警机制,即给你的手机发短信,告诉你什么时间地点出现了不认识的人。
三.测试环节
测试一下视频1.mp4文件,运行结果如下:

这里先测试一下视频中的人脸识别,可以发现代码识别出来了视频中我的偶像Amber,这里我就不放用摄像头测试我的脸的结果了,有兴趣的读者可以试一试,需要注意的是我设置的是:在运行时如果测试的是视频的话就按空格结束(按空格关闭视频),如果是摄像头识别自己的话也是按空格结束人脸识别。

















