December 18, 2018

디바이스마트 미디어:

[49호]영상인식을 통한 졸음 운전 추돌 사고 방지 소프트웨어

Cap 2018-07-12 14-10-54-440

  2018 ICT 융합 프로젝트 공모전 우수상  

영상인식을 통한 졸음 운전 추돌 사고 방지 소프트웨어

글 | 단국대학교 정의동

1. 심사평
칩센 아쉽게도 동일한 목표를 더 훌륭하게 구현한 팀이 있었습니다. open cv를 활용한 안면인식만으로 구현한 부분이 아쉽습니다. 보고서의 완성도 부분에서도 먼저 제출한 팀과 비교되는 점이 아쉽습니다.
뉴티씨 눈감음이나 얼굴인식 등을 통하여, 졸음운전시 경보음을 줘서, 졸음운전을 예방하는 것은 요즘 매우 중요한 이슈입니다. 인식도 잘 되고, 매우 실용적으로 잘 제작하신 것으로 보입니다. 다만, 운전하는 상황이 매우 위험하므로, 인식 후 경보까지 시간을 조금 더 줄여서 빠르게 경보를 해주면 좀 더 좋을 것 같습니다. 조금만 더 다듬으면, 실제 판매 가능한 제품으로도 만들 수 있을 것으로 생각되어 매우 좋은 점수를 드립니다.
위드로봇 전체적인 완성도가 높은 작품입니다. 다만 기존 제품과의 차별성이 없는 부분이 아쉽습니다.

2. 작품 개요

49 ict 영상 (1)
2012~2014년 3년간의 통계에 따르면, 졸음운전으로 인한 교통 사고는 7560건이 있었고, 하루에 약 7건이 발생하며 14명의 사상자가 발생하였다. 또한 전체 교통사고에 비하면 졸음운전으로 인한 사고는 1% 남짓에 불과하지만, 교통사고 치사율을 살펴보았을 때 전체 교통사고에 비하여 약 10배의 치사율을 보였다.
위와 같이 위험한 졸음운전으로 인한 사고를 방지하기 위해서 아이디어를 구상하였는데, 영상 처리 및 이미지 내 대상 인식을 통해 졸음운전을 미연에 인지하고 대처하자는 요지로 프로젝트를 추진하게 되었다.

3. 작품 설명
3.1. 주요 동작 및 특징
졸음 인식을 위해 얼굴 인식을 사용한 후 (p 입력 시 인식 시작) 눈의 특징 점을 추출하여 눈꺼풀 사이의 간격 비율을 이용해 졸고 있는지를 판단한다. 그 후 졸음이 인식될 경우 2.5초 후 알람음을 발생시키고 이용자가 알람을 해제할 때까지 지속시킨다. (s 입력 시 알람 해제) 정면을 응시하지 않아 얼굴이 인식되지 않을 경우 위험을 감지, 4.5초 후 알람을 출력한다. 정면을 다시 응시할 경우 알람은 자동으로 종료된다. 얼굴 인식을 다시 시작하고 싶은 경우 p를 눌러 재시작을 할 수 있다.

49 ict 영상 (2)

시중에 많이 사용되는 얼굴인식 라이브러리 OpenCV는 눈 부위를 인식하는 기능이 있으나 인식률이 현저히 떨어진다. 이 부분을 보완하기 위해 dlib 이라는 라이브러리에 포함된 Face Landmark Detection 이라는 Trained Data Set 라이브러리를 사용했다. 데이터 셋 적용 후, 인식률도 크게 상향되었고 인식 속도 또한 딜레이가 거의 없을 정도로 발전하였다.

49 ict 영상 (3)

그러나 Face Landmark Detection에 한계가 있다. 얼굴의 각도가 변할 경우 얼굴의 특징점을 추출하는 데 정확성이 크게 떨어진다. 때문에 이 프로젝트에선 이중 얼굴 인식 시스템을 이용하였다. 한번 인식한 얼굴에서 얼굴의 위치와 각도를 계산하고 얼굴 부분만 회전하여 정면으로 바꿔준 뒤 다시 인식하는 방식이다. 이 시스템을 이용하여 기존 라이브러리의 단점을 크게 보완하였다.

49 ict 영상 (4)

