OpenCv做一个简单的人脸识别

#人脸识别# #opencv#

最近想做一个人脸识别,正好手上面有一块树莓派4B,借这个机会正好把树莓派玩一下。

一.准备阶段

1.软硬件搭配

  树莓派(树莓派最好还是搞个风扇,不然又烫又卡)

  摄像头(随便找的一块,不是很好,但是够用)

 pycharm:

如果需要下载可以直接去官网下载,分为社区版和专业版,其中社区版免费但是被阉割过了,缺少部分功能,专业版功能强大,但是需付费,专业版许可证和账号可以去淘宝买,不会超过十块钱。

2.环境安装

(1)资料查找

OpenCV是一个基于Apache2.0许可(开源)发行的跨平台计算机视觉和机器学习软件库,可以运行在LinuxWindowsAndroidMac OS操作系统上。 它轻量级而且高效——由一系列 C 函数和少量 C++ 类构成,同时提供了Python、RubyMATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。

(2)库文件安装:下载opencv和扩展包。

这里的opencv的两个包区别:

1.opencv-python 只包含了主要模块的包

2.opencv-contrib-python 包含了主要模块以及扩展模块

pycharm终端命令行输入pip指令,但是注意自己的opencv版本和python环境版本对应。

pip install opencv-python
pip install opencv-contrib-python

输入 python -V  或者 python --version

 python -V  
 python --version

如果下载缓慢或者异常中断,可以加入国内镜像源去安装,例如

​pip install <安装包> -i https://pypi.tuna.tsinghua.edu.cn/simple/

下面是常用的几个源推荐:

//清华源:
https://pypi.tuna.tsinghua.edu.cn/simple/
//中科大学:
https://pypi.mirrors.ustc.edu.cn/simple/
//华科大:
http://pypi.hustunique.com/simple/
//上海交大:
https://mirror.sjtu.edu.cn/pypi/web/simple/
//豆瓣:
http://pypi.douban.com/simple/
//山东理工:
http://pypi.sdutlinux.org/
//阿里云
https://mirrors.aliyun.com/pypi/simple/

这里的源参考来源:国内常见pip使用镜像源地址_清华镜像源-CSDN博客

 下载好了之后在解释器查看

3.过程设计

二.代码部分

代码使用的别人的,但是根据我的使用情况做了一些调整,原始代码出处:

opencv+python+pycharm实现人脸识别_pycharm怎么关闭摄像头-CSDN博客

1.代码分析

导入库文件:

import cv2 as cv#引入OpenCV库,并使用cv作为库的别名
import imutils#图像处理工具库,可以简化常见的图像操作
cv.ocl.setUseOpenCL(False)#禁止利用GPU等设备来加速图像处理和计算任务。
这里cv.ocl.setUseOpenCL(False)是因为不用GPU,而且报错,就删掉了openCL的库,也禁用它,如果你的电脑有GPU就把这句删掉就可以了。

打开摄像头读取每一帧,并转为灰度图片

  while (camera.isOpened()):  # 从摄像头读取图片
        success, img = camera.read()#读取图像帧
        if not success:
            break
        gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)  # 转为灰度图片

初始化人脸检测分类器,这里要找到你的这个工程目录下的site-packages里面的.xml文件。

 # 加载OpenCV人脸检测分类器
    face_cascade = cv.CascadeClassifier(
        "D:\python23\Facetext\.venv\Lib\site-packages\cv2\data\haarcascade_frontalface_default.xml")
    recognizer = cv.face.LBPHFaceRecognizer_create()

分类器检测人脸,得到一个合适的窗口顶点坐标,高度,宽度

face_detector = face_cascade#face_cascade的人脸检测器
        faces = face_detector.detectMultiScale(gray, 1.1, 5, 0, (W_size, H_size))#face_detector.detectMultiScale()用于检测输入图像中的人脸

这里调用face_detector(即face_cascade)的detectMultiScale方法来检测灰度图像gray中的人脸,然后返回一个四元组(x, y, w, h),其中(x, y)是矩形左上角的坐标,w是矩形的宽度,h是矩形的高度。​​​​​​​

遍历人脸图片,生成数组

 for imagePath in imagePaths:#打开图片,灰度化
        PIL_img = Image.open(imagePath).convert('L') #把图像转换为数组,
        img_numpy = np.array(PIL_img,'uint8')#获取图片人脸特征
        faces = face_detecter.detectMultiScale(img_numpy)#获取每张图片的id和姓名
        id = int(os.path.split(imagePath)[1].split('.')[0])#预防无面容照片
        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

