近幾天微軟的釋出會上講到了不少認臉解鎖的內容,經過探索,其實利用手頭的資源我們完全自己也可以完成這樣一個過程。
本文講解了如何使用Python,基於OpenCV與Face++實現人臉解鎖的功能。
本文基於Python 2.7.11,Windows 8.1 系統。
主要內容
- Windows 8.1上配置OpenCV
- OpenCV的人臉檢測應用
- 使用Face++完成人臉辨識(如果你想自己實現這部分的功能,可以借鑑例如這個專案)
Windows 8.1上配置OpenCV
入門的時候配置環境總是一個非常麻煩的事情,在Windows上配置OpenCV更是如此。
既然寫了這個推廣的科普教程,總不能讓讀者卡在環境配置上吧。
下面用到的檔案都可以在這裡(提取碼:b6ec)下載,但是注意,目前OpenCV僅支援Python2.7。
將cv2加入site-packages
將下載下來的cv2.pyd
檔案放入Python安裝的資料夾下的Libsite-packages
目錄。
就我的電腦而言,這個目錄就是C:/Python27/Lib/site-packages/
。
記得不要直接使用pip安裝,將檔案拖過去即可。
安裝numpy元件
在命令列下進入到下載下來的檔案所在的目錄(按住Shift右鍵有在該目錄開啟命令列的選項)
鍵入命令:
1 |
pip install numpy-1.11.0rc2-cp27-cp27m-win32.whl |
如果你的系統或者Python不適配,可以在這裡下載別的輪子。
測試OpenCV安裝
在命令列鍵入命令:
1 |
python -c "import cv2" |
如果沒有出現錯誤提示,那麼cv2就已經安裝好了。
OpenCV的人臉檢測應用
人臉檢測應用,簡而言之就是一個在照片裡找到人臉,然後用方框框起來的過程(我們的相機經常做這件事情)
那麼具體而言就是這樣一個過程:
- 獲取攝像頭的圖片
- 在圖片中檢測到人臉的區域
- 在人臉的區域周圍繪製方框
獲取攝像頭的圖片
這裡簡單的講解一下OpenCV的基本操作。
以下操作是開啟攝像頭的基本操作:
1 2 3 4 5 6 7 |
#coding=utf8 import cv2 # 一般筆記本的預設攝像頭都是0 capInput = cv2.VideoCapture(0) # 我們可以用這條命令檢測攝像頭是否可以讀取資料 if not capInput.isOpened(): print('Capture failed because of camera') |
那麼怎麼從攝像頭讀取資料呢?
1 2 3 4 5 6 7 8 |
# 接上段程式 # 現在攝像頭已經開啟了,我們可以使用這條命令讀取影像 # img就是我們讀取到的影像,就和我們使用open('pic.jpg', 'rb').read()讀取到的資料是一樣的 ret, img = capInput.read() # 你可以使用open的方式儲存,也可以使用cv2提供的方式儲存 cv2.imwrite('pic.jpg', img) # 同樣,你可以使用open的方式讀取,也可以使用cv2提供的方式讀取 img = cv2.imread('pic.jpg') |
為了方便顯示圖片,cv2也提供了顯示圖片的方法:
1 2 3 4 5 6 |
# 接上段程式 # 定義一個視窗,當然也可以不定義 imgWindowName = 'ImageCaptured' imgWindow = cv2.namedWindow(imgWindowName, cv2.WINDOW_NORMAL) # 在視窗中顯示圖片 cv2.imshow(imgWindowName, img) |
當然在完成所有操作以後需要把攝像頭和視窗都做一個釋放:
1 2 3 4 5 |
# 接上段程式 # 釋放攝像頭 capInput.release() # 釋放所有視窗 cv2.destroyAllWindows() |
在圖片中檢測到人臉的區域
OpenCV給我們提供了已經訓練好的人臉的xml模板,我們只需要載入然後比對即可。
1 2 3 4 5 6 7 8 |
# 接上段程式 # 載入xml模板 faceCascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml') # 將圖形儲存的方式進行轉換 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 使用模板匹配圖形 faces = faceCascade.detectMultiScale(gray, 1.3, 5) print(faces) |
在人臉的區域周圍繪製方框
在上一個步驟中,faces中的四個量分別為左上角的橫座標、縱座標、寬度、長度。
所以我們根據這四個量很容易的就可以繪製出方框。
1 2 3 |
# 接上段程式 # 函式的引數分別為:影像,左上角座標,右下角座標,顏色,寬度 img = cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2) |
成果
根據上面講述的內容,我們現在已經可以完成一個簡單的人臉辨認了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
#coding=utf8 import cv2 print('Press Esc to exit') faceCascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml') imgWindow = cv2.namedWindow('FaceDetect', cv2.WINDOW_NORMAL) def detect_face(): capInput = cv2.VideoCapture(0) # 避免處理時間過長造成畫面卡頓 nextCaptureTime = time.time() faces = [] if not capInput.isOpened(): print('Capture failed because of camera') while 1: ret, img = capInput.read() gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) if nextCaptureTime < time.time(): nextCaptureTime = time.time() + 0.1 faces = faceCascade.detectMultiScale(gray, 1.3, 5) if faces: for x, y, w, h in faces: img = cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2) cv2.imshow('FaceDetect', img) # 這是簡單的讀取鍵盤輸入,27即Esc的acsii碼 if cv2.waitKey(1) & 0xFF == 27: break capInput.release() cv2.destroyAllWindows() if __name__ == '__main__': detect_face() |
使用Face++完成人臉辨識
第一次認識Face++還是因為支付寶的人臉支付,響應速度還是非常讓人滿意的。
現在只需要免費註冊一個賬號然後新建一個應用就可以使用了,非常方便。
他的官方網址是這個,註冊好之後在這裡的我的應用中建立應用即可。
建立好應用之後你會獲得API Key與API Secret。
Face++的API呼叫邏輯簡單來說是這樣的:
- 上傳圖片獲取讀取到的人的face_id
- 建立Person,獲取person_id(Person中的圖片可以增加、刪除)
- 比較兩個face_id,判斷是否是一個人
- 比較face_id與person_id,判斷是否是一個人
上傳圖片獲取face_id
在將圖片通過post方法上傳到特定的地址後將返回一個json的值。
如果api_key, api_secret沒有問題,且在上傳的圖片中有識別到人臉,那麼會儲存在json的face鍵值下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
#coding=utf8 import requests # 這裡填寫你的應用的API Key與API Secret API_KEY = '' API_SECRET = '' # 目前的API網址是這個,你可以在API文件裡找到這些 BASE_URL = 'http://apicn.faceplusplus.com/v2' # 使用Requests上傳圖片 url = '%s/detection/detect?api_key=%s&api_secret=%s&attribute=none'%( BASE_URL, API_KEY, API_SECRET) files = {'img': (os.path.basename(fileDir), open(fileDir, 'rb'), mimetypes.guess_type(fileDir)[0]), } r = requests.post(url, files = files) # 如果讀取到圖片中的頭像則輸出他們,其中的'face_id'就是我們所需要的值 faces = r.json().get('face') print faces |
建立Person
這個操作沒有什麼可以講的內容,可以對照這段程式和官方的API介紹。
官方的API介紹可以見這裡,相信看完這一段程式以後你就可以自己完成其餘的API了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# 上接上一段程式 # 讀取face_id if not faces is None: faceIdList = [face['face_id'] for face in faces] # 使用Requests建立Person url = '%s/person/create'%BASE_URL params = { 'api_key': API_KEY, 'api_secret': API_SECRET, 'person_name': 'LittleCoder', 'face_id': ','.join(faceIdList), } r = requests.get(url, params = params) # 獲取person_id print r.json.()['person_id'] |
進度確認
到目前為止,你應該已經可以就給定的兩張圖片比對是否是同一個人了。
那麼讓我們來試著寫一下這個程式吧,兩張圖片分別為’pic1.jpg’, ‘pic2.jpg’好了。
下面我給出了我的程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
def upload_img(fileDir, oneface = True): url = '%s/detection/detect?api_key=%s&api_secret=%s&attribute=none'%( BASE_URL, API_KEY, API_SECRET) if oneface: url += '&mode=oneface' files = {'img': (os.path.basename(fileDir), open(fileDir, 'rb'), mimetypes.guess_type(fileDir)[0]), } r = requests.post(url, files = files) faces = r.json().get('face') if faces is None: print('There is no face found in %s'%fileDir) else: return faces[0]['face_id'] def compare(faceId1, faceId2): url = '%s/recognition/compare'%BASE_URL params = BASE_PARAMS params['face_id1'] = faceId1 params['face_id2'] = faceId2 r = requests.get(url, params) return r.json() faceId1 = upload_img('pic1.jpg') faceId2 = upload_img('pic2.jpg') if face_id1 and face_id2: print(compare(faceId1, faceId2)) else: print('Please change two pictures') |
成品
到此,所有的知識介紹都結束了,相比大致如何完成這個專案各位讀者也已經有想法了吧。
下面我們需要構思一下人臉解鎖的思路,大致而言是這樣的:
- 使用一個程式設定賬戶(包括向賬戶中儲存解鎖用的圖片)
- 使用另一個程式登陸(根據輸入的使用者名稱測試解鎖)
這裡會有很多重複的程式碼,就不再贅述了,你可以在這裡或者這裡(提取碼:c073)下載原始碼測試使用。
這裡是設定賬戶的截圖:
設定賬戶
這裡是登陸的截圖:
登陸
結束語
希望讀完這篇文章能對你有幫助,有什麼不足之處萬望指正(鞠躬)。
打賞支援我寫出更多好文章,謝謝!
打賞作者
打賞支援我寫出更多好文章,謝謝!