눈이 감기는 것을 인식하는 부분에서 눈 사이의 거리만 계산한 것이 아니라 가로와 세로의 비율로 계산을 하였기 때문에 카메라에서 멀어진다 해도 눈이 감겨진 정도를 거리에 따른 오차 없이 계산할 수 있었다.

3.2. 전체 시스템 구성

49 ict 영상 (5)
3.3. 개발 환경
Operation System : Windows 10
Programming Language : Python
Used IDE Tool : Anaconda3 Python 3.6
Used Libraries :OpenCV, Dlib, numpy, scipy, winsound, time

3.4. 단계별 제작 과정
3.4.1. 눈 감김 비율 계산

video_capture = cv2.VideoCapture(0)
face_detector = dlib.get_frontal_face_detector()
shape_predictor = dlib.shape_predictor(“shape_predictor_68_face_landmarks.dat”)
#비디오를 불러옴, dlib에서 frontal face detector, shape predictor를 불러옴
def eye_ratio(eyepoint):
A = dist.euclidean(eyepoint[1],eyepoint[5])
B = dist.euclidean(eyepoint[2],eyepoint[4])
C = dist.euclidean(eyepoint[0],eyepoint[3])
ER = (A+B) / (2.0*C)

return ER
#눈 비율 값 계산 define

3.4.2. 얼굴 재정렬 -점 회전 함수 선언

def rotate (brx,bry):
crx = brx – midx
cry = bry – midy
arx = np.cos(-angle)*crx – np.sin(-angle)*cry
ary = np.sin(-angle)*crx + np.cos(-angle)*cry
rx = int (arx + midx)
ry = int (ary + midy)

return(rx,ry)
#점 회전 define

3.4.3. 동영상 좌우반전 후 gray화 및 clahe 후 face detector

while True:
ret, frame = video_capture.read()
flip_frame = cv2.flip(frame,1)
gray = cv2.cvtColor(flip_frame, cv2.COLOR_BGR2GRAY)
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
clahe_image = clahe.apply(gray)
detection = face_detector(clahe_image)

3.4.4. 화면 내 인터페이스 작성 (메시지 팝업)

key = cv2.waitKey(10) & 0xFF
# 키 입력

if message_popup == True:
if print_counter == 0:
cv2.putText(flip_frame, “”, (230, 450), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
if print_counter == 1:
cv2.putText(flip_frame, “Try again”, (260, 450), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
if print_counter == 2:
cv2.putText(flip_frame, “Gaze the camera”, (230, 450), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
if print_counter == 3:
cv2.putText(flip_frame, “Program starts in : 3″, (200, 450), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 0, 0), 2)
if print_counter == 4:
cv2.putText(flip_frame, “Program starts in : 2″, (200, 450), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 0, 0), 2)
if print_counter == 5:
cv2.putText(flip_frame, “Program starts in : 1″, (200, 450), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 0, 0), 2)
if print_counter == 6:
cv2.putText(flip_frame, “CALCULATING”, (240, 450), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)

3.4.5. 프로그램 시작 분기문

if key == ord(“p”):
if not eye_cap == True:

eye_open_done = False

#p 눌렸을 때 인식 측정 시작
else :
eye_open_done = True
eye_cap = False
cv2.destroyWindow(“image2″)
program_switch = False
eye_ratio_limit = 0.00
left_ar = [0,] right_ar = [0,]

count_ar = 0
winsound.PlaySound(None, winsound.SND_ASYNC)
txt_switch = False
alarm = False

#다시 누르면 이미지창 제거 메세지창 제거
if eye_open_done == False:
# 측정 시작
for fd in detection:
eye_open_shape = shape_predictor(clahe_image, fd)

eye_open_landmarks = np.matrix([[p.x, p.y] for p in eye_open_shape.parts()])

eye_open_left_eye = eye_open_landmarks[left_eye_points] eye_open_right_eye = eye_open_landmarks[right_eye_points]

eye_open_ER_left = eye_ratio(eye_open_left_eye)
eye_open_ER_right = eye_ratio(eye_open_right_eye)

# ER값 측정 시작
if(count_ar < 100):
count_ar += 1