对比置信度,判断为存储的人像还是其他

 ids, confidence = recognizer.predict(gray_img[y:y + h, x:x + w])
        if confidence > 70:
            img = cv2AddChineseText(img, "外来人员(" + str(int(confidence)) + ")", (x + 10, y + 10), (0, 255, 0), 30)
        else:
            img = cv2AddChineseText(img, str(names[idn.index(ids)]) + "(" + str(int(confidence)) + ")",(x + 10, y - 25), (0, 255, 0), 30)
2.完整代码

代码分为了三个.py文件,face_collection,face_training,face_detection

其中face_collection(提前设置一个文件夹去存放采集到的图片)

face_training(提前设置一个文件夹去存放.xml模型文件)

1.face_collection

import cv2 as cv#引入OpenCV库,并使用cv作为库的别名
import imutils#图像处理工具库,可以简化常见的图像操作
cv.ocl.setUseOpenCL(False)#禁止利用GPU等设备来加速图像处理和计算任务。

#人脸采集
def get_face(face_cascade, recognizer, camera, face_id, face_name, W_size, H_size, maximums_picture):
   #定义get_face,该函数接受参数face_cascade、recognizer、camera、face_id、face_name、W_size、H_size和maximums_picture。
    #从摄像头捕获人脸图像,并使用级联分类器(face_cascade)和识别器(recognizer)来检测和识别人脸。
    print("正在从摄像头采集新人脸信息 \n")
    picture_num = 0  # 设置录入照片的初始编号
    while (camera.isOpened()):  # 从摄像头读取图片
        success, img = camera.read()#读取图像帧
        if not success:
            break
        gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)  # 转为灰度图片
        #具体用法如下:dst_image = cv.cvtColor(src_image, code[, dstCn])
        #src_image 是输入图像
        #code 是颜色空间转换的标志,cv.COLOR_BGR2GRAY(BGR 到灰度)

        face_detector = face_cascade#face_cascade的人脸检测器
        faces = face_detector.detectMultiScale(gray, 1.1, 5, 0, (W_size, H_size))#face_detector.detectMultiScale()用于检测输入图像中的人脸
        for (x, y, w, h) in faces:  # 矩形框选人脸(xy为左上角的坐标,w为宽,h为高)
            cv.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0))#函数在图像上绘制矩形框
            picture_num += 1  # 照片编号加一
            t = face_name
            d = face_id
            # 截取人脸部分,保存图片,图片名格式为:人脸唯一编号.人脸姓名.camera照片编号.jpg
            cv.imencode(".jpg", img[y:y + h, x:x + w])[1].tofile(
                "D:\\python23\\Facetext\\picture\\" + str(d) + "." + str(t) + ".camera" + str(picture_num) + ".jpg")
            print('保存图片:' + str(d) + "." + str(t) + ".camera" + str(picture_num) + ".jpg")
        # 采集规定数量人脸后退出
        if picture_num > maximums_picture:#定义数目
            break
        cv.namedWindow("ShowFace", cv.WINDOW_AUTOSIZE)  # 命名窗口
        img = imutils.resize(img, height=800)
        cv.imshow("ShowFace", img)
        k = cv.waitKey(1) & 0xFF
        if k == ord(' '):
            break


if __name__ == '__main__':
    #face_id = 0  # 该人脸的唯一编号
    face_id = input("请输入人脸编号: ")
    face_name = input("请输入人脸的名字: ")
    maximums_picture = 200  # 设置人脸照片数量的上限


    # 加载OpenCV人脸检测分类器
    face_cascade = cv.CascadeClassifier(
        "D:\python23\Facetext\.venv\Lib\site-packages\cv2\data\haarcascade_frontalface_default.xml")
    recognizer = cv.face.LBPHFaceRecognizer_create()

    camera = cv.VideoCapture(0)  # 0:电脑摄像头, 2是外接的摄像头
    # 网络摄像头,iphone可以安装免费APP:IP摄像头Lite
    # camera = cv.VideoCapture("http://admin:123456@192.168.137.20:8081/video")

    W_size = int(0.1 * camera.get(3))  # 在视频流的帧的宽度
    H_size = int(0.1 * camera.get(4))  # 在视频流的帧的高度
    print(str(W_size) + '×' + str(H_size))

    get_face(face_cascade, recognizer, camera, face_id, face_name, W_size, H_size, maximums_picture)
    #获取人脸的函数。它接受的参数包括:
    #face_cascade:人脸级联分类器,用于检测和识别人脸。
    #recognizer:人脸识别器,用于识别已知的人脸。
    #camera:相机设备,用于捕获图像或视频流。
    #face_id:人脸ID,用于标识不同的人脸。
    #face_name:人脸名称,用于关联人脸ID和人脸的姓名。3
    #W_size 和 H_size:图像或视频流的宽度和高度尺寸。
    #maximums_picture:最大图像数量,用于限制获取的人脸图像数量。
    camera.release()
    cv.destroyAllWindows()
