天天看點

Dlib模型實作人臉識别一、安裝dlib庫二、利用dlib實作人臉68個關鍵點檢測并标注三、人臉特征提取四、人臉識别參考連結

文章目錄

  • 一、安裝dlib庫
  • 二、利用dlib實作人臉68個關鍵點檢測并标注
  • 三、人臉特征提取
  • 四、人臉識别
  • 參考連結

環境說明:

python3.6+spyder

第三方庫的說明

skimage,playsound

安裝指令:

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple scikit-image

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple playsound

一、安裝dlib庫

  1. 下載下傳Dlib安裝包

    下載下傳連結:http://dlib.net/files/

    本文章下載下傳的是

    dlib-19.14.zip

    ,下載下傳完成後解壓安裝dlib
  2. 安裝Cmake

    下載下傳連結:https://cmake.org/download/

    下載下傳安裝包直接點選安裝就行,注意環境變量的設定

  3. 下載下傳boost

    下載下傳連結:http://www.boost.org/

    下載下傳之後将其解壓縮,進入解壓後的檔案夾中,找到bootstrap.bat批處理檔案,輕按兩下運作,等待運作完成後(指令行自動消失)會生成檔案b2.exe

    win+R,打開指令行,進入b2.exe所在的檔案夾,運作下面指令 b2編譯庫檔案

    b2 -a -python address-model=64 toolset=msvc runtime-link=static
    #cmake下載下傳的64位這裡(address-model)寫64,如果是32位的就把之前的64改成32
               
    安裝完成後配置boost環境變量
    Dlib模型實作人臉識别一、安裝dlib庫二、利用dlib實作人臉68個關鍵點檢測并标注三、人臉特征提取四、人臉識别參考連結
  4. 安裝dlib

    指令行進入dlib的檔案夾中 安裝完成後,在檔案夾下面會出現dlib,dlib.egg-info,dist的三個檔案夾

    将dlib 和dlib.egg-info 複制對應python環境下的Lib檔案,同時将build\lib.win-amd64-3.6檔案夾下的dlib.cp36-win_amd64.pyd複制到對應python環境下的DLL檔案夾

    測試是否安裝成功(沒有報錯,表示安裝成功)

    Dlib模型實作人臉識别一、安裝dlib庫二、利用dlib實作人臉68個關鍵點檢測并标注三、人臉特征提取四、人臉識别參考連結

二、利用dlib實作人臉68個關鍵點檢測并标注

  1. 下載下傳官方的訓練模型

    下載下傳連結:

    http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2

  2. 人臉檢測和标注
    import numpy as np
    import cv2
    import dlib 
    
    #detector = dlib.get_frontal_face_detector()
    detector=dlib.get_frontal_face_detector()
    predictor = dlib.shape_predictor('E:\\PersonRecognitionDlib\\shape_predictor_68_face_landmarks.dat\\shape_predictor_68_face_landmarks.dat')
    
    # cv2讀取圖像
    img = cv2.imread("E:\\PersonRecognitionDlib\\text.jpg")
    #print(img)
    # 取灰階
    img_gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
    
    # 人臉數rects
    rects = detector(img_gray, 1)
    for i in range(len(rects)):
        landmarks = np.matrix([[p.x, p.y] for p in predictor(img,rects[i]).parts()])
        for idx, point in enumerate(landmarks):
            # 68點的坐标
            pos = (point[0, 0], point[0, 1])
            print(idx,pos)
    
            # 利用cv2.circle給每個特征點畫一個圈,共68個
            cv2.circle(img, pos, 5, color=(0, 255, 0))
            # 利用cv2.putText輸出1-68
            font = cv2.FONT_HERSHEY_SIMPLEX
            cv2.putText(img, str(idx+1), pos, font, 0.8, (0, 0, 255), 1,cv2.LINE_AA)
    
    cv2.namedWindow("img", 2)
    cv2.imshow("img", img)
    cv2.waitKey(0)
               
    标注結果
    Dlib模型實作人臉識别一、安裝dlib庫二、利用dlib實作人臉68個關鍵點檢測并标注三、人臉特征提取四、人臉識别參考連結
    問題描述:

    module 'dlib' has no attribute 'get_frontal_face_detector'

    解決方法:将python環境更換為3.6

