OpenCV–基于python人脸LBPH识别

前言:因为我要做选修课的关于ai的项目,所以整个代码其实是摘录自hwtl0703598这个csdn博客主的python人脸识别源码,不过也在调试的过程过发现了那位博客主的一些代码的问题,并改善了,我会在整篇文章后端指出改正,基本上是可以配好环境后直接使用。

简要概述之LBPH是什么?

LBPH(Local Binary PatternsHistograms)局部二进制编码直方图,建立在LBPH基础之上的人脸识别法基本思想如下:首先以每个像素为中心,判断与周围像素灰度值大小关系,对其进行二进制编码,从而获得整幅图像的LBP编码图像;再将LBP图像分为个区域,获取每个区域的LBP编码直方图,继而得到整幅图像的LBP编码直方图,通过比较不同人脸图像LBP编码直方图达到人脸识别的目的,其优点是不会受到光照、缩放、旋转和平移的影响。

PS:OpenCV提供了三种人脸识别的方法,分别是LBPH方法、EigenFishfaces方法、Fisherfaces方法。

为什么要使用LBPH而不是其他?

LBPH:将检测到的人脸分为小单元, 并将其与模型中的对应单元进行比较, 对每个区域的匹配值产生一个直方图。 由于这种方法的灵活性, LBPH是唯一允许模型样本人脸和检测到的人脸在形状、 大小上可以不同的人脸识别算法

人脸识别的步骤

  • step1:进行人脸的录入
  • step2:用保存的人脸进行训练
  • step3:利用训练好的数据去识别特别的人

准备工作:

  • step1.使用python,任意一个编译器,eclipse或者pycharm
  • step2.准备好opencv,OpenCV是一个开源的计算机视觉库,在本项目中用于图像的识别和摄像头的调用
  • step3.numpy(Numerical Python):python语言的一个扩展程序库,支持大量的维度数组与矩阵运算,此外也针对数组提供大量的数学函数库。
  • step4.PIL:Python Imaging Library,Python平台用于图像处理的标准库

 人脸录入流程:

  • step1:利用opencv的VideoCapture函数打开摄像头并获取视频流。
  • step2:获取视频流的每一帧的图像,将图像转成灰度图,在图像上利用opencv人脸检测器去检测人脸,并在人脸上画个框,保存框里面的人脸的图像到自己选定的图像文件夹,保存200张左右,实际是训练越多,识别的成功率也越高。
  • step3:最后保存完200张图像,程序自动结束,释放摄像头缓存并关闭窗口。

PS:每张人脸需要转成灰度图,图像灰度化的目的是为了简化矩阵,提高运算速度,这里是提高识别效率。

 人脸录入完整代码

import cv2

cap = cv2.VideoCapture(0)
face_detector = cv2.CascadeClassifier('D:/opencv\sources/data/haarcascades/haarcascade_frontalface_default.xml')
face_id = input('User data input,Look at the camera and wait ...')
count = 0

while cap.isOpened():
    ret, frame = cap.read()
    if ret is True:
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    else:
        break
    faces = face_detector.detectMultiScale(gray, 1.3, 5)
    for (x, y, w, h) in faces:
        cv2.rectangle(frame, (x, y), (x + w, y + w), (255, 0, 0))
        count += 1
        cv2.imwrite("D:/opencv_test/" + str(face_id) + '.' + str(count) + '.jpg', gray[y:y + h, x:x + w])
        cv2.imshow('image', frame)
    k = cv2.waitKey(1)
    if k == 27:
        break
    elif count >= 200:
        break


cap.release()
cv2.destroyAllWindows()

代码解析:

  • cap = cv2.VideoCapture(0):调用摄像头,参数0表示默认为笔记本的内置第一个摄像头
  • cap.isOpened():判断视频对象是否成功读取,成功读取视频对象返回True,这里作为循环一直执行的条件。
  • ret,frame = cap.read():按帧读取视频,返回值ret是布尔型,正确读取则返回True,读取失败或读取视频结尾则会返回False;frame为每一帧的图像。
  •  faces = face_detector.detectMultiScale(gray, 1.3, 5):#第一个参数是灰度图像,第二个参数是尺度变换,就是向上或者向下每次是原来的多少倍,这里是1.02倍,第三个参数是人脸检测次数,设置越高,误检率越低,但是对于迷糊图片,我们设置越高,越不易检测出来,要适当降低
  • key = cv2.waitKey(1):等待键盘输入,参数1表示延时1ms切换到下一帧,参数为0表示显示当前帧,相当于暂停,让其等于27,27在电脑上表示Esc退出。
  • 这里根据count的数值,录入200张结束,实际也可以录入更多,但也不是更多更好。
  • 这里的保存的图片都固定放到了一个人脸图像集里面,里面的图片名为user.count.jpg
  • 运行代码会在User data input,Look at the camera and wait …停下,这里是要输入,因为后期是需要用names数组来显示名字,所以这里的user名为0,1,2的下标,输入为0,1,2……

