【opencv】基于opencv实现人脸识别,原理&代码部分

上一部分我们解决了环境问题,这一部分我们可以开始上代码,环境没有配好的可以参照上一篇博客:环境搭建解决:

下面先说一下原理:

一.原理部分

  本文基于opencv来实现人脸识别,大致实现流程可以描述为:

在这里插入图片描述
  当计算机拿到你输入的图片以后,首先对整个图片先进行灰度处理,即将图片拆解成一个矩阵,矩阵中的每个元素分别代表着图片中每个像素点的像素值,映射范围是0~255,再提取图片中人脸的部分将其框出,然后提取图片特征,即把人脸那一块数据提取出来,经过多个人脸的特征数据和图片的id进行对应,经过大量数据的训练后,计算机就可以生成人脸识别模型,然后再调用视频,图片或者摄像头就可以识别出来图片里的人是谁。
  在opencv中筛选人脸的代码在刚刚下载好的opencv文件夹中,找到刚刚下载好的opencv文件夹,打开source—>data—>haarcascades,找到里面的haarcascade_frontalface_alt2.xml或者haarcascade_frontalface_default.xml
这两个代码的作用都是将图片中人脸的信息框选出来,以我自己的电脑为例
【opencv】基于opencv实现人脸识别,原理&代码部分_第1张图片
  在写代码的时候调用这两个中的一个就好,就例如在这里我们调用的是_alt2,还有就是这个路径中不能出现中文,否则会报错,所以opencv最好不要安装到文件名中带有中文的文件夹里。【opencv】基于opencv实现人脸识别,原理&代码部分_第2张图片

二.代码部分

  首先安装必备的包
【opencv】基于opencv实现人脸识别,原理&代码部分_第3张图片
  这几个包必须有,因为在中间做计算的时候会用到

数据训练的代码

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和图片名
【opencv】基于opencv实现人脸识别,原理&代码部分_第4张图片

人脸识别的代码

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文件,运行结果如下:
【opencv】基于opencv实现人脸识别,原理&代码部分_第5张图片
  这里先测试一下视频中的人脸识别,可以发现代码识别出来了视频中我的偶像Amber,这里我就不放用摄像头测试我的脸的结果了,有兴趣的读者可以试一试,需要注意的是我设置的是:在运行时如果测试的是视频的话就按空格结束(按空格关闭视频),如果是摄像头识别自己的话也是按空格结束人脸识别。

你可能感兴趣的:(人脸识别系统,opencv,计算机视觉,python,人工智能)