iT邦幫忙

2021 iThome 鐵人賽

DAY 16
0
AI & Data

[Computer Vision] 電腦視覺下的人臉系列 第 16

[Day 16] Facial Recognition - Local Binary Patterns (LBPs)

如果說特徵臉方法是嬰兒,我會說局部二值方法是會跑會跳的幼兒

局部二值方法(Local Binary Patterns),透過將
圖片中的每一個像素,與其相鄰的其他像素做值的大小比對與加總,得出一個圖片全域相對值

lbp_1
圖片左方是原始人臉,右方是計算LBP後的結果

從上圖有幾個重點可以看出:

  • 整塊區域有類似的特徵或顏色 (如頭髮、臉部等),在執行LBP後得出的值相對比較小而且差異不大
  • LBP中顏色較深的,對應到原始圖片大多是人臉的特徵 (如眉毛、眼睛、鼻子等),這類特徵就是經過LBP後可以用來辨識

理論上,我們是可以透過LBP計算後的特徵值,跟昨天介紹的特徵臉方法一樣,來用作人臉辨識 (只要特徵一樣就表示同一人);

但實際上直接使用LBP的特徵值會受特徵相對位置不一樣而產生很大的誤差(比如說人臉不是照片照、人臉離鏡頭的位置不一樣等等)。

比較可行的方式,是將LBP後的特徵圖片劃分多個等大小的子區域,分別做直方統計圖

然後真正用來辨識的依據是這些直方統計值組合而成的局部二值直方圖 (Local Binary Patterns Histogram)

講這麼多終於進入今天的重點 -- LBPH

接下來我們會使用OpenCV內建的face_LBPHFaceRecognizer來建立我們的人臉辨識。

