insightface 是目前公認人臉辨識準確度最高的套件之一,支援 GPU 硬体加速,準確度據官方說法達 99.8%。請先安裝套件如下。
pip install insightface onnxruntime-gpu #有顯示卡 pip install insightface onnxruntime #無顯示卡
人臉偵測
底下是多人臉辨識完整代碼,如果有顯卡,ctx_id 指定要使用的顯卡,編號由 0 開始。若沒顯卡,或不想使用顯卡,編號為 -1。
import insightface
import time
from cv import cv
import cv2
import pylab as plt
img=cv.read("a.jpg")
model = insightface.app.FaceAnalysis()
model.prepare(ctx_id=0) #使用GPU 0
t1=time.time()
faces = model.get(img)
t2=time.time()
print(f"花費時間 : {t2-t1}秒")
for face in faces:
x1, y1, x2, y2 = face.bbox.astype(int)
img=cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2, cv2.LINE_AA)
plt.imshow(img[..., ::-1].copy())
plt.axis("off")
plt.show()

上述如果 ctx_id = -1 約 2 秒多。若使用 RTX 3080 Ti,ctx_id = 0 只需 0.7 秒。
68 個特徵點
人臉有 68 個特徵點,為別如下
0–16 下巴輪廓 17–21 左眉毛 22–26 右眉毛 27–30 鼻樑 31–35 鼻子 36–41 左眼 42–47 右眼 48–59 嘴巴外圈 60–67 嘴巴內圈
請下載如下圖片至專案中

底下代碼可以將 68 個特徵點列出。FaceAnalysis 需載入 buffalo_1 模型,第一次執行會連網下載模型到C:\Users\mahal\.insightface\models 之下。
import time
import insightface
from cv import cv
import cv2
import pylab as plt
import cv2
from insightface.app import FaceAnalysis
img=cv.read("景甜.jpg")
app = FaceAnalysis(name="buffalo_l") # 模型支援68 landmarks
app.prepare(ctx_id=0, det_size=(640,640))
faces = app.get(img)
for face in faces:
print("5 keypoints:", face.kps)
print("68 landmarks shape:", face.landmark_3d_68.shape)
print("68 landmarks shape:", face.landmark_3d_68)
for x, y,_ in face.landmark_3d_68:
cv2.circle(img, (int(x), int(y)), 5, (0, 255, 255), -1)
#cv.write(img, "特徵.jpg")
plt.imshow(img[...,::-1].copy())
plt.axis('off')
plt.show()
結果如下

