主頁 >  其他 > Python 3 利用 Dlib 實作攝像頭實時人臉識別

Python 3 利用 Dlib 實作攝像頭實時人臉識別

2021-09-02 07:17:46 其他

引言

利用python開發,對于輸入的攝像頭視頻流,借助Dlib提供的檢測識別模式來進行人臉識別,首先,從攝像頭中錄入(裁剪)人臉圖片存蓄到本地,然后提取特征,構建預設人臉特征,根據摳取的/已有的同一個人多張人臉圖片提取128D特征值,然后計算該人的128D特征均值,然后和攝像頭中實時獲取到的人臉提取出特征值,計算歐式距離,斷定是否同同一張人臉,

識別模式:

基于 Dlib 的 ResNet 預訓練模型(dlib_face_recognition_resnet_model_v1.dat)

識別演算法:

ResNet 神經網路(This model is a ResNet network with 29 conv layers. It's 
essentially a version of the ResNet-34 network from the paper Deep 
Residual Learning for Image Recognition by He, Zhang, Ren, and Sun 
with a few layers removed and the number of filters per layer reduced 
by half)

1.人臉檢測

faces = detector(img_gray, 0) -> <class 'dlib.dlib.rectangles'> -> 

2.計算人臉特征點

shape = predictor(img_rd, faces[i]) -> <class 'dlib.dlib.full_object_detection'> -> 

3.人臉特征描述子

facerec.compute_face_descriptor(img_rd, shape) -> <class 'dlib.dlib.vector'>

呼叫的模式以及大概的耗時:

Features:

·支持人臉資料采集,自行建立人臉資料庫/Support face register

·呼叫攝像頭實時人臉檢測和識別/Using camera to real-time detect and recognize faces

·支持多張人臉/Support multi-faces

·利用OT來加速識別/Use OT to improve FPS

人臉識別/Face Recognition的說明:

Wikipedia上關于人臉識別系統/Face Recognition System的描述:they work by comparing selected facial features from given image with faces within a database.

本專案中就是比較預設的人臉識別的特征和攝像頭實時獲取到的人臉的特征,核心就是提取128D人臉特征,然后計算攝像頭人臉特征和預設的特征臉的歐式距離,進行比對,

效果如下:

1.總體流程

