文章目錄
- dlib庫
- dlib庫——人臉應用實例——表情識別
- dlib庫——人臉應用實例——疲勞檢測
dlib庫
dlib庫的基礎用法介紹可以參考這篇文章:https://blog.csdn.net/lou0720/article/details/145968062?spm=1011.2415.3001.5331,故此這篇文章只介紹dlib的人臉應用實例。
dlib庫——人臉應用實例——表情識別
代碼:
import numpy as np
import cv2
import dlib
from sklearn.metrics.pairwise import euclidean_distances
from PIL import Image, ImageDraw, ImageFontdef cv2AddChineseText(img, text, position, textColor=(0, 255, 0), textSize=20):""" 向圖片中添加中文 """# 判斷輸入的 img 是否為 OpenCV 格式的圖片(即 numpy.ndarray 類型)if isinstance(img, np.ndarray):# 如果是 OpenCV 格式,將其從 BGR 顏色空間轉換為 RGB 顏色空間,# 因為 PIL 庫使用 RGB 顏色空間,而 OpenCV 使用 BGR 顏色空間img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))# 在 img 圖片上創建一個繪圖對象,用于后續繪制文本draw = ImageDraw.Draw(img)# 定義字體的格式,使用 "simsun.ttc" 字體文件,指定字體大小為 textSize,# 并設置編碼為 UTF - 8 以支持中文顯示fontStyle = ImageFont.truetype("simsun.ttc", textSize, encoding="utf-8")# 在指定的 position 位置,使用指定的 textColor 顏色和 fontStyle 字體繪制文本draw.text(position, text, textColor, font=fontStyle)# 將繪制好文本的 PIL 圖片轉換回 numpy.ndarray 類型,并將顏色空間從 RGB 轉換回 BGR,# 以符合 OpenCV 的要求return cv2.cvtColor(np.asarray(img), cv2.COLOR_RGB2BGR)def MAR(shape):"""計算嘴巴縱橫比(Mouth Aspect Ratio):param shape: 68 個人臉特征點的坐標數組:return: 嘴巴縱橫比"""# 計算嘴巴上下部分特定點之間的歐氏距離A = euclidean_distances(shape[50].reshape(1, 2), shape[58].reshape(1, 2))B = euclidean_distances(shape[51].reshape(1, 2), shape[57].reshape(1, 2))C = euclidean_distances(shape[52].reshape(1, 2), shape[56].reshape(1, 2))# 計算嘴巴左右兩側特定點之間的歐氏距離D = euclidean_distances(shape[48].reshape(1, 2), shape[54].reshape(1, 2))# 計算嘴巴縱橫比,即上下部分平均距離與左右距離的比值return ((A + B + C) / 3) / Ddef MJR(shape):"""計算嘴巴與下巴寬度比(Mouth to Jaw Ratio):param shape: 68 個人臉特征點的坐標數組:return: 嘴巴與下巴寬度比"""# 計算嘴巴左右兩側特定點之間的歐氏距離M = euclidean_distances(shape[48].reshape(1, 2), shape[54].reshape(1, 2))# 計算下巴左右兩側特定點之間的歐氏距離J = euclidean_distances(shape[3].reshape(1, 2), shape[13].reshape(1, 2))# 計算嘴巴與下巴寬度比return M / Jdef MBR(shape):"""計算眉毛間距比(Mouth to Brow Ratio):param shape: 68 個人臉特征點的坐標數組:return: 眉毛間距比"""# 計算左右眉毛內側特定點之間的歐氏距離F = euclidean_distances(shape[21].reshape(1, 2), shape[22].reshape(1, 2))# 計算左右眉毛外側特定點之間的歐氏距離I = euclidean_distances(shape[17].reshape(1, 2), shape[26].reshape(1, 2))# 計算眉毛間距比return F / I# 打開默認攝像頭,用于實時視頻捕獲
cap = cv2.VideoCapture(0)
# 加載預訓練的 68 點人臉特征預測模型
predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat')
# 創建人臉檢測器對象
detector = dlib.get_frontal_face_detector()while True:# 從攝像頭讀取一幀視頻ret, frame = cap.read()# 水平翻轉視頻幀,使畫面看起來更自然frame = cv2.flip(frame, 1)# 如果讀取失敗,跳出循環if ret is None:break# 檢測視頻幀中的人臉faces = detector(frame, 0)for face in faces:# 預測人臉的 68 個特征點shape = predictor(frame, face)# 將特征點轉換為 numpy 數組shape = np.array([[p.x, p.y] for p in shape.parts()])# 計算嘴巴縱橫比mar = MAR(shape)# 計算嘴巴與下巴寬度比mjr = MJR(shape)# 計算眉毛間距比mbr = MBR(shape)# 初始化表情結果為正常result = '正常'# 打印各個比值print("mar", mar, '\tmjr', mjr, 'mbr', mbr)# 根據比值判斷表情if mar > 0.5:result = "大笑"elif mjr > 0.45:result = '微笑'elif mbr < 0.15:result = '生氣'# 計算嘴巴輪廓的凸包mouthHull = cv2.convexHull(shape[48:61])# 在視頻幀上添加中文表情結果frame = cv2AddChineseText(frame, result, mouthHull[0, 0])# 在視頻幀上繪制嘴巴輪廓cv2.drawContours(frame, [mouthHull], -1, (0, 255, 0), 1)# 顯示處理后的視頻幀cv2.imshow('img', frame)# 等待用戶按鍵,等待時間為 1 毫秒key = cv2.waitKey(1)# 如果用戶按下 ESC 鍵(ASCII 碼為 27),跳出循環if key == 27:break
# 釋放攝像頭資源
cap.release()
# 關閉所有 OpenCV 窗口
cv2.destroyAllWindows()
dlib庫——人臉應用實例——疲勞檢測
當閉眼時間長時,發出危險警告。
代碼:
import numpy as np
import cv2
import dlib
from sklearn.metrics.pairwise import euclidean_distances
from PIL import Image, ImageDraw, ImageFontdef cv2AddChineseText(img, text, position, textColor=(0, 255, 0), textSize=20):""" 向圖片中添加中文 """# 判斷輸入的 img 是否為 OpenCV 格式的圖片(即 numpy.ndarray 類型)if isinstance(img, np.ndarray):# 如果是 OpenCV 格式,將其從 BGR 顏色空間轉換為 RGB 顏色空間,# 因為 PIL 庫使用 RGB 顏色空間,而 OpenCV 使用 BGR 顏色空間img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))# 在 img 圖片上創建一個繪圖對象,用于后續繪制文本draw = ImageDraw.Draw(img)# 定義字體的格式,使用 "simsun.ttc" 字體文件,指定字體大小為 textSize,# 并設置編碼為 UTF - 8 以支持中文顯示fontStyle = ImageFont.truetype("simsun.ttc", textSize, encoding="utf-8")# 在指定的 position 位置,使用指定的 textColor 顏色和 fontStyle 字體繪制文本draw.text(position, text, textColor, font=fontStyle)# 將繪制好文本的 PIL 圖片轉換回 numpy.ndarray 類型,并將顏色空間從 RGB 轉換回 BGR,# 以符合 OpenCV 的要求return cv2.cvtColor(np.asarray(img), cv2.COLOR_RGB2BGR)def eye_aspect_ratio(eye):"""計算眼睛的縱橫比(Eye Aspect Ratio,EAR):param eye: 眼睛的特征點坐標數組:return: 眼睛的縱橫比"""# 計算眼睛垂直方向上的距離A = euclidean_distances(eye[1].reshape(1, 2), eye[5].reshape(1, 2))B = euclidean_distances(eye[2].reshape(1, 2), eye[4].reshape(1, 2))# 計算眼睛水平方向上的距離C = euclidean_distances(eye[0].reshape(1, 2), eye[3].reshape(1, 2))# 計算眼睛縱橫比,即垂直方向平均距離與水平距離的比值ear = ((A + B) / 2) / Creturn eardef drawEye(eye):"""在圖像上繪制眼睛的輪廓:param eye: 眼睛的特征點坐標數組"""# 計算眼睛特征點的凸包eyeHull = cv2.convexHull(eye)# 在圖像 frame 上繪制眼睛的輪廓cv2.drawContours(frame, [eyeHull], -1, (0, 255, 0), 1)# 初始化計數器,用于記錄眼睛閉合的幀數
COUNTER = 0
# 創建人臉檢測器對象,用于檢測圖像中的人臉
detector = dlib.get_frontal_face_detector()
# 打開默認攝像頭,用于實時視頻捕獲
cap = cv2.VideoCapture(0)
# 加載預訓練的 68 點人臉特征預測模型
predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat')while True:# 從攝像頭讀取一幀視頻ret, frame = cap.read()# 水平翻轉視頻幀,使畫面看起來更自然frame = cv2.flip(frame, 1)# 如果讀取失敗,跳出循環if ret is None:break# 檢測視頻幀中的人臉faces = detector(frame, 0)for face in faces:# 預測人臉的 68 個特征點shape = predictor(frame, face)# 將特征點轉換為 numpy 數組shape = np.array([[p.x, p.y] for p in shape.parts()])# 提取右眼的特征點rightEye = shape[36:42]# 提取左眼的特征點leftEye = shape[42:48]# 計算右眼的縱橫比rightEAR = eye_aspect_ratio(rightEye)# 計算左眼的縱橫比leftEAR = eye_aspect_ratio(leftEye)# 計算左右眼縱橫比的平均值ear = (leftEAR + rightEAR) / 2# 如果眼睛縱橫比小于 0.3,認為眼睛處于閉合狀態if ear < 0.3:# 閉合幀數計數器加 1COUNTER += 1# 如果閉合幀數超過 50 幀,認為可能存在危險情況if COUNTER >= 50:# 在視頻幀上添加中文提示信息frame = cv2AddChineseText(frame, "!!!危險!!!", (250, 250))else:# 如果眼睛處于睜開狀態,將閉合幀數計數器重置為 0COUNTER = 0# 繪制左眼的輪廓drawEye(leftEye)# 繪制右眼的輪廓drawEye(rightEye)# 格式化眼睛縱橫比信息,保留兩位小數info = "EAR:{:.2f}".format(ear[0][0])# 在視頻幀上添加眼睛縱橫比信息frame = cv2AddChineseText(frame, info, (0, 30))# 顯示處理后的視頻幀cv2.imshow('Frame', frame)# 等待用戶按鍵,等待時間為 1 毫秒key = cv2.waitKey(1)# 如果用戶按下 ESC 鍵(ASCII 碼為 27),跳出循環if key == 27:break# 釋放攝像頭資源
cap.release()
# 關閉所有 OpenCV 窗口
cv2.destroyAllWindows()