0. 引言html
利用 Python 開發,藉助 Dlib 庫捕獲攝像頭中的人臉,進行實時人臉 68 個特徵點標定;python
支持多張人臉;git
有截圖功能;github
圖 1 工程效果示例( gif )app
圖 2 工程效果示例( 靜態圖片 )機器學習
1. 開發環境ide
Python: 3.6.3函數
Dlib: 19.7post
OpenCv, NumPy學習
import dlib # 人臉檢測的庫 Dlib
import numpy as np # 數據處理的庫 NumPy
import cv2 # 圖像處理的庫 OpenCv
2. 源碼介紹
其實實現很簡單,主要分爲兩個部分:攝像頭調用 + 人臉特徵點標定
2.1 攝像頭調用
介紹下 OpenCv 中攝像頭的調用方法,用到如下幾個 OpenCv 函數:
cv2.VideoCapture(0) 建立一個對象;
cv2.VideoCapture.set(propId, value) 設置視頻參數;
cv2.VideoCapture.isOpened() 檢測讀取視頻是否成功;
cv2.VideoCapture.read() 返回是否讀取成功和讀取到的幀圖像;
(具體能夠參考官方文檔:https://docs.opencv.org/2.4/modules/highgui/doc/reading_and_writing_images_and_video.html)
關於 cv2 中 VideoCapture 類的一些函數參數的說明以下:
# Sort by coneypo # Updated at 10, Oct # Blog: http://www.cnblogs.com/AdaminXie
###### 1. cv2.VideoCapture(), 建立cv2攝像頭對象 / Open the default camera ######
""" Python: cv2.VideoCapture() → <VideoCapture object> Python: cv2.VideoCapture(filename) → <VideoCapture object> filename – name of the opened video file (eg. video.avi) or image sequence (eg. img_%02d.jpg, which will read samples like img_00.jpg, img_01.jpg, img_02.jpg, ...) Python: cv2.VideoCapture(device) → <VideoCapture object> device – id of the opened video capturing device (i.e. a camera index). If there is a single camera connected, just pass 0. """ cap = cv2.VideoCapture(0) ##### 2. cv2.VideoCapture.set(propId, value),設置視頻參數; #####
""" propId: CV_CAP_PROP_POS_MSEC Current position of the video file in milliseconds. CV_CAP_PROP_POS_FRAMES 0-based index of the frame to be decoded/captured next. CV_CAP_PROP_POS_AVI_RATIO Relative position of the video file: 0 - start of the film, 1 - end of the film. CV_CAP_PROP_FRAME_WIDTH Width of the frames in the video stream. CV_CAP_PROP_FRAME_HEIGHT Height of the frames in the video stream. CV_CAP_PROP_FPS Frame rate. ... value: 設置的參數值/ Value of the property """ cap.set(3, 480) ##### 3. cv2.VideoCapture.isOpened(), 檢查攝像頭初始化是否成功, 返回true或false / check if open camera successfully #####
cap.isOpened() ##### 4. cv2.VideoCapture.read([imgage]) -> retval,image, 讀取視頻 / Grabs, decodes and returns the next video frame #####
""" 返回兩個值: 一個是布爾值true/false,用來判斷讀取視頻是否成功/是否到視頻末尾 圖像對象,圖像的三維矩陣 """ flag, im_rd = cap.read()
2.2 人臉特徵點標定
調用預測器 「shape_predictor_68_face_landmarks.dat」 進行 68 點標定,這是 Dlib 訓練好的模型,能夠直接調用,進行人臉 68 我的臉特徵點的標定;
須要進行的後續工做是,利用座標值進行特徵點繪製;
具體能夠參考個人另外一篇博客(Python 3 利用 Dlib 19.7 實現人臉68個特徵點的標定);
圖 3 Dlib 中人臉 68 個特徵點位置說明
2.3 源碼
既然已經可以利用訓練好的模型進行特徵點檢測,須要進行的工做是將攝像頭捕獲到的視頻流,轉換爲 OpenCv 的圖像對象,這樣才能進行人臉特徵點檢測;
而後利用返回的特徵點座標值,繪製特徵點,實時的再繪製到攝像頭界面上,達到實時人臉檢測追蹤的目的;
利用 cv2.VideoCapture() 建立攝像頭對象,而後利用 flag, im_rd = cv2.VideoCapture.read() 讀取攝像頭視頻,im_rd 就是視頻中的一幀幀圖像;
而後就相似於單張圖像進行人臉檢測,對這一幀幀的圖像 im_rd 利用 Dlib 進行特徵點標定,而後繪製特徵點;
能夠按下 's' 鍵來獲取當前截圖,會存下帶有時間戳的本地圖像文件如 「screenshoot_1_2018-05-14-11-04-23.jpg」;
或者按下 'q' 鍵來退出攝像頭窗口;
有四個 python 文件:
how_to_use_camera.py OpenCv 調用攝像頭;
get_features_from_image.py 繪製 "data/face_to_detect/face_x.jpg" 本地圖像人臉文件的特徵點;
get_features_from_camera.py 從攝像頭實時人臉檢測繪製特徵點;
remove_ss.py: 刪除 "data/screenshots/" 路徑下的全部截圖;
( 源碼都上傳到了 GitHub: https://github.com/coneypo/Dlib_face_detection_from_camera )
這裏只給出 get_features_from_camera.py 的源碼;
get_features_from_camera.py:
1 # 調用攝像頭,進行人臉捕獲,和 68 個特徵點的追蹤 2 3 # Author: coneypo 4 # Blog: http://www.cnblogs.com/AdaminXie 5 # GitHub: https://github.com/coneypo/Dlib_face_detection_from_camera 6 7 # Created at 2018-02-26 8 # Updated at 2019-01-28 9 10 import dlib # 機器學習的庫 Dlib 11 import numpy as np # 數據處理的庫 numpy 12 import cv2 # 圖像處理的庫 OpenCv 13 import time 14 import timeit 15 import statistics 16 17 # 儲存截圖的目錄 18 path_screenshots = "data/screenshots/" 19 20 detector = dlib.get_frontal_face_detector() 21 predictor = dlib.shape_predictor('data/dlib/shape_predictor_68_face_landmarks.dat') 22 23 # 建立 cv2 攝像頭對象 24 cap = cv2.VideoCapture(0) 25 26 # cap.set(propId, value) 27 # 設置視頻參數,propId 設置的視頻參數,value 設置的參數值 28 cap.set(3, 480) 29 30 # 截圖 screenshots 的計數器 31 cnt = 0 32 33 time_cost_list = [] 34 35 # cap.isOpened() 返回 true/false 檢查初始化是否成功 36 while cap.isOpened(): 37 38 # cap.read() 39 # 返回兩個值: 40 # 一個布爾值 true/false,用來判斷讀取視頻是否成功/是否到視頻末尾 41 # 圖像對象,圖像的三維矩陣 42 flag, im_rd = cap.read() 43 44 # 每幀數據延時 1ms,延時爲 0 讀取的是靜態幀 45 k = cv2.waitKey(1) 46 47 # 取灰度 48 img_gray = cv2.cvtColor(im_rd, cv2.COLOR_RGB2GRAY) 49 50 # start point 51 start = timeit.default_timer() 52 53 # 人臉數 54 faces = detector(img_gray, 0) 55 56 # print(len(faces)) 57 58 # 待會要寫的字體 59 font = cv2.FONT_HERSHEY_SIMPLEX 60 61 # 標 68 個點 62 if len(faces) != 0: 63 # 檢測到人臉 64 for i in range(len(faces)): 65 landmarks = np.matrix([[p.x, p.y] for p in predictor(im_rd, faces[i]).parts()]) 66 67 for idx, point in enumerate(landmarks): 68 # 68 點的座標 69 pos = (point[0, 0], point[0, 1]) 70 71 # 利用 cv2.circle 給每一個特徵點畫一個圈,共 68 個 72 cv2.circle(im_rd, pos, 2, color=(139, 0, 0)) 73 74 # 利用 cv2.putText 輸出 1-68 75 cv2.putText(im_rd, str(idx + 1), pos, font, 0.2, (187, 255, 255), 1, cv2.LINE_AA) 76 77 cv2.putText(im_rd, "faces: " + str(len(faces)), (20, 50), font, 1, (0, 0, 0), 1, cv2.LINE_AA) 78 79 # end point 80 stop = timeit.default_timer() 81 time_cost_list.append(stop - start) 82 print("%-15s %f" % ("Time cost:", (stop - start))) 83 84 else: 85 # 沒有檢測到人臉 86 cv2.putText(im_rd, "no face", (20, 50), font, 1, (0, 0, 0), 1, cv2.LINE_AA) 87 88 89 # 添加說明 90 im_rd = cv2.putText(im_rd, "press 'S': screenshot", (20, 400), font, 0.8, (255, 255, 255), 1, cv2.LINE_AA) 91 im_rd = cv2.putText(im_rd, "press 'Q': quit", (20, 450), font, 0.8, (255, 255, 255), 1, cv2.LINE_AA) 92 93 # 按下 's' 鍵保存 94 if k == ord('s'): 95 cnt += 1 96 print(path_screenshots + "screenshot" + "_" + str(cnt) + "_" + time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime()) + ".jpg") 97 cv2.imwrite(path_screenshots + "screenshot" + "_" + str(cnt) + "_" + time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime()) + ".jpg", im_rd) 98 99 # 按下 'q' 鍵退出 100 if k == ord('q'): 101 break 102 103 # 窗口顯示 104 # 參數取 0 能夠拖動縮放窗口,爲 1 不能夠 105 # cv2.namedWindow("camera", 0) 106 cv2.namedWindow("camera", 1) 107 108 cv2.imshow("camera", im_rd) 109 110 # 釋放攝像頭 111 cap.release() 112 113 # 刪除創建的窗口 114 cv2.destroyAllWindows() 115 116 print("%-15s" % "Result:") 117 print("%-15s %f" % ("Max time:", (max(time_cost_list)))) 118 print("%-15s %f" % ("Min time:", (min(time_cost_list)))) 119 print("%-15s %f" % ("Average time:", statistics.mean(time_cost_list)))
實時輸出處理時間:
...
Time cost: 0.065273 Time cost: 0.059348 Time cost: 0.093570 Time cost: 0.091448 Time cost: 0.084946 Time cost: 0.089457 Time cost: 0.084367 Time cost: 0.094103 Time cost: 0.096082 Time cost: 0.073331 Time cost: 0.073685 Time cost: 0.065583 Time cost: 0.061161 Time cost: 0.061650 Time cost: 0.060952 Time cost: 0.084485 Result: Max time: 0.112430 Min time: 0.057525 Average time: 0.085478
筆記本 CPU: i5-6200U@2.30GHz, Memory: 8G 處理時間平均在 0.08s;
# 請尊重他人勞動成果,轉載或者使用源碼請註明出處:http://www.cnblogs.com/AdaminXie
# 若是對您有幫助,歡迎在 GitHub 上 star 支持下: https://github.com/coneypo/Dlib_face_detection_from_camera
# 若有問題能夠聯繫本人郵箱,商業合做勿擾謝謝: coneypo@foxmail.com