欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

****树莓派基于opencv的人脸识别和口罩检测****

程序员文章站 2022-03-20 21:57:18
...

树莓派基于opencv的人脸识别和口罩检测

学习目标:

目标:人脸识别和口罩的检测
实现的功能:
1:检测到人脸,画框,并识别已训练的人的模型,并打印出名字
2:识别是否带了口罩


学习内容:

内容:基于python的opencv和face_recognition来实现
1、 掌握opencv,face_recognition的安装
2、 掌握 训练模型
3、 掌握调用模型
4、 掌握树莓派安装opencv和contrib以及face_recognition



前言

打电赛输了,在比赛的几天后一个人做出来,也了解到了硬件的重要性

一、opencv是什么?

OpenCV是一个基于BSD许可(开源)发行的跨平台计算机视觉和机器学习软件库,可以运行在Linux、Windows、Android和Mac OS操作系统上。 [1] 它轻量级而且高效——由一系列 C 函数和少量 C++ 类构成,同时提供了Python、Ruby、MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。
OpenCV用C++语言编写,它具有C ++,Python,Java和MATLAB接口,并支持Windows,Linux,Android和Mac OS,OpenCV主要倾向于实时视觉应用,并在可用时利用MMX和SSE指令, 如今也提供对于C#、Ch、Ruby,GO的支持。

二、步骤

1.树莓派安装模块

值得一提,我就是安装不上才失败的,因为有的模块需要很大的内存,而树莓派分不出来,所以经常就是安装到99%的时候卡住,然后就是程序已杀死,我心态崩了都!!!!

安装教程链接:

1:安装opencv:

https://zhuanlan.zhihu.com/p/92184435

2:安装dlib:

https://blog.csdn.net/weixin_44086593/article/details/87467537

3:安装face_recognition:

https://blog.csdn.net/weixin_43106043/article/details/104962026

4:xml模型的下载:
链接:https://pan.baidu.com/s/1ULupRUJGRtRRPfLw-Iooyw
提取码:6zf8

祝大家成功哈哈哈哈哈

2.设计思路

有点长,希望大家不要嫌啰嗦
1;首先,在多种优秀的人脸识别的方法中,我们还是毅然决然的选择了最为有效,最为方便的python+opencv,因为其有相对应的函数库供我们使用,效果明显,代码简洁。

2;收集:一开始,因为只需要测试三个队员和其他未知者,所以先通过face_collect.py开始通过电脑内置摄像头对三个队员进行人脸采集,并输入自己的id号和顺序,便于后期的数组遍历寻找匹配对象,加载人脸分类识别器,导入人脸识别的模型找出人脸进行截取,经过测试,由***于彩色的照片会占据大量内存并且受外界干扰明显,所以使用OpenCV调用摄像头获取图像并进行基础的处理(灰度等)转为灰度图片,减少程序符合,提高识别度,特定功能库Dlib进行特征获取,然后以jpg格式保存,并每个人都存储101张在totalfaces的文件中。***

3;训练:对得到的303张jpg图片,通过python中的os文件处理,PIL以及numpy数据库的结合,再次导入人脸识别模型和输入输出格式的绝对路径的设置,通过遍历照片文件进行对其整体的一个封装,并且保存为以yml为后缀的训练型文件。我们在前一部分的同目录下创建一个Python文件,文件名为trainner.py,用于编写数据集生成脚本。同目录下,创建一个文件夹,名为trainner,用于存放我们训练后的识别器。