2.face_training
import os#os模块可以用于文件路径操作、目录创建等操作
import cv2 as cv#导入 OpenCV 库,并将其命名为 cv
from PIL import Image#PIL模块是Python Imaging Library,用于图像处理和操作
import numpy as np#导入numpy做数学计算,和数组变换

def getImageAndLabels(path):#获取图片
    #存储人脸数据
    faceSamples = []
    #存储姓名数据
    ids=[]
    #储存图片信息
    imagePaths = [os.path.join(path,f) for f in os.listdir(path)]
    #os.path.join(path, f) 用于将路径 path 和文件名 f 连接起来,生成完整的文件路径。
    #os.listdir(path) 函数用于获取指定路径下的所有文件和目录的名称,并返回一个字符串列表
    #print(imagePaths)
    #人脸检测分类器
    face_detecter = cv.CascadeClassifier("D:\python23\Facetext\.venv\Lib\site-packages\cv2\data\haarcascade_frontalface_default.xml")
    #遍历列表中的图片
    for imagePath in imagePaths:#打开图片,灰度化
        PIL_img = Image.open(imagePath).convert('L') #把图像转换为数组,
        img_numpy = np.array(PIL_img,'uint8')#获取图片人脸特征
        faces = face_detecter.detectMultiScale(img_numpy)#获取每张图片的id和姓名
        id = int(os.path.split(imagePath)[1].split('.')[0])#预防无面容照片
        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:\python23\Facetext\picture\\"
    #获取图像数组和id标签数组
    faces,ids = getImageAndLabels(path) #加载识别器
    recognizer = cv.face.LBPHFaceRecognizer_create()
    #调用 cv.face.LBPHFaceRecognizer_create(),你正在初始化一个可以用于后续训练和识别人脸的模型。
    recognizer.train(faces,np.array(ids))#识别器如何根据给定的图像和标签数据来“学习”识别不同的人脸
    #保存文件
    recognizer.write('D:\\python23\\Facetext\\face_trainer\\face_trainer.xml')
3.face_detection
import cv2 as cv
import imutils
from PIL import ImageDraw, ImageFont, Image
import numpy as np
import os

def cv2AddChineseText(img, text, position, textColor=(0, 255, 0), textSize=30):
    if (isinstance(img, np.ndarray)):  # 判断是否OpenCV图片类型
        img = Image.fromarray(cv.cvtColor(img, cv.COLOR_BGR2RGB))
    # 创建一个可以在给定图像上绘图的对象
    draw = ImageDraw.Draw(img)
    # 字体的格式
    fontStyle = ImageFont.truetype("simsun.ttc", textSize, encoding="utf-8")
    # 绘制文本
    draw.text(position, text, textColor, font=fontStyle)
    # 转换回OpenCV格式
    return cv.cvtColor(np.asarray(img), cv.COLOR_RGB2BGR)

def name():
    path = "D:\\python23\\Facetext\\picture\\"
    names = []
    # 对应的标签
    idn = []
    # 准备识别的图片
    imagePaths = [os.path.join(path, f) for f in os.listdir(path)]
    for imagePath in imagePaths:
        name = str(os.path.split(imagePath)[1].split('.')[1])
        id = int(os.path.split(imagePath)[1].split('.')[0])   #预防无面容照片
        # 避免重复
        if id not in idn:
            names.append(name)
            idn.append(id)
    return names, idn

# 人脸检测
def face_detect_method(img, names, idn):
    gray_img = cv.cvtColor(img, cv.COLOR_BGRA2GRAY)
    imgsize = min(gray_img.shape)  # 灰度图长宽最小尺寸
    facemin = int(imgsize * 0.04)
    facemax = int(imgsize * 0.8)
    # 加载训练数据集文件
    recognizer = cv.face.LBPHFaceRecognizer_create()
    # 读取训练好的系统文件
    recognizer.read('D:\\python23\\Facetext\\face_trainer\\face_trainer.xml')
    face_detector = cv.CascadeClassifier(
        "D:\python23\Facetext\.venv\Lib\site-packages\cv2\data\haarcascade_frontalface_alt2.xml")
    #人脸检测级联分类器模型,采用的是基于树的分类器结构,相比于前面的模型,对于一些复杂情况下的人脸检测可能会更准确,但可能需要更长的计算时间

    face = face_detector.detectMultiScale(gray_img, 1.1, 3, 0, (facemin, facemin), (facemax, facemax))
    for x, y, w, h in face:
        cv.rectangle(img, (x, y), (x + w, y + h), color=(255, 255, 0), thickness=3)
        # 人脸识别
        ids, confidence = recognizer.predict(gray_img[y:y + h, x:x + w])
        if confidence > 70:
            img = cv2AddChineseText(img, "外来人员(" + str(int(confidence)) + ")", (x + 10, y + 10), (0, 255, 0), 30)
        else:
            img = cv2AddChineseText(img, str(names[idn.index(ids)]) + "(" + str(int(confidence)) + ")",(x + 10, y - 25), (0, 255, 0), 30)

    cv.namedWindow("ShowFace", cv.WINDOW_AUTOSIZE)  # 命名窗口
    img = imutils.resize(img, width=850)
    cv.imshow("ShowFace", img)
    return img