本文開始

  1. 在前幾天的專案中,找到你的face_recognition目錄,新增一個檔案lbp.py
  2. 在該檔案下新增以下程式碼:
    import ntpath
    import sys
    
    # resolve module import error in PyCharm
    sys.path.append(ntpath.dirname(ntpath.dirname(ntpath.abspath(__file__))))
    
    # 匯入必要套件
    import argparse
    import random
    import time
    
    import cv2
    import numpy as np
    from imutils import paths
    from skimage import feature
    from sklearn.metrics import classification_report
    from sklearn.model_selection import train_test_split
    from sklearn.preprocessing import LabelEncoder
    
    from dataset.load_dataset import images_to_faces
    
    
    def main():
        # 初始化arguments
        ap = argparse.ArgumentParser()
        ap.add_argument("-i", "--input", type=str, required=True, help="the input dataset path")
        args = vars(ap.parse_args())
    
        print("[INFO] loading dataset....")
        (faces, labels) = images_to_faces(args["input"])
        print(f"[INFO] {len(faces)} images in dataset")
    
        # 將名稱從字串轉成整數 (在做訓練時時常會用到這個方法:label encoding)
        le = LabelEncoder()
        labels = le.fit_transform(labels)
    
        # 將資料拆分訓練用與測試用;測試資料佔總資料1/4 (方便後續我們判斷這個方法的準確率)
        split = train_test_split(faces, labels, test_size=0.25, stratify=labels, random_state=9527)
        (trainX, testX, trainY, testY) = split
    
        print("[INFO] training...")
        start = time.time()
        recognizer = cv2.face_LBPHFaceRecognizer().create(radius=1, neighbors=8, grid_x=8, grid_y=8)
        recognizer.train(trainX, trainY)
        end = time.time()
        print(f"[INFO] training took: {round(end - start, 2)} seconds")
    
        # 辨識測試資料
        print("[INFO] predicting...")
        start = time.time()
        predictions = []
        confidence = []
        # loop over the test data
        for i in range(0, len(testX)):
            (prediction, conf) = recognizer.predict(testX[i])
            predictions.append(prediction)
            confidence.append(conf)
        end = time.time()
        print(f"[INFO] training took: {round(end - start, 2)} seconds")
        print(classification_report(testY, predictions, target_names=le.classes_))
    
        # 隨機挑選測試資料來看結果
        idxs = np.random.choice(range(0, len(testY)), size=10, replace=False)
        for i in idxs:
            predName = le.inverse_transform([predictions[i]])[0]
            actualName = le.classes_[testY[i]]
    
            face = np.dstack([testX[i]] * 3)
            face = imutils.resize(face, width=250)
    
            cv2.putText(face, f"pred:{predName}", (5, 25), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2)
            cv2.putText(face, f"actual:{actualName}", (5, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 2)
    
            print(f"[INFO] prediction: {predName}, actual: {actualName}")
            cv2.imshow("Face", face)
            cv2.waitKey(0)
    
    if __name__ == '__main__':
        main()
    
    
  3. 在terminal下輸入python face_recognition/lbp.py -i dataset/caltech_faces觀看結果:
    最後辨識準確率有95% (可以通過更改程式第47行的radiusneighbors參數來提高辨識率)
                   precision    recall  f1-score   support
    
            man_1       0.83      1.00      0.91         5
           man_10       1.00      1.00      1.00         6
           man_11       0.86      1.00      0.92         6
           man_13       1.00      1.00      1.00         5
           man_14       1.00      0.86      0.92         7
           man_15       0.86      1.00      0.92         6
            man_2       1.00      1.00      1.00         5
            man_4       1.00      1.00      1.00         6
            man_5       0.86      1.00      0.92         6
            man_7       1.00      1.00      1.00         5
            man_9       1.00      1.00      1.00         6
          woman_1       1.00      1.00      1.00         5
         woman_10       1.00      1.00      1.00         6
          woman_2       1.00      1.00      1.00         5
          woman_5       1.00      0.67      0.80         6
          woman_6       1.00      0.60      0.75         5
          woman_7       1.00      1.00      1.00         6
          woman_8       0.86      1.00      0.92         6
          woman_9       1.00      1.00      1.00         5
    
         accuracy                           0.95       107
        macro avg       0.96      0.95      0.95       107
     weighted avg       0.96      0.95      0.95       107
    
    辨識完隨機選擇測試圖片驗證
    lbp_2
  4. 我們也可以隨便找一張照片來看看LBP結果圖像化的樣子:
    # 隨機選取一張照片來看LBP的結果
    image_path = random.choice(list(paths.list_images(args["input"])))
    image = cv2.imread(image_path)
    rects = detect(image)
    
    (x, y, w, h) = rects[0]["box"]
    roi = image[y:y + h, x:x + w]
    
    gray = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY)
    lbp = feature.local_binary_pattern(gray, 8, 1, method="default")
    lbp = rescale_intensity(lbp, out_range=(0, 255))
    lbp = lbp.astype("uint8")
    
    img = np.hstack([roi, np.dstack([lbp] * 3)])
    cv2.imshow("img", img)
    cv2.waitKey(0)
    
    lbp_3

結論

  1. 局部二值方法相對昨天的特徵臉方法,辨識的準確度更高 (94% -> 95%)、對原始圖片的亮度或平移旋轉等變化比較不會受影響
  2. 與特徵臉方法一樣,是經由取出圖片中人臉的特徵來比對與辨識,因此原始圖片通常都需要人臉是正面的
  3. OpenCV內建的FaceRecognizer在一些比較簡單的情景中就已經可以提供很高的人臉辨識準確率了

實際應用中 (比如像Day14前言提到的那種情境),人臉辨識會有各種奇怪的狀況發生:

  • 人臉影像過於模糊
  • 人臉太小
  • 有遮蔽物在臉上
  • 假臉 (如使用手機中的相片)
  • ...

因此為了要讓辨識模型更加的完善,我們需要讓模型"學習"如何去辨識人臉。

這將是我們明天談論的內容,See you!


上一篇
[Day 15] Facial Recognition - Eigenfaces
下一篇
[Day 17] Facial Recognition - siamese networks: 只是一個開始
系列文
[Computer Vision] 電腦視覺下的人臉30

尚未有邦友留言

立即登入留言