dlib 面部表情跟蹤
阿新 • • 發佈:2019-01-11
原理
面部表情跟蹤就是根據檢測的人臉特徵點對應到特定的器官,比如眼睛、鼻子、嘴巴、耳朵等等,以此來跟蹤各個面部器官的動作。
本文首先開啟攝像頭,然後利用dlib中dlib.get_frontal_face_detector()識別人臉,並利用dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")預測人臉的68點,之後根據特徵點對應關係,在新建的影象中,繪製面部各個器官的輪廓,最終顯示的影象統一為500*500.
程式碼實現:
# -*- coding: utf-8 -*- import cv2 import dlib #import datetime import numpy as np def face_boundary(img, shape): # enumerate方法同時返回資料物件的索引和資料 for i, d in enumerate(shape.parts()): if i == 0: x_min = d.x x_max = d.x y_min = d.y y_max = d.y else: if d.x < x_min: x_min = d.x if d.x > x_max: x_max = d.x if d.y < y_min: y_min = d.y if d.y > y_max: y_max = d.y #如果出現負值,即人臉位於影象框之外的情況,應忽檢視像外的部分,將負值置為0 if x_min < 0: x_min = 0 if y_min < 0: y_min = 0 if x_min == x_max or y_min == y_max: return None else: return img[y_min:y_max, x_min:x_max] def draw_left_eyebrow(img, shape): #17 - 21 pt_pos = [] for index, pt in enumerate(shape.parts()[17:22]): pt_pos.append((pt.x, pt.y)) for num in range(len(pt_pos)-1): cv2.line(img, pt_pos[num], pt_pos[num+1], 255, 2) def draw_right_eyebrow(img, shape): # 22 - 26 pt_pos = [] for index, pt in enumerate(shape.parts()[22:27]): pt_pos.append((pt.x, pt.y)) for num in range(len(pt_pos) - 1): cv2.line(img, pt_pos[num], pt_pos[num + 1], 255, 2) def draw_left_eye(img, shape): # 36 - 41 pt_pos = [] for index, pt in enumerate(shape.parts()[36:42]): pt_pos.append((pt.x, pt.y)) for num in range(len(pt_pos) - 1): cv2.line(img, pt_pos[num], pt_pos[num + 1], 255, 2) cv2.line(img, pt_pos[0], pt_pos[-1], 255, 2) def draw_right_eye(img, shape): # 42 - 47 pt_pos = [] for index, pt in enumerate(shape.parts()[42:48]): pt_pos.append((pt.x, pt.y)) for num in range(len(pt_pos) - 1): cv2.line(img, pt_pos[num], pt_pos[num + 1], 255, 2) cv2.line(img, pt_pos[0], pt_pos[-1], 255, 2) def draw_nose(img, shape): # 27 - 35 pt_pos = [] for index, pt in enumerate(shape.parts()[27:36]): pt_pos.append((pt.x, pt.y)) for num in range(len(pt_pos) - 1): cv2.line(img, pt_pos[num], pt_pos[num + 1], 255, 2) cv2.line(img, pt_pos[0], pt_pos[4], 255, 2) cv2.line(img, pt_pos[0], pt_pos[-1], 255, 2) cv2.line(img, pt_pos[3], pt_pos[-1], 255, 2) def draw_mouth(img, shape): # 48 - 59 pt_pos = [] for index, pt in enumerate(shape.parts()[48:60]): pt_pos.append((pt.x, pt.y)) for num in range(len(pt_pos) - 1): cv2.line(img, pt_pos[num], pt_pos[num + 1], 255, 2) cv2.line(img, pt_pos[0], pt_pos[-1], 255, 2) # 60 - 67 pt_pos = [] for index, pt in enumerate(shape.parts()[60:]): pt_pos.append((pt.x, pt.y)) for num in range(len(pt_pos) - 1): cv2.line(img, pt_pos[num], pt_pos[num + 1], 255, 2) cv2.line(img, pt_pos[0], pt_pos[-1], 255, 2) def draw_jaw(img, shape): # 0 - 16 pt_pos = [] for index, pt in enumerate(shape.parts()[0:17]): pt_pos.append((pt.x, pt.y)) for num in range(len(pt_pos) - 1): cv2.line(img, pt_pos[num], pt_pos[num + 1], 255, 2) # 使用特徵提取器get_frontal_face_detector detector = dlib.get_frontal_face_detector() # dlib的68點模型,使用訓練好的特徵預測器 predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat") #使用電腦自帶攝像頭 cap = cv2.VideoCapture(0) font = cv2.FONT_HERSHEY_SIMPLEX while(1): # cap.read() # 返回兩個值: # 一個布林值true/false,用來判斷讀取視訊是否成功/是否到視訊末尾 # 影象物件,影象的三維矩陣 ret, frame = cap.read() img = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) dets = detector(img, 1) for index, face in enumerate(dets): # 使用預測器得到68點資料的座標 shape = predictor(img, face) #image.shape獲取影象的形狀,返回值是一個包含行數、列數、通道數的元組 features = np.zeros(img.shape[0:-1], dtype=np.uint8)#黑色影象 for i, d in enumerate(shape.parts()): d_pos = (d.x, d.y) cv2.circle(features, d_pos, 2, 255, 1) draw_left_eyebrow(features, shape) draw_right_eyebrow(features, shape) draw_left_eye(features, shape) draw_right_eye(features, shape) draw_nose(features, shape) draw_mouth(features, shape) draw_jaw(features, shape) faceROI = face_boundary(features, shape) faceROI = cv2.resize(faceROI, (500, 500), interpolation=cv2.INTER_LINEAR) cv2.imshow('face {}'.format(index), faceROI) if cv2.waitKey(10) == 27: #按ESC Break