1. 程式人生 > >使用dlib庫進行人臉識別

使用dlib庫進行人臉識別

一、安裝opencv和dlib

我使用的anaconda,安裝比較方便。

安裝opencv,在指定環境下輸入:

conda install opencv

安裝dlib:

conda install -c conda-forge dlib

二、實現

1、專案結構介紹

其中face_detect資料夾儲存檢查到的人臉,face_repo裡是待檢測的人臉照片,face_test裡是用來測試的照片。

2、人臉檢測

定義檢測器和識別模型:

detector = dlib.get_frontal_face_detector()
# detector = dlib.cnn_face_detection_model_v1('mmod_human_face_detector.dat')
sp = dlib.shape_predictor(FLAGS.shape_predictor)
facerec = dlib.face_recognition_model_v1(FLAGS.reco_model)

detector有兩種選擇,其中dlib.cnn_face_detection_model_v1使用的cnn進行檢測。

對於單張圖片的檢測如下:

def return_face_features(path_img):
    img = cv2.imread(path_img)
    if img.shape[0] * img.shape[1] > 400000:  # 對大圖可以進行壓縮,閾值可以自己設定
        img = cv2.resize(img, (0, 0), fx=0.5, fy=0.5)
    dets = detector(img, 1)  # 使用檢測運算元檢測人臉,返回的是所有的檢測到的人臉區域
    print("檢測的人臉影象:", path_img, "\n")
    d = dets[0]     # 預設處理第一個檢測到的人臉區域
    bb = np.zeros(4, dtype=np.int32)
    bb[0] = np.maximum(d.left(), 0)
    bb[1] = np.maximum(d.top(), 0)
    bb[2] = np.minimum(d.right(), img.shape[1])
    bb[3] = np.minimum(d.bottom(), img.shape[0])

    rec = dlib.rectangle(bb[0], bb[1], bb[2], bb[3])
    shape = sp(img, rec)  # 獲取landmark
    face_descriptor = facerec.compute_face_descriptor(img, shape)  # 使用resNet獲取128維的人臉特徵向量
    face_array = np.array(face_descriptor).reshape((1, 128))  # 轉換成numpy中的資料結構

    # 顯示人臉區域
    cv2.rectangle(img, (bb[0], bb[1]), (bb[2], bb[3]), (0, 255, 0), 2)
    cv2.waitKey(2)
    cropped = img[bb[1]:bb[3], bb[0]:bb[2], :]
    scaled = cv2.resize(cropped, (100, 100), interpolation=cv2.INTER_LINEAR)
    cv2.imwrite(os.path.join(FLAGS.detected_faces, path_img.split('\\')[-1]), scaled)
    cv2.imshow('image', img)
    cv2.waitKey(1000)

    return face_array

遍歷face_repo資料夾下所有人的所有圖片,呼叫上述方法進行檢測:

def main():
    data = np.zeros((1, 128))  # 定義一個128維的空向量data
    label = []  # 定義空的list存放人臉的標籤
    for file in os.listdir(FLAGS.input_faces):  # 遍歷目錄下的資料夾及檔案
        path = os.path.join(FLAGS.input_faces, file)
        if os.path.isdir(path):     # 如果是目錄
            feature_tmp = np.zeros((1, 128))
            label_name = file
            img_num = 0
            for image in os.listdir(path):
                if '.jpg' in image or '.png' in image:
                    img_num += 1
                    file_path = os.path.join(path, image)
                    print('current image: {}, current label: {}'.format(file_path, label_name))
                    feature_tmp += return_face_features(file_path)
            if img_num > 0:
                feature = feature_tmp / img_num
                data = np.concatenate((data, feature))  # 儲存每個人的人臉特徵
                label.append(label_name)  # 儲存標籤

    data = data[1:, :]  # 因為data的第一行是128維0向量,所以實際儲存的時候從第二行開始
    np.savetxt(FLAGS.feature_dir, data, fmt='%f')  # 儲存人臉特徵向量合成的矩陣到本地
    label_file = open(FLAGS.label_dir, 'w')
    json.dump(label, label_file)  # 使用json儲存list到本地
    label_file.close()
    cv2.destroyAllWindows()  # 關閉所有的視窗

該過程主要是檢測單張圖片中的人臉,並儲存其人臉特徵資料和其label。此時輸入的照片中應只有一個人臉,以便將不同人的人臉資料記錄下來,作為後續識別對比之用。在這裡將檢測到的人臉擷取並儲存到face_detect資料夾中,如下:

選擇了五個人,每人各有幾張照片,檢測區域還可以。

 3、人臉識別

對於單張圖片的識別過程如下:

def recognition(img):
    dets = detector(img, 1)
    bb = np.zeros(4, dtype=np.int32)
    for k, d in enumerate(dets):
        print("Detection {}: Left: {} Top: {} Right: {} Bottom: {}".format(
            k, d.left(), d.top(), d.right(), d.bottom()))

        bb[0] = np.maximum(d.left(), 0)
        bb[1] = np.maximum(d.top(), 0)
        bb[2] = np.minimum(d.right(), img.shape[1])
        bb[3] = np.minimum(d.bottom(), img.shape[0])
        rec = dlib.rectangle(bb[0], bb[1], bb[2], bb[3])
        shape = sp(img, rec)
        face_descriptor = facerec.compute_face_descriptor(img, shape)

        class_pre = find_most_likely_face(face_descriptor)
        print(class_pre)
        cv2.rectangle(img, (rec.left(), rec.top()), (rec.right(), rec.bottom()), (0, 255, 0), 2)
        cv2.putText(img, class_pre, (rec.left(), rec.top()), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2, cv2.LINE_AA)

    cv2.imshow('image', img)
    cv2.waitKey()

檢測圖片中的人臉(可以有多個),針對每個人臉,將其和儲存的人臉特徵資料進行對比,選擇距離最小的人臉特徵,如果最小距離大於設定閾值,說明該人臉不屬於已儲存的任何一個人。

我隨便找了幾張包含劉詩詩和劉亦菲的照片,測試一下識別效果,其中幾張結果如下:

測試結果發現效果很一般,尤其對於遮擋和側臉。

4、視覺化

可以使用tensorboard對資料進行視覺化

2D效果如下:

圖片資料太少,視覺化效果不好

後續會介紹一下基於face_net的人臉識別,那個效果要好很多。