cap = cv.VideoCapture(0)
#cap = cv.VideoCapture(camera_id)
num = 1
# 读取姓名
names, idn = name()
while (cap.isOpened()):
    ret, frame = cap.read()
    if not ret:
        break
    img = face_detect_method(frame, names, idn)

    k = cv.waitKey(1) & 0xFF
    if k == ord('s'):
        
        cv.imwrite("E:\\Python_Program\\figs\\save\\people" + str(num) + ".face.jpg", img)
        print("Saved people" + str(num) + "'s face!!")
        num += 1
    elif k == ord(' '):
        break
#空格键退出
cap.release()
cv.destroyAllWindows()

三.效果演示

写入一个标签0,名称为“老李”,获取人脸:

训练模型:

导入第二个人脸,标签为3,名称为“ll”:

识别出两人:

多人识别也能搞定:

四.问题与解决方法

1.python和opencv版本不对应,报错

对应版本可以看这个博文:Python版本与opencv版本的对应关系_opencv-python对应版本-CSDN博客

2.使用的外接摄像头打不开

将代码部分摄像头编号从0改成2,3等就好了

4.faces = detector.detectMultiScale(img_numpy) # 人脸检测
cv2.error: OpenCV(3.4.11) C:\Users\appveyor\AppData\Local\Temp\1\pip-req-build-9ii_q38u\opencv\modules\objdetect\src\cascadedetect.cpp:1729: error: (-215:Assertion failed) !empty() in function 'cv::CascadeClassifier::detectMultiScale'

这个报错表明在进行人脸检测时,CascadeClassifier 检测器未成功加载分类器模型文件导致的问题。在使用 detectMultiScale() 函数之前,需要确保已经成功加载了人脸检测的分类器 XML 文件。其实就是路径要找对。
5.File "D:\python23\Facetext\face_training.py", line 47, in <module>
recognizer.write("D:\python23\Facetext\face_trainer\\trainer.yml")
cv2.error: OpenCV(3.4.11) C:\Users\appveyor\AppData\Local\Temp\1\pip-req-build-9ii_q38u\opencv_contrib\modules\face\src\facerec.cpp:70: error: (-2:Unspecified error) File can't be opened for writing! in function 'cv::face::FaceRecognizer::write'

这个错误提示表明 OpenCV 在尝试将人脸识别器的训练结果写入指定的文件时遇到了问题。具体原因是因为文件无法被打开进行写入操作

6.cv2.error: OpenCV(3.4.11) C:\Users\appveyor\AppData\Local\Temp\1\pip-req-build-9ii_q38u\opencv\modules\core\src\ocl.cpp:5518: error: (-220:Unknown error code -220) OpenCL error CL_INVALID_COMMAND_QUEUE (-36) during call: clEnqueueWriteBuffer(q, handle=000002BD87B27A20, CL_TRUE, offset=0, sz=186432, data=000002BD87B6D820, 0, 0, 0) in function 'cv::ocl::OpenCLAllocator::upload'

表明在使用 OpenCV 进行 OpenCL 相关操作时出现了 CL_INVALID_COMMAND_QUEUE (-36) 错误。这种错误通常是由于 OpenCL 中的命令队列无效或者已经关闭导致的。
这个时候可以禁用opencl也就是cv2.ocl.setUseOpenCL(False),
7. recognizer = cv2.face.LBPHFaceRecognizer_create()
AttributeError: module 'cv2.cv2' has no attribute 'face'

这个问题也就是说opencv里面没有cv2库,由于版本问题,很多版本的cv2已经被包含在opencv-contrib-python里面了,所以根据版本去下载opencv和opencv-contrib-python就可以解决这个问题

8.AttributeError: module 'cv2.cv2' has no attribute 'face_LBPHFaceRecognizer'

可能是由于OpenCV版本不同导致的方法名称不匹配。在新版本的OpenCV中,可能已经对LBPH人脸识别器的方法进行了更改。所以这个问题还是跟版本有关系,找到合适的版本就可以解决了。

OK了,这就是这次的全部内容了,还是一样,希望对大家有微薄的帮助,如果有什么问题,也希望大家能提出。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值