python 面部识别_一文教你在Python中打造你自己专属的面部识别系统
原標(biāo)題:一文教你在Python中打造你自己專屬的面部識別系統(tǒng)
人臉識別是用戶身份驗證的最新趨勢。蘋果推出的新一代iPhone X使用面部識別技術(shù)來驗證用戶身份。百度也在使“刷臉”的方式允許員工進(jìn)入辦公室。對于很多人來說,這些應(yīng)用程序有一種魔力。但在這篇文章中,我們的目的是通過教你如何在Python中制作你自己的面部識別系統(tǒng)的簡化版本來揭開這個主題的神秘性。
Github庫代碼:https://github.com/Skuldur/facenet-face-recognition
背景
在討論實(shí)現(xiàn)的細(xì)節(jié)之前,我想討論FaceNet的細(xì)節(jié),它是我們將在我們的系統(tǒng)中使用的網(wǎng)絡(luò)。
FaceNetFaceNet是一個神經(jīng)網(wǎng)絡(luò),它可以學(xué)習(xí)從臉部圖像到緊湊的歐幾里得空間(Euclidean space)的映射,在這個空間里,距離對應(yīng)的是人臉的相似性。也就是說,兩張面部圖像越相似,它們之間的距離就越小。
Triplet LossFaceNet使用了一種名為Triplet Loss的獨(dú)特的損失方法來計算損失。Triplet Loss最小化了anchor與正數(shù)之間的距離,這些圖像包含相同的身份,并最大化了anchor與負(fù)數(shù)之間的距離,這些圖像包含不同的身份。
圖1: Triplet Loss等式
f(a)指的是anchor的輸出編碼f(p)指的是正的輸出編碼f(n)指的是負(fù)的輸出編碼α是一個常量,用來確保網(wǎng)絡(luò)不會對f(a)-f(p)=f(a)-f(n)=0進(jìn)行優(yōu)化[…]+等于最大值(0,總和)
Siamese網(wǎng)絡(luò)
圖2:一個Siamese網(wǎng)絡(luò)的例子,它使用面部圖像作為輸入,輸出一個128位數(shù)字編碼的圖像。
FaceNet是一個Siamese網(wǎng)絡(luò)。Siamese網(wǎng)絡(luò)是一種神經(jīng)網(wǎng)絡(luò)體系結(jié)構(gòu),它學(xué)習(xí)如何區(qū)分兩個輸入。這使他們能夠了解哪些圖像是相似的,哪些不是。這些圖像可以包含面部圖像。
Siamese網(wǎng)絡(luò)由兩個完全相同的神經(jīng)網(wǎng)絡(luò)組成,每個神經(jīng)網(wǎng)絡(luò)都有相同的權(quán)重。首先,每個網(wǎng)絡(luò)將兩個輸入圖像中的一個作為輸入。然后,每個網(wǎng)絡(luò)的最后一層的輸出被發(fā)送到一個函數(shù),該函數(shù)決定這些圖像是否包含相同的身份。
在FaceNet中,這是通過計算兩個輸出之間的距離來完成的。
實(shí)現(xiàn)
既然我們已經(jīng)闡明了這個理論,我們就可以直接去實(shí)現(xiàn)這個過程。在我們的實(shí)現(xiàn)中,我們將使用Keras和Tensorflow。此外,我們還使用了從deeplearning.ai的repo中得到的兩個實(shí)用程序文件來為所有與FaceNet網(wǎng)絡(luò)的交互做了個摘要:
fr_utils.py包含了向網(wǎng)絡(luò)提供圖像的函數(shù),并獲取圖像的編碼inception_blocks_v2.py包含了準(zhǔn)備和編譯FaceNet網(wǎng)絡(luò)的函數(shù)
Kera地址:https://keras.io/
Tensorflow地址:https://www.tensorflow.org/
deeplearning.ai的repo地址:https://github.com/shahariarrabby/deeplearning.ai/tree/master/COURSE%204%20Convolutional%20Neural%20Networks/Week%2004/Face%20Recognition
編譯FaceNet網(wǎng)絡(luò)我們要做的第一件事就是編譯FaceNet網(wǎng)絡(luò),這樣我們就可以在面部識別系統(tǒng)中使用它。
import osimport globimport numpy as npimport cv2import tensorflow as tffrom fr_utils import *from inception_blocks_v2 import *from keras import backend as KK.set_image_data_format('channels_first')FRmodel = faceRecoModel(input_shape=(3, 96, 96))def triplet_loss(y_true, y_pred, alpha = 0.3): anchor, positive, negative = y_pred[0], y_pred[1], y_pred[2]pos_dist = tf.reduce_sum(tf.square(tf.subtract(anchor, positive)), axis=-1) neg_dist = tf.reduce_sum(tf.square(tf.subtract(anchor, negative)), axis=-1) basic_loss = tf.add(tf.subtract(pos_dist, neg_dist), alpha) loss = tf.reduce_sum(tf.maximum(basic_loss, 0.0)) return lossFRmodel.compile(optimizer = 'adam', loss = triplet_loss, metrics = ['accuracy'])load_weights_from_FaceNet(FRmodel)
我們將以一個(3,96,96)的輸入形狀開始初始化我們的網(wǎng)絡(luò)。這意味著紅-綠-藍(lán)(RGB)通道是向網(wǎng)絡(luò)饋送的圖像卷(image volume)的第一個維度。所有被饋送網(wǎng)絡(luò)的圖像必須是96×96像素的圖像。
接下來,我們將定義Triplet Loss函數(shù)。上面的代碼片段中的函數(shù)遵循我們在上一節(jié)中定義的Triplet Loss方程的定義。
一旦我們有了損失函數(shù),我們就可以使用Keras來編譯我們的面部識別模型。我們將使用Adam優(yōu)化器來最小化由Triplet Loss函數(shù)計算的損失。
Adam優(yōu)化器:https://keras.io/optimizers/#adam
準(zhǔn)備一個數(shù)據(jù)庫現(xiàn)在我們已經(jīng)編譯了FaceNet,我們準(zhǔn)備一個我們希望我們的系統(tǒng)能夠識別的個人數(shù)據(jù)庫。我們將使用圖像目錄中包含的所有圖像,以供我們的個人數(shù)據(jù)庫使用。
注意:我們將只在實(shí)現(xiàn)中使用每個單獨(dú)的圖像。原因是FaceNet網(wǎng)絡(luò)強(qiáng)大到只需要一個單獨(dú)的圖像就能識別它們!
def prepare_database(): database = {} for file in glob.glob("images/*"): identity = os.path.splitext(os.path.basename(file))[0] database[identity] = img_path_to_encoding(file, FRmodel) return database
對于每個圖像,我們將把圖像數(shù)據(jù)轉(zhuǎn)換為128個浮點(diǎn)數(shù)的編碼。我們通過調(diào)用函數(shù)img_path_to_encoding來實(shí)現(xiàn)這一點(diǎn)。該函數(shù)接受一個圖像的路徑,并將圖像輸入到我們的面部識別網(wǎng)絡(luò)中。然后,它返回來自網(wǎng)絡(luò)的輸出,這恰好是圖像的編碼。
一旦我們將每個圖像的編碼添加到我們的數(shù)據(jù)庫,我們的系統(tǒng)就可以開始識別人臉了!
識別人臉正如在背景部分所討論的,FaceNet被訓(xùn)練來盡可能地最小化同一個體的圖像之間的距離,并使不同個體之間的圖像之間的距離最大化。我們的實(shí)現(xiàn)使用這些信息來確定為我們的系統(tǒng)饋送的新圖像最有可能是哪一個個體。
def who_is_it(image, database, model): encoding = img_to_encoding(image, model) min_dist = 100 identity = None # Loop over the database dictionary's names and encodings. for (name, db_enc) in database.items(): dist = np.linalg.norm(db_enc - encoding) print('distance for %s is %s' %(name, dist)) if dist < min_dist: min_dist = dist identity = name if min_dist > 0.52: return None else: return identity
上面的函數(shù)將新圖像輸入到一個名為img_to_encoding的效用函數(shù)中。該函數(shù)使用FaceNet處理圖像,并返回圖像的編碼。既然我們有了編碼,我們就能找到最可能屬于這個圖像的那個個體。
為了找到個體,我們通過數(shù)據(jù)庫,計算新圖像和數(shù)據(jù)庫中的每個個體之間的距離。在新圖像中距離最小的個體被選為最有可能的候選。
最后,我們必須確定候選圖像和新圖像是否包含相同的對象。因為在我們的循環(huán)結(jié)束時,我們只確定了最有可能的個體。這就是下面的代碼片段所發(fā)揮的作用。
if min_dist > 0.52: return Noneelse: return identity如果距離大于0.52,那么我們將確定新圖像中的個體不存在于我們的數(shù)據(jù)庫中。但是,如果距離等于或小于0.52,那么我們確定它們是相同的個體!
這里比較棘手的部分是,值0.52是通過在我的特定數(shù)據(jù)集上反復(fù)實(shí)驗來實(shí)現(xiàn)的。最好的值可能要低得多或稍微高一些,這取決于你的實(shí)現(xiàn)和數(shù)據(jù)。我建議嘗試不同的值,看看哪個值最適合你的系統(tǒng)!
使用面部識別建立一個系統(tǒng)在這篇文章的開頭,我鏈接到的Github庫中的代碼是一個演示,它使用筆記本電腦的攝像頭來為我們的面部識別算法饋送視頻幀。一旦算法識別出框架中的一個人,演示就會播放一個音頻信息,它允許用戶在數(shù)據(jù)庫中使用它們的圖像名稱。圖3顯示了演示示例。
圖3:當(dāng)網(wǎng)絡(luò)在圖片中識別出個體時,圖片即時被捕捉。數(shù)據(jù)庫中圖像的名稱是“skuli.jpg”,因此播出的音頻信息是“Welcome skuli, have a nice day!”
結(jié)論
現(xiàn)在,你應(yīng)該熟悉了面部識別系統(tǒng)的工作方式,以及如何使用python中的FaceNet網(wǎng)絡(luò)的預(yù)先訓(xùn)練版本來創(chuàng)建你自己的簡化的面部識別系統(tǒng)。如果你想在Github庫中進(jìn)行演示,并添加你認(rèn)識的人的圖像,那么就可以繼續(xù)使用這個庫來進(jìn)行你的下一次實(shí)驗。
本文為atyun出品,轉(zhuǎn)載請注明出處。更多內(nèi)容關(guān)注微信公眾號atyun_com 或訪問網(wǎng)站www.atyun.com返回搜狐,查看更多
責(zé)任編輯:
總結(jié)
以上是生活随笔為你收集整理的python 面部识别_一文教你在Python中打造你自己专属的面部识别系统的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: .NET(c#) 移动APP开发平台 -
- 下一篇: matlab自带kfcm函数,kfcmF