深度有趣 | 14 Dlib快速入門
Dlib由C++編寫,提供了和機器學習、數值計算、圖模型演算法、影象處理等領域相關的一系列功能
安裝
安裝Dlib之前需要先安裝 cmake
,這裡以原始碼方式安裝,去官網根據系統下載相應的原始碼,cmake.org/download/
解壓之後,在終端裡進入原始碼目錄,依次執行以下命令
./bootstrap make sudo make install 複製程式碼
sudo
是以root許可權執行命令,適用於Linux和Mac OS
如果是Windows,則以管理員身份開啟cmd,並且最後一行命令改為
make install 複製程式碼
接下來,在終端中執行以下命令,檢查cmake是否成功安裝
cmake --version 複製程式碼
如果出現了相應的版本資訊,則說明cmake安裝成功
之後便可以使用pip安裝Dlib
pip install dlib 複製程式碼
安裝之後進入Python,如果能正常import,則說明Dlib安裝成功
import dlib 複製程式碼
如果是Mac OS,還需要安裝 XQuartz
用於顯示影象
安裝 XQuartz
之後如果碰到類似以下問題
xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun 複製程式碼
那麼在命令列執行以下命令即可解決
xcode-select --install 複製程式碼
完成以上安裝工作之後,我們來體驗下Dlib提供的一些和圖片處理相關的例子
人臉檢測
載入庫
# -*- coding: utf-8 -*- import dlib from imageio import imread import glob 複製程式碼
準備好人臉檢測器和顯示視窗,獲取圖片路徑
detector = dlib.get_frontal_face_detector() win = dlib.image_window() paths = glob.glob('faces/*.jpg') 複製程式碼
對每一張圖片進行檢測,並顯示檢測結果對應的矩形框
for path in paths: img = imread(path) # 1 表示將圖片放大一倍,便於檢測到更多人臉 dets = detector(img, 1) print('檢測到了 %d 個人臉' % len(dets)) for i, d in enumerate(dets): print('- %d:Left %d Top %d Right %d Bottom %d' % (i, d.left(), d.top(), d.right(), d.bottom())) win.clear_overlay() win.set_image(img) win.add_overlay(dets) dlib.hit_enter_to_continue() 複製程式碼
檢測時也可以指定一個閾值
path = 'faces/2007_007763.jpg' img = imread(path) # -1 表示人臉檢測的判定閾值 # scores 為每個檢測結果的得分,idx 為人臉檢測器的型別 dets, scores, idx = detector.run(img, 1, -1) for i, d in enumerate(dets): print('%d:score %f, face_type %f' % (i, scores[i], idx[i])) win.clear_overlay() win.set_image(img) win.add_overlay(dets) dlib.hit_enter_to_continue() 複製程式碼

人臉關鍵點檢測
使用訓練好的模型 shape_predictor_68_face_landmarks.dat
,在檢測出人臉的同時,檢測出人臉上的68個關鍵點
載入庫
# -*- coding: utf-8 -*- import dlib from imageio import imread import glob 複製程式碼
準備好人臉檢測器、關鍵點檢測模型、顯示視窗、圖片路徑
detector = dlib.get_frontal_face_detector() predictor_path = 'shape_predictor_68_face_landmarks.dat' predictor = dlib.shape_predictor(predictor_path) win = dlib.image_window() paths = glob.glob('faces/*.jpg') 複製程式碼
檢測每一張圖片
for path in paths: img = imread(path) win.clear_overlay() win.set_image(img) # 1 表示將圖片放大一倍,便於檢測到更多人臉 dets = detector(img, 1) print('檢測到了 %d 個人臉' % len(dets)) for i, d in enumerate(dets): print('- %d: Left %d Top %d Right %d Bottom %d' % (i, d.left(), d.top(), d.right(), d.bottom())) shape = predictor(img, d) # 第 0 個點和第 1 個點的座標 print('Part 0: {}, Part 1: {}'.format(shape.part(0), shape.part(1))) win.add_overlay(shape) win.add_overlay(dets) dlib.hit_enter_to_continue() 複製程式碼