特徵向量
每個 face 都有 .embedding,裏面有 512 組資料,稱為特徵向量。使用如下計算二組人臉的分數
score=np.dot(test_embedding, embed) / (cv2.norm(test_embedding)*cv2.norm(embed))
各個分數的可能性如下
0.8~1.0 → 同一個人
0.5~0.7 → 可能
<0.4 → 不同人
請下載 face.zip,解開後將 test、train 置於專案之下。底下代碼先計算 ./train 每張圖片的特徵向量並存於 database 變數中,然後取得 ./test 的一張人臉計算特徵向量,再與 database 中的資料逐筆比對。
import os
from cv import cv
import cv2
import pylab as plt
import cv2
from insightface.app import FaceAnalysis
import numpy as np
app = FaceAnalysis(name="buffalo_l") # 模型支援68 landmarks
app.prepare(ctx_id=0, det_size=(640,640))
database=[]
names=[]
path="./train"
for file in os.listdir(path):
name=file.split(".")[0]
img=cv.read(os.path.join(path,file))
faces = app.get(img)
names.append(name.split("_")[0])
database.append(faces[0].embedding)
database = database / np.linalg.norm(database, axis=1, keepdims=True)
path="./test"
for file in os.listdir(path):
img=cv.read(os.path.join(path,file))
faces = app.get(img)
embed=faces[0].embedding/np.linalg.norm(faces[0].embedding)
scores=database @ embed
score=np.max(scores)
name=names[np.argmax(scores)]
if score < 0.4 : name="查無此人"
print(f"{file} : {name},{score:.6f}")
結果 :
劉亦菲_1.jpg : 劉亦菲,0.532001
劉亦菲_2.jpg : 劉亦菲,0.688530
劉亦菲_3.jpg : 劉亦菲,0.590871
劉浩存_1.jpg : 劉浩存,0.750559
唐嫣_1.jpg : 唐嫣,0.486599
唐嫣_2.jpg : 唐嫣,0.553667
唐嫣_3.jpg : 唐嫣,0.534827
景甜_1.jpg : 景甜,0.522782
景甜_2.jpg : 景甜,0.721469
景甜_3.jpg : 景甜,0.621045
李小冉_1.jpg : 李小冉,0.559545
李小冉_2.jpg : 李小冉,0.496194
李小冉_3.jpg : 李小冉,0.493204
李沁_1.png : 李沁,0.498419
柳岩_1.jpg : 柳岩,0.698833
楊冪_1.jpg : 楊冪,0.571157
田馥甄_1.jpg : 田馥甄,0.524016
虞書欣_1.jpg : 虞書欣,0.466840
虞書欣_2.jpg : 虞書欣,0.505071
虞書欣_3.jpg : 虞書欣,0.434246
許茹芸_1.jpg : 許茹芸,0.546798
趙麗穎_1.jpg : 趙麗穎,0.599677
辛芷蕾_1.jpg : 辛芷蕾,0.616558
辛芷蕾_2.jpg : 辛芷蕾,0.598436
辛芷蕾_3.jpg : 辛芷蕾,0.542310
辛芷蕾_4.jpg : 辛芷蕾,0.676726
陳喬恩_1.jpg : 陳喬恩,0.483464
陳映彤_1.jpg : 陳映彤,0.572368
database @ embed 等同 np.dot(database, embed),也就是求算矩陣的內積。
dlib Windows系統
人臉偵測就屬 dlib 函數庫最精準。dlib 使用 C++ 編寫,應用在機器學習、影像處理以及影像辨識等功能。此套件為 Open Source 且 free ,license 基於 BSD 授權條款。安裝 dlib 套件時是下載原始檔,必需經過編譯才能使用。所以在 Windows 需安裝 cmake 及 Visual Studio 2022 c++桌面開發。
2024/09/01 實際測試,dlib 可以在 Python 3.12.6/Cuda 12.6 正常執行,而且在 Windows10 及 ubunt 24.04 皆沒問題。
CMake : https://cmake.org/download/
Cmake 只有 3.24 版本可以正確編譯,3.25/3.26/3.27皆無法編譯出 GPU 版本。請注意 CMake安裝完後 Pycharm 需退出重新執行。
Visual Studio 2019/2022 : 工具/取得工具與功能, 需安裝 使用 C++的桌面開發,注意一定要使用 VS2019 或 VS2022的版本。VS2020 好像無法編譯出 GPU的版本。

Ubuntu
sudo apt-get install cmake python3-pip
安裝套件
dlib 自 19.21.0 版開始,不論在 Windows 或 Linux , 只要有安裝 Cuda/cudnn,直接使用如下指令即可編出支援 GPU 的 Dlib 版本。
pip install dlib --no-cache-dir
測試 GPU
測試是否支援 GPU 的代碼如下
import dlib print(dlib.DLIB_USE_CUDA) print(dlib.cuda.get_num_devices()) 結果 : True 1
上述結果如果為 True,表示能啟動 GPU 執行
如果 Cmake 或 VS 版本錯誤,卻又安裝了 dlib,則需先移除 Cmake 及 VS ,改裝正確版本。
然後重裝 dlib 時,又會使用 Python cache 安裝先前 dlib 錯誤版本。所以在 PyCharm 重新安裝 dlib 時,要執行如下指令
pip uninstall dlib
pip install dlib --no-cache-dir
Python程式碼
讀取圖片後丟給 dlib.get_frontal_face_detector 人臉偵測器(detector),即會傳回相關人臉的資訊。
detector 函數的第二個參數是指定反取樣 (unsample) 次數,預設值為 0。如果圖片太小,可將其設高一點以提高偵測精準度,當然也較耗時間。
圖檔解析度愈高當然愈精準,但更加耗時。若縮小圖片再偵測,速度較快但較不精準。此時就可以考慮提高反取樣參數。
detector 傳回的人臉資訊為 dlib.rectangle 資料結構, 如
[(256,61) (654,100)]
此結構分別是左上角座標及右下角座標, 可以用 left(), right() 等函數分別取出
import cv2
import dlib
import numpy as np
def resize(src, w=None, h=None, scale=1):
if w is None or h is None:
h, w = src.shape[:2]
w = int(w * scale)
h = int(h * scale)
dst = cv2.resize(src, (w, h), interpolation=cv2.INTER_LINEAR)
return dst
img=cv2.imdecode(np.fromfile('face4.jpg', dtype=np.uint8), cv2.IMREAD_COLOR)
img=resize(img, scale=0.2)
detector = dlib.get_frontal_face_detector()
faces=detector(img, 1)
for f in faces:
x1=f.left()
y1=f.top()
x2=f.right()
y2=f.bottom()
img=cv2.rectangle(img, (x1, y1), (x2, y2), (0,255,0), 2, cv2.LINE_AA)
cv2.imshow("Image", img)
cv2.waitKey(0)
cv2.destroyAllWindows()