三、人臉特征提取

  1. 人臉資料集

    ①使用攝像頭采集(視訊流截圖)

    采集的過程,最好使用同一裝置同一光線下進行采集

    import cv2
    import dlib
    import os
    import sys
    import random
    # 存儲位置
    output_dir = 'D:/myworkspace/JupyterNotebook/People/person/person1'
    size = 64
     
    if not os.path.exists(output_dir):
        os.makedirs(output_dir)
    # 改變圖檔的亮度與對比度
     
    def relight(img, light=1, bias=0):
        w = img.shape[1]
        h = img.shape[0]
        #image = []
        for i in range(0,w):
            for j in range(0,h):
                for c in range(3):
                    tmp = int(img[j,i,c]*light + bias)
                    if tmp > 255:
                        tmp = 255
                    elif tmp < 0:
                        tmp = 0
                    img[j,i,c] = tmp
        return img
     
    #使用dlib自帶的frontal_face_detector作為我們的特征提取器
    detector = dlib.get_frontal_face_detector()
    # 打開攝像頭 參數為輸入流,可以為攝像頭或視訊檔案
    camera = cv2.VideoCapture(0)
    index = 1
    while True:
        if (index <= 15):#存儲15張人臉特征圖像
            print('Being processed picture %s' % index)
            # 從攝像頭讀取照片
            success, img = camera.read()
            # 轉為灰階圖檔
            gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
            # 使用detector進行人臉檢測
            dets = detector(gray_img, 1)
     
            for i, d in enumerate(dets):
                x1 = d.top() if d.top() > 0 else 0
                y1 = d.bottom() if d.bottom() > 0 else 0
                x2 = d.left() if d.left() > 0 else 0
                y2 = d.right() if d.right() > 0 else 0
     
                face = img[x1:y1,x2:y2]
                # 調整圖檔的對比度與亮度, 對比度與亮度值都取随機數,這樣能增加樣本的多樣性
                face = relight(face, random.uniform(0.5, 1.5), random.randint(-50, 50))
     
                face = cv2.resize(face, (size,size))
     
                cv2.imshow('image', face)
     
                cv2.imwrite(output_dir+'/'+str(index)+'.jpg', face)
     
                index += 1
            key = cv2.waitKey(30) & 0xff
            if key == 27:
                break
        else:
            print('Finished!')
            # 釋放攝像頭 release camera
            camera.release()
            # 删除建立的視窗 delete all the windows
            cv2.destroyAllWindows()
            break
               
    Dlib模型實作人臉識别一、安裝dlib庫二、利用dlib實作人臉68個關鍵點檢測并标注三、人臉特征提取四、人臉識别參考連結

    在對應的輸出目錄下,會得到15張攝像頭采集得到的圖檔。

    ②網絡爬蟲擷取

    具體内容可以參考連結:

    https://blog.csdn.net/cungudafa/article/details/87862687

  2. 資料集的處理
  3. 擷取特征點

    ①下載下傳dlib的人臉識别模型

    下載下傳連結:

    https://pan.baidu.com/s/1sBH4TvIfIYLFYs7zCTH4nA

    提取碼:b8zu

    ②擷取每個人68個特征資料并儲存到csv中

    from cv2 import cv2 as cv2
    import os
    import dlib
    from skimage import io
    import csv
    import numpy as np
    
    # 要讀取人臉圖像檔案的路徑
    path_images_from_camera = "E:/PersonRecognitionDlib/Person/"
    
    # Dlib 正向人臉檢測器
    detector = dlib.get_frontal_face_detector()
    
    # Dlib 人臉預測器
    predictor = dlib.shape_predictor("E:/PersonRecognitionDlib/model/shape_predictor_68_face_landmarks.dat")
    
    # Dlib 人臉識别模型
    # Face recognition model, the object maps human faces into 128D vectors
    face_rec = dlib.face_recognition_model_v1("E:/PersonRecognitionDlib/model/dlib_face_recognition_resnet_model_v1.dat")
    
    
    # 傳回單張圖像的 128D 特征
    def return_128d_features(path_img):
        img_rd = io.imread(path_img)
        img_gray = cv2.cvtColor(img_rd, cv2.COLOR_BGR2RGB)
        faces = detector(img_gray, 1)
    
        print("%-40s %-20s" % ("檢測到人臉的圖像 / image with faces detected:", path_img), '\n')
    
        # 因為有可能截下來的人臉再去檢測,檢測不出來人臉了
        # 是以要確定是 檢測到人臉的人臉圖像 拿去算特征
        if len(faces) != 0:
            shape = predictor(img_gray, faces[0])
            face_descriptor = face_rec.compute_face_descriptor(img_gray, shape)
        else:
            face_descriptor = 0
            print("no face")
    
        return face_descriptor
    
    
    # 将檔案夾中照片特征提取出來, 寫入 CSV
    def return_features_mean_personX(path_faces_personX):
        features_list_personX = []
        photos_list = os.listdir(path_faces_personX)
        if photos_list:
            for i in range(len(photos_list)):
                # 調用return_128d_features()得到128d特征
                print("%-40s %-20s" % ("正在讀的人臉圖像 / image to read:", path_faces_personX + "/" + photos_list[i]))
                features_128d = return_128d_features(path_faces_personX + "/" + photos_list[i])
                #  print(features_128d)
                # 遇到沒有檢測出人臉的圖檔跳過
                if features_128d == 0:
                    i += 1
                else:
                    features_list_personX.append(features_128d)
        else:
            print("檔案夾内圖像檔案為空 / Warning: No images in " + path_faces_personX + '/', '\n')
    
        # 計算 128D 特征的均值
        # N x 128D -> 1 x 128D
        if features_list_personX:
            features_mean_personX = np.array(features_list_personX).mean(axis=0)
        else:
            features_mean_personX = '0'
    
        return features_mean_personX
    
    
    # 讀取某人所有的人臉圖像的資料
    people = os.listdir(path_images_from_camera)
    people.sort()
    
    with open("E:/PersonRecognitionDlib/feature/features2_all.csv", "w", newline="") as csvfile:
        writer = csv.writer(csvfile)
        for person in people:
            print("##### " + person + " #####")
            # Get the mean/average features of face/personX, it will be a list with a length of 128D
            features_mean_personX = return_features_mean_personX(path_images_from_camera + person)
            writer.writerow(features_mean_personX)
            print("特征均值 / The mean of features:", list(features_mean_personX))
            print('\n')
        print("所有錄入人臉資料存入 / Save all the features of faces registered into: D:/myworkspace/JupyterNotebook/People/feature/features_all2.csv")
               
    Dlib模型實作人臉識别一、安裝dlib庫二、利用dlib實作人臉68個關鍵點檢測并标注三、人臉特征提取四、人臉識别參考連結

