用树莓派实现人脸识别打卡门禁系统

2023-05-16

用树莓派实现人脸识别打卡门禁系统的构建

    • 背景
    • 功能
    • 硬件
    • 效果
    • 源码
      • 摄像头测试代码
      • 录入信息
      • 人脸识别
    • 结论

背景

源于实习公司的人脸识别打卡系统,完成之前的项目后正好没有事情干,于是想到了这个,公司的这个打卡系统操作流程是这样的,首先用手机把你的人脸录进去,要求绕头半圈,也就是右脸,正脸,左脸,然后你再去摄像头那里,识别到你后就会帮你把门打开,顺便帮你在钉钉上打卡。

功能

我做的是简易版,实现了这个打卡系统的主要功能,能完成:信息录入,正脸识别,开门关门,名字与时间的保存。

硬件

树莓派一个,摄像头一个,显示屏一个

效果

并没有打马赛克,文件大小还被限制了,大家将就着看,
这是在电脑上的效果:
在这里插入图片描述
在树莓派上效果:
在这里插入图片描述
打卡记录:
在这里插入图片描述
看起来效果还是不错的

源码

源码使用的电脑上的源码,其实是差不多的,路径不一样而已
如果树莓派打不开摄像头,参考这个:
https://www.jianshu.com/p/5653b2b7248c
代码注释很全,不详细解释

摄像头测试代码

import cv2

capCamera = cv2.VideoCapture(0)
if(not capCamera.isOpened()):
    print("can't open this camera")
    exit(0)

capCamera.set(cv2.CAP_PROP_FRAME_WIDTH, 320)
capCamera.set(cv2.CAP_PROP_FRAME_HEIGHT, 240)

while(True):
    # handle for the camera
    ret, frame = capCamera.read()
    if ret == True:
        cv2.imshow('camera',frame)
    else:
        break

    # handle for the video

    # handle for exit
    if (cv2.waitKey(1)) == ord('q'):
        break

capCamera.release()
cv2.destroyAllWindows()

录入信息

import cv2
import os

#config
add_name = 'xiaoming'#要录入的人名


target_dir = './pic_dir/{}/'.format(add_name)
if os.path.exists(target_dir) is False:
    os.makedirs(target_dir)

