树莓派 --- 人脸口罩识别智能监控

目录

初步效果设想

像SIRI那样的语音唤醒,开启服务
只有当摄像头检测到人脸时,舵机才开始调整位置,让人脸保持C位
检测人脸是否戴口罩了,没带就发出“提示”,戴了就不管
长时间不戴例如8s,就拍一张照,并发到我的qq邮箱

应用场景:疫情期间,超市、食堂、餐厅用该装置,相比让工作人员去提醒,可以省去大量人力、财力

分五大模块开发:语音唤醒、控制舵机、人脸追踪定位、人脸口罩识别、发送人脸图片至qq邮箱

1.语音唤醒模块

2.控制舵机模块

用两个舵机做一个二自由度云台, 云台外壳可从淘宝买

参考博客

①servoControl.py封装了controlTwoServos(pin1, angle1, pin2, angle2)方法,用来控制舵机
pin1、pin2分别指的是舵机1、舵机2的信号线所接引脚(BCM编码方式)
angle1、angle2分别指舵机1、舵机2要旋转的角度

舵机1控制水平旋转方向, 舵机2控制垂直旋转方向

servoControl.py 

import RPi.GPIO as GPIO
from time import sleep

GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)

# 旋转角度转换到PWM占空比
def angleToDutyCycle(angle):
    return 2.5 + angle / 180.0 * 10

# 控制两个舵机的函数
# pin1、pin2分别指的是舵机1、舵机2的信号线所接引脚
# angle1、angle2分别指舵机1、舵机2要旋转的角度
def controlTwoServos(pin1, angle1, pin2, angle2):
    GPIO.setup(pin1, GPIO.OUT, initial=False)
    GPIO.setup(pin2, GPIO.OUT, initial=False)

    p1 = GPIO.PWM(pin1, 50)             # 舵机1初始频率为50HZ
    p1.start(angleToDutyCycle(90))      # 舵机1初始化角度为90
    sleep(0.5)
    p1.ChangeDutyCycle(angleToDutyCycle(angle1))          
    
    p2 = GPIO.PWM(pin2, 50)             # 舵机2初始频率为50HZ
    p2.start(angleToDutyCycle(90))      # 舵机2初始化角度为90
    p2.ChangeDutyCycle(angleToDutyCycle(angle2))
    sleep(0.5)

 ②测试

 main.py (main.py、servoControl.py在同一目录)

from servoControl import controlTwoServos

if __name__ == '__main__':
    controlTwoServos(23, 80, 24, 80)

测试运行 python3  main.py 

3.人脸追踪定位模块 

 参考博客

拍摄的照片640x480

算法如下(参考我上面画的图)

① 我这里规定摄像头拍摄的照片分辨率 640 x 480,所以照片中心坐标(320, 240)
② 利用face_recognition库中的face_locations()函数,算出人脸框的中心坐标

face_locations()会返回一个list,有几个人脸,list就有几个tuple,tuple=(top,right,bottom,left)
top指人脸框上边框到x轴的距离,right指人脸框右边框到y轴的距离
bottom指人脸框下边框到x轴的距离,left指人脸框左边框边到y轴的距离
人脸框的中心坐标((left+right)/2, (top+bottom)/2)

③ 根据照片中心坐标和人脸框的中心坐标很容易算出△x,△y
后面算法参考博客 博客地址

faceTracking.py 

# coding = utf-8
import face_recognition as fr
import cv2
from time import sleep
from servoControl import controlTwoServos

while True:
    video_capture = cv2.VideoCapture(0)  # 创建视频对象,打开摄像头
    print('Capturing image...')
    # 摄像头抓取一帧照片
    # ret是布尔值,读取帧成功返回True,文件读到结尾,返回False(如果你读取的是视频,而不是在线拍摄)
    # frame就是每一帧的图像,一个三维矩阵
    # 默认拍摄的画面分辨率是640x480,想改可以去翻opencv官方文档
    ret, frame = video_capture.read()
    video_capture.release()
    # 缩小图片,加快处理速度,fx,fy表示x,y轴方向的缩小系数
    frame = cv2.resize(frame, (0,0), fx=0.5, fy=0.5)    
    rgb_frame = frame[:, :, ::-1]                   # 将cv2用的BGR颜色转换为face_recognition用的RGB颜色
    face_locations = fr.face_locations(rgb_frame)   # 获取这一帧里所有脸的位置
    # 如果画面中有人脸,任选一张人脸,记录下它的位置
    if len(face_locations) > 0:
        face_location = face_locations[0]
        top = face_location[0]
        right = face_location[1]
        bottom = face_location[2]
        left = face_location[3]
        center_x = (top + bottom) / 2
        center_y = (left + right) / 2
        print('捕捉到人脸!')
    else:
        center_x, center_y = 160, 120
    dx = (center_x - 160) * 0.3
    dy = (center_y - 120) * 0.3
    print(dx)
    print(dy)
    # 设置一个阈值,当角度大于3时,才移动
    if abs(dx) >= 3 or abs(dy) >= 3:
        x0 = 90 + dx
        if x0 > 180:  # 设置界限,超出范围不再转动,下同
            x0 = 180
        elif x0 < 0:
            x0 = 0
        y0 = 90 + dy
        if y0 > 180:
            y0 = 180
        elif y0 < 0:
            y0 = 0
        controlTwoServos(23, x0, 24, y0)