效果展示1 

 

 效果展示2

 人脸数据集训练流程

  • step1:给出保存好的人脸图像文件夹的路径,遍历该路径下所有的图片,通过os函数,导入图片的名字和图像进face_samples和ids两个list数组,图片通过numpy中的array函数转成数组。
  • step2:调用LBPH人脸识别器,将图像数组和对应的图像名进行训练,并将结果保存到trainer/trainer.yml这个文件下。

 人脸训练完整代码

import os
import cv2
import numpy as np
from PIL import Image

path = 'D:/opencv_test/'
recognizer = cv2.face.LBPHFaceRecognizer_create()
detector = cv2.CascadeClassifier('D:/opencv\sources/data/haarcascades/haarcascade_frontalface_default.xml')


def get_images_and_labels(path):
    image_paths = [os.path.join(path, f) for f in os.listdir(path)]
    face_samples = []
    ids = []

    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 = int(os.path.split(image_path)[-1].split(".")[0])
        faces = detector.detectMultiScale(img_np)

        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


faces, ids = get_images_and_labels(path)
recognizer.train(faces, np.array(ids))
recognizer.save('trainer/trainer.yml')

代码解析:

  • recognizer = cv2.face.LBPHFaceRecognizer_create():生成LBPH识别器实例模型      
  • cv2.face_FaceRecognizer.train():对每个参考图像计算LBPH,得到一个向量,每个人脸都是整个向量集中的一个点
  • detector = cv2.CascadeClassifier(‘sources/data/haarcascades/haarcascade_frontalface_default.xml’):调用Opencv自带训练好的人脸检测器(默认) 
  • OpenCV自带的人脸检测器在sources/data/目录下,根据每个人OpenCV安装的目录不同,这里也都是用的绝对地址
  • 这里获取的id是user而不是count,这也就是我改善了那位博客主的代码问题,将对应路径下的所有人脸图片按对应的user名进行训练,保存训练好的数据集。

 人脸识别流程:

  • step1:调用摄像头,获取视频流的图像帧,框出人脸,用训练好的人脸图像集去和视频中的人脸进行匹配,使用预测函数predict()获取置信评分。
  • step2:LBPH识别置信评分80以上就算是不合格,所以判断预测出来的置信评分,如果视频流中的人脸没有在训练集中,那么就表示成unknow。
  • step3:框出的视频流图像帧,把人脸框出来,显示置信评分和预测出来的人脸的标签,用标签去指定输出是图像集中的哪个人。
  • step4:释放摄像头资源并关闭窗口。

人脸识别完整代码 

import cv2

recognizer = cv2.face.LBPHFaceRecognizer_create()
recognizer.read('trainer/trainer.yml')
face_cascade = cv2.CascadeClassifier("D:/opencv\sources/data/haarcascades/haarcascade_frontalface_default.xml")
font = cv2.FONT_HERSHEY_SIMPLEX
idnum = 0

cam = cv2.VideoCapture(0)
cam.set(6, cv2.VideoWriter.fourcc('M', 'J', 'P', 'G'))
minW = 0.1 * cam.get(3)
minH = 0.1 * cam.get(4)

names = ['linluocheng','zhupengcheng']

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 < 80:
                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(10)
    if k == 27:
        break


cam.release()
cv2.destroyAllWindows()

 代码解析:

  • recongnizer.predict():一个预测函数,获取图像的标签和图像和训练集的相似度,也称置信评分。
  • cv2.putText():参数(图片 添加的文字 位置 字体 字体大小 字体颜色 字体粗细),将文字显示到图像上,中文会显示乱码。
  • format 格式化函数:基本语法是通过{}和:来代替之前前的%,有点类似C语言的格式符 
  • round() 方法返回浮点数x的四舍五入值 
  • 转成灰度图并在上面框住人脸,用人脸和训练好的去比较,当置信评分达到一定程度,即为匹配成功,显示人脸和置信评分。
  • 这里还是有一处是那位博客主的错误,就是format函数和前面的“”之前是用.隔开,而不是逗号,

效果展示图 1

效果展示图2

OpenCV--基于python人脸LBPH识别

 

 

鉴于使用源码出现的各种问题做个总结:

1、这里的代码是我通过别人的代码稍作修改的,如果你碰到了问题去找其他的人的意见去修改,还是会出现问题,如果出现函数没有找到,不存在的问题,那就是opencv的版本问题,在更新迭代后各种函数会出现相应修改。

2、有人用这个博客的代码出了各种问题,原因是一个训练的流程不是很清楚,关键在于人脸录入的时候的输入名称,这里针对能运行程序,给出以下的流程。

step1(注意这里输入的是0,1,2,最好按照顺序输入):

step2:

人脸训练直接运行即可。

step3(在人脸识别代码中,会有一个类似的names列表,这个就是我们自定义的名字,在录入人脸的时候的序号,即对应这里的下标,然后取得对应的人脸标签):

step3:

然后进行识别,最终识别完成。

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
扎眼的阳光的头像扎眼的阳光普通用户
上一篇 2023年4月27日
下一篇 2023年4月27日

相关推荐