def generate():
    face_cascade = cv2.CascadeClassifier('.\cascades\haarcascade_frontalface_default.xml')
    #打开摄像头
    camera = cv2.VideoCapture(0)
    forword_count = 0
    #正脸采集,一共20张图片
    while (forword_count <= 20):
        ret, frame = camera.read()
        #转化为灰度图像,用来检测人脸
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

        faces = face_cascade.detectMultiScale(gray, 1.3, 5)

        for (x, y, w, h) in faces:
            #画出预测框
            cv2.rectangle(frame, (x, y), (x + w, y + h), (255, 0, 0), 2)

            f = cv2.resize(gray[y:y + h, x:x + w], (200, 200))
            #保存录入的图片
            cv2.imwrite('./pic_dir/{0}/{1}.png'.format(add_name, forword_count), f)
            print(forword_count)
            forword_count += 1
        #展示图片
        cv2.imshow("camera", frame)
        #一秒钟24帧
        if cv2.waitKey(1000 // 24) & 0xff == ord("q"):
            break

    camera.release()
    cv2.destroyAllWindows()


if __name__ == "__main__":
    generate()

人脸识别

import os
import sys
import cv2
import numpy as np
import time

def change_door(open_later_time,isOpen,new_face_position):
    if len(new_face_position) > 0 and isOpen == False:
        print('打开')
        isOpen = True
    if len(new_face_position) == 0 and isOpen == True:
        open_later_time += 1
    else:
        open_later_time = 0
    if open_later_time == 100:
        open_later_time = 0
        print('关闭')
        isOpen = False
    return open_later_time,isOpen,new_face_position

def read_images(path, sz=None):#给一个地址,返回训练集
    c = 0
    X, Y = [], []
    names = []
    for dirname, dirnames, filenames in os.walk(path):#目录,子目录,子文件(只限一层目录)
        for subdirname in dirnames:
            names.append(subdirname)
            subject_path = os.path.join(dirname, subdirname)
            for filename in os.listdir(subject_path):#遍历每个名字
                try:
                    if (filename == ".directory"):
                        continue
                    filepath = os.path.join(subject_path, filename)
                    im = cv2.imread(filepath, cv2.IMREAD_GRAYSCALE)
                    if (im is None):
                        print("image " + filepath + " is none")
                    else:
                        print(filepath)
                    if (sz is not None):
                        im = cv2.resize(im, (200, 200))

                    X.append(np.asarray(im, dtype=np.uint8))
                    Y.append(c)
                except IOError:
                    print("I/O error({0}): {1}".format(IOError.errno, IOError.strerror))

                except:
                    print("Unexpected error:", sys.exc_info()[0])

                    raise
            print(c)
            c = c + 1

    print(Y)
    print(names)

    return [X, Y], names


def face_rec():
    image_dir = './pic_dir_1'
    isOpen = False
    open_later_time = 0

    [X, Y] , names = read_images(image_dir)
    Y = np.asarray(Y, dtype=np.int32)

    model = cv2.face.LBPHFaceRecognizer_create()

    model.train(np.asarray(X), np.asarray(Y))
    camera = cv2.VideoCapture(0)
    camera.set(cv2.CAP_PROP_FRAME_WIDTH, 400)
    camera.set(cv2.CAP_PROP_FRAME_HEIGHT, 350)
    face_cascade = cv2.CascadeClassifier('./cascades/haarcascade_frontalface_default.xml')
    re_count = 0
    old_face_position = {}#用来绘制预测框
    new_face_position = {}#用来收集新数据
    while (True):
        #print(old_face_position)
        #print(new_face_position)
        re_count += 1
        read, img = camera.read()
        faces = face_cascade.detectMultiScale(img, scaleFactor =1.3, minNeighbors=5)
        #print('{}的类型{}'.format(faces, type(faces)))
        for (x, y, w, h) in faces:
            gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
            roi = gray[x:x + w, y:y + h]
            try:
                roi = cv2.resize(roi, (200, 200), interpolation=cv2.INTER_LINEAR)
                #print(roi.shape)
                params = model.predict(roi)
                #print("Label: %s, Confidence: %.2f" % (params[0], params[1]))
                new_face_position[names[params[0]]] = (x, y, w, h)
            except:
                continue

        #优化用户体验
        #采集三帧的人脸识别信息,将预测框画出,预测框三帧一刷新,防止预测框频繁抖动的现象
        if re_count == 3:
            re_count = 0
            #print(new_face_position)
            if len(new_face_position) > 0:
                for key in new_face_position.keys():
                    (x, y, w, h) = new_face_position[key]
                    if old_face_position.__contains__(key) is False:
                        img = cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)
                        cv2.putText(img, key, (x, y - 20), cv2.FONT_HERSHEY_SIMPLEX, 1, 255, 2)
                        old_face_position[key] = (x, y, w, h)
                    else:
                        (o_x, o_y, o_w, o_h) = new_face_position[key]
                        if abs((o_x-x)) <= 5 and abs((o_y-y)) <= 5:
                            img = cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)
                            cv2.putText(img, key, (x, y - 20), cv2.FONT_HERSHEY_SIMPLEX, 1, 255, 2)
                            old_face_position[key] = (x, y, w, h)
            else:
                old_face_position = {}
            new_face_position = {}
        else:
            for key in old_face_position.keys():
                (o_x, o_y, o_w, o_h) = old_face_position[key]
                img = cv2.rectangle(img, (o_x, o_y), (o_x + o_w, o_y + o_h), (255, 0, 0), 2)
                cv2.putText(img, key, (o_x, o_y - 20), cv2.FONT_HERSHEY_SIMPLEX, 1, 255, 2)

        #开关门模拟和保存打卡信息
        #如果检测到人,并且门没有开,则打开门,并且录入信息
        if len(new_face_position) > 0 and isOpen == False:
            print('开门')
            #保存打卡信息
            t = time.strftime('%Y.%m.%d %H:%M:%S', time.localtime(time.time()))
            with open('jilu.txt', 'a') as file:
                file.writelines('{},{}\n'.format(new_face_position.keys(),t))
            isOpen = True
        #如果没有检测到人,并且门开了,计数器+1,否则计数器为0
        if len(new_face_position) == 0 and isOpen == True:
            open_later_time += 1
        else:
            open_later_time = 0
        #当计数器为100的时候关门
        if open_later_time == 100:
            print('关门')
            isOpen = False
            open_later_time = 0

        cv2.imshow("camera", img)
        #树莓派最好将帧数设为最大,不然看起来不舒服
        if cv2.waitKey(1000 // 25) & 0xff == ord("q"):
        #if cv2.waitKey(1000 // 25) & 0xff == ord("q"):
            break
    cv2.destroyAllWindows()


if __name__ == "__main__":
    face_rec()

结论

在电脑上运行的很流畅,在树莓派上运行的话因树莓派而异,能明显感觉到帧数下降,不过基本功能还是能完成的

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

用树莓派实现人脸识别打卡门禁系统 的相关文章

随机推荐

  • leetcode42--接雨水(JS)

    给定 n 个非负整数表示每个宽度为 1 的柱子的高度图 xff0c 计算按此排列的柱子 xff0c 下雨之后能接多少雨水 上面是由数组 0 1 0 2 1 0 1 3 2 1 2 1 表示的高度图 xff0c 在这种情况下 xff0c 可以
  • 自定义组件继承的组件基类React.Component是什么

    我们平时写React组件时都要继承一个父类 xff0c 那就是React Component 也会用到props state和setState xff0c 我们只是会使用它 xff0c 然而不知道它们怎么来的 xff0c 既要知其然也要知其
  • Java 在二维坐标系绘制矩形、圆形、多边形

    最近遇到一个需求 xff0c 大概要求是 xff1a 根据前端传递的参数 xff0c 在Java侧绘制虚拟的二维封闭图形 xff0c 判断各个图形间是否有交集 在java awt包下有个名为Shape的接口 xff0c 可以实现在二维坐标系
  • Uncaught (in promise) TypeError: Cannot read property 'data' of undefined

    最近在学习Redux的时 xff0c 自己写了个Demo xff0c 用fetch异步调用接口时返回这个脑壳疼的问题 问题 xff1a 问题排查 xff1a 一步一步在控制台打印 xff0c 并检测类型 xff0c 发现控制台打印undef
  • Ajax、fetch、axios的区别与优缺点

    背景 前端的技术发展速度非常的快 xff0c 异步请求也是其重要的体现之一 xff0c 从最早的原生XHR xff0c 再到JqueryAjax的统治时代 xff0c 再到近来 xff0c fetch axios等技术也开始出现并大量投入使
  • 什么是 Promise.allSettled() !新手老手都要会?

    什么是 Promise allSettled xff01 新手老手都要会 xff1f Promise allSettled 方法返回一个在所有给定的 promise 都已经 fulfilled 或 rejected 后的 promise x
  • 一份稳进Shopee的简历长啥样?

    小伙伴们好 xff0c 我是Eason 简历是求职流程的第一步 xff0c 是很关键的一环 Eason在做Shopee招聘工作时 xff0c 收到了投递的1000 43 的简历 xff0c 简历也修改过50多次 xff0c 最近也帮10多个
  • Vue项目中较优雅地封装Echarts

    场景 1 Echarts 1 使用时 xff0c 都需要写一堆的 option xff0c 如果每个图表都要写一个 xff0c 一个文件里面的代码量是很大的 2 不方便复用 需求 1 方便复用 2 展示类的图表 xff0c 数据与业务 样式
  • React系列--JSX到底是什么东西

    JSX 简介 JSX的全称是 Javascript and XML xff0c React发明了JSX xff0c 它是一种可以在JS中编写XML的语言 JSX更像一种模板 xff0c 类似于Vue中的 template 为什么使用JSX
  • https请求+basic认证

    目录 1 工具类 SSLClient 2 工具类HttpsClientUtil 3 使用 1 工具类 SSLClient 此类可绕过https证书 import org apache http conn ClientConnectionMa
  • 自旋锁的原理及使用

    什么是自旋锁 是指当一个线程在获取锁的时候 xff0c 如果锁已经被其它线程获取 xff0c 那么该线程将循环等待 xff0c 然后不断的判断锁是否能够被成功获取 xff0c 直到获取到锁才会退出循环 获取锁的线程一直处于活跃状态 xff0
  • 实验11 多线程

    1 设有一个银行账户 xff0c 里面有2000元钱 该账户归tom和jack两个人共同所有 每个人每 次可以取100元钱 编写一个类BankAccount表示银行账户 xff0c void withdraw int count 方法表 示
  • stm32 esp8266 ota升级-自建mqtt和文件服务器全量升级

    stm32 esp8266 ota系列文章 xff1a stm32 esp8266 ota 快速搭建web服务器之docker安装openresty stm32 esp8266 ota升级 tcp模拟http stm32 esp8266 o
  • rk1126开发板开发记录—SDK环境准备和系统烧录

    序言 最近在弄rk系列的开发板 xff0c 手上正好有一台rk1126的板子 xff0c 因为之前很少接触到嵌入式的东西 xff0c 所以在模型部署的同时遇到了很多坑 xff0c 在此期间也有很多收获 xff0c 习惯性的用文章记录一下开发
  • linux 应用层串口调试函数

    tcgetattr函数与tcsetattr函数 xff08 获取终端信息 xff09 波特率的设置通常使用cfsetospeed和cfsetispeed函数来完成
  • 安装MySQl 8.0遇到的问题及解决方法

    一 官网下载最新版本mysql xff0c 安装完成后 xff0c 安装SQLyog 二 在 C Program Files MySQL MySQL Server 8 0目录中查找是否存在 my ini文件 xff0c 如不存在 xff0c
  • Cmakelists.txt添加.h和.cpp文件

    文件目录结构是这样 代码都是最基本的代码 仅仅是个小的demo cmakelists txt里面的内容 span class token comment cmake的版本要求 span cmake minimum required span
  • 【tcpdump命令使用总结】

    1 tcpdump说明 linux系统的tcpdump命令用来分析数据包分析工具 xff0c 相似的工具有wireshark等 xff0c wireshark使用见 wireshark报文解析ping baidu com 执行tcpdump
  • 使用graphviz+pycallgraph绘制python调用关系图

    绘制python代码调用关系图 前言1 工具安装1 1 安装graphviz1 2 安装pycallgraph2 可视化调用关系 参考文献 前言 一个 python project 中往往包含很多 py 文件 python文件中又会包含很多
  • 用树莓派实现人脸识别打卡门禁系统

    用树莓派实现人脸识别打卡门禁系统的构建 背景功能硬件效果源码摄像头测试代码录入信息人脸识别 结论 背景 源于实习公司的人脸识别打卡系统 xff0c 完成之前的项目后正好没有事情干 xff0c 于是想到了这个 xff0c 公司的这个打卡系统操