4.人脸口罩识别模块 

鉴于树莓派没有Nivida显卡,树莓派4的显卡是VideoCore VI GPU树莓派3的显卡我也不清楚,所以很多项目跑不了,调百度的API好像还要花钱o(╥﹏╥)o

我找了一个只需要opencv的项目,但是效果一般
【武汉加油!中国加油!】挑战七天 实现机器视觉检测有没有戴口罩系统——第四五六七天_云敬山-CSDN博客

我又找了一个基于opencv的,感觉可以
博客地址

项目地址

环境配置:安装opencv、numpy和pygame

pip3 install opencv-python
pip3 install numpy==1.21.4         # 安装numpy,我这里指定了版本
pip3 install pygame

我这里安装的opencv版本是4.5.4,默认有dnn模块,opencv如果版本低了好像还要安装扩展,反正保证要有dnn模块

在windows上跑没问题,在树莓派上跑有点问题,我改了一下 

原文
修改之后

后来我还做了一点改动,察觉没有戴口罩就播放提示语音,还有,视频窗口就不展示了,树莓派配置差点

5.图片发送模块

①先基于下文进行配置  

 树莓派 --- 开机自动发送IP到自己的QQ邮箱

②send_pic.py封装一个send_mail(file_path)方法,只要传入图片路径file_path,就能实现图片发送到我的qq邮箱

send_pic.py

# coding=utf-8
import smtplib
from email.mime.text import MIMEText
from email.utils import formataddr
from email.mime.multipart import MIMEMultipart  # 创建附件类型

# 设置发件人和收件人信息
my_sender='xxxxxxxxxxxxxxxxx'  # 发件人邮箱账号
my_pass = 'xxxxxxxxxxxxxxxxx'   # 发件人邮箱密码(之前获取的授权码)
my_user='xxxxxxxxxxxxxxxxx'    # 收件人邮箱账号
msg = MIMEMultipart('related')  # 邮件信息为空,相当于信封,related表示使用内嵌资源的形式,将邮件发送给对方

def send_mail(file_path):
    ret=True
    try:
        # 发送信息内容
        msg_html = MIMEText('自拍照', 'html', 'utf-8')
        msg.attach(msg_html)
        # 发送图片,以附件形式
        msg_image = MIMEText(open(file_path, 'rb').read(), 'base64', 'utf-8')
        msg_image['Content-disposition'] = "attachment;filename='me.jpg'" # 设置图片在附件中的名字
        msg.attach(msg_image)
        
        msg['From']=formataddr(["Jack",my_sender])          # 括号里的对应发件人邮箱昵称、发件人邮箱账号
        msg['To']=formataddr(["Rose",my_user])              # 括号里的对应收件人邮箱昵称、收件人邮箱账号
        msg['Subject']="我的自拍照"                         # 邮件的主题,也可以说是标题
        server=smtplib.SMTP("smtp.qq.com", 587)             # 发件人邮箱中的SMTP服务器,端口是587
        server.login(my_sender, my_pass)                    # 括号中对应的是发件人邮箱账号、邮箱密码
        server.sendmail(my_sender,[my_user,],msg.as_string())  # 括号中对应的是发件人邮箱账号、收件人邮箱账号、发送邮件
        server.quit()  # 关闭连接
    except Exception:
        ret=False
    return ret

③测试上面封装的send_mail(file_path)函数

main.py (main.py、send_pic.py、test.jpg在同一目录)

from send_pic import send_mail

if __name__ == '__main__':
    if send_mail('test.jpg'):
        print('发送邮件成功!')
    else:
        print('发送邮件失败!')

6.模块整合

7.深入思考

①如果很多人不戴口罩,用qq邮件一张张发送人脸照片太麻烦了,还不如存到一个固定文件夹中

②如果一个人在监控范围内因为长时间不戴口罩(尽管有语音提示)而被记录下人脸,他走出监控范围才戴了口罩,第二次进入监控范围,如何消除上次记下的人脸记录?
其实我想了想,长时间不戴口罩就已经算是危险分子了,就不消除记录了吧,哈哈

③在超市、餐厅这样的地方,需要放多个这样的装置才能覆盖更大的范围

④人脸追踪云台监控相比传统固定监控,优势在于扩大了监控的范围

⑤舵机不能360度控制也是一个缺陷

  • 6
    点赞
  • 63
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

漂流の少年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值