for i in range(36,41):
cv2.line(flip_frame,(eye_open_shape.part(i).x, eye_open_shape.part(i).y),(eye_open_shape.part(i+1).x, eye_open_shape.part(i+1).y),(255,0,0),1)
cv2.line(flip_frame,(eye_open_shape.part(41).x, eye_open_shape.part(41).y),(eye_open_shape.part(36).x, eye_open_shape.part(36).y),(255,0,0),1)
for i in range(42,47):
cv2.line(flip_frame,(eye_open_shape.part(i).x, eye_open_shape.part(i).y),(eye_open_shape.part(i+1).x, eye_open_shape.part(i+1).y),(255,0,0),1)
cv2.line(flip_frame,(eye_open_shape.part(47).x, eye_open_shape.part(47).y),(eye_open_shape.part(42).x, eye_open_shape.part(42).y),(255,0,0),1)
print_counter = 2
message_popup = True

if(30<count_ar<=60):
left_ar.append(eye_open_ER_left)
right_ar.append(eye_open_ER_right)
print_counter = 6
if(60<count_ar<=70):
print_counter = 0
Max_ER_left = max(left_ar)
Max_ER_right = max(right_ar)
eye_ratio_limit = (Max_ER_left + Max_ER_right)/2*0.65
if(70<count_ar<=80):
print_counter = 3
if(80<count_ar<=90):
print_counter = 4
if(90<count_ar<100):
print_counter = 5

#얼굴이 인식되는 동안 count_ar이 올라가면서 어레이에 저장후 최대값으로 설정, 메시지 팝업

if(count_ar == 100):
eye_open_done = True
eye_cap = True
program_switch = True
print_counter = 0
count_ar = 0
count_time = time.time()

#count_ar이 최대일떄 측정 중단, 프로그램 시작

3.4.6. 얼굴 인식 범위 지정 및 얼굴 재정렬

if program_switch == True:
#프로그램 시작
face_reco = False
face_reco_n = True

for d in detection:

face_reco = True
fnd_count = 0
count_time2 = time.time()

if txt_switch2 == True:
winsound.PlaySound(None, winsound.SND_ASYNC)
face_alarm = False
txt_switch2 = False
#얼굴 인식 불가 알람이 ON일때 알람을 끔

x = d.left()
y = d.top()
x1 = d.right()
y1 = d.bottom()
#d 값 저장
bdx = x-(x1-x)/2
bdy = y-(y1-y)/2
bdx1 = x1+(x1-x)/2
bdy1 = y1+(y1-y)/2
# 큰 d값 저장
midx = (x+x1)/2
midy = (y+y1)/2
# d의 가운데 포인트 저장

shape = shape_predictor(clahe_image, d)

rex = shape.part(45).x
rey = shape.part(45).y
lex = shape.part(36).x
ley = shape.part(36).y

mex = int (lex + (rex-lex)/2)
mey = int (ley + (rey-ley)/2)
#눈의 양끝점 좌표 설정 및 눈 사이 가운데 점 설정

tanx = mex – lex
tany = ley – mey
tan = tany/tanx
#tan 값 계산
angle = np.arctan(tan)
degree = np.degrees(angle)
#각도 계산

rsd_1 = rotate(x,y)
rsd_2 = rotate(x1,y)
rsd_3 = rotate(x,y1)
rsd_4 = rotate(x1,y1)
d2_1 = rotate(bdx,bdy)
d2_2 = rotate(bdx1,bdy)
d2_3 = rotate(bdx,bdy1)
d2_4 = rotate(bdx1,bdy1)
#좌표 회전

pts1 = np.float32([[d2_1[0],d2_1[1]],[d2_2[0],d2_2[1]],[d2_3[0],d2_3[1]],[d2_4[0],d2_4[1]]])
pts2 = np.float32([[0,0],[400,0],[0,400],[400,400]])
M = cv2.getPerspectiveTransform(pts1,pts2)
dst = cv2.warpPerspective(flip_frame,M,(400,400))
#회전된 좌표를 이용하여 새로운 창으로 프린트

3.4.7. 회전된 d2에서 얼굴 인식 실행

d2gray = cv2.cvtColor(dst, cv2.COLOR_BGR2GRAY)
d2clahe_image = clahe.apply(d2gray)
d2detections = face_detector(d2clahe_image)

for d2 in d2detections:
xx = d2.left()
yy = d2.top()
xx1 = d2.right()
yy1 = d2.bottom()
d2shape = shape_predictor(d2clahe_image, d2)

 cv2.rectangle(dst, (xx, yy), (xx1, yy1), (0, 255, 255), 1)
 for i in range(1,68):
