New file |
| | |
| | | import cv2 |
| | | import imutils |
| | | import dlib |
| | | import numpy as np |
| | | import random |
| | | import time |
| | | from imutils import face_utils |
| | | |
| | | |
| | | class FaceDetector: |
| | | def __init__(self, cap, win_width, win_height): |
| | | self.cap = cap |
| | | self.WIN_WIDTH = win_width |
| | | self.WIN_HEIGHT = win_height |
| | | |
| | | self.detector = None # äººè¸æ£æµå¨ |
| | | self.predictor = None # ç¹å¾ç¹æ£æµå¨ |
| | | # éªçéå¼ |
| | | self.EAR_THRESH = None |
| | | self.MOUTH_THRESH = None |
| | | # æ»éªçæ¬¡æ° |
| | | self.eye_flash_counter = None |
| | | self.mouth_open_counter = None |
| | | self.turn_left_counter = None |
| | | self.turn_right_counter = None |
| | | # è¿ç»å¸§æ°éå¼ |
| | | self.EAR_CONSTANT_FRAMES = None |
| | | self.MOUTH_CONSTANT_FRAMES = None |
| | | self.LEFT_CONSTANT_FRAMES = None |
| | | self.RIGHT_CONSTANT_FRAMES = None |
| | | # è¿ç»å¸§è®¡æ°å¨ |
| | | self.eye_flash_continuous_frame = 0 |
| | | self.mouth_open_continuous_frame = 0 |
| | | self.turn_left_continuous_frame = 0 |
| | | self.turn_right_continuous_frame = 0 |
| | | |
| | | # 计ç®ç¼é¿å®½æ¯ä¾ EARå¼ |
| | | @staticmethod |
| | | def count_EAR(eye): |
| | | A = np.linalg.norm(eye[1] - eye[5]) |
| | | B = np.linalg.norm(eye[2] - eye[4]) |
| | | C = np.linalg.norm(eye[0] - eye[3]) |
| | | EAR = (A + B) / (2.0 * C) |
| | | return EAR |
| | | |
| | | # 计ç®å´é¿å®½æ¯ä¾ MARå¼ |
| | | @staticmethod |
| | | def count_MAR(mouth): |
| | | A = np.linalg.norm(mouth[1] - mouth[11]) |
| | | B = np.linalg.norm(mouth[2] - mouth[10]) |
| | | C = np.linalg.norm(mouth[3] - mouth[9]) |
| | | D = np.linalg.norm(mouth[4] - mouth[8]) |
| | | E = np.linalg.norm(mouth[5] - mouth[7]) |
| | | F = np.linalg.norm(mouth[0] - mouth[6]) # 水平欧å éå¾·è·ç¦» |
| | | ratio = (A + B + C + D + E) / (5.0 * F) |
| | | return ratio |
| | | |
| | | # 计ç®å·¦å³è¸è½¬å¨æ¯ä¾ FRå¼ |
| | | @staticmethod |
| | | def count_FR(face): |
| | | rightA = np.linalg.norm(face[0] - face[27]) |
| | | rightB = np.linalg.norm(face[2] - face[30]) |
| | | rightC = np.linalg.norm(face[4] - face[48]) |
| | | leftA = np.linalg.norm(face[16] - face[27]) |
| | | leftB = np.linalg.norm(face[14] - face[30]) |
| | | leftC = np.linalg.norm(face[12] - face[54]) |
| | | ratioA = rightA / leftA |
| | | ratioB = rightB / leftB |
| | | ratioC = rightC / leftC |
| | | ratio = (ratioA + ratioB + ratioC) / 3 |
| | | return ratio |
| | | |
| | | # æ¬å°æ´»ä½æ£æµ |
| | | def detect_face_local(self): |
| | | self.detect_start_time = time.time() |
| | | |
| | | # ç¹å¾ç¹æ£æµå¨é¦æ¬¡å è½½æ¯è¾æ
¢ï¼éè¿å¤æåå°åé¢å è½½çé度 |
| | | if self.detector is None: |
| | | self.detector = dlib.get_frontal_face_detector() |
| | | if self.predictor is None: |
| | | self.predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat') |
| | | |
| | | # éªçéå¼ |
| | | self.EAR_THRESH = 0.25 |
| | | self.MOUTH_THRESH = 0.7 |
| | | |
| | | # æ»éªçæ¬¡æ° |
| | | self.eye_flash_counter = 0 |
| | | self.mouth_open_counter = 0 |
| | | self.turn_left_counter = 0 |
| | | self.turn_right_counter = 0 |
| | | |
| | | # è¿ç»å¸§æ°éå¼ |
| | | self.EAR_CONSTANT_FRAMES = 2 |
| | | self.MOUTH_CONSTANT_FRAMES = 2 |
| | | self.LEFT_CONSTANT_FRAMES = 4 |
| | | self.RIGHT_CONSTANT_FRAMES = 4 |
| | | |
| | | # è¿ç»å¸§è®¡æ°å¨ |
| | | self.eye_flash_continuous_frame = 0 |
| | | self.mouth_open_continuous_frame = 0 |
| | | self.turn_left_continuous_frame = 0 |
| | | self.turn_right_continuous_frame = 0 |
| | | |
| | | print("æ´»ä½æ£æµ åå§åæ¶é´:", time.time() - self.detect_start_time) |
| | | |
| | | # å½åæ»å¸§æ° |
| | | total_frame_counter = 0 |
| | | |
| | | # è®¾ç½®éæºå¼ |
| | | now_flag = 0 |
| | | random_type = [0, 1, 2, 3] |
| | | random.shuffle(random_type) |
| | | |
| | | random_eye_flash_number = random.randint(4, 6) |
| | | random_mouth_open_number = random.randint(2, 4) |
| | | print('请æç
§æç¤ºæ§è¡ç¸å
³å¨ä½') # ç®åè¾åºæç¤ºä¿¡æ¯ |
| | | |
| | | # æåé¢é¨ç¹å¾ç¹çç´¢å¼ |
| | | (lStart, lEnd) = face_utils.FACIAL_LANDMARKS_IDXS["left_eye"] |
| | | (rStart, rEnd) = face_utils.FACIAL_LANDMARKS_IDXS["right_eye"] |
| | | (mStart, mEnd) = face_utils.FACIAL_LANDMARKS_IDXS["mouth"] |
| | | |
| | | while self.cap.isOpened(): |
| | | ret, frame = self.cap.read() |
| | | total_frame_counter += 1 |
| | | frame = imutils.resize(frame) |
| | | gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) |
| | | rects = self.detector(gray, 0) |
| | | |
| | | if len(rects) == 1: |
| | | shape = self.predictor(gray, rects[0]) |
| | | shape = face_utils.shape_to_np(shape) |
| | | |
| | | # æåé¢é¨åæ |
| | | left_eye = shape[lStart:lEnd] |
| | | right_eye = shape[rStart:rEnd] |
| | | mouth = shape[mStart:mEnd] |
| | | |
| | | # 计ç®é¿å®½æ¯ |
| | | left_EAR = self.count_EAR(left_eye) |
| | | right_EAR = self.count_EAR(right_eye) |
| | | mouth_MAR = self.count_MAR(mouth) |
| | | leftRight_FR = self.count_FR(shape) |
| | | average_EAR = (left_EAR + right_EAR) / 2.0 |
| | | |
| | | # 计ç®å·¦ç¼ãå³ç¼ãå´å·´çå¸å
|
| | | left_eye_hull = cv2.convexHull(left_eye) |
| | | right_eye_hull = cv2.convexHull(right_eye) |
| | | mouth_hull = cv2.convexHull(mouth) |
| | | |
| | | # å¯è§å |
| | | cv2.drawContours(frame, [left_eye_hull], -1, (0, 255, 0), 1) |
| | | cv2.drawContours(frame, [right_eye_hull], -1, (0, 255, 0), 1) |
| | | cv2.drawContours(frame, [mouth_hull], -1, (0, 255, 0), 1) |
| | | |
| | | if now_flag >= 4: |
| | | return True |
| | | |
| | | if random_type[now_flag] == 0: |
| | | if self.turn_left_counter > 0: |
| | | now_flag += 1 |
| | | else: |
| | | self.check_left_turn(leftRight_FR) |
| | | self.turn_right_counter = 0 |
| | | self.mouth_open_counter = 0 |
| | | self.eye_flash_counter = 0 |
| | | |
| | | elif random_type[now_flag] == 1: |
| | | if self.turn_right_counter > 0: |
| | | now_flag += 1 |
| | | else: |
| | | self.check_right_turn(leftRight_FR) |
| | | self.turn_left_counter = 0 |
| | | self.mouth_open_counter = 0 |
| | | self.eye_flash_counter = 0 |
| | | |
| | | elif random_type[now_flag] == 2: |
| | | if self.mouth_open_counter >= random_mouth_open_number: |
| | | now_flag += 1 |
| | | |
| | | else: |
| | | self.check_mouth_open(mouth_MAR) |
| | | self.turn_right_counter = 0 |
| | | self.turn_left_counter = 0 |
| | | self.eye_flash_counter = 0 |
| | | |
| | | elif random_type[now_flag] == 3: |
| | | if self.eye_flash_counter >= random_eye_flash_number: |
| | | now_flag += 1 |
| | | else: |
| | | self.check_eye_flash(average_EAR) |
| | | self.turn_right_counter = 0 |
| | | self.turn_left_counter = 0 |
| | | self.mouth_open_counter = 0 |
| | | |
| | | elif len(rects) == 0: |
| | | pass # è¿éå¯ä»¥æ·»å æªæ£æµå°äººè¸çæç¤ºé»è¾ |
| | | |
| | | elif len(rects) > 1: |
| | | pass # è¿éå¯ä»¥æ·»å æ£æµå°å¤å¼ 人è¸çæç¤ºé»è¾ |
| | | |
| | | show_video = cv2.cvtColor(cv2.resize(frame, (self.WIN_WIDTH, self.WIN_HEIGHT)), cv2.COLOR_BGR2RGB) |
| | | # è¿éåè®¾ä½ æå°æ¹æ¾ç¤ºç»é¢ï¼å®é
éè¦å
³èå°å¯¹åºççé¢å
ç´ |
| | | |
| | | if total_frame_counter >= 1000.0: |
| | | return False |
| | | |
| | | def check_eye_flash(self, average_EAR): |
| | | if average_EAR < self.EAR_THRESH: |
| | | self.eye_flash_continuous_frame += 1 |
| | | else: |
| | | if self.eye_flash_continuous_frame >= self.EAR_CONSTANT_FRAMES: |
| | | self.eye_flash_counter += 1 |
| | | self.eye_flash_continuous_frame = 0 |
| | | |
| | | def check_mouth_open(self, mouth_MAR): |
| | | if mouth_MAR > self.MOUTH_THRESH: |
| | | self.mouth_open_continuous_frame += 1 |
| | | else: |
| | | if self.mouth_open_continuous_frame >= self.MOUTH_CONSTANT_FRAMES: |
| | | self.mouth_open_counter += 1 |
| | | self.mouth_open_continuous_frame = 0 |
| | | |
| | | def check_right_turn(self, leftRight_FR): |
| | | if leftRight_FR <= 0.5: |
| | | self.turn_right_continuous_frame += 1 |
| | | else: |
| | | if self.turn_right_continuous_frame >= self.RIGHT_CONSTANT_FRAMES: |
| | | self.turn_right_counter += 1 |
| | | self.turn_right_continuous_frame = 0 |
| | | |
| | | def check_left_turn(self, leftRight_FR): |
| | | if leftRight_FR >= 2.0: |
| | | self.turn_left_continuous_frame += 1 |
| | | else: |
| | | if self.turn_left_continuous_frame >= self.LEFT_CONSTANT_FRAMES: |
| | | self.turn_left_counter += 1 |
| | | self.turn_left_continuous_frame = 0 |