四、人臉識别

  1. 計算距離——歐氏距離

    将要識别的對象與已經存在的對象進行距離計算

    def return_euclidean_distance(feature_1, feature_2):
        feature_1 = np.array(feature_1)
        feature_2 = np.array(feature_2)
        dist = np.sqrt(np.sum(np.square(feature_1 - feature_2)))
        return dist
               
  2. 實作人臉識别
    # 攝像頭實時人臉識别
    import os
    import winsound # 系統音效
    from playsound import playsound # 音頻播放
    import dlib          # 人臉處理的庫 Dlib
    import csv # 存入表格
    import time
    import sys
    import numpy as np   # 資料處理的庫 numpy
    from cv2 import cv2 as cv2           # 圖像處理的庫 OpenCv
    import pandas as pd  # 資料處理的庫 Pandas
    
    
    # 人臉識别模型,提取128D的特征矢量
    # face recognition model, the object maps human faces into 128D vectors
    # Refer this tutorial: http://dlib.net/python/index.html#dlib.face_recognition_model_v1
    facerec = dlib.face_recognition_model_v1("E:/PersonRecognitionDlib/model/dlib_face_recognition_resnet_model_v1.dat")
    
    
    # 計算兩個128D向量間的歐式距離
    # compute the e-distance between two 128D features
    def return_euclidean_distance(feature_1, feature_2):
        feature_1 = np.array(feature_1)
        feature_2 = np.array(feature_2)
        dist = np.sqrt(np.sum(np.square(feature_1 - feature_2)))
        return dist
    
    
    # 處理存放所有人臉特征的 csv
    path_features_known_csv = "E:/PersonRecognitionDlib/feature/features2_all.csv"
    csv_rd = pd.read_csv(path_features_known_csv, header=None)
    
    
    # 用來存放所有錄入人臉特征的數組
    # the array to save the features of faces in the database
    features_known_arr = []
    
    # 讀取已知人臉資料
    # print known faces
    for i in range(csv_rd.shape[0]):
        features_someone_arr = []
        for j in range(0, len(csv_rd.iloc[i, :])):
            features_someone_arr.append(csv_rd.iloc[i, :][j])
        features_known_arr.append(features_someone_arr)
    print("Faces in Database:", len(features_known_arr))
    
    # Dlib 檢測器和預測器
    # The detector and predictor will be used
    detector = dlib.get_frontal_face_detector()
    predictor = dlib.shape_predictor('E:/PersonRecognitionDlib/model/shape_predictor_68_face_landmarks.dat')
    
    # 建立 cv2 攝像頭對象
    # cv2.VideoCapture(0) to use the default camera of PC,
    # and you can use local video name by use cv2.VideoCapture(filename)
    cap = cv2.VideoCapture(0)
    
    # cap.set(propId, value)
    # 設定視訊參數,propId 設定的視訊參數,value 設定的參數值
    cap.set(3, 480)
    
    # cap.isOpened() 傳回 true/false 檢查初始化是否成功
    # when the camera is open
    while cap.isOpened():
    
        flag, img_rd = cap.read()
        kk = cv2.waitKey(1)
    
        # 取灰階
        img_gray = cv2.cvtColor(img_rd, cv2.COLOR_RGB2GRAY)
    
        # 人臉數 faces
        faces = detector(img_gray, 0)
    
        # 待會要寫的字型 font to write later
        font = cv2.FONT_HERSHEY_COMPLEX
    
        # 存儲目前攝像頭中捕獲到的所有人臉的坐标/名字
        # the list to save the positions and names of current faces captured
        pos_namelist = []
        name_namelist = []
    
        # 按下 q 鍵退出
        # press 'q' to exit
        if kk == ord('q'):
            break
        else:
            # 檢測到人臉 when face detected
            if len(faces) != 0:  
                # 擷取目前捕獲到的圖像的所有人臉的特征,存儲到 features_cap_arr
                # get the features captured and save into features_cap_arr
                features_cap_arr = []
                for i in range(len(faces)):
                    shape = predictor(img_rd, faces[i])
                    features_cap_arr.append(facerec.compute_face_descriptor(img_rd, shape))
    
                # 周遊捕獲到的圖像中所有的人臉
                # traversal all the faces in the database
                for k in range(len(faces)):
                    print("##### camera person", k+1, "#####")
                    # 讓人名跟随在矩形框的下方
                    # 确定人名的位置坐标
                    # 先預設所有人不認識,是 unknown
                    # set the default names of faces with "unknown"
                    name_namelist.append("unknown")
    
                    # 每個捕獲人臉的名字坐标 the positions of faces captured
                    pos_namelist.append(tuple([faces[k].left(), int(faces[k].bottom() + (faces[k].bottom() - faces[k].top())/4)]))
    
                    # 對于某張人臉,周遊所有存儲的人臉特征
                    # for every faces detected, compare the faces in the database
                    e_distance_list = []
                    for i in range(len(features_known_arr)):
                        # 如果 person_X 資料不為空
                        if str(features_known_arr[i][0]) != '0.0':
                            print("with person", str(i + 1), "the e distance: ", end='')
                            e_distance_tmp = return_euclidean_distance(features_cap_arr[k], features_known_arr[i])
                            print(e_distance_tmp)
                            e_distance_list.append(e_distance_tmp)
                        else:
                            # 空資料 person_X
                            e_distance_list.append(999999999)
                    # 找出最接近的一個人臉資料是第幾個
                    # Find the one with minimum e distance
                    similar_person_num = e_distance_list.index(min(e_distance_list))
                    print("Minimum e distance with person", int(similar_person_num)+1)
                    
                    # 計算人臉識别特征與資料集特征的歐氏距離
                    # 距離小于0.4則标出為可識别人物
                    if min(e_distance_list) < 0.4:
                        # 這裡可以修改攝像頭中标出的人名
                        # Here you can modify the names shown on the camera
                        # 1、周遊檔案夾目錄
                        folder_name = 'E:/PersonRecognitionDlib/Person'
                        # 最接近的人臉
                        sum=similar_person_num+1
                        key_id=1 # 從第一個人臉資料檔案夾進行對比
                        # 擷取檔案夾中的檔案名:LQH、YYQX、WY、WL...
                        file_names = os.listdir(folder_name)
                        for name in file_names:
                            # print(name+'->'+str(key_id))
                            if sum ==key_id:
                                #winsound.Beep(300,500)# 響鈴:300頻率,500持續時間
                                name_namelist[k] = name[0:]#人名删去第一個數字(用于視訊輸出辨別)
                            key_id += 1
                        # 播放歡迎光臨音效
                        #playsound('D:/myworkspace/JupyterNotebook/People/music/welcome.wav')
                        # print("May be person "+str(int(similar_person_num)+1))
                        # -----------篩選出人臉并儲存到visitor檔案夾------------
                        for i, d in enumerate(faces):
                            x1 = d.top() if d.top() > 0 else 0
                            y1 = d.bottom() if d.bottom() > 0 else 0
                            x2 = d.left() if d.left() > 0 else 0
                            y2 = d.right() if d.right() > 0 else 0
                            face = img_rd[x1:y1,x2:y2]
                            size = 64
                            face = cv2.resize(face, (size,size))
                            # 要存儲visitor人臉圖像檔案的路徑
                            path_visitors_save_dir = "E:/PersonRecognitionDlib/visitor/known"
                            # 存儲格式:2019-06-24-14-33-40LQH.jpg
                            now_time = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime())
                            save_name = str(now_time)+str(name_namelist[k])+'.jpg'
                            # print(save_name)
                            # 本次圖檔儲存的完整url
                            save_path = path_visitors_save_dir+'/'+ save_name    
                            # 周遊visitor檔案夾所有檔案名
                            visitor_names = os.listdir(path_visitors_save_dir)
                            visitor_name=''
                            for name in visitor_names:
                                # 名字切片到分鐘數:2019-06-26-11-33-00LQH.jpg
                                visitor_name=(name[0:16]+'-00'+name[19:])
                            # print(visitor_name)
                            visitor_save=(save_name[0:16]+'-00'+save_name[19:])
                            # print(visitor_save)
                            # 一分鐘之内重複的人名不儲存
                            if visitor_save!=visitor_name:
                                cv2.imwrite(save_path, face)
                                print('新存儲:'+path_visitors_save_dir+'/'+str(now_time)+str(name_namelist[k])+'.jpg')
                            else:
                                print('重複,未儲存!')
                                
                    else:
                        # 播放無法識别音效
                        #playsound('D:/myworkspace/JupyterNotebook/People/music/sorry.wav')
                        print("Unknown person")
                        # -----儲存圖檔-------
                        # -----------篩選出人臉并儲存到visitor檔案夾------------
                        for i, d in enumerate(faces):
                            x1 = d.top() if d.top() > 0 else 0
                            y1 = d.bottom() if d.bottom() > 0 else 0
                            x2 = d.left() if d.left() > 0 else 0
                            y2 = d.right() if d.right() > 0 else 0
                            face = img_rd[x1:y1,x2:y2]
                            size = 64
                            face = cv2.resize(face, (size,size))
                            # 要存儲visitor-》unknown人臉圖像檔案的路徑
                            path_visitors_save_dir = "E:/PersonRecognitionDlib/visitor/unknown"
                            # 存儲格式:2019-06-24-14-33-40unknown.jpg
                            now_time = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime())
                            # print(save_name)
                            # 本次圖檔儲存的完整url
                            save_path = path_visitors_save_dir+'/'+ str(now_time)+'unknown.jpg'
                            cv2.imwrite(save_path, face)
                            print('新存儲:'+path_visitors_save_dir+'/'+str(now_time)+'unknown.jpg')
                    
                    # 矩形框
                    # draw rectangle
                    for kk, d in enumerate(faces):
                        # 繪制矩形框
                        cv2.rectangle(img_rd, tuple([d.left(), d.top()]), tuple([d.right(), d.bottom()]), (0, 255, 255), 2)
                    print('\n')
    
                # 在人臉框下面寫人臉名字
                # write names under rectangle
                for i in range(len(faces)):
                    cv2.putText(img_rd, name_namelist[i], pos_namelist[i], font, 0.8, (0, 255, 255), 1, cv2.LINE_AA)
    
        print("Faces in camera now:", name_namelist, "\n")
    
        #cv2.putText(img_rd, "Press 'q': Quit", (20, 450), font, 0.8, (84, 255, 159), 1, cv2.LINE_AA)
        cv2.putText(img_rd, "Face Recognition", (20, 40), font, 1, (0, 0, 255), 1, cv2.LINE_AA)
        cv2.putText(img_rd, "Visitors: " + str(len(faces)), (20, 100), font, 1, (0, 0, 255), 1, cv2.LINE_AA)
    
        # 視窗顯示 show with opencv
        cv2.imshow("camera", img_rd)
    
    # 釋放攝像頭 release camera
    cap.release()
    
    # 删除建立的視窗 delete all the windows
    cv2.destroyAllWindows()
               
    整個過程是先進行人臉的檢測,檢測攝像頭所采集到的人臉,然後将檢測到的人臉對象與資料集中的人臉68個特征點進行一個距離計算,然後,選出最接近的那個人,接着判斷距離小于0.4,就可以辨別出識别人物。
    Dlib模型實作人臉識别一、安裝dlib庫二、利用dlib實作人臉68個關鍵點檢測并标注三、人臉特征提取四、人臉識别參考連結
    Dlib模型實作人臉識别一、安裝dlib庫二、利用dlib實作人臉68個關鍵點檢測并标注三、人臉特征提取四、人臉識别參考連結

參考連結

  1. python3.7添加dlib子產品
  2. python+OpenCv+dlib實作人臉68個關鍵點檢測并标注
  3. 基于dlib庫人臉特征提取【建構自己的人臉識别資料集】

繼續閱讀