cv2.circle(dst, (d2shape.part(i).x, d2shape.part(i).y), 1, (255,0,255), thickness=1)
for i in range(36,41):
cv2.line(dst,(d2shape.part(i).x, d2shape.part(i).y),(d2shape.part(i+1).x, d2shape.part(i+1).y),(255,0,0),1)
cv2.line(dst,(d2shape.part(41).x, d2shape.part(41).y),(d2shape.part(36).x, d2shape.part(36).y),(255,0,0),1)
for i in range(42,47):
cv2.line(dst,(d2shape.part(i).x, d2shape.part(i).y),(d2shape.part(i+1).x, d2shape.part(i+1).y),(255,0,0),1)
cv2.line(dst,(d2shape.part(47).x, d2shape.part(47).y),(d2shape.part(42).x, d2shape.part(42).y),(255,0,0),1)

landmarks = np.matrix([[p.x, p.y] for p in d2shape.parts()])

right_eye = landmarks[left_eye_points] left_eye = landmarks[right_eye_points] ER_right = eye_ratio(right_eye)
ER_left = eye_ratio(left_eye)
if ER_left <= eye_ratio_limit and ER_right <= eye_ratio_limit:
open_eye = False
if ER_left > eye_ratio_limit and ER_right > eye_ratio_limit:
open_eye = True
# 눈 감았을때 open eye가 꺼짐, 눈 뜨면 다시 켜짐

if open_eye == True:
count_time = time.time()
#눈이 감겨있으면 그 순간 count_time 측정 기록, 떠있으면 계속 갱신

cv2.line(flip_frame,rsd_1,rsd_2,(100,255,100),1)
cv2.line(flip_frame,rsd_1,rsd_3,(100,255,100),1)
cv2.line(flip_frame,rsd_4,rsd_2,(100,255,100),1)
cv2.line(flip_frame,rsd_4,rsd_3,(100,255,100),1)
#회전된 작은 d 프린트

for i in range(0,67):
cv2.circle(flip_frame, (shape.part(i).x, shape.part(i).y), 1, (0,0,255), thickness=1)
for i in range(36,41):
cv2.line(flip_frame,(shape.part(i).x, shape.part(i).y),(shape.part(i+1).x, shape.part(i+1).y),(255,0,0),1)
cv2.line(flip_frame,(shape.part(41).x, shape.part(41).y),(shape.part(36).x, shape.part(36).y),(255,0,0),1)
for i in range(42,47):
cv2.line(flip_frame,(shape.part(i).x, shape.part(i).y),(shape.part(i+1).x, shape.part(i+1).y),(255,0,0),1)
cv2.line(flip_frame,(shape.part(47).x, shape.part(47).y),(shape.part(42).x, shape.part(42).y),(255,0,0),1)

