乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      史上最全 OpenCV 活體檢測教程!

       niudp 2019-04-08

      AI 科技評論按:本文來自著名的計(jì)算機(jī)視覺教學(xué)網(wǎng)站「pyimagesearch」,文章作者為 Adrian Rosebrock。在本文中,Adrian 將就「如何鑒別圖像/視頻中的真實(shí)人臉和偽造人臉」這一問題進(jìn)行深入的分析,并介紹使用基于 OpenCV 的模型進(jìn)行活體檢測的具體方法。雷鋒網(wǎng) AI 科技評論編譯如下。

      本教程將教授你如何使用 OpenCV 進(jìn)行活性檢測。通過學(xué)習(xí),你將能夠在人臉識別系統(tǒng)中創(chuàng)建一個(gè)可以發(fā)現(xiàn)偽造人臉并執(zhí)行反人臉欺騙的活體檢測器。

      在過去一年中,本文作者已經(jīng)寫過了多篇人臉識別教程,包括:

      • 基于 OpenCV 的人臉識別(閱讀地址:https://www./2018/09/24/opencv-face-recognition/)

      • 使用 dlib、Python 和深度學(xué)習(xí)進(jìn)行人臉識別(閱讀地址:https://www./2018/06/18/face-recognition-with-opencv-python-and-deep-learning/)

      • 基于樹莓派的人臉識別(閱讀地址:https://www./2018/06/25/raspberry-pi-face-recognition/)

      然而,在我收到的一些郵件以及這些關(guān)于人臉識別的博文的評論中,我經(jīng)常被問到的一個(gè)問題是:

      我如何才能區(qū)分真人臉和偽造人臉?

      試想一下,如果一個(gè)居心叵測的用戶有目的地試圖騙過你的人臉識別系統(tǒng),會(huì)發(fā)生什么?

      他們可能會(huì)嘗試向執(zhí)行人臉識別的攝像頭展示一張照片或一段視頻(例如在本文頂部的圖像)。而這張照片和視頻中的人并不是這些用戶本人。

      在這種情況下,人臉識別系統(tǒng)完全有可能把展示到它們面前的圖片識別為正確的人臉,這最終會(huì)導(dǎo)致未授權(quán)的用戶躲過人臉識別系統(tǒng)!

      如何才能區(qū)分出這些「偽造的」與「真實(shí)的/合法的」人臉呢? 如何才能將反人臉欺騙算法應(yīng)用到你的人臉識別應(yīng)用中呢?

      答案是使用 OpenCV 進(jìn)行活體檢測,這正是本文要討論的內(nèi)容。

      那么,如何將基于 OpenCV 的活體檢測功能結(jié)合到你自己的人臉識別系統(tǒng)中呢?本文接下來將給出答案。

      基于 OpenCV 的活體檢測

      在本教程的第一部分,我們將對活體檢測進(jìn)行討論,包括「活體檢測是什么?」以及「為什么我們需要活體檢測來改進(jìn)人臉識別系統(tǒng)?」

      在這里,我們首先回顧一下接下來將用來進(jìn)行活體檢測的數(shù)據(jù)集,內(nèi)容包括:

      • 如何構(gòu)建用于活體檢測的數(shù)據(jù)集

      • 我們的真假人臉的圖像示例

      我們還將回顧針對活體檢測器項(xiàng)目的項(xiàng)目結(jié)構(gòu)。

      我們將訓(xùn)練一個(gè)能夠區(qū)分真人臉和偽造人臉的深度神經(jīng)網(wǎng)絡(luò),來創(chuàng)建活體檢測器。

      因此,我們需要:

      1. 構(gòu)建圖像數(shù)據(jù)集

      2. 實(shí)現(xiàn)一個(gè)能夠進(jìn)行活體檢測的卷積神經(jīng)網(wǎng)絡(luò)(我們稱之為「LivenessNet」)

      3. 訓(xùn)練活體檢測網(wǎng)絡(luò)

      4. 創(chuàng)建一個(gè)能夠使用我們訓(xùn)練好的活體檢測模型并將其應(yīng)用于實(shí)時(shí)視頻的 Python+OpenCV 的腳本

      接下來,讓我們進(jìn)入正題吧!

      什么是活體檢測, 我們?yōu)槭裁葱枰?/strong>

      干貨 | 史上最全 OpenCV 活體檢測教程!

      圖 1:基于 OpenCV 的活體檢測。左圖是一個(gè)我的活體(真人)的視頻,而在右圖中可以看到我正拿著我的 iPhone(屏幕上有偽造人臉/用來欺騙人臉識別系統(tǒng)的人臉圖片)。

      人臉識別系統(tǒng)正變得越來越普及。從 iphone / 智能手機(jī)上的人臉識別系統(tǒng),到中國用來進(jìn)行大規(guī)模監(jiān)控的人臉識別系統(tǒng)——人臉識別變得無處不在。

      然而,人臉識別系統(tǒng)卻很容易被「具有欺騙性的」和「不真實(shí)」的人臉?biāo)夼?/p>

      通過將一個(gè)人的照片(無論是打印出來的,或者是顯示在智能手機(jī)屏幕上的,等等)展示給用于人臉識別的攝像頭,可以很容易地騙過人臉識別系統(tǒng)。

      為了使人臉識別系統(tǒng)變得更加安全,我們需要檢測出這種偽造的/不真實(shí)的人臉——而「活體檢測」就是被用來指代這種算法的術(shù)語。

      活體檢測的方法有很多,包括:

      • 紋理分析,包括在人臉區(qū)域上計(jì)算局部二值模式(LBP,https://www./2015/12/07/local-binary-patterns-with-python-opencv/)和使用支持向量機(jī)(SVM)將人臉分類為真實(shí)的或偽造的。

      頻率分析,如查看人臉圖片的傅里葉域(對其進(jìn)行傅里葉變換)。

      • 變量聚焦分析,例如查看兩個(gè)連續(xù)幀之間像素值的變化。

      • 基于啟發(fā)式的算法,包括眼球運(yùn)動(dòng)、嘴唇運(yùn)動(dòng)和眨眼檢測(https://www./2017/04/24/eye-blink-detection-opencv-python-dlib/)。這類算法試圖跟蹤眼球運(yùn)動(dòng)和眨眼,以確保用戶展示的并非另一個(gè)人的照片(因?yàn)檎掌粫?huì)眨眼或移動(dòng)嘴唇)。

      • 光流算法,即查看由三維物體和二維平面產(chǎn)生的光流的差異和特性。

      • 三維人臉形狀,類似于蘋果 iPhone 所使用的人臉識別系統(tǒng),使人臉識別系統(tǒng)能夠區(qū)分真實(shí)的人臉和打印出來 / 照片中的 / 圖像中的另一個(gè)人的人臉。

      • 將上述方法結(jié)合起來,使人臉識別系統(tǒng)工程師能夠選擇適合其特定應(yīng)用程序的活體檢測模型。

      在 Chakraborty 和 Das 于 2014 年發(fā)表的論文「An Overview of Face liveness Detection」(論文閱讀地址:https:///pdf/1405.2227.pdf)中,對活體檢測算法進(jìn)行了全面的回顧。

      在本文的教程中,我們將活體檢測作為一個(gè)二分類問題來看待。

      給定一張輸入圖像,我們將訓(xùn)練一個(gè)能夠識別出真假人臉的卷積神經(jīng)網(wǎng)絡(luò)。

      在開始訓(xùn)練我們的活體檢測模型前, 我們先查看一下使用的數(shù)據(jù)集。

      我們的活體檢測視頻

      干貨 | 史上最全 OpenCV 活體檢測教程!

      圖 2:一個(gè)收集到的真實(shí)人臉和偽造/欺騙性人臉的例子。左邊的視頻是一個(gè)我的人臉的合法錄像。右邊是我的筆記本電腦將左邊的這段視頻錄下來的視頻。

      為了簡化我們的例子,我們在本文中構(gòu)建的活體檢測器將重點(diǎn)關(guān)注區(qū)分屏幕上的真實(shí)人臉和欺騙性的人臉。

      該算法可以很被容易地?cái)U(kuò)展到其他類型的欺騙性人臉中,包括打印機(jī)或高分辨率打印出來的人臉等。

      為了構(gòu)建活體檢測數(shù)據(jù)集,我將:

      1. 使用我的 iPhone,把它調(diào)成人像 / 自拍模式。

      2. 錄制一段大約 25 秒的我自己在辦公室內(nèi)走來走去的視頻。

      3. 將我的 iPhone 朝向我的桌面重放這個(gè) 25 秒的視頻,我從桌面的角度錄制了這段重放的視頻;

      4. 這會(huì)產(chǎn)生兩個(gè)示例視頻。一個(gè)被用作「真實(shí)」人臉,另一個(gè)被用作「偽造/欺騙性」人臉。

      5. 最終,我將人臉檢測技術(shù)同時(shí)應(yīng)用在了這兩組視頻上,以提取兩類人臉各自的 ROI。

      我在本文的「下載」部分為大家提供了真實(shí)人臉視頻和偽造人臉視頻。

      你可以直接使用這些視頻開始構(gòu)建數(shù)據(jù)集,但是我建議你收集更多的數(shù)據(jù),從而幫助提升你的活體檢測器的魯棒性和準(zhǔn)確率。

      通過測試,我確認(rèn)這個(gè)模型會(huì)偏向于檢測出我自己的人臉——因?yàn)樗械哪P投际鞘褂梦易约旱囊曨l訓(xùn)練的,因此這個(gè)模型依舊是有意義的。此外,由于我是白種人,我并不奢望該數(shù)據(jù)集被用于檢測其它膚色的人臉時(shí)有同樣出色的表現(xiàn)。

      理想情況下,你可以使用包含多個(gè)種族的人臉的數(shù)據(jù)來訓(xùn)練一個(gè)模型。如果讀者想要獲得更多關(guān)于改進(jìn)活體檢測模型的建議,請務(wù)必參考下面的「局限性和進(jìn)一步工作」章節(jié)。

      在接下來的教程中,你將學(xué)習(xí)到如何利用我記錄下來的數(shù)據(jù)集,并使用 OpenCV 和深度學(xué)習(xí)技術(shù)得到一個(gè)真正的活體檢測器。

      項(xiàng)目架構(gòu)

      在繼續(xù)閱讀的過程中,讀者可以使用「下載」部分提供的鏈接獲取代碼、數(shù)據(jù)集以及活體檢測模型,并解壓存檔。

      當(dāng)你導(dǎo)航到項(xiàng)目的目錄時(shí),你會(huì)注意到如下所示的架構(gòu):

      $ tree --dirsfirst --filelimit 10

      ├── dataset

      │ ├── fake [150 entries]

      │ └── real [161 entries]

      ├── face_detector

      │ ├── deploy.prototxt

      │ └── res10_300x300_ssd_iter_140000.caffemodel

      ├── pyimagesearch

      │ ├── __init__.py

      │ └── livenessnet.py

      ├── videos

      │ ├── fake.mp4

      │ └── real.mov

      ├── gather_examples.py

      ├── train_liveness.py

      ├── liveness_demo.py

      ├── le.pickle

      ├── liveness.model

      └── plot.png

      6 directories, 12 files

      在我們的項(xiàng)目中有四個(gè)主要的目錄:

      • 「dataset/」:我們的數(shù)據(jù)集目錄包含兩類圖像:

      (1)攝像頭對著正在播放我的人臉視頻的手機(jī)屏幕所拍下的偽造圖像。

      (2)我用手機(jī)自拍的視頻中的真實(shí)圖像。

      • 「face_detector/ 」:包括我們用來定位人臉 ROI 的、預(yù)訓(xùn)練好的 Caffe 人臉檢測器。

      • 「pyimagesearch/」:該模塊包含我們的 LivenessNet 類。

      • 「videos/」:我提供了兩個(gè)用來訓(xùn)練 LivenessNet 分類器的輸入視頻。

      現(xiàn)在,我們將仔細(xì)回顧三個(gè) Python 腳本。在本文的最后,你可以在自己的數(shù)據(jù)和輸入視頻上運(yùn)行這些腳本。按照在本教程中出現(xiàn)的順序,這三個(gè)腳本依次是:

      1. 「gather_examples.py」:該腳本從輸入的視頻文件中抓取人臉的 ROI,并幫助我們創(chuàng)建一個(gè)深度學(xué)習(xí)人臉活體檢測數(shù)據(jù)集。

      2.「train_liveness.py」: 如文件名所示,該腳本將訓(xùn)練我們的 LivenessNet 分類器。 我們將使用 Keras 和 TensorFlow 來訓(xùn)練模型。訓(xùn)練的過程會(huì)產(chǎn)生以下幾個(gè)文件:

      (1)le.pickle:我們的類標(biāo)簽編碼器。

      (2)liveness.model:我們用來訓(xùn)練人臉活體檢測器的一系列 Keras 模型。

      (3)plot.png:訓(xùn)練歷史示意圖顯示出了模型的準(zhǔn)確率和損失曲線,我們可以根據(jù)它評估我們的模型(即過擬合 / 欠擬合)。

      3.「liveness_demo.py」:我們的演示腳本將啟動(dòng)你的網(wǎng)絡(luò)攝像頭拍下視頻幀,來進(jìn)行實(shí)時(shí)人臉活體檢測。

      從我們的訓(xùn)練(視頻)數(shù)據(jù)集中檢測并提取人臉的 ROI

      干貨 | 史上最全 OpenCV 活體檢測教程!

      圖 3:為了建立一個(gè)活體檢測數(shù)據(jù)集,首先需要檢測出視頻中的人臉 ROI 區(qū)域

      現(xiàn)在我們可以回顧一下我們初始化的數(shù)據(jù)集和項(xiàng)目架構(gòu),讓我們看看如何從輸入的視頻中提取真實(shí)和偽造的人臉圖像。

      這個(gè)腳本的最終目標(biāo)是向兩個(gè)目錄中填充數(shù)據(jù):

      1. 「dataset/fake/」:包含「fake.mp4」文件中的人臉 ROI 區(qū)域。

      2. 「dataset/real/」:包含「real.mov」文件中的人臉 ROI 區(qū)域。

      基于這些幀,我們接下來將在圖像上訓(xùn)練一個(gè)基于深度學(xué)習(xí)的活體檢測器。

      打開「gather_examples.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)

      第 2-5 行引入了我們需要的安裝包。除了內(nèi)置的 Python 模塊,該腳本僅僅需要用到 OpenCV 和 NumPy 。

      第 8-19 行代碼將解析我們的命令行參數(shù)(https://www./2018/03/12/python-argparse-command-line-arguments/):

      • 「--input」:我們的輸入視頻文件的路徑。

      • 「--output」:儲(chǔ)存每個(gè)裁剪出來的人臉圖像的輸出目錄的路徑。

      • 「--detector」:人臉檢測器的路徑。我們將使用 OpenCV 的深度學(xué)習(xí)人臉檢測器(https://www./2018/02/26/face-detection-with-opencv-and-deep-learning/)。為了方便讀者使用,Caffe 模型可在本文的「下載」部分獲得。

      • 「--confidence」:過濾弱人臉檢測結(jié)果的最小概率。默認(rèn)情況下,該值為 50%。

      • 「--skip」:我們不需要檢測并存儲(chǔ)每個(gè)圖像,因?yàn)橄噜彽膸窍嗨频?。相反我們?huì)在兩次人臉檢測任務(wù)之間跳過 N 個(gè)幀。你可以使用此參數(shù)修改默認(rèn)的 N 值(16)。

      讓我們繼續(xù)加載人臉檢測器并初始化我們的視頻流:

      # 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

      vs = cv2.VideoCapture(args['input'])

      read = 0

      saved = 0

      第 23-26 行加載了 OpenCV 的深度學(xué)習(xí)人臉檢測器(相關(guān)閱讀:https://www./2018/02/26/face-detection-with-opencv-and-deep-learning/)。

      之后,我們在第 30 行打開了我們的視頻流。

      我們還在循環(huán)執(zhí)行時(shí),為讀取到的幀數(shù)以及保存下來的幀數(shù)初始化了兩個(gè)變量(第 31 和第 32 行)。

      接下來,我們將創(chuàng)建一個(gè)循環(huán)來處理這些幀:

      # loop over frames from the video file stream

      while True:

      # grab the frame from the file

      (grabbed, frame) = vs.read

      # if the frame was not grabbed, then we have reached the end

      # of the stream

      if not grabbed:

      break

      # increment the total number of frames read thus far

      read += 1

      # check to see if we should process this frame

      if read % args['skip'] != 0:

      continue

      我們在第 35 行開始「while」循環(huán)。

      接著,我們抓取到了一個(gè)幀并對其進(jìn)行驗(yàn)證(第 37-42 行)。

      這時(shí),由于我們已經(jīng)讀取了一個(gè)幀,我們將增加「read」計(jì)數(shù)器的計(jì)數(shù)(第 48 行)。如果需要跳過這個(gè)特定的幀,我們將不做任何操作繼續(xù)進(jìn)入下一輪循環(huán)(第 48 和 49 行)。

      讓我們繼續(xù)檢測人臉:

      # grab the frame dimensions and construct a blob from the frame

      (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

      # 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]

      為了執(zhí)行人臉檢測,我們需要根據(jù)圖像創(chuàng)建一個(gè)二進(jìn)制大對象數(shù)據(jù)(blob)(第 53 和 54 行)。為了適應(yīng)于 Caffe 人臉檢測器,這個(gè)「blob」的寬、高為 300*300。稍后還需要對邊界框進(jìn)行放縮,因此在第 52 行中,我們會(huì)抓取到幀的維度。

      第 58 和 59 行通過深度學(xué)習(xí)人臉檢測器前饋傳遞這個(gè)「blob」。

      我們的腳本假設(shè)在視頻的每一幀中只出現(xiàn)了一張人臉(第 62-65 行),這有助于防止假正例的產(chǎn)生。如果你正在處理包含多個(gè)面孔的視頻,我建議你相應(yīng)地調(diào)整邏輯。

      因此,第 65 行獲取到了最高的人臉檢測索引的概率。第 66 行使用該索引提取出檢測的置信度(confidence)。

      接下來,讓我們過濾掉弱人臉檢測結(jié)果并將人臉的 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 = frame[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))

      # do a bit of cleanup

      vs.release

      cv2.destroyAllWindows

      第 71 行保證了我們的人臉檢測 ROI 能夠滿足減少假正例所需要的最小閾值。

      在此基礎(chǔ)上,我們提取出了人臉的 ROI 邊界框「box」坐標(biāo)以及相應(yīng)的人臉 ROI 數(shù)值(第 74-76 行)。

      我們?yōu)槿四?ROI 生成了一個(gè)「路徑+文件名」,并在第 79-81 行中將其寫入了磁盤。在這里,我們可以增加「saved」人的數(shù)量。

      處理完成后,我們將在第 86 和 87 行中清空 OpenCV 的工作內(nèi)存。

      構(gòu)建我們的活體檢測圖片數(shù)據(jù)集

      干貨 | 史上最全 OpenCV 活體檢測教程!

      圖 4:我們的 OpenCV 人臉活體檢測數(shù)據(jù)集。我們將使用 Keras 和 OpenCV 訓(xùn)練一個(gè)活體檢測模型的演示樣例。

      請確保你使用了本教程「下載」部分的鏈接獲取到了源代碼以及輸入視頻的示例。

      在此基礎(chǔ)上,請打開一個(gè)終端并執(zhí)行下面的命令,從而提取出我們的「偽造/欺騙性」的類別所需要的人臉圖像:

      $ python gather_examples.py --input videos/real.mov --output dataset/real \

      --detector face_detector --skip 1

      [INFO] loading face detector...

      [INFO] saved datasets/fake/0.png to disk

      [INFO] saved datasets/fake/1.png to disk

      [INFO] saved datasets/fake/2.png to disk

      [INFO] saved datasets/fake/3.png to disk

      [INFO] saved datasets/fake/4.png to disk

      [INFO] saved datasets/fake/5.png to disk

      ...

      [INFO] saved datasets/fake/145.png to disk

      [INFO] saved datasets/fake/146.png to disk

      [INFO] saved datasets/fake/147.png to disk

      [INFO] saved datasets/fake/148.png to disk

      [INFO] saved datasets/fake/149.png to disk

      類似地,我們可以為獲取「真實(shí)」類別的人臉圖像進(jìn)行相同的操作:

      $ python gather_examples.py --input videos/fake.mov --output dataset/fake \

      --detector face_detector --skip 4

      [INFO] loading face detector...

      [INFO] saved datasets/real/0.png to disk

      [INFO] saved datasets/real/1.png to disk

      [INFO] saved datasets/real/2.png to disk

      [INFO] saved datasets/real/3.png to disk

      [INFO] saved datasets/real/4.png to disk

      ...

      [INFO] saved datasets/real/156.png to disk

      [INFO] saved datasets/real/157.png to disk

      [INFO] saved datasets/real/158.png to disk

      [INFO] saved datasets/real/159.png to disk

      [INFO] saved datasets/real/160.png to disk

      由于「真實(shí)」的人臉視頻比「偽造」的人臉視頻文件要更長一些,我們將使用更長的跳幀值來平衡每一類輸出的人臉 ROI 的數(shù)量。

      在執(zhí)行了上面的腳本后,你應(yīng)該已經(jīng)獲得了如下所示的圖像數(shù)據(jù):

      • 偽造人臉:150 張圖像

      • 真實(shí)人臉:161 張圖像

      • 總計(jì):311 張圖像

      實(shí)現(xiàn)我們的深度學(xué)習(xí)活體檢測器「LivenessNet」

      干貨 | 史上最全 OpenCV 活體檢測教程!

      圖 5:LivenessNet 的深度學(xué)習(xí)架構(gòu),這是一個(gè)被設(shè)計(jì)用來在圖像和視頻中檢測出活體人臉的卷積神經(jīng)網(wǎng)絡(luò)(CNN)。

      接下來,我們將實(shí)現(xiàn)基于深度學(xué)習(xí)技術(shù)的活體檢測器「LivenessNet」。

      實(shí)質(zhì)上,「LivenessNet」就是一個(gè)簡單的卷積神經(jīng)網(wǎng)絡(luò)。

      出于以下兩點(diǎn)原因,我們將刻意讓該網(wǎng)絡(luò)保持盡可能淺的層數(shù)和盡可能少的參數(shù):

      1. 為了降低在我們的小型數(shù)據(jù)集上發(fā)生過擬合現(xiàn)象的可能性。

      2. 為了確保我們的活體檢測器能夠快速、實(shí)時(shí)運(yùn)行(即使在諸如樹莓派等計(jì)算資源受限的設(shè)備上)。

      現(xiàn)在,我們將開始實(shí)現(xiàn)「LivenessNet」,請打開「livenessnet.py」文件并插入下列代碼:

      # import the necessary packages

      from keras.models import Sequential

      from keras.layers.normalization import BatchNormalization

      from keras.layers.convolutional import Conv2D

      from keras.layers.convolutional import MaxPooling2D

      from keras.layers.core import Activation

      from keras.layers.core import Flatten

      from keras.layers.core import Dropout

      from keras.layers.core import Dense

      from 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

      我們將從 Keras 包中引入所有需要的方法(第 2-10 行)。如果你想要進(jìn)一步了解每一個(gè)網(wǎng)絡(luò)層和函數(shù),請參閱「 Deep Learning for Computer Vision with Python」(網(wǎng)址為:https://www./deep-learning-computer-vision-python-book/)。

      我們在第 12 行開始定義「LivenessNet」類。它包含一個(gè)靜態(tài)的構(gòu)造方法「build」(第 14 行)?!竍uild」方法將接受四個(gè)輸入?yún)?shù):

      • 「width」:圖像/視頻的寬度

      • 「height」:圖像的高度

      • 「depth」:圖像的通道數(shù)(由于我們將使用 RGB 圖像,本例中 depth 為 3)。

      • 「classes」:檢測類別的數(shù)目。我們共有兩類輸出人臉:「真實(shí)」人臉和「偽造」人臉。

      我們在第 17 行將「model」初始化。

      第 18 行定義了模型的「inputShape」,而第 23-25 行指定了通道的順序。

      下面我們將向卷積神經(jīng)網(wǎng)絡(luò)中加入一些網(wǎng)絡(luò)層組件:

      # 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))

      我們的卷積神經(jīng)網(wǎng)路表現(xiàn)出了 VGGNet 的一些特性。它非常淺,只有少許幾個(gè)學(xué)習(xí)到的卷積核。理想情況下,我們并不需要用通過一個(gè)深度網(wǎng)絡(luò)來區(qū)分真實(shí)人臉和偽造人臉。

      第 28-36 行指定了第一個(gè)「CONV => RELU => CONV => RELU => POOL」(卷積層=> RELU 激活函數(shù)層=>卷積層=>RELU 激活函數(shù)層=>池化層)網(wǎng)絡(luò)層集合,其中也加入了批量歸一化層和 dropout 層。

      第 39-46 行加上了另一個(gè)「CONV => RELU => CONV => RELU => POOL」(卷積層=>RELU 激活函數(shù)層=>卷積層=>RELU 激活函數(shù)層=>池化層)網(wǎng)絡(luò)層集合。

      最后加入我們的「FC => RELU」(全連接=>RELU 激活函數(shù)層)層:

      # 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

      第 49-57 行由全連接層和 ReLU 激活函數(shù)層以及一個(gè) softmax 分類器的頭組成。

      在第 60 行中將該模型返回給訓(xùn)練腳本。

      創(chuàng)建活體檢測器的訓(xùn)練腳本

      干貨 | 史上最全 OpenCV 活體檢測教程!

      圖 6:訓(xùn)練 LivenessNet 的處理流程。同時(shí)使用「真實(shí)」人臉和「欺騙性/偽造」人臉圖像作為我們的數(shù)據(jù)集,我們可以使用 OpenCV、Keras 框架以及深度學(xué)習(xí)技術(shù)訓(xùn)練一個(gè)活體檢測模型。

      給定我們的真實(shí)/欺騙性人臉圖像數(shù)據(jù)集以及對 LivenessNet 實(shí)現(xiàn),我們現(xiàn)在已經(jīng)做好了訓(xùn)練該網(wǎng)絡(luò)的準(zhǔn)備:

      請打開「train_liveness.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 keras.preprocessing.image import ImageDataGenerator

      from keras.optimizers import Adam

      from keras.utils import np_utils

      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」:用以生成訓(xùn)練情況示意圖。在第 3 行中,我們將后端指定為「Agg」,從而使我們可以很容易地將示意圖寫入磁盤。

      「LivenessNet」:我們在前面的章節(jié)定義過的活體檢測卷積神經(jīng)網(wǎng)絡(luò)。

      • 「train_test_split」:從 scikit-learn 引入的函數(shù),它構(gòu)造了用于訓(xùn)練和測試的數(shù)據(jù)劃分。

      • 「classification_report」:同樣從 scikit-learn 引入的函數(shù),它將生成一個(gè)描述我們模型性能的簡短的統(tǒng)計(jì)報(bào)告。

      • 「ImageDataGenerator」:用于進(jìn)行數(shù)據(jù)增強(qiáng),向我們提供批量的隨機(jī)突變增強(qiáng)的圖像。

      • 「Adam」:一個(gè)非常適用于該模型的優(yōu)化器(可選方案包括隨機(jī)梯度下降算法(SGD)、RMSprop 等)。

      • 「paths」:從我的「imutils」包中引入,該模塊可以幫助我們收集磁盤上所有圖像文件的路徑。

      • 「pyplot」:用來生成一個(gè)精美的訓(xùn)練過程示意圖。

      • 「numpy」:一個(gè)用于 Python 的數(shù)字處理開發(fā)庫,它也是 OpenCV 的所需要的。

      • 「argparse」:用于處理命令行參數(shù)(相關(guān)閱讀:https://www./2018/03/12/python-argparse-command-line-arguments/)

      • 「pickle」:被用來將我們的標(biāo)簽編碼器序列化,從而寫入磁盤。

      • 「cv2」:用于綁定 OpenCV。

      • 「os」:該模塊有很多功能,但在這里我們僅使用它來創(chuàng)建操作系統(tǒng)路徑分隔符。

      輸入似乎有點(diǎn)多,但是在了解這些輸入的目的后,檢查腳本的其余部分就應(yīng)該更加直觀了。

      該腳本接受四個(gè)命令行參數(shù):

      • 「--dataset」:輸入數(shù)據(jù)集的路徑。本文前面通過「gather_examples.py」腳本創(chuàng)建了該數(shù)據(jù)集。

      • 「--model」:我們的腳本會(huì)生成一個(gè)輸出模型文件,通過該參數(shù)指定其路徑。

      • 「--le」:輸出序列化標(biāo)簽編碼器文件所需要提供的路徑。

      • 「--plot」:訓(xùn)練腳本將生成一個(gè)訓(xùn)練過程示意圖。如果你想重寫「plot.png」的缺省值,你應(yīng)該在命令行中指定該值。

      下面的代碼塊將執(zhí)行一系列初始化工作,并創(chuàng)建我們的數(shù)據(jù):

      # 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 =

      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

      在第 35-37 行設(shè)置的訓(xùn)練參數(shù)包括學(xué)習(xí)率、批處理規(guī)模以及迭代的次數(shù)。

      到這里,我們就獲取到了「iamgePaths」中的路徑,同時(shí)也初始化了兩個(gè)用來存放「data」和類「labels」的列表(第 42-44 行)。

      第 46-55 行的循環(huán)創(chuàng)建好了「data」和「labels」列表?!竏ata」列表由我們加載并重新調(diào)整尺寸到 32*32 像素的圖像組成。而每張圖像則都有一個(gè)對應(yīng)的標(biāo)簽被存儲(chǔ)在「labels」列表中。

      每個(gè)像素的亮度都被放縮到了 [0,1] 區(qū)間內(nèi),我們在第 59 行將列表轉(zhuǎn)換成了 NumPy array 的形式。

      接下來,我們將對標(biāo)簽進(jìn)行編碼并對數(shù)據(jù)進(jìn)行劃分:

      # encode the labels (which are currently strings) as integers and then

      # one-hot encode them

      le = LabelEncoder

      labels = le.fit_transform(labels)

      labels = np_utils.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)

      第 63-65 行將標(biāo)簽編碼成了獨(dú)熱向量。

      我們使用 scikit-learn 對數(shù)據(jù)進(jìn)行劃分——將 75% 的數(shù)據(jù)用來做訓(xùn)練,其余 25% 的數(shù)據(jù)則被留作測試之用(第 69 和 70 行)。

      接下來,我們將初始化我們的數(shù)據(jù)增強(qiáng)對象,并編譯、訓(xùn)練我們的人臉活體檢測模型:

      # 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_generator(aug.flow(trainX, trainY, batch_size=BS),

      validation_data=(testX, testY), steps_per_epoch=len(trainX) // BS,

      epochs=EPOCHS)

      第 73-75 行構(gòu)造了一個(gè)數(shù)據(jù)增強(qiáng)對象,它將通過隨機(jī)的旋轉(zhuǎn),縮放、平移、剪切和翻轉(zhuǎn)生成新的圖像。想要了解更多關(guān)于數(shù)據(jù)增強(qiáng)的知識,請參閱下面這篇博文:https://www./2018/12/24/how-to-use-keras-fit-and-fit_generator-a-hands-on-tutorial/

      我們在第 79-83 行構(gòu)建并編譯了「LivenessNet」模型。

      接著,我們在第 87-89 行開始訓(xùn)練模型。由于我們使用了淺層網(wǎng)絡(luò)和小型數(shù)據(jù)集,這個(gè)過程相對會(huì)比較快。

      當(dāng)模型訓(xùn)練完成后,我們可以評估訓(xùn)練結(jié)果,并生成一個(gè)訓(xùn)練過程示意圖:

      # evaluate the network

      print('[INFO] evaluating network...')

      predictions = model.predict(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 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['acc'], label='train_acc')

      plt.plot(np.arange(0, EPOCHS), H.history['val_acc'], 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'])

      第 93 行給出了在測試集上得到的預(yù)測結(jié)果。以此為基礎(chǔ),生成了分類結(jié)果報(bào)告「classification_report」并顯示在終端中(第 94 和 95 行)。

      「LivenessNet」模型和標(biāo)簽編碼器在第 99-104 行被序列化并寫入磁盤。

      剩余的第 107-117 行生成了一個(gè)訓(xùn)練過程示意圖,以待查看。

      訓(xùn)練我們的活體檢測器

      現(xiàn)在,我們已經(jīng)為訓(xùn)練活體檢測器做好了準(zhǔn)備。

      請確保你通過本教程「下載」部分的鏈接下載了源代碼和數(shù)據(jù)集。接著,請執(zhí)行下面你的命令:

      $ python train.py --dataset dataset --model liveness.model --le le.pickle

      [INFO] loading images...

      [INFO] compiling model...

      [INFO] training network for 50 epochs...

      Epoch 1/50

      29/29 [==============================] - 2s 58ms/step - loss: 1.0113 - acc: 0.5862 - val_loss: 0.4749 - val_acc: 0.7436

      Epoch 2/50

      29/29 [==============================] - 1s 21ms/step - loss: 0.9418 - acc: 0.6127 - val_loss: 0.4436 - val_acc: 0.7949

      Epoch 3/50

      29/29 [==============================] - 1s 21ms/step - loss: 0.8926 - acc: 0.6472 - val_loss: 0.3837 - val_acc: 0.8077

      ...

      Epoch 48/50

      29/29 [==============================] - 1s 21ms/step - loss: 0.2796 - acc: 0.9094 - val_loss: 0.0299 - val_acc: 1.0000

      Epoch 49/50

      29/29 [==============================] - 1s 21ms/step - loss: 0.3733 - acc: 0.8792 - val_loss: 0.0346 - val_acc: 0.9872

      Epoch 50/50

      29/29 [==============================] - 1s 21ms/step - loss: 0.2660 - acc: 0.9008 - val_loss: 0.0322 - val_acc: 0.9872

      [INFO] evaluating network...

      precision recall f1-score support

      fake 0.97 1.00 0.99 35

      real 1.00 0.98 0.99 43

      micro avg 0.99 0.99 0.99 78

      macro avg 0.99 0.99 0.99 78

      weighted avg 0.99 0.99 0.99 78

      [INFO] serializing network to 'liveness.model'...

      干貨 | 史上最全 OpenCV 活體檢測教程!

      圖 6:使用 OpenCV、Keras 以及深度學(xué)習(xí)技術(shù)訓(xùn)練一個(gè)人臉活體檢測模型的訓(xùn)練過程示意圖。

      如結(jié)果所示,我們在驗(yàn)證集上實(shí)現(xiàn) 99% 的活體檢測準(zhǔn)確率。

      整合一下:通過 OpenCV 實(shí)現(xiàn)活體檢測

      干貨 | 史上最全 OpenCV 活體檢測教程!

      圖 7:使用 OpenCV 和深度學(xué)習(xí)技術(shù)實(shí)現(xiàn)人臉活體檢測

      最后,我們需要做的是將以上內(nèi)容整合起來:

      1. 連接到我們的網(wǎng)絡(luò)攝像頭/視頻流

      2. 將人臉檢測應(yīng)用到每一幀上

      3. 對每一個(gè)檢測到的人臉應(yīng)用我們的活體檢測模型

      請打開「liveness_demo.py」文件并插入下列代碼:

      # import the necessary packages

      from imutils.video import VideoStream

      from keras.preprocessing.image import img_to_array

      from keras.models import load_model

      import numpy as np

      import argparse

      import imutils

      import pickle

      import time

      import cv2

      import os

      # construct the argument parse 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)

      第 2-11 行輸入了我們需要的安裝包。 注意,我們將使用:

      • 「VideoStream」:用來連接到我們的攝像頭。

      • 「img_to_array」:令我們的視頻幀存儲(chǔ)在一個(gè)兼容的數(shù)組格式中。

      • 「load_model」:加載我們的序列化 Keras 模型。

      • 「imutils」:包含一些方便使用的工具函數(shù)。

      • 「cv2」:綁定 OpenCV。

      在第 14-23 行中,我們將解析命令行參數(shù):

      • 「--model」:我們預(yù)訓(xùn)練好的用于活體檢測的 Keras 模型的路徑。

      • 「--le」:標(biāo)簽編碼器的路徑。

      • 「--detector」:用于計(jì)算出人臉 ROI 的 OpenCV 的深度學(xué)習(xí)人臉檢測器的路徑。

      • 「--confidence」:過濾掉較弱的檢測結(jié)果的最小閾值概率。

      接下來,我們將初始化人臉檢測器、LivenessNet 模型 + 標(biāo)簽編碼器,以及我們的視頻流:

      # 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)

      在第 27-30 行加載 OpenCV 的人臉檢測器。

      在此基礎(chǔ)上,我們加載了序列化、預(yù)訓(xùn)練的 LivenessNet 模型以及標(biāo)簽編碼器(第 34-35 行)。

      在第 39 和 40 行中,我們的「VideoStream」對象被實(shí)例化,并且允許攝像頭預(yù)熱 2 秒。

      至此,是時(shí)候開始循環(huán)輸入視頻幀來檢測「真實(shí)」人臉和「偽造/欺騙性」人臉了:

      # 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

      第 43 行開啟了一個(gè)無限的「while」循環(huán)代碼塊,我們首先讀取某一幀然后對其進(jìn)行放縮(第46 和 47 行)。

      重新定義圖像尺寸后,獲取幀的尺寸,以便稍后執(zhí)行縮放(第 50 行)。

      使用 OpenCV 的「blobFromImage」函數(shù)(https://www./2017/11/06/deep-learning-opencvs-blobfromimage-works/)生成一個(gè)「blob」(第 51 行和 52 行),然后讓其通過人臉檢測網(wǎng)絡(luò),完成推理過程(第 56 和 57 行)。

      現(xiàn)在,讓我們進(jìn)入有趣的部分——使用 OpenCV 和深度學(xué)習(xí)進(jìn)行活體檢測。

      # 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)

      在第 60 行中,我們開始循環(huán)進(jìn)行人臉檢測。在循環(huán)過程中,我們做到了:

      • 過濾掉較弱的檢測結(jié)果(第 63-66 行)。

      • 抽取出人臉邊界「box」的坐標(biāo),并確保它們不會(huì)超出檢測框的尺寸范圍(第 69-77 行)。

      • 抽取出人臉 ROI,并使用訓(xùn)練數(shù)據(jù)所采取的同樣方式對其進(jìn)行預(yù)處理。(第 81-85 行)

      • 使用活體檢測模型來判別輸入的人臉是「真實(shí)的」還是「偽造/欺騙性」的(第 89-91 行)。

      • 在第 91 行中,你可以插入自己的代碼執(zhí)行人臉識別任務(wù),但是只能在真實(shí)圖像上進(jìn)行。偽代碼與「if label == 'real': run_face_reconition」類似,可以直接添加到第 91 行之后。

      • 最后(在這個(gè)演示樣例中),我們會(huì)繪制出「label」文本和一個(gè)包圍人臉的「rectangle」(第 94-98 行)。

      接下來,我們將展示檢測結(jié)果并清理內(nèi)存:

      # 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

      當(dāng)捕獲到鍵盤按鍵時(shí),循環(huán)過程中的每一輪迭代都會(huì)顯示出輸出幀(第 101-102 行)。只要用戶按下「q」(quit)鍵,檢測器就停止循環(huán)、開啟指示器并關(guān)閉窗口(第 105-110 行)。

      將我們的活體檢測器應(yīng)用到實(shí)時(shí)視頻上

      如果讀者想跟著我們的活體檢測演示完成整個(gè)執(zhí)行過程,請確保你已經(jīng)通過本文「下載」部分的鏈接下載到了源代碼和預(yù)訓(xùn)練好的活體檢測模型。

      接著,請打開一個(gè)終端并執(zhí)行下面的命令:

      $ python liveness_demo.py --model liveness.model --le le.pickle \

      --detector face_detector

      Using TensorFlow backend.

      [INFO] loading face detector...

      [INFO] loading liveness detector...

      [INFO] starting video stream...

      干貨 | 史上最全 OpenCV 活體檢測教程!

      在這里,你可以看到我們的活體檢測器成功地將真實(shí)人臉和偽造人臉區(qū)分了開來。

      我在下面的視頻匯中展示了一段更長的演示樣例。

      局限性、改進(jìn)和未來的工作

      我們的活性檢測器的主要限制實(shí)際上是數(shù)據(jù)集比較有限——總共只有 311 張圖像(包含「真實(shí)」類的 161 張圖像和「偽造」類的 150 張圖像)。

      這項(xiàng)工作的一項(xiàng)擴(kuò)展,就是收集額外的訓(xùn)練數(shù)據(jù),更具體地說,可以收集來自于你、我之外的人的圖像/視頻幀數(shù)據(jù)。

      請記住,這里使用的示例數(shù)據(jù)集只包含一個(gè)人(我自己)的人臉。我是白人/白種人,而你應(yīng)該收集其他種族和膚色的人臉訓(xùn)練數(shù)據(jù)。

      我們的活體檢測器只在屏幕上具有欺騙性攻擊的人臉進(jìn)行訓(xùn)練,而沒有對打印出來的圖像或照片進(jìn)行訓(xùn)練。因此,我的第三個(gè)建議是,除了簡單的屏幕錄制回放之外,還要收集其它種類的圖像/人臉資源。

      最后,我想說:想實(shí)現(xiàn)活體檢測并沒有什么捷徑。

      最好的活體檢測器應(yīng)該包含多種活體檢測方法(請參閱上面的「什么是活體檢測, 我們?yōu)槭裁葱枰??」一?jié))。

      你需要花點(diǎn)時(shí)間來考慮和評估你自己的項(xiàng)目、指導(dǎo)方針和需求。在某些情況下,你可能只需要用到基本的眨眼檢測啟發(fā)方法。

      而在其他情況下,你需要將基于深度學(xué)習(xí)的活體檢測與其它啟發(fā)式方法相結(jié)合。

      不要急于進(jìn)行人臉識別和活體檢測。你克制一下自己,花點(diǎn)時(shí)間考慮自己獨(dú)特的項(xiàng)目需求。這樣的話將確保你獲得更好、更準(zhǔn)確的結(jié)果。

      總結(jié)

      通過學(xué)習(xí)本教程,你就可以掌握如何使用 OpenCV 進(jìn)行活體檢測。

      現(xiàn)在通過使用活體檢測器,你就可以檢測出偽造的人臉,并在你自己的人臉識別系統(tǒng)中執(zhí)行反人臉欺騙過程。

      在活體檢測器的創(chuàng)建過程中,我們用到了 OpenCV、深度學(xué)習(xí)技術(shù)以及 Python 語言。

      首先,我們需要收集自己的「真實(shí) vs 偽造」人臉數(shù)據(jù)集。為了完成該任務(wù),我們要做到:

      1. 用智能手機(jī)錄制一段我們自己的視頻(即「真實(shí)」人臉)。

      2. 將我們的智能手機(jī)屏幕展示給筆記本電腦/桌面電腦的攝像頭,重放在上一步中錄制的同一個(gè)視頻,然后使用你的網(wǎng)絡(luò)攝像頭錄下視頻回放(即「偽造」人臉)。

      3. 將人臉檢測技術(shù)同時(shí)應(yīng)用到上面兩個(gè)視頻集合中,以構(gòu)建最終的活體檢測數(shù)據(jù)集。

      在構(gòu)建好數(shù)據(jù)集后,我們實(shí)現(xiàn)了「LivenessNet」——它是一個(gè)用 Keras 和深度學(xué)習(xí)技術(shù)實(shí)現(xiàn)的卷積神經(jīng)網(wǎng)絡(luò)。

      我們特意將網(wǎng)絡(luò)設(shè)計(jì)得很淺,這是為了確保:

      1. 在我們的小型數(shù)據(jù)集上減少過擬合現(xiàn)象。

      2. 模型能夠?qū)崟r(shí)運(yùn)行(包括在樹莓派等硬件上)。

      總的來說,該活體檢測器在我們的驗(yàn)證集上的表現(xiàn),準(zhǔn)確率高達(dá) 99% 。

      為了演示完整的活體檢測工作流程,我們創(chuàng)建了一個(gè) Python + OpenCV 的腳本,該腳本加載了我們的活體檢測程序并將其應(yīng)用在了實(shí)時(shí)視頻流上。

      正如我們的演示樣例所示,我們的活體檢測器能夠區(qū)分真假人臉。

      希望你喜歡這篇使用 OpenCV 進(jìn)行活體檢測的文章!

      資源下載鏈接:https://www./forms/321809846/submissions

      via: https://www./2019/03/11/liveness-detection-with-opencv

        本站是提供個(gè)人知識管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多