上一部分我们解决了环境问题,这一部分我们可以开始上代码,环境没有配好的可以参照上一篇博客:环境搭建解决:
下面先说一下原理:
本文基于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 contrib
def 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])
#打印面部特征和id
print('id:',id)
print('fs:',faceSamples)
return faceSamples,ids
if __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 hashlib
m = 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?' + data
response = 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*300
face = 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 warningtime
warningtime += 1
if warningtime > 100:
warning() # 遇到不认识的人长时间在摄像头面前徘徊就调用报警模块
warningtime = 0
cv2.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:
break
face_detect_demo(frame)
if ord(' ') == cv2.waitKey(10): # 按空格结束
break
cv2.destroyAllWindows()
cap.release()
#print(names)
这里使用了一个短信网站,其实完全可以删掉,加上这段代码的用处在于在进行人脸识别的时候可以附加一个功能:当摄像头前出现了不认识的人的时候,如果停留时间过长就会触发报警机制,即给你的手机发短信,告诉你什么时间地点出现了不认识的人。
测试一下视频1.mp4文件,运行结果如下:
这里先测试一下视频中的人脸识别,可以发现代码识别出来了视频中我的偶像Amber,这里我就不放用摄像头测试我的脸的结果了,有兴趣的读者可以试一试,需要注意的是我设置的是:在运行时如果测试的是视频的话就按空格结束(按空格关闭视频),如果是摄像头识别自己的话也是按空格结束人脸识别。