import dlib
import joblib
import numpy as np
import copy
import pandas as pd
import pygame
from imutils import face_utils
from scipy.spatial import distance
from tkinter import *
from PIL import Image, ImageTk
import tkinter.ttk
import numpy
from PIL import Image, ImageDraw, ImageFont
import cv2
from collections import OrderedDict
from tkinter import filedialog
import time
global canva_r, canva_l, FPS, root,switch,txt
upload_flag=0
eyes_blink = 0.2
eyes_ratio = 30
count = 0
eye_close = False
yawn = False
yawn_flag = 0
t=0
thresh_mouth = 0.65
num =1
switch=1
txt=‘’
(mStart, mEnd) = face_utils.FACIAL_LANDMARKS_68_IDXS[“mouth”] # 48~67
pygame.mixer.init() # 语音模块初始化
SHAPE_68_INDEX = OrderedDict([
(“left_eye”, (42, 48)),
(“right_eye”, (36, 42))
])
(lstart,lend) = SHAPE_68_INDEX[‘left_eye’]
(rstart,rend) = SHAPE_68_INDEX[‘right_eye’]
def main_detect(cap):
print(“开始进行疲劳检测!!!”)
while switch == 1:
start = cv2.getTickCount()
#result_show.grid_forget()
# result_show.grid_forget()#grid_forget()方法只是将控件隐藏
canva_r.delete("all")#清屏
global t, eye_close,count,yawn,yawn_flag
ret, frame = cap.read() # 读取摄像头 大小:(480x640)
if ret is False:
canva_r.create_text(200, 200, text="视频播放完成", font=("Lucida Console", 15), fill="red")
print("视频播放完毕")
break
frame = frame[0:1080, 0:1440]#裁剪画幅
#原始图像(0,0)-(1080,1440)
#缩放大小
frame = cv2.resize(frame, (int(frame.shape[1] / 2.25), int(frame.shape[0] / 2.25)))
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # 转化为灰度图
# 利用模型文件对脸型上的68个点进行定位寻找
faces = detection(gray,0)
for face in faces:
shape = predictor(gray, face)
shape = face_utils.shape_to_np(shape)
# 左右眼坐标
leftEye = shape[lstart:lend]
rightEye = shape[rstart:rend]
# 调用参数计算上眼皮和下眼皮的距离
leftEyeDistance = calculate_EAR(leftEye)
rightEyeDistance = calculate_EAR(rightEye)
# 计算均值
ER = (leftEyeDistance+rightEyeDistance) / 2
# 利用cv2.convexhull 寻找图像凸包(凸包就是:打比方一个五角星,每一个尖点相连)
leftEyeHull = cv2.convexHull(leftEye)
rightEyeHull = cv2.convexHull(rightEye)
# 将眼睛画线
cv2.drawContours(frame, [leftEyeHull], -1, (0, 255, 0), 1)
cv2.drawContours(frame, [rightEyeHull], -1, (0, 255, 0), 1)
#
#
# 计算嘴巴宽高比
mouth = shape[mStart:mEnd]
mouthRatio = mouth_aspect_ratio(mouth)
#画出嘴巴
mymouth = cv2.convexHull(mouth)
cv2.drawContours(frame, [mymouth], -1, (0, 255, 0), 1)
# 判断是否打哈欠
if mouthRatio > thresh_mouth:
yawn = True
yawn_flag = 0
if yawn == True and yawn_flag < 40:
canva_r.create_text(200, 200, text="检测到您打了一个哈欠,\n请注意不要疲劳驾驶!", font=("Lucida Console", 15), fill="red")
if yawn == True and t == 0:
t = 1
pygame.mixer.music.stop()
pygame.mixer.music.load('sound\\yawn.mp3')
pygame.mixer.music.play()
yawn_flag = yawn_flag + 1
elif yawn == True and yawn_flag == 40:
yawn = False
yawn_flag = 0
t = 0
# 判断是否闭上眼睛
if (ER < eyes_blink):
count +=1
if count >= eyes_ratio:
eye_close = True
eye_flag = 0
else:
count = 0
if eye_close == True and eye_flag < 40:
# WARNING
canva_r.create_text(200, 200, text="警告!!!\n检测到您的眼睛已经闭合,\n请注意不要疲劳驾驶!", justify=LEFT,
font=("Lucida Console", 15), fill="red")
if eye_close == True and t == 0:
t = 1
pygame.mixer.music.stop()
pygame.mixer.music.load('sound\\eyes.mp3')
pygame.mixer.music.play()
eye_flag = eye_flag + 1
elif eye_close == True and eye_flag == 40:
eye_close = False
eye_flag = 0
t = 0
end = cv2.getTickCount()
during1 = (end - start) / cv2.getTickFrequency()
# 计算代码运行的时间消耗,其中最后一个参数是时钟周期
FPS.set("FPS:" + str(round(1 / during1, 2)))
Showimage(frame, canva_l, "fit")
root.update()
def load_dlib():
global detection,predictor
# 加载dlib人脸分类器
detection = dlib.get_frontal_face_detector()
# 读取68点模型文件
predictor = dlib.shape_predictor(‘./shape_predictor_68_face_landmarks.dat’)
#EAR算法
def eye_aspect_ratio(eye):
A = distance.euclidean(eye[1], eye[5])
B = distance.euclidean(eye[2], eye[4])
C = distance.euclidean(eye[0], eye[3])
ratio = (A + B) / (2.0 * C)
return ratio
def mouth_aspect_ratio(mouth):
A = distance.euclidean(mouth[2], mouth[10])
B = distance.euclidean(mouth[4], mouth[8])
C = distance.euclidean(mouth[0], mouth[6])
ratio = (A + B) / (2.0 * C)
return ratio
def calculate_EAR(eye):
# 计算眼睛之间的距离,利用scipy distance 计算上眼皮和下眼皮之间欧氏距离
A = distance.euclidean(eye[1], eye[5])
B = distance.euclidean(eye[2], eye[4])
C = distance.euclidean(eye[0], eye[3])
ear_aspect_ratio = (A + B) / (2.0 * C)
return ear_aspect_ratio
def mouth_aspect_ratio(mouth):
A = distance.euclidean(mouth[2], mouth[10])
B = distance.euclidean(mouth[4], mouth[8])
C = distance.euclidean(mouth[0], mouth[6])
ratio = (A + B) / (2.0 * C)
return ratio
def upload_file():
global cap,txt,upload_flag,ret,frame
selectFile = tkinter.filedialog.askopenfilename() # askopenfilename 1次上传1个;askopenfilenames1次上传多个
entry1.insert(0, selectFile)
txt=entry1.get()
print(“上传的文件地址是:”)
print(txt)
cap = cv2.VideoCapture(txt)
print(“成功捕捉视频”)
upload_flag=1
if upload_flag==1:
canva_l.delete(‘all’)
canva_l.create_text(200, 200, text=“成功打开视频”, font=(“Lucida Console”, 15), fill=“red”)
main_detect(cap=cap)
def swi():
global num,cut
print(1111111)
if cap.isOpened():
ret,frame = cap.read() #按帧读取视频
cv2.imwrite('./pic/'+str(num)+".jpg",frame) #保存视频帧图像
print("已保存一张图片")
num += 1
if ret is False:
canva_r.create_text(200, 200, text="视频播放完成", font=("Lucida Console", 15), fill="red")
print("视频播放完毕")
def open_camera():
canva_l.delete(‘all’)
canva_l.create_text(200, 200, text=“成功打开摄像头”, font=(“Lucida Console”, 15), fill=“red”)
cap=cap = cv2.VideoCapture(0)
main_detect(cap=cap)
def Showimage(imgCV_in, canva, layout=“null”):
global imgTK
canvawidth = int(canva.winfo_reqwidth())
canvaheight = int(canva.winfo_reqheight())
#获取cv图像的高度和宽度 sp(hight,width,通道)
sp = imgCV_in.shape
cvheight = sp[0] # height(rows) of image
cvwidth = sp[1] # width(colums) of image
if (layout == "fill"):
imgCV = cv2.resize(imgCV_in, (canvawidth, canvaheight), interpolation=cv2.INTER_AREA)
elif (layout == "fit"):
if (float(cvwidth / cvheight) > float(canvawidth / canvaheight)):
imgCV = cv2.resize(imgCV_in, (canvawidth, int(canvawidth * cvheight / cvwidth)),
interpolation=cv2.INTER_AREA)
else:
imgCV = cv2.resize(imgCV_in, (int(canvaheight * cvwidth / cvheight), canvaheight),
interpolation=cv2.INTER_AREA)
else:
imgCV = imgCV_in
imgCV2 = cv2.cvtColor(imgCV, cv2.COLOR_BGR2RGBA) # 转换颜色从BGR到RGBA
current_image = Image.fromarray(imgCV2) # 将图像转换成Image对象
imgTK = ImageTk.PhotoImage(image=current_image) # 将image对象转换为imageTK对象
canva.create_image(0, 0, anchor=NW, image=imgTK)
def GUI_init():
global entry1,canva_l,canva_r,FPS,root
root = Tk() #主窗口
root.title(“姿态检测系统”)
root.minsize(710, 410)#大小
# 创建视频播放幕布
canva_l = Canvas(root, width=480, height=360, bg=“white”)
canva_l.grid(row=0, column=0) #row:第一行 column第一个位置
# 创建信息幕布
canva_r = Canvas(root, width=350, height=360, bg=“white”)
canva_r.grid(row=0, column=1) #row:第一行 column第二个位置
# 显示FPS
FPS = tkinter.StringVar()
FPS_show = tkinter.Label(root, textvariable=FPS, bg=“white”, font=(“Lucida Console”, 10))
FPS_show.grid(row=1, column=0)
if upload_flag==0:
canva_l.create_text(200, 200, text=“欢迎使用本系统”, font=(“Lucida Console”, 15), fill=“red”)
# 创建拍照按钮
cut = tkinter.Button(root, text="拍照", font=("Lucida Console", 14),command=swi)
cut.grid(row=2,column=1)
cut.place(x=350, y=366)
#创建上传文件按钮
upload = tkinter.Button(root, text='上传文件',command=upload_file)
upload.grid(row=1,column=1)
entry1 = tkinter.Entry(root, width='40')
entry1.grid(row=2,column=1)
#创建实时摄像头按钮
camera = tkinter.Button(root,text="开启摄像头",command=open_camera)
camera.grid(row=3,column=1)
root.mainloop()
load_dlib()
GUI_init()