先說下人臉檢測(Face detection)和人臉識別(Face Recognition),前者是達到檢測出場景中人臉的目的就可以了,而后者不僅需要檢測出人臉,還要和已有人臉資料進行對比,識別出是否在資料庫中,或者進行身份標注之類處理,人臉檢測和人臉識別兩者有時候可能會被人理解混淆,實作人臉識別功能,借助的是Dlib官方網中face_recognition.py這個例程:(Link:http://dlib.net/face_recognition.py.html )

我們直接利用“dlib_face_recognition_resnet_model_v1.dat”這個訓練好的resnet模型,提取人臉頭像的128D特征,然后比對不同人臉圖片的128D特征的歐式距離,設定一個閾值來判斷是否為同一張臉:

#face recognition model, the object maps human faces into 128D vectors
facerec = dlib.face_recognition_model_v1("dlib_face_recognition_resnet_model_v1.dat")
 
shape = predictor(img, dets[0])
face_descriptor = facerec.compute_face_descriptor(img, shape)

2.原始碼介紹

主要有

·get_faces_from_camera.py(代號g)

·features_extraction_to_csv.py(代號fe)

·face_reco_from_camera.py(代號fa)

這三個Python檔案,接下來會分別介紹實作功能:

2.1 g/人臉注冊錄入

人臉識別需要將提取到的頭像資料和已有圖片資料進行比對分析,所有這部分代碼實作的功能就是人臉錄入,

程式會生成一個視窗,顯示呼叫的攝像頭實時獲取的影像,

然后根據鍵盤輸入進行人臉捕捉:

·“N”新錄入人臉,新建檔案夾person_X/用來存蓄某人的人臉影像

·“S”開始捕獲人臉,將捕獲到的人臉放到person_X/路徑下

·“Q”退出視窗

攝像頭的呼叫是利用opencv庫的cv2.VideoCapture(0),此處引數為0代表呼叫的是筆記本的默認攝像頭,你也可以讓它呼叫傳入已有的視頻檔案,

可以參考https://github.com/coneypo/Dlib_face_recognition_from_camera/blob/master/how_to_use_camera.py如何通過OpenCV呼叫攝像頭,

get faces from camera.py原始碼:

# Copyright (C) 2020 coneypo
# SPDX-License-Identifier: MIT

# Author:   coneypo
# Blog:     http://www.cnblogs.com/AdaminXie
# GitHub:   https://github.com/coneypo/Dlib_face_recognition_from_camera
# Mail:     coneypo@foxmail.com

# 進行人臉錄入 / Face register

import dlib
import numpy as np
import cv2
import os
import shutil
import time

# Dlib 正向人臉檢測器 / Use frontal face detector of Dlib
detector = dlib.get_frontal_face_detector()


class Face_Register:
    def __init__(self):
        self.path_photos_from_camera = "data/data_faces_from_camera/"
        self.font = cv2.FONT_ITALIC

        self.existing_faces_cnt = 0         # 已錄入的人臉計數器 / cnt for counting saved faces
        self.ss_cnt = 0                     # 錄入 personX 人臉時圖片計數器 / cnt for screen shots
        self.current_frame_faces_cnt = 0    # 錄入人臉計數器 / cnt for counting faces in current frame

        self.save_flag = 1                  # 之后用來控制是否保存影像的 flag / The flag to control if save
        self.press_n_flag = 0               # 之后用來檢查是否先按 'n' 再按 's' / The flag to check if press 'n' before 's'

        # FPS
        self.frame_time = 0
        self.frame_start_time = 0
        self.fps = 0

    # 新建保存人臉影像檔案和資料CSV檔案夾 / Make dir for saving photos and csv
    def pre_work_mkdir(self):
        # 新建檔案夾 / Create folders to save faces images and csv
        if os.path.isdir(self.path_photos_from_camera):
            pass
        else:
            os.mkdir(self.path_photos_from_camera)

    # 洗掉之前存的人臉資料檔案夾 / Delete the old data of faces
    def pre_work_del_old_face_folders(self):
        # 洗掉之前存的人臉資料檔案夾, 洗掉 "/data_faces_from_camera/person_x/"...
        folders_rd = os.listdir(self.path_photos_from_camera)
        for i in range(len(folders_rd)):
            shutil.rmtree(self.path_photos_from_camera+folders_rd[i])
        if os.path.isfile("data/features_all.csv"):
            os.remove("data/features_all.csv")

    # 如果有之前錄入的人臉, 在之前 person_x 的序號按照 person_x+1 開始錄入 / Start from person_x+1
    def check_existing_faces_cnt(self):
        if os.listdir("data/data_faces_from_camera/"):
            # 獲取已錄入的最后一個人臉序號 / Get the order of latest person
            person_list = os.listdir("data/data_faces_from_camera/")
            person_num_list = []
            for person in person_list:
                person_num_list.append(int(person.split('_')[-1]))
            self.existing_faces_cnt = max(person_num_list)

        # 如果第一次存盤或者沒有之前錄入的人臉, 按照 person_1 開始錄入 / Start from person_1
        else:
            self.existing_faces_cnt = 0

    # 獲取處理之后 stream 的幀數 / Update FPS of video stream
    def update_fps(self):
        now = time.time()
        self.frame_time = now - self.frame_start_time
        self.fps = 1.0 / self.frame_time
        self.frame_start_time = now

    # 生成的 cv2 window 上面添加說明文字 / PutText on cv2 window
    def draw_note(self, img_rd):
        # 添加說明 / Add some notes
        cv2.putText(img_rd, "Face Register", (20, 40), self.font, 1, (255, 255, 255), 1, cv2.LINE_AA)
        cv2.putText(img_rd, "FPS:   " + str(self.fps.__round__(2)), (20, 100), self.font, 0.8, (0, 255, 0), 1,
                    cv2.LINE_AA)
        cv2.putText(img_rd, "Faces: " + str(self.current_frame_faces_cnt), (20, 140), self.font, 0.8, (0, 255, 0), 1, cv2.LINE_AA)
        cv2.putText(img_rd, "N: Create face folder", (20, 350), self.font, 0.8, (255, 255, 255), 1, cv2.LINE_AA)
        cv2.putText(img_rd, "S: Save current face", (20, 400), self.font, 0.8, (255, 255, 255), 1, cv2.LINE_AA)
        cv2.putText(img_rd, "Q: Quit", (20, 450), self.font, 0.8, (255, 255, 255), 1, cv2.LINE_AA)

    # 獲取人臉 / Main process of face detection and saving
    def process(self, stream):
        # 1. 新建儲存人臉影像檔案目錄 / Create folders to save photos
        self.pre_work_mkdir()

        # 2. 洗掉 "/data/data_faces_from_camera" 中已有人臉影像檔案 / Uncomment if want to delete the saved faces and start from person_1
        if os.path.isdir(self.path_photos_from_camera):
            self.pre_work_del_old_face_folders()

        # 3. 檢查 "/data/data_faces_from_camera" 中已有人臉檔案
        self.check_existing_faces_cnt()

        while stream.isOpened():
            flag, img_rd = stream.read()        # Get camera video stream
            kk = cv2.waitKey(1)
            faces = detector(img_rd, 0)         # Use Dlib face detector

            # 4. 按下 'n' 新建存盤人臉的檔案夾 / Press 'n' to create the folders for saving faces
            if kk == ord('n'):
                self.existing_faces_cnt += 1
                current_face_dir = self.path_photos_from_camera + "person_" + str(self.existing_faces_cnt)
                os.makedirs(current_face_dir)
                print('\n')
                print("新建的人臉檔案夾 / Create folders: ", current_face_dir)

                self.ss_cnt = 0                 # 將人臉計數器清零 / Clear the cnt of screen shots
                self.press_n_flag = 1           # 已經按下 'n' / Pressed 'n' already

            # 5. 檢測到人臉 / Face detected
            if len(faces) != 0:
                # 矩形框 / Show the ROI of faces
                for k, d in enumerate(faces):
                    # 計算矩形框大小 / Compute the size of rectangle box
                    height = (d.bottom() - d.top())
                    width = (d.right() - d.left())
                    hh = int(height/2)
                    ww = int(width/2)

                    # 6. 判斷人臉矩形框是否超出 480x640 / If the size of ROI > 480x640
                    if (d.right()+ww) > 640 or (d.bottom()+hh > 480) or (d.left()-ww < 0) or (d.top()-hh < 0):
                        cv2.putText(img_rd, "OUT OF RANGE", (20, 300), self.font, 0.8, (0, 0, 255), 1, cv2.LINE_AA)
                        color_rectangle = (0, 0, 255)
                        save_flag = 0
                        if kk == ord('s'):
                            print("請調整位置 / Please adjust your position")
                    else:
                        color_rectangle = (255, 255, 255)
                        save_flag = 1

                    cv2.rectangle(img_rd,
                                  tuple([d.left() - ww, d.top() - hh]),
                                  tuple([d.right() + ww, d.bottom() + hh]),
                                  color_rectangle, 2)

                    # 7. 根據人臉大小生成空的影像 / Create blank image according to the size of face detected
                    img_blank = np.zeros((int(height*2), width*2, 3), np.uint8)

                    if save_flag:
                        # 8. 按下 's' 保存攝像頭中的人臉到本地 / Press 's' to save faces into local images
                        if kk == ord('s'):
                            # 檢查有沒有先按'n'新建檔案夾 / Check if you have pressed 'n'
                            if self.press_n_flag:
                                self.ss_cnt += 1
                                for ii in range(height*2):
                                    for jj in range(width*2):
                                        img_blank[ii][jj] = img_rd[d.top()-hh + ii][d.left()-ww + jj]
                                cv2.imwrite(current_face_dir + "/img_face_" + str(self.ss_cnt) + ".jpg", img_blank)
                                print("寫入本地 / Save into:", str(current_face_dir) + "/img_face_" + str(self.ss_cnt) + ".jpg")
                            else:
                                print("請先按 'N' 來建檔案夾, 按 'S' / Please press 'N' and press 'S'")

            self.current_frame_faces_cnt = len(faces)

            # 9. 生成的視窗添加說明文字 / Add note on cv2 window
            self.draw_note(img_rd)

            # 10. 按下 'q' 鍵退出 / Press 'q' to exit
            if kk == ord('q'):
                break

            # 11. Update FPS
            self.update_fps()

            cv2.namedWindow("camera", 1)
            cv2.imshow("camera", img_rd)

    def run(self):
        cap = cv2.VideoCapture(0)
        self.process(cap)

        cap.release()
        cv2.destroyAllWindows()


def main():
    Face_Register_con = Face_Register()
    Face_Register_con.run()


if __name__ == '__main__':
    main()

考慮到有可能需要保存的矩形框超出攝像頭范圍,對于這種例外,如果矩形框超出范圍,矩形框就會從白變紅,然后提示“OUT OF RANGE”

get_face_from_camera.py的輸出log

新建的人臉檔案夾 / Create folders:  data/data_faces_from_camera/person_1
寫入本地 / Save into: data/data_faces_from_camera/person_1/img_face_1.jpg
寫入本地 / Save into: data/data_faces_from_camera/person_1/img_face_2.jpg
寫入本地 / Save into: data/data_faces_from_camera/person_1/img_face_3.jpg
寫入本地 / Save into: data/data_faces_from_camera/person_1/img_face_4.jpg


新建的人臉檔案夾 / Create folders:  data/data_faces_from_camera/person_2
寫入本地 / Save into: data/data_faces_from_camera/person_2/img_face_1.jpg
寫入本地 / Save into: data/data_faces_from_camera/person_2/img_face_2.jpg


新建的人臉檔案夾 / Create folders:  data/data_faces_from_camera/person_3
寫入本地 / Save into: data/data_faces_from_camera/person_3/img_face_1.jpg
寫入本地 / Save into: data/data_faces_from_camera/person_3/img_face_2.jpg

2.2 fa/將影像檔案中人臉資料提取出來存入CSV

這部分代碼實作的功能是將之前捕獲到的人臉影像檔案,提取出128D特征,然后計算出某人人臉資料的特征均值存入CSV中,方便之后識別時候進行比對,利用numpy.mean()計算特征均值,生成一個存盤所有錄入人臉資料database的“features_all.csv”,

features extraction to csv.py原始碼:

# Copyright (C) 2020 coneypo
# SPDX-License-Identifier: MIT

# Author:   coneypo
# Blog:     http://www.cnblogs.com/AdaminXie
# GitHub:   https://github.com/coneypo/Dlib_face_recognition_from_camera
# Mail:     coneypo@foxmail.com

# 從人臉影像檔案中提取人臉特征存入 "features_all.csv" / Extract features from images and save into "features_all.csv"

import os
import dlib
from skimage import io
import csv
import numpy as np

# 要讀取人臉影像檔案的路徑 / Path of cropped faces
path_images_from_camera = "data/data_faces_from_camera/"

# Dlib 正向人臉檢測器 / Use frontal face detector of Dlib
detector = dlib.get_frontal_face_detector()

# Dlib 人臉 landmark 特征點檢測器 / Get face landmarks
predictor = dlib.shape_predictor('data/data_dlib/shape_predictor_68_face_landmarks.dat')

# Dlib Resnet 人臉識別模型,提取 128D 的特征矢量 / Use Dlib resnet50 model to get 128D face descriptor
face_reco_model = dlib.face_recognition_model_v1("data/data_dlib/dlib_face_recognition_resnet_model_v1.dat")


# 回傳單張影像的 128D 特征 / Return 128D features for single image
# Input:    path_img           <class 'str'>
# Output:   face_descriptor    <class 'dlib.vector'>
def return_128d_features(path_img):
    img_rd = io.imread(path_img)
    faces = detector(img_rd, 1)

    print("%-40s %-20s" % ("檢測到人臉的影像 / Image with faces detected:", path_img), '\n')

    # 因為有可能截下來的人臉再去檢測,檢測不出來人臉了, 所以要確保是 檢測到人臉的人臉影像拿去算特征
    # For photos of faces saved, we need to make sure that we can detect faces from the cropped images
    if len(faces) != 0:
        shape = predictor(img_rd, faces[0])
        face_descriptor = face_reco_model.compute_face_descriptor(img_rd, shape)
    else:
        face_descriptor = 0
        print("no face")
    return face_descriptor


# 回傳 personX 的 128D 特征均值 / Return the mean value of 128D face descriptor for person X
# Input:    path_faces_personX       <class 'str'>
# Output:   features_mean_personX    <class 'numpy.ndarray'>
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 特征 / Get 128D features for single image of personX
            print("%-40s %-20s" % ("正在讀的人臉影像 / Reading image:", path_faces_personX + "/" + photos_list[i]))
            features_128d = return_128d_features(path_faces_personX + "/" + photos_list[i])
            # 遇到沒有檢測出人臉的圖片跳過 / Jump if no face detected from image
            if features_128d == 0:
                i += 1
            else:
                features_list_personX.append(features_128d)
    else:
        print("檔案夾內影像檔案為空 / Warning: No images in " + path_faces_personX + '/', '\n')

    # 計算 128D 特征的均值 / Compute the mean
    # personX 的 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 = np.zeros(128, dtype=int, order='C')
    print(type(features_mean_personX))
    return features_mean_personX


# 獲取已錄入的最后一個人臉序號 / Get the order of latest person
person_list = os.listdir("data/data_faces_from_camera/")
person_num_list = []
for person in person_list:
    person_num_list.append(int(person.split('_')[-1]))
person_cnt = max(person_num_list)

with open("data/features_all.csv", "w", newline="") as csvfile:
    writer = csv.writer(csvfile)
    for person in range(person_cnt):
        # Get the mean/average features of face/personX, it will be a list with a length of 128D
        print(path_images_from_camera + "person_" + str(person + 1))
        features_mean_personX = return_features_mean_personX(path_images_from_camera + "person_" + str(person + 1))
        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: data/features_all.csv")

我們可以看下對于某張圖片,face_descriptor這個128D vectors的輸出結果:

綠框我們的回傳128D特征的函式,

紅框呼叫該函式來計算img_face_13.jpg,

黃框輸出為128D的向量,

之后就需要人臉影像進行批量化操作,提取出128D的特征,然后計算特征均值,存入features_all.csv是一個n行的CSV,n是錄入的人臉數,128列是某人的128D特征,這存盤的就是錄入的人臉資料,之后攝像頭捕獲的人臉將要過來和這些特征均值進行比對,如果歐式距離比較近的話,就可以認為是同一張人臉

get_festures_into_CSV.py的輸出log:

##### person_1 #####
data/data_csvs_from_camera/person_1.csv
正在讀的人臉影像 / image to read:                data/data_faces_from_camera/person_1/img_face_1.jpg
檢測到人臉的影像 / image with faces detected:    data/data_faces_from_camera/person_1/img_face_1.jpg 

正在讀的人臉影像 / image to read:                data/data_faces_from_camera/person_1/img_face_2.jpg
檢測到人臉的影像 / image with faces detected:    data/data_faces_from_camera/person_1/img_face_2.jpg 

正在讀的人臉影像 / image to read:                data/data_faces_from_camera/person_1/img_face_3.jpg
檢測到人臉的影像 / image with faces detected:    data/data_faces_from_camera/person_1/img_face_3.jpg 

正在讀的人臉影像 / image to read:                data/data_faces_from_camera/person_1/img_face_4.jpg
檢測到人臉的影像 / image with faces detected:    data/data_faces_from_camera/person_1/img_face_4.jpg 

##### person_2 #####
data/data_csvs_from_camera/person_2.csv
正在讀的人臉影像 / image to read:                data/data_faces_from_camera/person_2/img_face_1.jpg
檢測到人臉的影像 / image with faces detected:    data/data_faces_from_camera/person_2/img_face_1.jpg 

正在讀的人臉影像 / image to read:                data/data_faces_from_camera/person_2/img_face_2.jpg
檢測到人臉的影像 / image with faces detected:    data/data_faces_from_camera/person_2/img_face_2.jpg 

##### person_3 #####
data/data_csvs_from_camera/person_3.csv
正在讀的人臉影像 / image to read:                data/data_faces_from_camera/person_3/img_face_1.jpg
檢測到人臉的影像 / image with faces detected:    data/data_faces_from_camera/person_3/img_face_1.jpg 

正在讀的人臉影像 / image to read:                data/data_faces_from_camera/person_3/img_face_2.jpg
檢測到人臉的影像 / image with faces detected:    data/data_faces_from_camera/person_3/img_face_2.jpg 


...

2.3 fa/實時人臉識別對比分析

這部分原始碼實作的功能:呼叫攝像頭,捕獲攝像頭中的人臉,然后如果檢測到人臉,將攝像頭中的人臉提取出128D的特征,然后和之前錄入人臉的128D特征進行計算歐式距離,如果比較小,可以判定為一個人,否則不是一個人:

所以設計的偽代碼如下:

# 人臉檢測器/預測器/識別模型
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor('data/data_dlib/shape_predictor_68_face_landmarks.dat')
facerec = dlib.face_recognition_model_v1("data/data_dlib/dlib_face_recognition_resnet_model_v1.dat")

faces = detector(img_gray, 0)

# 1. 如果檢測到人臉
if len(faces) != 0:
    # 遍歷所有檢測到的人臉
    for i in range(len(faces)):
        # 2. 提取當前幀人臉的特征描述子
        shape = predictor(img_rd, faces[i])
        facerec.compute_face_descriptor(img_rd, shape)
        # 3. 將當前幀人臉特征描述子和資料庫的特征描述子進行對比
        for i in range(len(self.features_known_list)):
            e_distance_tmp = self.return_euclidean_distance(self.features_camera_list[k], self.features_known_list[i])

關于 https://github.com/coneypo/Dlib_face_recognition_from_camera/blob/master/face_reco_from_camera.py里面變數的定義:

變數說明
self.feature_known_list存盤所有錄入人臉特征的陣列/Save the features of faces in the database
self.name_known_list存盤已錄入人臉的名字/Save the names of faces in the database
self.current_frame_face_cnt存盤當前攝像頭中捕獲到的人臉數/Counter for faces in current frame
self.current_frame_name_position_list存盤當前攝像頭中捕獲到的所有人臉的名字坐標/Positions of faces in current frame
self.current_frame_feature_list存盤當前攝像頭中捕獲到的人臉特征/Features of faces in current frame
self.current_frame_name_list存盤當前攝像頭中捕獲到的所有人臉的名字/Names of faces in current frame

關于用到dlib檢測器,預測器,識別器:

1.dlib.get_frontal_face_detector

Link:

http://dlib.net/python/index.html#dlib.get_frontal_face_detector

介紹:

回傳默認的人檢測器,為下面的fhog_object_detectorm/Returns the default face detector

2.class dlib.fhog_object_detector

Link:

http://dlib.net/python/index.html#dlib.fhog_object_detector

介紹:

基于滑動窗的HOG進行目標檢測,

This object represents a sliding window histogram-of-oriented-gradients based object detector.

引數:

__call__(self: dlib.fhog_object_detector, image: array, upsample_num_times: int=0L) → dlib.rectangles

3.class dlib.shape_predicter

Link:

http://dlib.net/python/index.html#dlib.shape_predictor

引數/parameters:

__call__(self: dlib.shape_predictor, image: array, box: dlib.rectangle) → dlib.full_object_detection

輸入:dlib.rectangle輸出:dlib.full_recognition_model_v1

引數/parameters:

compute_face_descriptor(self: dlib.face_recognition_model_v1, img: numpy.ndarray[(rows,cols,3),uint8], face: dlib.full_object_detection, num_jitters: int=0L, padding: float=0.25) -> dlib.vector

通過print(type())可以更清楚的看到dlib物件的傳遞:

# 人臉檢測器/預測器/識別模型
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor('data/data_dlib/shape_predictor_68_face_landmarks.dat')
facerec = dlib.face_recognition_model_v1("data/data_dlib/dlib_face_recognition_resnet_model_v1.dat")

faces = detector(img_gray, 0)

# 如果檢測到人臉
if len(faces) != 0:
    print(type(faces)                                                # <class 'dlib.dlib.rectangles'>
    # 遍歷所有檢測到的人臉
    for i in range(len(faces)):
        # 進行人臉比對
        shape = predictor(img_rd, faces[i])
        print(type(shape))                                            # <class 'dlib.dlib.full_object_detection'>
        facerec.compute_face_descriptor(img_rd, shape)
        print(type(facerec.compute_face_descriptor(img_rd, shape))    # <class 'dlib.dlib.vector'>

這樣一個物件傳遞程序:

faces = detector(img_gray, 0) -> <class 'dlib.dlib.rectangles'> -> 
shape = predictor(img_rd, faces[i]) -> <class 'dlib.dlib.full_object_detection'> -> 
facerec.compute_face_descriptor(img_rd, shape) -> <class 'dlib.dlib.vector'>

歐式距離對比的閾值設定,是在return_euclidean_distance函式的dist變數,我這里程式里面的指定的歐式距離判斷閾值是0.4,具體閾值可以根據實際情況或者測得結果進行修改,

這邊做了一個,讓人名跟隨顯示在頭像下方,如果想要在人臉矩形框下方顯示人名,首先想要知道Dlib生成的矩形框的尺寸怎么讀取,

Dlib回傳的dets變數是一系人臉的資料,此處對單張人臉處理,所有取dets[0]的引數,

可以通過dets[0].top(),dets[0].bottom(),dets[0].left()和dets[0].right()來確定要顯示的人名的坐標

得到矩形框的坐標,就可以獲取人名的相對位置,

face reco from camera.py原始碼:

# Copyright (C) 2020 coneypo
# SPDX-License-Identifier: MIT

# Author:   coneypo
# Blog:     http://www.cnblogs.com/AdaminXie
# GitHub:   https://github.com/coneypo/Dlib_face_recognition_from_camera
# Mail:     coneypo@foxmail.com

# 攝像頭實時人臉識別 / Real-time face detection and recognition

import dlib
import numpy as np
import cv2
import pandas as pd
import os
import time
from PIL import Image, ImageDraw, ImageFont

# Dlib 正向人臉檢測器 / Use frontal face detector of Dlib
detector = dlib.get_frontal_face_detector()

# Dlib 人臉 landmark 特征點檢測器 / Get face landmarks
predictor = dlib.shape_predictor('data/data_dlib/shape_predictor_68_face_landmarks.dat')

# Dlib Resnet 人臉識別模型,提取 128D 的特征矢量 / Use Dlib resnet50 model to get 128D face descriptor
face_reco_model = dlib.face_recognition_model_v1("data/data_dlib/dlib_face_recognition_resnet_model_v1.dat")


class Face_Recognizer:
    def __init__(self):
        self.feature_known_list = []                # 用來存放所有錄入人臉特征的陣列 / Save the features of faces in the database
        self.name_known_list = []                   # 存盤錄入人臉名字 / Save the name of faces in the database

        self.current_frame_face_cnt = 0             # 存盤當前攝像頭中捕獲到的人臉數 / Counter for faces in current frame
        self.current_frame_feature_list = []        # 存盤當前攝像頭中捕獲到的人臉特征 / Features of faces in current frame
        self.current_frame_name_position_list = []  # 存盤當前攝像頭中捕獲到的所有人臉的名字坐標 / Positions of faces in current frame
        self.current_frame_name_list = []           # 存盤當前攝像頭中捕獲到的所有人臉的名字 / Names of faces in current frame

        # Update FPS
        self.fps = 0
        self.frame_start_time = 0

    # 從 "features_all.csv" 讀取錄入人臉特征 / Get known faces from "features_all.csv"
    def get_face_database(self):
        if os.path.exists("data/features_all.csv"):
            path_features_known_csv = "data/features_all.csv"
            csv_rd = pd.read_csv(path_features_known_csv, header=None)
            for i in range(csv_rd.shape[0]):
                features_someone_arr = []
                for j in range(0, 128):
                    if csv_rd.iloc[i][j] == '':
                        features_someone_arr.append('0')
                    else:
                        features_someone_arr.append(csv_rd.iloc[i][j])
                self.feature_known_list.append(features_someone_arr)
                self.name_known_list.append("Person_"+str(i+1))
            print("Faces in Database:", len(self.feature_known_list))
            return 1
        else:
            print('##### Warning #####', '\n')
            print("'features_all.csv' not found!")
            print(
                "Please run 'get_faces_from_camera.py' and 'features_extraction_to_csv.py' before 'face_reco_from_camera.py'",
                '\n')
            print('##### End Warning #####')
            return 0

    # 計算兩個128D向量間的歐式距離 / Compute the e-distance between two 128D features
    @staticmethod
    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

    # 更新 FPS / Update FPS of Video stream
    def update_fps(self):
        now = time.time()
        self.frame_time = now - self.frame_start_time
        self.fps = 1.0 / self.frame_time
        self.frame_start_time = now

    def draw_note(self, img_rd):
        font = cv2.FONT_ITALIC

        cv2.putText(img_rd, "Face Recognizer", (20, 40), font, 1, (255, 255, 255), 1, cv2.LINE_AA)
        cv2.putText(img_rd, "FPS:   " + str(self.fps.__round__(2)), (20, 100), font, 0.8, (0, 255, 0), 1, cv2.LINE_AA)
        cv2.putText(img_rd, "Faces: " + str(self.current_frame_face_cnt), (20, 140), font, 0.8, (0, 255, 0), 1, cv2.LINE_AA)
        cv2.putText(img_rd, "Q: Quit", (20, 450), font, 0.8, (255, 255, 255), 1, cv2.LINE_AA)

    def draw_name(self, img_rd):
        # 在人臉框下面寫人臉名字 / Write names under rectangle
        font = ImageFont.truetype("simsun.ttc", 30)
        img = Image.fromarray(cv2.cvtColor(img_rd, cv2.COLOR_BGR2RGB))
        draw = ImageDraw.Draw(img)
        for i in range(self.current_frame_face_cnt):
            # cv2.putText(img_rd, self.current_frame_name_list[i], self.current_frame_name_position_list[i], font, 0.8, (0, 255, 255), 1, cv2.LINE_AA)
            draw.text(xy=self.current_frame_name_position_list[i], text=self.current_frame_name_list[i], font=font)
            img_with_name = cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)
        return img_with_name

    # 修改顯示人名 / Show names in chinese
    def show_chinese_name(self):
        # Default known name: person_1, person_2, person_3
        if self.current_frame_face_cnt >= 1:
            self.name_known_list[0] ='張三'.encode('utf-8').decode()
        # self.name_known_list[1] ='李四'.encode('utf-8').decode()
        # self.name_known_list[2] ='xx'.encode('utf-8').decode()
        # self.name_known_list[3] ='xx'.encode('utf-8').decode()
        # self.name_known_list[4] ='xx'.encode('utf-8').decode()

    # 處理獲取的視頻流,進行人臉識別 / Face detection and recognition from input video stream
    def process(self, stream):
        # 1. 讀取存放所有人臉特征的 csv / Get faces known from "features.all.csv"
        if self.get_face_database():
            while stream.isOpened():
                print(">>> Frame start")
                flag, img_rd = stream.read()
                faces = detector(img_rd, 0)
                kk = cv2.waitKey(1)
                # 按下 q 鍵退出 / Press 'q' to quit
                if kk == ord('q'):
                    break
                else:
                    self.draw_note(img_rd)
                    self.current_frame_feature_list = []
                    self.current_frame_face_cnt = 0
                    self.current_frame_name_position_list = []
                    self.current_frame_name_list = []

                    # 2. 檢測到人臉 / Face detected in current frame
                    if len(faces) != 0:
                        # 3. 獲取當前捕獲到的影像的所有人臉的特征 / Compute the face descriptors for faces in current frame
                        for i in range(len(faces)):
                            shape = predictor(img_rd, faces[i])
                            self.current_frame_feature_list.append(face_reco_model.compute_face_descriptor(img_rd, shape))
                        # 4. 遍歷捕獲到的影像中所有的人臉 / Traversal all the faces in the database
                        for k in range(len(faces)):
                            print(">>>>>> For face", k+1, " in camera")
                            # 先默認所有人不認識,是 unknown / Set the default names of faces with "unknown"
                            self.current_frame_name_list.append("unknown")

                            # 每個捕獲人臉的名字坐標 / Positions of faces captured
                            self.current_frame_name_position_list.append(tuple(
                                [faces[k].left(), int(faces[k].bottom() + (faces[k].bottom() - faces[k].top()) / 4)]))

                            # 5. 對于某張人臉,遍歷所有存盤的人臉特征
                            # For every faces detected, compare the faces in the database
                            current_frame_e_distance_list = []
                            for i in range(len(self.feature_known_list)):
                                # 如果 person_X 資料不為空
                                if str(self.feature_known_list[i][0]) != '0.0':
                                    print("   >>> With person", str(i + 1), ", the e distance: ", end='')
                                    e_distance_tmp = self.return_euclidean_distance(self.current_frame_feature_list[k],
                                                                                    self.feature_known_list[i])
                                    print(e_distance_tmp)
                                    current_frame_e_distance_list.append(e_distance_tmp)
                                else:
                                    # 空資料 person_X
                                    current_frame_e_distance_list.append(999999999)
                            # 6. 尋找出最小的歐式距離匹配 / Find the one with minimum e distance
                            similar_person_num = current_frame_e_distance_list.index(min(current_frame_e_distance_list))
                            print("   >>> Minimum e distance with ", self.name_known_list[similar_person_num], ": ", min(current_frame_e_distance_list))

                            if min(current_frame_e_distance_list) < 0.4:
                                self.current_frame_name_list[k] = self.name_known_list[similar_person_num]
                                print("   >>> Face recognition result:  " + str(self.name_known_list[similar_person_num]))
                            else:
                                print("   >>> Face recognition result: Unknown person")

                            # 矩形框 / 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)

                        self.current_frame_face_cnt = len(faces)

                        # 7. 在這里更改顯示的人名 / Modify name if needed
                        # self.show_chinese_name()

                        # 8. 寫名字 / Draw name
                        img_with_name = self.draw_name(img_rd)

                    else:
                        img_with_name = img_rd

                print(">>>>>> Faces in camera now:", self.current_frame_name_list)

                cv2.imshow("camera", img_with_name)

                # 9. 更新 FPS / Update stream FPS
                self.update_fps()
                print(">>> Frame ends\n\n")

    # OpenCV 呼叫攝像頭并進行 process
    def run(self):
        cap = cv2.VideoCapture(0)
        # cap = cv2.VideoCapture("video.mp4")
        cap.set(3, 480)     # 640x480
        self.process(cap)

        cap.release()
        cv2.destroyAllWindows()


def main():
    Face_Recognizer_con = Face_Recognizer()
    Face_Recognizer_con.run()


if __name__ == '__main__':
    main()

face_reco_from_camera.py輸出log:

Faces in Database: 3
>>> Frame start
>>>>>> For face 1  in camera
   >>> With person 2 , the e distance: 0.24747225595381367
   >>> With person 3 , the e distance: 0.22821104803792178
   >>> Minimum e distance with  Person_3 :  0.22821104803792178
   >>> Face recognition result:  Person_3
>>>>>> Faces in camera now: ['Person_3']
>>> Frame ends


>>> Frame start
>>>>>> For face 1  in camera
   >>> With person 2 , the e distance: 0.2490812900317618
   >>> With person 3 , the e distance: 0.22549497689337802
   >>> Minimum e distance with  Person_3 :  0.22549497689337802
   >>> Face recognition result:  Person_3
>>>>>> Faces in camera now: ['Person_3']
>>> Frame ends


>>> Frame start
>>>>>> For face 1  in camera
   >>> With person 2 , the e distance: 0.24569769385882426
   >>> With person 3 , the e distance: 0.2262102554355137
   >>> Minimum e distance with  Person_3 :  0.2262102554355137
   >>> Face recognition result:  Person_3
>>>>>> Faces in camera now: ['Person_3']
>>> Frame ends


>>> Frame start
>>>>>> For face 1  in camera
   >>> With person 2 , the e distance: 0.24387949251367172
   >>> With person 3 , the e distance: 0.22636200199905795
   >>> Minimum e distance with  Person_3 :  0.22636200199905795
   >>> Face recognition result:  Person_3
>>>>>> Faces in camera now: ['Person_3']
>>> Frame ends


>>> Frame start
>>>>>> For face 1  in camera
   >>> With person 2 , the e distance: 0.2473446948271673
   >>> With person 3 , the e distance: 0.22534075942468246
   >>> Minimum e distance with  Person_3 :  0.22534075942468246
   >>> Face recognition result:  Person_3
>>>>>> Faces in camera now: ['Person_3']
>>> Frame ends


>>> Frame start
>>>>>> For face 1  in camera
   >>> With person 2 , the e distance: 0.24465000646050672
   >>> With person 3 , the e distance: 0.2238005841538998
   >>> Minimum e distance with  Person_3 :  0.2238005841538998
   >>> Face recognition result:  Person_3
>>>>>> Faces in camera now: ['Person_3']
>>> Frame ends

如果對單個人臉,進行實時對比輸出:

通過實時的輸出結果,看的比較明顯

輸出綠色:當是我自己時,計算出來的歐式距離基本都是0.2左右,

輸出紅色:而換一張圖片,明顯看到歐式距離計算結果達到0.8,此時就可以判定,后來這張人臉不是一張人臉,

好了今天講到這了!

拜拜@!

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/296802.html

標籤:AI

上一篇:【Pytorch深度學習50篇】·······第三篇:【非監督學習】

下一篇:Yolov5-Pytorch版-Windows下訓練自己的資料集,內含voc批量轉yolo方法。(自稱宇宙超級巨詳細步驟)

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more