人臉識別
不光是檢測人臉,還要知道每張臉是誰
Dlib將每張人臉對映為一個128維的向量,當兩個向量之間的Euclidean距離小於0.6時,可以認為屬於同一個人
以上判定標準在LFW(Labeled Faces in the Wild,08課提到過)資料集上可以獲得99.38%的識別準確率
這裡需要用到兩個模型, shape_predictor_68_face_landmarks.dat
和 dlib_face_recognition_resnet_model_v1.dat
,根據人臉檢測結果得到關鍵點檢測結果,根據關鍵點檢測結果進一步得到128維向量表示
載入庫
# -*- coding: utf-8 -*- import dlib from imageio import imread import glob import numpy as np 複製程式碼
準備好模型和圖片
detector = dlib.get_frontal_face_detector() predictor_path = 'shape_predictor_68_face_landmarks.dat' predictor = dlib.shape_predictor(predictor_path) face_rec_model_path = 'dlib_face_recognition_resnet_model_v1.dat' facerec = dlib.face_recognition_model_v1(face_rec_model_path) labeled = glob.glob('labeled/*.jpg') labeled_data = {} unlabeled = glob.glob('unlabeled/*.jpg') 複製程式碼
距離計算函式
# 定義一個計算Euclidean距離的函式 def distance(a, b): # d = 0 # for i in range(len(a)): # d += (a[i] - b[i]) * (a[i] - b[i]) # return np.sqrt(d) return np.linalg.norm(np.array(a) - np.array(b), ord=2) 複製程式碼
獲取標註圖片對應的向量表示
# 讀取標註圖片並儲存對應的128向量 for path in labeled: img = imread(path) name = path.split('/')[1].rstrip('.jpg') dets = detector(img, 1) # 這裡假設每張圖只有一個人臉 shape = predictor(img, dets[0]) face_vector = facerec.compute_face_descriptor(img, shape) labeled_data[name] = face_vector 複製程式碼
將未標註圖片的向量表示,和標註圖片逐一匹配
# 讀取未標註圖片,並和標註圖片進行對比 for path in unlabeled: img = imread(path) name = path.split('/')[1].rstrip('.jpg') dets = detector(img, 1) # 這裡假設每張圖只有一個人臉 shape = predictor(img, dets[0]) face_vector = facerec.compute_face_descriptor(img, shape) matches = [] for key, value in labeled_data.items(): d = distance(face_vector, value) if d < 0.6: matches.append(key + ' %.2f' % d) print('{}:{}'.format(name, ';'.join(matches))) 複製程式碼
結果顯示,全部標註圖片都通過了匹配,說明白百合和王珞丹是真的像……
人臉聚類
對於大量圖片中的大量人臉,基於以上人臉識別標準進行聚類,把距離較近的人臉聚為一類,即有可能為同一個人
載入庫
# -*- coding: utf-8 -*- import dlib from imageio import imread import glob import os from collections import Counter 複製程式碼
準備好模型和圖片
detector = dlib.get_frontal_face_detector() predictor_path = 'shape_predictor_68_face_landmarks.dat' predictor = dlib.shape_predictor(predictor_path) face_rec_model_path = 'dlib_face_recognition_resnet_model_v1.dat' facerec = dlib.face_recognition_model_v1(face_rec_model_path) paths = glob.glob('faces/*.jpg') 複製程式碼
獲取所有圖片的關鍵點檢測結果和向量表示
vectors = [] images = [] for path in paths: img = imread(path) dets = detector(img, 1) for i, d in enumerate(dets): shape = predictor(img, d) face_vector = facerec.compute_face_descriptor(img, shape) vectors.append(face_vector) images.append((img, shape)) 複製程式碼
以0.5為閾值進行聚類,並找出人臉數量最多的類
labels = dlib.chinese_whispers_clustering(vectors, 0.5) num_classes = len(set(labels)) print('共聚為 %d 類' % num_classes) biggest_class = Counter(labels).most_common(1) print(biggest_class) 複製程式碼
將最大類中包含的人臉儲存下來,類似的也可以處理其他的類
output_dir = 'most_common' if not os.path.exists(output_dir): os.mkdir(output_dir) face_id = 1 for i in range(len(images)): if labels[i] == biggest_class[0][0]: img, shape = images[i] dlib.save_face_chip(img, shape, output_dir + '/face_%d' % face_id, size=150, padding=0.25) face_id += 1 複製程式碼
物體追蹤
物體追蹤是指,對於視訊檔案,在第一幀指定一個矩形區域,對於後續幀自動追蹤和更新區域的位置
載入庫
# -*- coding: utf-8 -*- import dlib from imageio import imread import glob 複製程式碼
準備好追蹤器和圖片
tracker = dlib.correlation_tracker() win = dlib.image_window() paths = sorted(glob.glob('video_frames/*.jpg')) 複製程式碼
追蹤圖片中的物體
for i, path in enumerate(paths): img = imread(path) # 第一幀,指定一個區域 if i == 0: tracker.start_track(img, dlib.rectangle(74, 67, 112, 153)) # 後續幀,自動追蹤 else: tracker.update(img) win.clear_overlay() win.set_image(img) win.add_overlay(tracker.get_position()) dlib.hit_enter_to_continue() 複製程式碼
儘管物體的位置在不斷變化,Dlib始終能夠比較準確地進行追蹤