cv2.putText(flip_frame, “Left : {:.2f}”.format(ER_left), (450, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 200, 200), 2)
cv2.putText(flip_frame, “Right : {:.2f}”.format(ER_right), (450, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 200, 200), 2)
cv2.putText(flip_frame, “Degree : {:.2f}”.format(degree), (450, 90), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 200, 200), 2)
cv2.putText(flip_frame, “Eye ratio limit: {:.2f}”.format(eye_ratio_limit), (10, 430), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
#라인 그리기 및 값 표현

3.4.8. 알람 기준 지정 및 알람 재생 및 종료

if time.time()-count_time > 2.5:
txt_switch = True

if alarm == False:
winsound.PlaySound(“school_alarm.wav”, winsound.SND_LOOP + winsound.SND_ASYNC)
print(“alarm on”)
alarm = True

#2.5초 후 알람 한번 출력, 메시지 스위치 온
if face_reco == False:
face_reco_n = False
fnd_count += 1
if fnd_count >= 10:
cv2.putText(dst, “FACE NOT DETECTED”, (100, 200), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
cv2.putText(flip_frame, “FACE NOT DETECTED”, (10, 460), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
count_time = time.time()
if txt_switch == False and time.time()-count_time2 > 4.5:
txt_switch2 = True
if txt_switch2 == True:
cv2.putText(flip_frame, “NO FACE ALARM!!!”, (10, 60),cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
if face_alarm == False:
winsound.PlaySound(“school_alarm.wav”, winsound.SND_LOOP + winsound.SND_ASYNC)
print(“face alarm on”)
face_alarm = True

#얼굴 인식이 안될 경우 눈 감는 카운트 초기화, 4.5 초 후 알람 및 메시지 출력
if face_reco == True and face_reco_n == True:
face = 2
#얼굴 인식이 되는 도중
if face_reco == False and face_reco_n == False:
face = 1
#얼굴 인식이 안되는 중
if face_reco == False and face_reco_n == True:
face = 0
#프로그램 시작 값

if txt_switch == True:
cv2.putText(flip_frame, “ALARM!!!”, (10, 30),cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)

#눈 감으면 알람
if face == 2 and key == ord(“s”):
txt_switch = False
alarm = False
winsound.PlaySound(None, winsound.SND_ASYNC)

#알람 울릴 때 (얼굴 인식이 되는 경우에만 알람 종료)

3.5. 소스코드

import cv2
import dlib
import numpy as np
from scipy.spatial import distance as dist
import winsound
import time

video_capture = cv2.VideoCapture(0)
face_detector = dlib.get_frontal_face_detector()
shape_predictor = dlib.shape_predictor(“shape_predictor_68_face_landmarks.dat”)

right_eye_points = list(range(36, 42))
left_eye_points = list(range(42, 48))

count_ar = 0
left_ar = 30*[] right_ar = 30*[]

eye_ratio_limit = 0.00

count_time = 0
count_time2 = 0

eye_cap = False
eye_open_done = True
program_switch = False
message_popup = False
print_counter = 0
txt_switch = False
txt_switch2 = False
alarm = False

face_alarm = False
face_reco = False

face_reco = False
face_reco_n = True
face = 0
fnd_count = 0

open_eye = True

def eye_ratio(eyepoint):
A = dist.euclidean(eyepoint[1],eyepoint[5])
B = dist.euclidean(eyepoint[2],eyepoint[4])
C = dist.euclidean(eyepoint[0],eyepoint[3])
ER = (A+B) / (2.0*C)

return ER

def rotate (brx,bry):
crx = brx – midx
cry = bry – midy
arx = np.cos(-angle)*crx – np.sin(-angle)*cry
ary = np.sin(-angle)*crx + np.cos(-angle)*cry
rx = int (arx + midx)
ry = int (ary + midy)

return(rx,ry)

while True:
ret, frame = video_capture.read()
flip_frame = cv2.flip(frame,1)
gray = cv2.cvtColor(flip_frame, cv2.COLOR_BGR2GRAY)
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
clahe_image = clahe.apply(gray)
detection = face_detector(clahe_image)

key = cv2.waitKey(10) & 0xFF

if message_popup == True:
if print_counter == 0:
cv2.putText(flip_frame, “”, (230, 450), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
if print_counter == 1:
cv2.putText(flip_frame, “Try again”, (260, 450), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
if print_counter == 2:
cv2.putText(flip_frame, “Gaze the camera”, (230, 450), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
if print_counter == 3:
cv2.putText(flip_frame, “Program starts in : 3″, (200, 450), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 0, 0), 2)
if print_counter == 4:
cv2.putText(flip_frame, “Program starts in : 2″, (200, 450), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 0, 0), 2)
if print_counter == 5:
cv2.putText(flip_frame, “Program starts in : 1″, (200, 450), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 0, 0), 2)
if print_counter == 6:
cv2.putText(flip_frame, “CALCULATING”, (240, 450), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)

if key == ord(“p”):
if not eye_cap == True:
eye_open_done = False
else :
eye_open_done = True
eye_cap = False
cv2.destroyWindow(“image2″)
program_switch = False
eye_ratio_limit = 0.00
left_ar = [0,] right_ar = [0,]

count_ar = 0
winsound.PlaySound(None, winsound.SND_ASYNC)
txt_switch = False
alarm = False

if eye_open_done == False:
for fd in detection:
eye_open_shape = shape_predictor(clahe_image, fd)
eye_open_landmarks = np.matrix([[p.x, p.y] for p in eye_open_shape.parts()])
eye_open_left_eye = eye_open_landmarks[left_eye_points] eye_open_right_eye = eye_open_landmarks[right_eye_points] eye_open_ER_left = eye_ratio(eye_open_left_eye)
eye_open_ER_right = eye_ratio(eye_open_right_eye)

if(count_ar < 100):
count_ar += 1

for i in range(36,41):
cv2.line(flip_frame,(eye_open_shape.part(i).x, eye_open_shape.part(i).y),(eye_open_shape.part(i+1).x, eye_open_shape.part(i+1).y),(255,0,0),1)
cv2.line(flip_frame,(eye_open_shape.part(41).x, eye_open_shape.part(41).y),(eye_open_shape.part(36).x, eye_open_shape.part(36).y),(255,0,0),1)
for i in range(42,47):
cv2.line(flip_frame,(eye_open_shape.part(i).x, eye_open_shape.part(i).y),(eye_open_shape.part(i+1).x, eye_open_shape.part(i+1).y),(255,0,0),1)
cv2.line(flip_frame,(eye_open_shape.part(47).x, eye_open_shape.part(47).y),(eye_open_shape.part(42).x, eye_open_shape.part(42).y),(255,0,0),1)
print_counter = 2
message_popup = True
if(30<count_ar<=60):
left_ar.append(eye_open_ER_left)
right_ar.append(eye_open_ER_right)
print_counter = 6
if(60<count_ar<=70):
print_counter = 0
Max_ER_left = max(left_ar)
Max_ER_right = max(right_ar)
eye_ratio_limit = (Max_ER_left + Max_ER_right)/2*0.65
if(70<count_ar<=80):
print_counter = 3
if(80<count_ar<=90):
print_counter = 4
if(90<count_ar<100):
print_counter = 5

if(count_ar == 100):
eye_open_done = True
eye_cap = True
program_switch = True
print_counter = 0
count_ar = 0
count_time = time.time()

if program_switch == True:
face_reco = False
face_reco_n = True
for d in detection:

face_reco = True
fnd_count = 0
count_time2 = time.time()

if txt_switch2 == True:
winsound.PlaySound(None, winsound.SND_ASYNC)
face_alarm = False
txt_switch2 = False

x = d.left()
y = d.top()
x1 = d.right()
y1 = d.bottom()
bdx = x-(x1-x)/2
bdy = y-(y1-y)/2
bdx1 = x1+(x1-x)/2
bdy1 = y1+(y1-y)/2
midx = (x+x1)/2
midy = (y+y1)/2

shape = shape_predictor(clahe_image, d)

rex = shape.part(45).x
rey = shape.part(45).y
lex = shape.part(36).x
ley = shape.part(36).y

mex = int (lex + (rex-lex)/2)
mey = int (ley + (rey-ley)/2)

tanx = mex – lex
tany = ley – mey
tan = tany/tanx
angle = np.arctan(tan)
degree = np.degrees(angle)

rsd_1 = rotate(x,y)
rsd_2 = rotate(x1,y)
rsd_3 = rotate(x,y1)
rsd_4 = rotate(x1,y1)
d2_1 = rotate(bdx,bdy)
d2_2 = rotate(bdx1,bdy)
d2_3 = rotate(bdx,bdy1)
d2_4 = rotate(bdx1,bdy1)

pts1 = np.float32([[d2_1[0],d2_1[1]],[d2_2[0],d2_2[1]],[d2_3[0],d2_3[1]],[d2_4[0],d2_4[1]]])
pts2 = np.float32([[0,0],[400,0],[0,400],[400,400]])

M = cv2.getPerspectiveTransform(pts1,pts2)

dst = cv2.warpPerspective(flip_frame,M,(400,400))

d2gray = cv2.cvtColor(dst, cv2.COLOR_BGR2GRAY)
d2clahe_image = clahe.apply(d2gray)
d2detections = face_detector(d2clahe_image)

for d2 in d2detections:
xx = d2.left()
yy = d2.top()
xx1 = d2.right()
yy1 = d2.bottom()
d2shape = shape_predictor(d2clahe_image, d2)

cv2.rectangle(dst, (xx, yy), (xx1, yy1), (0, 255, 255), 1)
for i in range(1,68):
cv2.circle(dst, (d2shape.part(i).x, d2shape.part(i).y), 1, (255,0,255), thickness=1)
for i in range(36,41):
cv2.line(dst,(d2shape.part(i).x, d2shape.part(i).y),(d2shape.part(i+1).x, d2shape.part(i+1).y),(255,0,0),1)
cv2.line(dst,(d2shape.part(41).x, d2shape.part(41).y),(d2shape.part(36).x, d2shape.part(36).y),(255,0,0),1)
for i in range(42,47):
cv2.line(dst,(d2shape.part(i).x, d2shape.part(i).y),(d2shape.part(i+1).x, d2shape.part(i+1).y),(255,0,0),1)
cv2.line(dst,(d2shape.part(47).x, d2shape.part(47).y),(d2shape.part(42).x, d2shape.part(42).y),(255,0,0),1)
landmarks = np.matrix([[p.x, p.y] for p in d2shape.parts()])
right_eye = landmarks[left_eye_points] left_eye = landmarks[right_eye_points] ER_right = eye_ratio(right_eye)
ER_left = eye_ratio(left_eye)

if ER_left <= eye_ratio_limit and ER_right <= eye_ratio_limit:
open_eye = False

if ER_left > eye_ratio_limit and ER_right > eye_ratio_limit:
open_eye = True

if open_eye == True:
count_time = time.time()

cv2.line(flip_frame,rsd_1,rsd_2,(100,255,100),1)
cv2.line(flip_frame,rsd_1,rsd_3,(100,255,100),1)
cv2.line(flip_frame,rsd_4,rsd_2,(100,255,100),1)
cv2.line(flip_frame,rsd_4,rsd_3,(100,255,100),1)

for i in range(0,67):
cv2.circle(flip_frame, (shape.part(i).x, shape.part(i).y), 1, (0,0,255), thickness=1)
for i in range(36,41):
cv2.line(flip_frame,(shape.part(i).x, shape.part(i).y),(shape.part(i+1).x, shape.part(i+1).y),(255,0,0),1)
cv2.line(flip_frame,(shape.part(41).x, shape.part(41).y),(shape.part(36).x, shape.part(36).y),(255,0,0),1)
for i in range(42,47):
cv2.line(flip_frame,(shape.part(i).x, shape.part(i).y),(shape.part(i+1).x, shape.part(i+1).y),(255,0,0),1)
cv2.line(flip_frame,(shape.part(47).x, shape.part(47).y),(shape.part(42).x, shape.part(42).y),(255,0,0),1)
cv2.putText(flip_frame, “Left : {:.2f}”.format(ER_left), (450, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 200, 200), 2)
cv2.putText(flip_frame, “Right : {:.2f}”.format(ER_right), (450, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 200, 200), 2)
cv2.putText(flip_frame, “Degree : {:.2f}”.format(degree), (450, 90), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 200, 200), 2)
cv2.putText(flip_frame, “Eye ratio limit: {:.2f}”.format(eye_ratio_limit), (10, 430), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)

if time.time()-count_time > 2.5:
txt_switch = True

if alarm == False:
winsound.PlaySound(“school_alarm.wav”, winsound.SND_LOOP + winsound.SND_ASYNC)
print(“alarm on”)
alarm = True

if face_reco == False:
face_reco_n = False
fnd_count += 1
if fnd_count >= 10:
cv2.putText(dst, “FACE NOT DETECTED”, (100, 200), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
cv2.putText(flip_frame, “FACE NOT DETECTED”, (10, 460), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)

count_time = time.time()

if txt_switch == False and time.time()-count_time2 > 4.5:
txt_switch2 = True
if txt_switch2 == True:
cv2.putText(flip_frame, “NO FACE ALARM!!!”, (10, 60),cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)

if face_alarm == False:
winsound.PlaySound(“school_alarm.wav”, winsound.SND_LOOP + winsound.SND_ASYNC)
print(“face alarm on”)
face_alarm = True

if face_reco == True and face_reco_n == True:
face = 2
if face_reco == False and face_reco_n == False:
face = 1
if face_reco == False and face_reco_n == True:
face = 0

if txt_switch == True:
cv2.putText(flip_frame, “ALARM!!!”, (10, 30),cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
cv2.imshow(“image2″, dst)

if face == 2 and key == ord(“s”):

txt_switch = False
alarm = False
winsound.PlaySound(None, winsound.SND_ASYNC)
cv2.imshow(“Frame”, flip_frame)
print(“time = “,time.time()-count_time)
print(“time2 = “,time.time()-count_time2)
print(“face = “,face)

if key == ord(“q”):
eye_ratio_limit = 0.00
winsound.PlaySound(None, winsound.SND_ASYNC)
break
cv2.destroyAllWindows()
video_capture.release()

4. 실행영상

49 ict 영상 (6) 49 ict 영상 (7)

49 ict 영상 (8)

 

 

 

 

 

 

 

Leave A Comment

*