4;测试:由于项目需要实现口罩的检测功能,但是经过查找opencv的API文档,并没有找到针对口罩的识别模型,所以,通过思考和小组讨论,因为口罩主要是掩盖了口鼻,所以以是否检测到下半部分的嘴巴替代,如果检测到嘴巴,并框选出来,则说明并没有佩戴口罩,若没有检测到嘴,则说明有按照防控标准佩戴口罩。LBP是一种特征提取方式,能提取出图像的局部的纹理特征,最开始的LBP算子是在3X3窗口中,取中心像素的像素值为阀值,与其周围八个像素点的像素值比较,若像素点的像素值大于阀值,则此像素点被标记为1,否则标记为0。这样就能得到一个八位二进制的码,转换为十进制即LBP码,于是得到了这个窗口的LBP值,用这个值来反映这个窗口内的纹理信息。LBPH是在原始LBP上的一个改进,在opencv支持下我们可以直接调用函数直接创建一个LBPH人脸识别的模型。就此开始通过face.LBPHFaceRecognizer_create读取前一步的训练模型,定义数组,填入队员姓名,同样的,通过内置摄像头扫出人脸,并转换为灰度,并记录下人脸是识别范围,作为下一步检测嘴的区域范围,进一步缩小工作量,以达到更为准确的识别读取。为了实现检测是否有嘴巴,我们通过len()方法对画出的矩形框进行与0的比较,大于0则打印没带口罩,小于0则打印有带口罩,并通过之前识别的数据,进行格式化输出并打印在对话框中,并在程序最后设置了窗口等待以及键盘控制退出等按钮的设置,以及在左上角设置了相关的fps参数,来显示面部识别的帧数,更加直观的呈现了数据,最后关闭摄像头,并释放窗口。

代码如下:
face_collect.py
这个是收集101张人脸
**

然后注意一下,下面的yml文件,和xml文件,必须都用绝对路径来写!!!!!!

**

import cv2
#计数
count = 0
#输入id
face_id = input('\n enter user id:')
#输入姓名
username = input('\n enter user name:')
print('\n 正在初始化脸部识别,请保持在摄像头前面 .......')
# 读取内置摄像头中的图像,获取图像grabbed为true
cap = cv2.VideoCapture(0)
# 加载人脸分类识别器
face_detector = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')#改成这个文件的绝对路径!!!

while True:
    grabbed, img = cap.read()
    # 图片转灰度
    img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    faces = face_detector.detectMultiScale(img_gray,1.3, 5)
    for x, y, w, h in faces:
        cv2.rectangle(img, (x, y), (x + w, y + h), color=(0, 255, 0), thickness=1)
        count += 1
        # 保存图像
        ''
        #待处理
        ''
        filename = r"mask_faces/" + username + "." + str(face_id) + '.' + str(count) + '.jpg'
        print(filename)
        #通过绝对路径保存jpg图片
        cv2.imwrite(filename, img_gray[y: y + h, x: x + w])
    #展示
    cv2.imshow("detecting", img)
    #按q退出并保持窗口10s
    if ord('q') == cv2.waitKey(10):
        break
        #若保存了100次,则退出保存程序
    elif count > 100:
        break

#关闭摄像头
cv2.destroyAllWindows()
cap.release()

face_trainer.py

将上文收集的jpg图片训练成自己的yml文件

YAML(Yet Another Markup Language)(发音 /ˈjæməl/ ) 一种基于Unicode容易阅读,容易和脚本语言交互的,用来表达资料序列的编程语言就很神奇,收集的人脸会变成一系列数据来使用,并存放在yml文件中

import numpy as np
from PIL import Image
import os
import cv2
print("开始")
# 人脸数据路径
path = r'total_faces/'
recognizer = cv2.face.LBPHFaceRecognizer_create()
detector = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')#这边建议全部使用绝对路径,确保能够调用的到!

def getImagesAndLabels(path):
    imagePaths = [os.path.join(path, f) for f in os.listdir(path)] 
    faceSamples = []
    ids = []
    for imagePath in imagePaths:
        PIL_img = Image.open(imagePath).convert('L')   # convert it to grayscale
        img_numpy = np.array(PIL_img, 'uint8')
        id = int(os.path.split(imagePath)[-1].split(".")[1])
        faces = detector.detectMultiScale(img_numpy)
        for (x, y, w, h) in faces:
            faceSamples.append(img_numpy[y:y + h, x: x + w])
            ids.append(id)
    return faceSamples, ids


print('Training faces. It will take a few seconds. Wait ...')
faces, ids = getImagesAndLabels(path)
recognizer.train(faces, np.array(ids))
#定义训练路径
recognizer.write(r'face_trainer\trainer.yml')
print("{0} faces trained. Exiting Program".format(len(np.unique(ids))))
print('over')

face_main.py

