步骤1 项目背景
夏天已到,火辣辣的太阳晒着大地,好像要把所有的东西都熔化掉似的。机器在不停地转动着,在这样的一个季节学习变得更加的艰辛了。由太阳散发出的热量会导致人们精神疲劳,因此在夏天需要有个小伙伴在我们瞌睡提醒我们,继续努力学习。就像每天早起时,我们需要“闹钟”叫醒我们。
步骤2 设计思路
本项目,使用树莓派上的摄像头获取学习者的人脸图像,通过EAR算法,判断瞌睡状态,利用声光提醒。如果还瞌睡,将使用“喷雾”装置进行提醒。
步骤3 硬件连接
步骤4 LED测试
LED灯接在树莓派(显示屏)的27引脚上。
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BCM)
GPIO.setup(27,GPIO.OUT)
for i in range(30):
GPIO.output(27,GPIO.HIGH)
time.sleep(1)
GPIO.output(27,GPIO.LOW)
time.sleep(1)
GPIO.cleanup()
步骤5 录放模块测试
录放模块接在接在显示屏的Gravity GPIO 引脚,对应引脚D26。
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BCM)
GPIO.setup(26,GPIO.OUT)
for i in range(30):
GPIO.output(26,GPIO.HIGH)
GPIO.output(26,GPIO.LOW)
time.sleep(5)
GPIO.cleanup()
步骤6 喷雾装置测试
喷雾装置中的舵机接在21引脚上,因使用的是DSS-M15舵机,因电流较大,单独供电。(大型号的舵机电流过大对控制板安全不利。)
GPIO的控制电压是 3.3 V。
树莓派1代B型的26个针脚里,有一个特殊的GPIO口是支持硬件PWM的,不过从B+开始不知道什么原因这个很实用的接口被去掉了。
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BCM)
GPIO.setup(21, GPIO.OUT)
# 初始化PWM的频率,frequency=50Hz
pwm = GPIO.PWM(21, 50)
pwm.start(2.5)
try:
for i in range(5):
# 修改pwm占空比
pwm.ChangeDutyCycle(3.0)
time.sleep(0.5)
pwm.ChangeDutyCycle(10)
time.sleep(3)
except KeyboardInterrupt:#试图强制中断时,程序不会马上停止而是会先跳到这里来做一些你想做完的事情,比如清理GPIO口。
pass
# 关闭pwm
pwm.stop()
GPIO.cleanup()
步骤7 程序环境搭建
(1)Python3.7安装与环境搭建 Python官网
(2)Opencv4.1 安装与环境搭建 Opencv官网
(3)安装pip 21.1.1(它是Python包管理工具,提供了Python包的查找、下载、安装、卸载的功能,有利于之后的环境搭建。)
(以下操作都可以用pip进行安装)
Win+R窗口输入“cmd”,然后输入对应的库安装,
(4)安装opencv-python 4.2.0.34 计算机视觉库。
在cmd里输入在线安装“pip3 install opencv-python”
(5)安装Numpy 1.18.5 开源的数值计算扩展,功能是科学计算,数据分析与处理。
“pip3 install Numpy”
(6)安装Scipy 1.7.0 距离计算库。
“pip3 install Scipy”
步骤8 人眼疲倦检测开源算法
EAR(eye aspect ratio)计算函数
我们首先需要确定眼睛的位置,在确定眼睛位置之后,选择6个点来表示眼睛,具体如下图所示:
标号的顺序是从眼睛的左角开始,然后顺时针绕着眼睛进行编号。
根据这六个点我们便可以表示眼睛的睁开和闭上的状态。当开启的时候,上图中竖着的黄色箭头会变得比较高,而眼睛闭上(疲劳状态)这个箭头就会变矮。但是由于观看的距离不同,单纯用高度来表示状态缺少参考比较,因此提出如下公式表示状态:
用这个数据便可以相对客观的表示眼睛的状态,于是通过大量测试发现一个统计结果,当EAR小于0.25很多的时候,便是疲劳状态。
步骤9 face_recognition人脸识别库
1、安装
face_recognition使用世界上最简单的人脸识别库,在Python或命令行中识别和操作人脸。 使用dlib最先进的人脸识别技术构建而成,并具有深度学习功能。
pip3 install face_recognition
2、识别人脸关键点
加载图像后,调用face_recognition.face_landmarks(image)可识别出人脸关键点信息,包括眼睛、鼻子、嘴巴和下巴等,参数仍是加载的图像image,返回值是包含面部特征字典的列表,列表中每一项对应一张人脸,包括nose_bridge、right_eyebrow、right_eye、chine、left_eyebrow、bottom_lip、nose_tip、top_lip、left_eye几个部分,每个部分包含若干个特征点(x,y),总共有68个特征点。列表长度就是图中识别出的人脸数,可遍历此列表和字典的键值对,打印出所有面部特征点,也可在图像上画出来,代码如下:
import numpy as np
import cv2
import face_recognition
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
print(ret)
frame = cv2.resize(frame, (0,0), fx=0.2, fy=0.2)
# Find all facial features in all the faces in the video
face_landmarks_list = face_recognition.face_landmarks(frame)
for face_landmarks in face_landmarks_list:
# Loop over each facial feature (eye, nose, mouth, lips, etc)
for name, list_of_points in face_landmarks.items():
#if name=="left_eye":
hull = np.array(face_landmarks[name])
hull_landmark = cv2.convexHull(hull)
cv2.drawContours(frame, hull_landmark, -1, (0, 255, 0), 3)
frame = cv2.resize(frame, (0,0), fx=2, fy=2)
cv2.imshow("Frame", frame)
ch = cv2.waitKey(1)
if ch & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
步骤10 眼睛纵横比(EAR)函数
# 这个方程的分子是计算垂直眼睛标志之间的距离,而分母是计算水平眼睛标志之间的距离,由于水平点只有一组,而两组垂直点,所以分母乘上了2,以保证两组特征点的权重相同。使用这个简单的方程,我们可以避免使用图像处理技术,简单地依靠眼睛地标距离的比例来确定一个人是否眨眼。
def eye_aspect_ratio(eye):
# 计算距离,竖直的
A = dist.euclidean(eye[1], eye[2])
B = dist.euclidean(eye[4], eye[5])
# 计算距离,水平的
C = dist.euclidean(eye[0], eye[3])
# ear值
ear = (A + B) / (2.0 * C)
return ear
步骤11 判断瞌睡代码
import numpy as np
import cv2
import face_recognition
from scipy.spatial import distance as dist
cap = cv2.VideoCapture(0)
# 眼睛纵横比(EAR)
# 这个方程的分子是计算垂直眼睛标志之间的距离,而分母是计算水平眼睛标志之间的距离,由于水平点只有一组,而两组垂直点,所以分母乘上了2,以保证两组特征点的权重相同。使用这个简单的方程,我们可以避免使用图像处理技术,简单地依靠眼睛地标距离的比例来确定一个人是否眨眼。
def eye_aspect_ratio(eye):
#计算距离,竖直的
A=dist.euclidean(eye[1],eye[5])
B=dist.euclidean(eye[2],eye[4])
#计算距离,水平的
C=dist.euclidean(eye[0],eye[3])
#ear值
ear=(A+B)/(2.0*C)
return ear
close_eye=0 # 闭眼计数
ClOSE_EYE=25 # 闭眼次数阈值
EYE_EAR = 0.25 # EAR阈值
while True:
ret, frame = cap.read()
frame = cv2.resize(frame, (0,0), fx=0.2, fy=0.2)
# Find all facial features in all the faces in the video
face_landmarks_list = face_recognition.face_landmarks(frame)
left_eye_points=[]
right_eye_points=[]
for face_landmarks in face_landmarks_list:
# Loop over each facial feature (eye, nose, mouth, lips, etc)
for name, list_of_points in face_landmarks.items():
if name=='left_eye':
left_eye_points=list_of_points
hull = np.array(face_landmarks[name])
hull_landmark = cv2.convexHull(hull)
cv2.drawContours(frame, hull_landmark, -1, (0, 255, 0), 3)
if name=='right_eye':
right_eye_points=list_of_points
hull = np.array(face_landmarks[name])
hull_landmark = cv2.convexHull(hull)
cv2.drawContours(frame, hull_landmark, -1, (0, 255, 0), 3)
if len(right_eye_points)!=0 and len(left_eye_points)!=0:
# 分别计算两眼ear值
leftEAR = eye_aspect_ratio(left_eye_points)
rightEAR = eye_aspect_ratio(right_eye_points)
# 算一个平均的ear值
ear = (leftEAR + rightEAR) / 2.0
# 当“ear”小于阈值时,为闭眼一次
if ear<EYE_EAR:
close_eye=close_eye+1
else:
close_eye=0
if close_eye>ClOSE_EYE:
cv2.putText(frame,"Sleep!",(20,200),cv2.FONT_HERSHEY_SIMPLEX,2,(0,0,255),3)
cv2.putText(frame,"close_eye:"+str(close_eye),(30,30),cv2.FONT_HERSHEY_SIMPLEX,1,(0,0,255),1)
print(ear)
frame = cv2.resize(frame, (0,0), fx=2, fy=2)
cv2.imshow("Frame", frame)
ch = cv2.waitKey(1)
if ch & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
步骤12 组装设备
hacker_2023.05.10
666