深度有趣 | 14 Dlib快速入門

張巨集倫發表於2019-03-02

簡介

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.datdlib_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始終能夠比較準確地進行追蹤

物體追蹤結果

參考

視訊講解課程

深度有趣(一)