人臉檢測實戰進階:使用 OpenCV 進行活體檢測
使用 OpenCV 進行活體檢測
在本篇博文中,您將學習如何使用 OpenCV 執行活體檢測。您將創建一個活體檢測器,該檢測器能夠在人臉識別系統中發現假人臉并執行反人臉欺騙。
在教程的第一部分,我們將討論活體檢測,包括它是什么以及我們為什么需要它來改進我們的人臉識別系統。
從那里我們將審查我們將用于執行活體檢測的數據集,包括:
如何構建用于活體檢測的數據集 我們的示例真人臉圖像與假人臉圖像
我們還將審查活體檢測器項目的項目結構。
為了創建活體檢測器,我們將訓練一個能夠區分真臉和假臉的深度神經網絡。 因此,我們需要: 構建圖像數據集本身。 實現一個能夠執行活體檢測器的 CNN(我們稱這個網絡為“LivenessNet”)。 訓練活體檢測器網絡。 創建一個 Python + OpenCV 腳本,該腳本能夠采用我們經過訓練的活體檢測器模型并將其應用于實時視頻。
讓我們開始吧!
什么是活體檢測,我們為什么需要它?
人臉識別系統正變得比以往任何時候都更加普遍。從 iPhone/智能手機上的人臉識別,到中國大規模監控的人臉識別,人臉識別系統無處不在。
然而,人臉識別系統很容易被“欺騙”和“非真實”的人臉所愚弄。 只需將一個人的照片(無論是打印的,還是在智能手機上等)放在人臉識別攝像頭上,就可以繞過人臉識別系統。
為了使人臉識別系統更安全,我們需要能夠檢測到此類假/非真實人臉——活體檢測是用于指代此類算法的術語。
有多種活體檢測方法,包括:
紋理分析,包括計算面部區域的局部二值模式 (LBP) 并使用 SVM 將面部分類為真實或欺騙。
頻率分析,例如檢查人臉的傅立葉域。
可變聚焦分析,例如檢查兩個連續幀之間像素值的變化。
基于啟發式的算法,包括眼球運動、嘴唇運動和眨眼檢測。這組算法試圖跟蹤眼球運動和眨眼,以確保用戶沒有舉起另一個人的照片(因為照片不會眨眼或移動嘴唇)。 光流算法,即檢查從 3D 對象和 2D 平面生成的光流的差異和特性。
3D 人臉形狀,類似于蘋果 iPhone 人臉識別系統上使用的形狀,使人臉識別系統能夠區分真實人臉和打印輸出/照片/另一個人的圖像。
結合上述內容,使人臉識別系統工程師能夠挑選適合其特定應用的活體檢測模型。
可以在 Chakraborty 和 Das 2014 年的論文“人臉活體檢測概述”中找到活體檢測算法的完整評論。
出于今天教程的目的,我們將把活體檢測視為一個二元分類問題。
給定輸入圖像,我們將訓練一個卷積神經網絡,該網絡能夠區分真實人臉和偽造/欺騙人臉。
項目結構
$ tree --dirsfirst --filelimit 10 . ├── dataset │ ├── fake [150 entries] │ └── real [161 entries] ├── face_detector │ ├── deploy.prototxt │ └── res10_300x300_ssd_iter_140000.caffemodel ├── model │ ├── __init__.py │ └── livenessnet.py ├── fake ├── real ├── gather_examples.py ├── train.py ├── liveness_demo.py ├── le.pickle ├── liveness.model └── plot.png
我們的項目中有四個主要目錄:
dataset/ :我們的數據集目錄由兩類圖像組成:
在播放我的臉部視頻時,來自相機的假圖像對準我的屏幕。
用我的手機從自拍視頻中捕捉到的我的真實圖像。
face_detector/ :由我們預訓練的 Caffe 人臉檢測器組成,用于定位人臉 ROI。
model/ :這個模塊包含我們的 LivenessNet 類。 視頻/:我提供了兩個輸入視頻來訓練我們的 LivenessNet 分類器。
fake:存放手機拍攝的圖片。
real:存放真實的圖片
今天我們將詳細回顧三個 Python 腳本。 到文章結束時,您將能夠在自己的數據上運行它們并輸入視頻源。 按照在本教程中出現的順序,這三個腳本是:
gather_examples.py :此腳本從輸入視頻文件中獲取人臉 ROI,并幫助我們創建深度學習人臉活躍度數據集。
train.py :正如文件名所示,此腳本將訓練我們的 LivenessNet 分類器。 我們將使用 Keras 和 TensorFlow 來訓練模型。 訓練過程產生幾個文件:
le.pickle :我們的類標簽編碼器。
liveness.model :我們的序列化 Keras 模型,用于檢測面部活力。
plot.png :訓練歷史圖顯示了準確性和損失曲線,因此我們可以評估我們的模型(即過度/欠擬合)。
liveness_demo.py :我們的演示腳本將啟動您的網絡攝像頭以抓取幀以實時進行面部活體檢測。
從我們的訓練(視頻)數據集中檢測和提取人臉 ROI
現在我們已經有機會回顧我們的初始數據集和項目結構,讓我們看看如何從我們的輸入視頻中提取真實和虛假的人臉圖像。 如果此腳本將填充兩個目錄,則最終目標是:
dataset/fake/:包含來自 fake文件夾的人臉 ROI
dataset/real/:保存 real文件夾中的面部 ROI。
鑒于這些幀,我們稍后將在圖像上訓練基于深度學習的活體檢測器。 打開gather_images.py文件并插入以下代碼:
# import the necessary packages import numpy as np import argparse import cv2 import os # construct the argument parse and parse the arguments ap = argparse.ArgumentParser() ap.add_argument("-i", "--input", type=str, required=True, help="path to input video") ap.add_argument("-o", "--output", type=str, required=True, help="path to output directory of cropped faces") ap.add_argument("-d", "--detector", type=str, required=True, help="path to OpenCV's deep learning face detector") ap.add_argument("-c", "--confidence", type=float, default=0.5, help="minimum probability to filter weak detections") ap.add_argument("-s", "--skip", type=int, default=16, help="# of frames to skip before applying face detection") args = vars(ap.parse_args())
導入需要的包。 除了內置的 Python 模塊,這個腳本只需要 OpenCV 和 NumPy。
解析命令行參數:
–input :我們輸入視頻文件的路徑。
–output :將存儲每個裁剪面的輸出目錄的路徑。
–detector :面部檢測器的路徑。 我們將使用 OpenCV 的深度學習人臉檢測器。 為方便起見,此 Caffe 模型包含在今天的“下載”中。
–confidence : 過濾弱人臉檢測的最小概率。 默認情況下,此值為 50%。
–skip :我們不需要檢測和存儲每個圖像,因為相鄰的幀是相似的。 相反,我們將在兩次檢測之間跳過 N 幀。 您可以使用此參數更改默認值 16。
讓我們繼續加載人臉檢測器并初始化我們的視頻流:
# load our serialized face detector from disk print("[INFO] loading face detector...") protoPath = os.path.sep.join([args["detector"], "deploy.prototxt"]) modelPath = os.path.sep.join([args["detector"], "res10_300x300_ssd_iter_140000.caffemodel"]) net = cv2.dnn.readNetFromCaffe(protoPath, modelPath) # open a pointer to the video file stream and initialize the total # number of frames read and saved thus far images = os.listdir(args["input"]) read = 0 saved = 0
加載 OpenCV 的深度學習人臉檢測器。
獲取所有的圖片。 我們還為讀取的幀數以及循環執行時保存的幀數初始化了兩個變量。 讓我們繼續創建一個循環來處理幀:
for filename in images: filepath = os.path.join(args["input"], filename) img = cv2.imread(filepath)
循環讀取圖片。
繼續檢測人臉:
(h, w) = img.shape[:2] blob = cv2.dnn.blobFromImage(cv2.resize(img, (300, 300)), 1.0, (300, 300), (104.0, 177.0, 123.0)) # pass the blob through the network and obtain the detections and # predictions net.setInput(blob) detections = net.forward() # ensure at least one face was found if len(detections) > 0: # we're making the assumption that each image has only ONE # face, so find the bounding box with the largest probability i = np.argmax(detections[0, 0, :, 2]) confidence = detections[0, 0, i, 2]
為了執行人臉檢測,我們需要從圖像中創建一個 blob。
這個 blob 有 300×300 的寬度和高度,以適應我們的 Caffe 人臉檢測器。 稍后將需要縮放邊界框,獲取框架尺寸。
執行 blob 通過深度學習人臉檢測器的前向傳遞。 我們的腳本假設視頻的每一幀中只有一張臉。 這有助于防止誤報。 如果您正在處理包含多個面孔的視頻,我建議您相應地調整邏輯。 因此,抓取了最高概率的人臉檢測指標。使用索引提取檢測的置信度。
讓我們過濾弱檢測并將人臉 ROI 寫入磁盤:
# ensure that the detection with the largest probability also # means our minimum probability test (thus helping filter out # weak detections) if confidence > args["confidence"]: # compute the (x, y)-coordinates of the bounding box for # the face and extract the face ROI box = detections[0, 0, i, 3:7] * np.array([w, h, w, h]) (startX, startY, endX, endY) = box.astype("int") face = img[startY:endY, startX:endX] # write the frame to disk p = os.path.sep.join([args["output"], "{}.png".format(saved)]) cv2.imwrite(p, face) saved += 1 print("[INFO] saved {} to disk".format(p)) cv2.destroyAllWindows()
確保我們的人臉檢測 ROI 滿足最小閾值以減少誤報。 從那里我們提取人臉 ROI 邊界框坐標和人臉 ROI 本身。 我們為面部 ROI 生成路徑 + 文件名,并將其寫入磁盤。 此時,我們可以增加保存的人臉數量。 處理完成后,執行清理。
構建我們的活體檢測圖像數據集
現在我們已經實現了 gather_examples.py 腳本,讓我們開始工作。
打開一個終端并執行以下命令為我們的“假/欺騙”類提取人臉:
python gather_images.py --input fake --output dataset/fake --detector face_detector
同樣,我們也可以對“真實”類做同樣的事情:
python gather_images.py --input real --output dataset/real --detector face_detector
由于“真實”視頻文件比“假”視頻文件長,我們將使用更長的跳幀值來幫助平衡每個類別的輸出人臉 ROI 的數量。 執行腳本后,您應該擁有以下圖像計數:
Fake: 55images
Real: 84images
Total: 139images
實施“LivenessNet”,我們的深度學習活性檢測器
下一步是實施“LivenessNet”,這是我們基于深度學習的活體檢測器。
LivenessNet 的核心其實只是一個簡單的卷積神經網絡。 出于兩個原因,我們會故意保持這個網絡的淺層和盡可能少的參數: 減少在我們的小數據集上過度擬合的機會。 確保我們的活體檢測器快速,能夠實時運行(即使在資源受限的設備上,例如 Raspberry Pi)。
現在讓我們實現 LivenessNet——打開 livenessnet.py 并插入以下代碼:
# import the necessary packages from tensorflow.keras.models import Sequential from tensorflow.keras.layers import BatchNormalization from tensorflow.keras.layers import Conv2D from tensorflow.keras.layers import MaxPooling2D from tensorflow.keras.layers import Activation from tensorflow.keras.layers import Flatten from tensorflow.keras.layers import Dropout from tensorflow.keras.layers import Dense from tensorflow.keras import backend as K class LivenessNet: @staticmethod def build(width, height, depth, classes): # initialize the model along with the input shape to be # "channels last" and the channels dimension itself model = Sequential() inputShape = (height, width, depth) chanDim = -1 # if we are using "channels first", update the input shape # and channels dimension if K.image_data_format() == "channels_first": inputShape = (depth, height, width) chanDim = 1
導入包。 要深入了解這些層和功能中的每一個,請務必參考使用 Python 進行計算機視覺深度學習。
定義 LivenessNet 類。它包含一個靜態方法 build。 build 方法接受四個參數:
width :圖像/體積的寬度。
height :圖像有多高。
depth :圖像的通道數(在本例中為 3,因為我們將使用 RGB 圖像)。
classes:類別的數量。 我們總共有兩個類:“real”和“fake”。
初始化模型。 定義inputShape ,而通道排序。 讓我們開始向我們的 CNN 添加層:
# first CONV => RELU => CONV => RELU => POOL layer set model.add(Conv2D(16, (3, 3), padding="same", input_shape=inputShape)) model.add(Activation("relu")) model.add(BatchNormalization(axis=chanDim)) model.add(Conv2D(16, (3, 3), padding="same")) model.add(Activation("relu")) model.add(BatchNormalization(axis=chanDim)) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Dropout(0.25)) # second CONV => RELU => CONV => RELU => POOL layer set model.add(Conv2D(32, (3, 3), padding="same")) model.add(Activation("relu")) model.add(BatchNormalization(axis=chanDim)) model.add(Conv2D(32, (3, 3), padding="same")) model.add(Activation("relu")) model.add(BatchNormalization(axis=chanDim)) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Dropout(0.25))
CNN網絡類似VGG。 它非常淺,只有幾個學習過的過濾器。 理想情況下,我們不需要深度網絡來區分真實和欺騙的面孔。
第一個 CONV => RELU => CONV => RELU => POOL 層,其中還添加了批量歸一化和 dropout。 第二個 CONV => RELU => CONV => RELU => POOL 層。 最后,我們將添加我們的 FC => RELU 層:
# first (and only) set of FC => RELU layers model.add(Flatten()) model.add(Dense(64)) model.add(Activation("relu")) model.add(BatchNormalization()) model.add(Dropout(0.5)) # softmax classifier model.add(Dense(classes)) model.add(Activation("softmax")) # return the constructed network architecture return model
全連接層和 ReLU 激活層組成,帶有 softmax 分類器頭。
模型返回。
創建活體檢測器訓練腳本
鑒于我們的真實/欺騙圖像數據集以及 LivenessNet 的實現,我們現在準備訓練網絡。 打開 train.py 文件并插入以下代碼:
# set the matplotlib backend so figures can be saved in the background import matplotlib matplotlib.use("Agg") # import the necessary packages from pyimagesearch.livenessnet import LivenessNet from sklearn.preprocessing import LabelEncoder from sklearn.model_selection import train_test_split from sklearn.metrics import classification_report from tensorflow.keras.preprocessing.image import ImageDataGenerator from tensorflow.keras.optimizers import Adam from tensorflow.keras.utils import to_categorical from imutils import paths import matplotlib.pyplot as plt import numpy as np import argparse import pickle import cv2 import os # construct the argument parser and parse the arguments ap = argparse.ArgumentParser() ap.add_argument("-d", "--dataset", required=True, help="path to input dataset") ap.add_argument("-m", "--model", type=str, required=True, help="path to trained model") ap.add_argument("-l", "--le", type=str, required=True, help="path to label encoder") ap.add_argument("-p", "--plot", type=str, default="plot.png", help="path to output loss/accuracy plot") args = vars(ap.parse_args())
我們的面部活力訓練腳本由許多導入(第 2-19 行)組成。現在讓我們回顧一下:
matplotlib :用于生成訓練圖。我們指定了“Agg”后端,以便我們可以輕松地將我們的繪圖保存到第 3 行的磁盤中。
LivenessNet :我們在上一節中定義的 liveness CNN。
train_test_split :來自 scikit-learn 的一個函數,它構建了我們的數據分割以進行訓練和測試。 分類報告:同樣來自 scikit-learn,該工具將生成關于我們模型性能的簡要統計報告。
ImageDataGenerator :用于執行數據增強,為我們提供批量隨機變異的圖像。
Adam :一個非常適合這個模型的優化器。 (替代方法包括 SGD、RMSprop 等)。 路徑:從我的 imutils 包中,該模塊將幫助我們收集磁盤上所有圖像文件的路徑。
pyplot :用于生成一個很好的訓練圖。
numpy :Python 的數值處理庫。這也是 OpenCV 的要求。
argparse :用于處理命令行參數。
pickle :用于將我們的標簽編碼器序列化到磁盤。
cv2 :我們的 OpenCV 綁定。
os :這個模塊可以做很多事情,但我們只是將它用作操作系統路徑分隔符。
查看腳本的其余部分應該更簡單。 此腳本接受四個命令行參數:
–dataset :輸入數據集的路徑。 在這篇文章的前面,我們使用 gather_examples.py 腳本創建了數據集。
–model :我們的腳本將生成一個輸出模型文件——在這里你提供它的路徑。
–le :還需要提供輸出序列化標簽編碼器文件的路徑。
–plot :訓練腳本將生成一個繪圖。 如果你想覆蓋 “plot.png” 的默認值,你應該在命令行中指定這個值。
下一個代碼塊將執行一些初始化并構建我們的數據:
# initialize the initial learning rate, batch size, and number of # epochs to train for INIT_LR = 1e-4 BS = 8 EPOCHS = 50 # grab the list of images in our dataset directory, then initialize # the list of data (i.e., images) and class images print("[INFO] loading images...") imagePaths = list(paths.list_images(args["dataset"])) data = [] labels = [] # loop over all image paths for imagePath in imagePaths: # extract the class label from the filename, load the image and # resize it to be a fixed 32x32 pixels, ignoring aspect ratio label = imagePath.split(os.path.sep)[-2] image = cv2.imread(imagePath) image = cv2.resize(image, (32, 32)) # update the data and labels lists, respectively data.append(image) labels.append(label) # convert the data into a NumPy array, then preprocess it by scaling # all pixel intensities to the range [0, 1] data = np.array(data, dtype="float") / 255.0
設置訓練參數,包括初始學習率、批量大小和EPOCHS。
從那里,我們的 imagePaths 被抓取。 我們還初始化了兩個列表來保存我們的數據和類標簽。 循環構建我們的數據和標簽列表。 數據由我們加載并調整為 32×32 像素的圖像組成。 每個圖像都有一個對應的標簽存儲在標簽列表中。
所有像素強度都縮放到 [0, 1] 范圍內,同時將列表制成 NumPy 數組。 現在讓我們對標簽進行編碼并對數據進行分區:
# encode the labels (which are currently strings) as integers and then # one-hot encode them le = LabelEncoder() labels = le.fit_transform(labels) labels = to_categorical(labels, 2) # partition the data into training and testing splits using 75% of # the data for training and the remaining 25% for testing (trainX, testX, trainY, testY) = train_test_split(data, labels, test_size=0.25, random_state=42)
單熱編碼標簽。 我們利用 scikit-learn 來劃分我們的數據——75% 用于訓練,而 25% 保留用于測試。 接下來,我們將初始化我們的數據增強對象并編譯+訓練我們的面部活力模型:
# construct the training image generator for data augmentation aug = ImageDataGenerator(rotation_range=20, zoom_range=0.15, width_shift_range=0.2, height_shift_range=0.2, shear_range=0.15, horizontal_flip=True, fill_mode="nearest") # initialize the optimizer and model print("[INFO] compiling model...") opt = Adam(lr=INIT_LR, decay=INIT_LR / EPOCHS) model = LivenessNet.build(width=32, height=32, depth=3, classes=len(le.classes_)) model.compile(loss="binary_crossentropy", optimizer=opt, metrics=["accuracy"]) # train the network print("[INFO] training network for {} epochs...".format(EPOCHS)) H = model.fit(x=aug.flow(trainX, trainY, batch_size=BS), validation_data=(testX, testY), steps_per_epoch=len(trainX) // BS, epochs=EPOCHS)
構造數據增強對象,該對象將生成具有隨機旋轉、縮放、移位、剪切和翻轉的圖像。
構建和編譯LivenessNet 模型。 然后我們開始訓練。 考慮到我們的淺層網絡和小數據集,這個過程會相對較快。 一旦模型經過訓練,我們就可以評估結果并生成訓練圖:
# evaluate the network print("[INFO] evaluating network...") predictions = model.predict(x=testX, batch_size=BS) print(classification_report(testY.argmax(axis=1), predictions.argmax(axis=1), target_names=le.classes_)) # save the network to disk print("[INFO] serializing network to '{}'...".format(args["model"])) model.save(args["model"], save_format="h5") # save the label encoder to disk f = open(args["le"], "wb") f.write(pickle.dumps(le)) f.close() # plot the training loss and accuracy plt.style.use("ggplot") plt.figure() plt.plot(np.arange(0, EPOCHS), H.history["loss"], label="train_loss") plt.plot(np.arange(0, EPOCHS), H.history["val_loss"], label="val_loss") plt.plot(np.arange(0, EPOCHS), H.history["accuracy"], label="train_acc") plt.plot(np.arange(0, EPOCHS), H.history["val_accuracy"], label="val_acc") plt.title("Training Loss and Accuracy on Dataset") plt.xlabel("Epoch #") plt.ylabel("Loss/Accuracy") plt.legend(loc="lower left") plt.savefig(args["plot"])
在測試集上進行預測。 從那里生成一個分類報告并將其打印到終端。 LivenessNet 模型與標簽編碼器一起序列化到磁盤。
生成訓練歷史圖以供以后檢查。
訓練LivenessNet
python train.py --dataset dataset --model liveness.model --le le.pickle
使用 OpenCV 進行活體檢測
最后一步是組合所有部分:
我們將訪問我們的網絡攝像頭/視頻流
對每一幀應用人臉檢測
對于檢測到的每個人臉,應用我們的活體檢測器模型
打開 liveness_demo.py 并插入以下代碼:
# import the necessary packages from imutils.video import VideoStream from tensorflow.keras.preprocessing.image import img_to_array from tensorflow.keras.models import load_model import numpy as np import argparse import imutils import pickle import time import cv2 import os # construct the argument parser and parse the arguments ap = argparse.ArgumentParser() ap.add_argument("-m", "--model", type=str, required=True, help="path to trained model") ap.add_argument("-l", "--le", type=str, required=True, help="path to label encoder") ap.add_argument("-d", "--detector", type=str, required=True, help="path to OpenCV's deep learning face detector") ap.add_argument("-c", "--confidence", type=float, default=0.5, help="minimum probability to filter weak detections") args = vars(ap.parse_args())
導入我們需要的包。 值得注意的是,我們將使用 -
VideoStream 以訪問我們的相機提要。
img_to_array 以便我們的框架采用兼容的數組格式。
load_model 加載我們序列化的 Keras 模型。
imutils 的便利功能。
cv2 用于我們的 OpenCV 綁定。
讓我們解析我們的命令行參數:
–model :我們用于活體檢測的預訓練 Keras 模型的路徑。
–le :我們到標簽編碼器的路徑。
–detector :OpenCV 的深度學習人臉檢測器的路徑,用于查找人臉 ROI。
–confidence :過濾掉弱檢測的最小概率閾值。
現在讓我們繼續初始化人臉檢測器、LivenessNet 模型 + 標簽編碼器和我們的視頻流:
# load our serialized face detector from disk print("[INFO] loading face detector...") protoPath = os.path.sep.join([args["detector"], "deploy.prototxt"]) modelPath = os.path.sep.join([args["detector"], "res10_300x300_ssd_iter_140000.caffemodel"]) net = cv2.dnn.readNetFromCaffe(protoPath, modelPath) # load the liveness detector model and label encoder from disk print("[INFO] loading liveness detector...") model = load_model(args["model"]) le = pickle.loads(open(args["le"], "rb").read()) # initialize the video stream and allow the camera sensor to warmup print("[INFO] starting video stream...") vs = VideoStream(src=0).start() time.sleep(2.0)
OpenCV 加載人臉檢測器通。
從那里我們加載我們的序列化、預訓練模型 (LivenessNet) 和標簽編碼器。 我們的 VideoStream 對象被實例化,我們的相機被允許預熱兩秒鐘。 在這一點上,是時候開始遍歷幀來檢測真人臉與假人臉/欺騙人臉了:
# loop over the frames from the video stream while True: # grab the frame from the threaded video stream and resize it # to have a maximum width of 600 pixels frame = vs.read() frame = imutils.resize(frame, width=600) # grab the frame dimensions and convert it to a blob (h, w) = frame.shape[:2] blob = cv2.dnn.blobFromImage(cv2.resize(frame, (300, 300)), 1.0, (300, 300), (104.0, 177.0, 123.0)) # pass the blob through the network and obtain the detections and # predictions net.setInput(blob) detections = net.forward()
打開一個無限 while 循環塊,我們從捕獲和調整單個幀的大小開始。
調整大小后,會抓取框架的尺寸,以便我們稍后執行縮放。 使用 OpenCV 的 blobFromImage 函數,我們生成一個 blob,然后通過將其傳遞到人臉檢測器網絡來繼續執行推理。
現在我們準備好迎接有趣的部分——使用 OpenCV 和深度學習進行活體檢測:
# loop over the detections for i in range(0, detections.shape[2]): # extract the confidence (i.e., probability) associated with the # prediction confidence = detections[0, 0, i, 2] # filter out weak detections if confidence > args["confidence"]: # compute the (x, y)-coordinates of the bounding box for # the face and extract the face ROI box = detections[0, 0, i, 3:7] * np.array([w, h, w, h]) (startX, startY, endX, endY) = box.astype("int") # ensure the detected bounding box does fall outside the # dimensions of the frame startX = max(0, startX) startY = max(0, startY) endX = min(w, endX) endY = min(h, endY) # extract the face ROI and then preproces it in the exact # same manner as our training data face = frame[startY:endY, startX:endX] face = cv2.resize(face, (32, 32)) face = face.astype("float") / 255.0 face = img_to_array(face) face = np.expand_dims(face, axis=0) # pass the face ROI through the trained liveness detector # model to determine if the face is "real" or "fake" preds = model.predict(face)[0] j = np.argmax(preds) label = le.classes_[j] # draw the label and bounding box on the frame label = "{}: {:.4f}".format(label, preds[j]) cv2.putText(frame, label, (startX, startY - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2) cv2.rectangle(frame, (startX, startY), (endX, endY), (0, 0, 255), 2)
遍歷人臉檢測。 在循環里面:
過濾掉弱檢測。
提取人臉邊界框坐標并確保它們不超出框架的尺寸。
提取人臉 ROI 并以與我們的訓練數據相同的方式對其進行預處理。
使用我們的活體檢測器模型來確定面部是“真實的”還是“假的/欺騙的”。
接下來是您插入自己的代碼以執行人臉識別的地方,但僅限于真實圖像。 偽代碼類似于 if label == “real”: run_face_reconition() )。
最后(對于這個演示),我們在臉部周圍繪制標簽文本和一個矩形。
讓我們顯示我們的結果并清理:
# show the output frame and wait for a key press cv2.imshow("Frame", frame) key = cv2.waitKey(1) & 0xFF # if the `q` key was pressed, break from the loop if key == ord("q"): break # do a bit of cleanup cv2.destroyAllWindows() vs.stop()
將我們的活體檢測器部署到實時視頻中
打開一個終端并執行以下命令:
python liveness_demo.py --model liveness.model --le le.pickle \ --detector face_detector
總結
在本教程中,您學習了如何使用 OpenCV 執行活體檢測。 使用此活體檢測器,您現在可以在您自己的面部識別系統中發現假貨并執行反面部欺騙。 為了創建我們的活性檢測器,我們使用了 OpenCV、深度學習和 Python。
第一步是收集我們的真假數據集。為了完成這項任務,我們:
首先使用我們的智能手機錄制我們自己的視頻(即“真實”面孔)。 將智能手機放在筆記本電腦/臺式機上,重播相同的視頻,然后使用我們的網絡攝像頭(即“假”臉)錄制重播。
對兩組視頻應用人臉檢測以形成我們最終的活體檢測數據集。 在構建我們的數據集后,我們實現了“LivenessNet”,一個 Keras + 深度學習 CNN。
這個網絡故意是淺的,確保: 我們減少了在我們的小數據集上過度擬合的機會。 該模型本身能夠實時運行(包括在 Raspberry Pi 上)。
總的來說,我們的活體檢測器能夠在我們的驗證集上獲得 99% 的準確率。 為了演示完整的活體檢測管道,我們創建了一個 Python + OpenCV 腳本,該腳本加載我們的活體檢測器并將其應用于實時視頻流。 正如我們的演示所示,我們的活體檢測器能夠區分真假面孔。
我希望你喜歡今天關于 OpenCV 活體檢測的博文。
完整項目詳見:
https://download.csdn.net/download/hhhhhhhhhhwwwwwwwwww/48148645
AI OpenCV 人臉識別服務 FRS
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。