# 从视频中识别人脸
import cv2 as cv
import time
def face_recognition():
    t_start = time.time()
    fps = 0
    recognizer = cv.face.LBPHFaceRecognizer_create()
    # 读取训练数据
    recognizer.read('G:/python_program/Basement/face_trainer/trainer.yml')  #之前训练的模型
    face_detector = cv.CascadeClassifier(cv.data.haarcascades + 'haarcascade_frontalface_default.xml')  #那个包里面下载的模型
    mouth_detector = cv.CascadeClassifier("G:/haarshare/haarcascade_mcs_mouth.xml")   #嘴巴模型
    #字体
    font = cv.FONT_HERSHEY_SIMPLEX
    feature_id=None
    # 以训练的时候,按人脸id进行排序
    names = [' ','dai jun','li zhi ming','wang fei']  #下角标是从0开始,所以起始插入一个空字符来占位

    cap = cv.VideoCapture(0)
    # minW = 0.1*cap.get(3)
    # minH = 0.1*cap.get(4)

    while True:
        grabbed, img = cap.read()
        if grabbed:
            print("frame:", img.shape)
        else:
            break
        # 图片转灰度
        img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
        faces = face_detector.detectMultiScale(img_gray)
        for x, y, w, h in faces:
            cv.rectangle(img, (x, y), (x + w, y + h), color=(0, 255, 0), thickness=1)
            # 预测
            feature_id, confidence = recognizer.predict(img_gray[y:y + h, x:x + w])
            print(feature_id-1, " ", confidence)
            # 检查嘴
            # mouth_zone = mouth_detector.detectMultiScale(head_down, 1.3, 3, minSize=(10, 10))
            # 记录下脸部位置,作为识别嘴巴的区域范围
            face_area = img[y:y + h, x:x + w]
            # # 在记录下的脸部区域识别嘴巴
            mouth = mouth_detector.detectMultiScale(face_area,scaleFactor=1.1,minNeighbors=5,minSize=(50, 50))
            print(mouth)
            # 框出嘴巴
            for (mx, my, mw, mh) in mouth:
                cv.rectangle(face_area, (mx, my), (mx + mw, my + mh), (0, 255, 0), 1)
            #判断是否有嘴巴
                #问题:如何检测矩形框的有无返回值的方法,如果返回有,则没带口罩,无,则有带
                if len(mouth) > 0:
                    print(len(mouth))
                    print("没有戴口罩")
                    cv.putText(img, 'no mask', (x-50, y + 200), 3, 1.3, (0, 255, 0), 2)
                else:
                    pass
                    #cv.putText(img, 'has mask', (x - 50, y + 200), 3, 1.3, (0, 255, 0), 2)
            else:
                if len(mouth) <= 0:
                    cv.putText(img, 'has mask', (x - 50, y + 200), 3, 1.3, (0, 255, 0), 2)


            if confidence < 100:
                features = names[feature_id]
                print(features)
                confidence = "{0}%".format(round(100 - confidence))
            else:
                features = "unknown"
                confidence = "{0}%".format(round(100 - confidence))

            cv.putText(img, str(features), (x + 5, y - 5), font, 1, (0, 255, 0), 4)
            cv.putText(img, str(confidence), (x + 5, y + h - 5), font, 1, (0, 255, 0), 4)

        # Calculate and show the FPS

        fps = fps + 1

        sfps = fps / (time.time() - t_start)

        cv.putText(img, "FPS : " + str(int(sfps)), (10, 10), cv.FONT_HERSHEY_SIMPLEX, 0.5, (255,0,0), 2)



        cv.imshow("recognizing", img)
        if ord('q') == cv.waitKey(10):
            break

    cv.destroyAllWindows()
    cap.release()


if __name__ == '__main__':
    face_recognition()

成果展示

本人上镜哈哈哈哈哈
****树莓派基于opencv的人脸识别和口罩检测****

总结

其实这些也都是抄来抄去,改来改去的,懂大概就行了,这个识别度说真的,不咋地,只能拿来骗人哈哈哈,要真拿去用就糗大了哈哈哈哈,主要就是三步走:****树莓派基于opencv的人脸识别和口罩检测****
第一次写,就这样啦,比赛是输了,也敲醒了警钟,电子信息专业不会硬件????重新做人