偵測分數
dlib 人臉偵測演算法使用方向梯度直方圖(HOG) 的特徵, 加上線性分類器(linear classifier)、影像金字塔(image pyramid) 與滑動窗格 (sliding window) 計算出來。演算的結果會有一個分數,此分數愈大,表示愈接近人臉。分數愈低表示愈接近誤判。調用 detector.run() 即可取得分數
faces, scores, indexs = detector.run(img, 1, 0.5)
上述第二個參數為反取樣次數,第三個參數為分數的門檻值,要超過 0.5 才會列出。至於返回值 indexs 為子偵測器的編號,用來判斷人臉的方向,詳細說明請看官網
完整代碼如下
import cv2
import dlib
def resize(src, w=None, h=None, scale=1):
if w is None or h is None:
h, w = src.shape[:2]
w = int(w * scale)
h = int(h * scale)
dst = cv2.resize(src, (w, h), interpolation=cv2.INTER_LINEAR)
return dst
img=cv2.imdecode(np.fromfile('face4.jpg', dtype=np.uint8), cv2.IMREAD_COLOR)
img=resize(img, scale=0.3)
detector = dlib.get_frontal_face_detector()
faces, scores, indexs=detector.run(img, 1, 0.5)
print(faces)
print(scores)
print(indexs)
for i, f in enumerate(faces):
x1=f.left()
y1=f.top()
x2=f.right()
y2=f.bottom()
img=cv2.rectangle(img, (x1, y1), (x2, y2), (0,255,0), 2, cv2.LINE_AA)
text = f"{indexs[i]}({scores[i]:2.2f})"
cv2.putText(img, text, (x1, y1-5), cv2.FONT_HERSHEY_DUPLEX, 0.4, (0, 0, 255), 1,)
cv2.imshow("Image", img)
cv2.waitKey(0)
cv2.destroyAllWindows()

Web Came 人臉偵測 – GPU版
偵測人臉位置的偵測器,使用 dlib.cnn_face_detection_model_v1 卷積神經網路人臉偵測器,此偵測器需載入 mmod_human_face_detector.data 人臉訓練資料。下網址下載 : mmod_human_face_detector.bz2 。下載完後請將 .bz2 檔解壓縮成 .dat 檔
cnn_face_detection_model_v1 比get_frontal_face_detector 更加的精準,且因使用 GPU 運算,就算偵測影片也非常順暢,感覺不到任何延遲,但如果沒有 GPU 的話就論當別論。
import cv2
import dlib
print(dlib.DLIB_USE_CUDA)
print(dlib.cuda.get_num_devices())
cam=cv2.VideoCapture(0)
cam.set(cv2.CAP_PROP_FRAME_WIDTH, 1920)
cam.set(cv2.CAP_PROP_FRAME_HEIGHT, 1080)
#cam.set(cv2.CAP_PROP_POS_MSEC, 900000)
#detector = dlib.get_frontal_face_detector()
detector=dlib.cnn_face_detection_model_v1('mmod_human_face_detector.dat')
while True:
_,frame=cam.read()
rate=4
h, w, _=frame.shape
x = cv2.resize(
frame,
(int(w/rate), int(h/rate)),
interpolation=cv2.INTER_LINEAR
)
faces=detector(x, 1)
for face in faces:
f=face.rect
x1=f.left()*rate
y1=f.top()*rate
x2=f.right()*rate
y2=f.bottom()*rate
cv2.rectangle(
frame,
(x1, y1),
(x2, y2),
(0,255,0), 2, cv2.LINE_AA)
img=cv2.resize(
frame,
(1280,720),
interpolation=cv2.INTER_LINEAR
)
cv2.imshow("Face",img)
key=cv2.waitKey(1)
if key==ord('q') or key==27:break;
cam.release()
cv2.destroyAllWindows()

