生活随笔
收集整理的這篇文章主要介紹了
【facenet人脸识别】利用LFW数据集进行人脸比对测试
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
近期,做人臉識(shí)別項(xiàng)目,用到了facenet這個(gè)開源框架,并使用LFW人臉數(shù)據(jù)集進(jìn)行了測(cè)試?,F(xiàn)將該過程總結(jié)如下:
1 facenet簡(jiǎn)介
GitHub地址:https://github.com/davidsandberg/facenet.git
facenet的原理就是基于同一人臉總是比不同人臉更相似這一先驗(yàn)知識(shí),然后利用傳統(tǒng)卷積神經(jīng)網(wǎng)絡(luò)特征提取,利用三元損失函數(shù)進(jìn)行訓(xùn)練。最終,將人臉映射到特征空間后,同一身份的人臉距離較近,不同身份的人臉距離較遠(yuǎn)。模型的輸出是一個(gè)512維的向量(原來是128維)。
算法詳情可參考其論文:https://arxiv.org/pdf/1503.03832.pdf。
2 LFW數(shù)據(jù)集簡(jiǎn)介
網(wǎng)盤鏈接: https://pan.baidu.com/s/1qOrFv_8RhIhUJvAmwE8p0g 提取碼: kfwh?
LFW數(shù)據(jù)集是對(duì)5000多人在自然場(chǎng)景下采集的共13000多張圖像。lfw_funneled文件夾中每個(gè)子文件夾代表一個(gè)人,其中包含其若干張同一身份不同場(chǎng)景下的照片,有的只有一張,有的有多張。
lfw_funneled中還包含了幾個(gè)txt文檔,這里面記錄了這些人臉的不同組合,我們使用其中的pairs.txt中的組合進(jìn)行人臉比對(duì)測(cè)試。
pairs.txt里面包含了6000對(duì)人臉,3000對(duì)同一身份,3000對(duì)不同身份。文檔第一行的10? 300代表正負(fù)樣本以300的數(shù)量依次羅列,重復(fù)10次,因此共10*(300對(duì)正樣本+300對(duì)負(fù)樣本)= 6000對(duì)人臉。
3? 測(cè)試過程
3.1 圖像路徑提取
首先,我們根據(jù)pairs.txt進(jìn)行圖片路徑的提取:
def get_img_pairs_list(pairs_txt_path,img_path): """ 指定圖片組合及其所在文件,返回各圖片對(duì)的絕對(duì)路徑 Args: pairs_txt_path:圖片pairs文件,里面是6000對(duì)圖片名字的組合 img_path:圖片所在文件夾 return: img_pairs_list:深度為2的list,每一個(gè)二級(jí)list存放的是一對(duì)圖片的絕對(duì)路徑 """file = open(pairs_txt_path)img_pairs_list,labels = [],[] while 1:img_pairs = []line = file.readline().replace('\n','') if line == '': breakline_list = line.split('\t') if len(line_list) == 3: img_pairs.append(img_path+'\\'+line_list[0]+'\\'+line_list[0]+'_'+('000'+line_list[1])[-4:]+'.jpg')img_pairs.append(img_path+'\\'+line_list[0]+'\\'+line_list[0]+'_'+('000'+line_list[2])[-4:]+'.jpg')labels.append(1) elif len(line_list) == 4:img_pairs.append(img_path+'\\'+line_list[0]+'\\'+line_list[0]+'_'+('000'+line_list[1])[-4:]+'.jpg')img_pairs.append(img_path+'\\'+line_list[2]+'\\'+line_list[2]+'_'+('000'+line_list[3])[-4:]+'.jpg')labels.append(0) else: continue img_pairs_list.append(img_pairs) return img_pairs_list,labels 利用上述代碼,即可提取所有人類對(duì)的絕對(duì)路徑,返回一個(gè)路徑list及其標(biāo)簽(1或0)。
3.2 人臉檢測(cè)、對(duì)比
獲取到人臉對(duì)的圖片路徑及標(biāo)簽之后,在使用facenet將其轉(zhuǎn)化為512維的向量之前,需要先對(duì)圖像進(jìn)行人臉提取,即截取其中的人臉區(qū)域。這里用到了MTCNN模型,用于檢測(cè)出人臉并將人臉區(qū)域單獨(dú)提出來,然后就可以利用facenet進(jìn)行人臉特征向量的轉(zhuǎn)化了。得到這對(duì)人臉的特征向量之后,求其歐氏距離,即可根據(jù)該距離判斷其是否為同一身份了。提取及比對(duì)過程如下(其中模型model是MTCNN的參數(shù),在facenet的GitHub項(xiàng)目的“facenet/src/models/”路徑下已有;model_facenet模型因?yàn)楸容^大,需要單獨(dú)下載,點(diǎn)擊下載:鏈接: https://pan.baidu.com/s/1ty7NfBYIretHhnZwwl2dTg 提取碼: g3jy):
def face_verification(img_pairs_list):model = './model/'model_facenet = r'XXX\XXX\20180402-114759.pb' minsize=40threshold=[0.4,0.5,0.6] factor = 0.709 with tf.Graph().as_default():sess=tf.Session() with sess.as_default():pnet,rnet,onet=detect_face.create_mtcnn(sess, model) margin = 44image_size = 160 with tf.Graph().as_default(): with tf.Session() as sess: facenet.load_model(model_facenet) images_placeholder = tf.get_default_graph().get_tensor_by_name("input:0")embeddings = tf.get_default_graph().get_tensor_by_name("embeddings:0")phase_train_placeholder = tf.get_default_graph().get_tensor_by_name("phase_train:0") jd = '\r %2d%%\t [%s%s]'bar_num_total = 50 total_num = len(img_pairs_list)result, dist = [],[] for i in range(len(img_pairs_list)): if i%round(total_num/bar_num_total) == 0 or i == total_num-1:bar_num_alright = round(bar_num_total*i/total_num)alright = '#'*bar_num_alrightnot_alright = '□'*(bar_num_total-bar_num_alright)percent = (bar_num_alright/bar_num_total)*100print(jd % (percent,alright,not_alright),end='') img_pairs = img_pairs_list[i]img_list = []img1 = cv2.imread(img_pairs[0])img2 = cv2.imread(img_pairs[1]) img_size1 = np.asarray(img1.shape)[0:2]img_size2 = np.asarray(img2.shape)[0:2] bounding_box1,_1=detect_face.detect_face(img1,minsize,pnet,rnet,onet,threshold,factor)bounding_box2,_2=detect_face.detect_face(img2,minsize,pnet,rnet,onet,threshold,factor) if len(bounding_box1)<1 or len(bounding_box2)<1:result.append(-1)dist.append(-1) continue det = np.squeeze(bounding_box1[0,0:4])bb = np.zeros(4, dtype=np.int32)bb[0] = np.maximum(det[0]-margin/2, 0)bb[1] = np.maximum(det[1]-margin/2, 0)bb[2] = np.minimum(det[2]+margin/2, img_size1[1])bb[3] = np.minimum(det[3]+margin/2, img_size1[0])cropped = img1[bb[1]:bb[3],bb[0]:bb[2],:]aligned = cv2.resize(cropped, (image_size, image_size))prewhitened = facenet.prewhiten(aligned)img_list.append(prewhitened) det = np.squeeze(bounding_box2[0,0:4])bb = np.zeros(4, dtype=np.int32)bb[0] = np.maximum(det[0]-margin/2, 0)bb[1] = np.maximum(det[1]-margin/2, 0)bb[2] = np.minimum(det[2]+margin/2, img_size2[1])bb[3] = np.minimum(det[3]+margin/2, img_size2[0])cropped = img2[bb[1]:bb[3],bb[0]:bb[2],:]aligned = cv2.resize(cropped, (image_size, image_size))prewhitened = facenet.prewhiten(aligned)img_list.append(prewhitened) images = np.stack(img_list) feed_dict = { images_placeholder: images, phase_train_placeholder:False }emb = sess.run(embeddings, feed_dict=feed_dict) ed = np.sqrt( np.sum( np.square( np.subtract(emb[0], emb[1]) ) ) )dist.append(ed) if ed<=1.1:result.append(1) else:result.append(0) return result,dist 上述代碼可以實(shí)現(xiàn)在某一指定閾值下,進(jìn)行人臉比對(duì),得出對(duì)比結(jié)果存于result中,用于后續(xù)計(jì)算準(zhǔn)確率;同時(shí),為了畫出ROC曲線,這里還返回了,所有人臉對(duì)的歐氏距離,存于dist中。
實(shí)際上,上述result是dist在某一個(gè)閾值下的截面數(shù)據(jù),通過設(shè)置不同閾值,即可根據(jù)dist得出不同的result,下面正是利用這個(gè)原理畫出的ROC曲線。
3.3 ROC曲線
根據(jù)3.2得出的每對(duì)人臉的歐氏距離,還有3.1得出的各對(duì)人臉樣本的標(biāo)簽,即可畫出計(jì)算出ROC曲線所需指標(biāo):TPR、FPR。
代碼如下:
def roc(dist,labels):TP_list,TN_list,FP_list,FN_list,TPR,FPR = [],[],[],[],[],[] for t in range(180):threh = 0.1+t*0.01 TP,TN,FP,FN = 0,0,0,0 for i in range(len(dist)): if labels[i]==1 and dist[i]!=-1: if dist[i]<threh:TP += 1 else:FN += 1 elif labels[i]==0 and dist[i]!=-1: if dist[i]>=threh:TN += 1 else:FP += 1TP_list.append(TP)TN_list.append(TN)FP_list.append(FP)FN_list.append(FN)TPR.append(TP/(TP+FN))FPR.append(FP/(FP+TN)) return TP_list,TN_list,FP_list,FN_list,TPR,FPR ?4 完整代碼
"""Created on Fri Mar 22 09:59:41 2019@author: Leon內(nèi)容:人臉驗(yàn)證準(zhǔn)確率測(cè)試樣本:LFW人臉集,共6000對(duì)人臉,中3000對(duì)同一身份、3000對(duì)不同身份。"""import numpy as npimport cv2import tensorflow as tfimport matplotlib.pyplot as pltimport facenetimport align.detect_face as detect_face def face_verification(img_pairs_list):model = './model/'model_facenet = r'XXX\XXX\20180402-114759.pb' minsize=40threshold=[0.4,0.5,0.6] factor = 0.709 with tf.Graph().as_default():sess=tf.Session() with sess.as_default():pnet,rnet,onet=detect_face.create_mtcnn(sess, model) margin = 44image_size = 160 with tf.Graph().as_default(): with tf.Session() as sess: facenet.load_model(model_facenet) images_placeholder = tf.get_default_graph().get_tensor_by_name("input:0")embeddings = tf.get_default_graph().get_tensor_by_name("embeddings:0")phase_train_placeholder = tf.get_default_graph().get_tensor_by_name("phase_train:0") jd = '\r %2d%%\t [%s%s]'bar_num_total = 50 total_num = len(img_pairs_list)result, dist = [],[] for i in range(len(img_pairs_list)): if i%round(total_num/bar_num_total) == 0 or i == total_num-1:bar_num_alright = round(bar_num_total*i/total_num)alright = '#'*bar_num_alrightnot_alright = '□'*(bar_num_total-bar_num_alright)percent = (bar_num_alright/bar_num_total)*100print(jd % (percent,alright,not_alright),end='') img_pairs = img_pairs_list[i]img_list = []img1 = cv2.imread(img_pairs[0])img2 = cv2.imread(img_pairs[1]) img_size1 = np.asarray(img1.shape)[0:2]img_size2 = np.asarray(img2.shape)[0:2] bounding_box1,_1=detect_face.detect_face(img1,minsize,pnet,rnet,onet,threshold,factor)bounding_box2,_2=detect_face.detect_face(img2,minsize,pnet,rnet,onet,threshold,factor) if len(bounding_box1)<1 or len(bounding_box2)<1:result.append(-1)dist.append(-1) continue det = np.squeeze(bounding_box1[0,0:4])bb = np.zeros(4, dtype=np.int32)bb[0] = np.maximum(det[0]-margin/2, 0)bb[1] = np.maximum(det[1]-margin/2, 0)bb[2] = np.minimum(det[2]+margin/2, img_size1[1])bb[3] = np.minimum(det[3]+margin/2, img_size1[0])cropped = img1[bb[1]:bb[3],bb[0]:bb[2],:]aligned = cv2.resize(cropped, (image_size, image_size))prewhitened = facenet.prewhiten(aligned)img_list.append(prewhitened) det = np.squeeze(bounding_box2[0,0:4])bb = np.zeros(4, dtype=np.int32)bb[0] = np.maximum(det[0]-margin/2, 0)bb[1] = np.maximum(det[1]-margin/2, 0)bb[2] = np.minimum(det[2]+margin/2, img_size2[1])bb[3] = np.minimum(det[3]+margin/2, img_size2[0])cropped = img2[bb[1]:bb[3],bb[0]:bb[2],:]aligned = cv2.resize(cropped, (image_size, image_size))prewhitened = facenet.prewhiten(aligned)img_list.append(prewhitened) images = np.stack(img_list) feed_dict = { images_placeholder: images, phase_train_placeholder:False }emb = sess.run(embeddings, feed_dict=feed_dict) ed = np.sqrt( np.sum( np.square( np.subtract(emb[0], emb[1]) ) ) )dist.append(ed) if ed<=1.1:result.append(1) else:result.append(0) return result,dist def get_img_pairs_list(pairs_txt_path,img_path): """ 指定圖片組合及其所在文件,返回各圖片對(duì)的絕對(duì)路徑 Args: pairs_txt_path:圖片pairs文件,里面是6000對(duì)圖片名字的組合 img_path:圖片所在文件夾 return: img_pairs_list:深度為2的list,每一個(gè)二級(jí)list存放的是一對(duì)圖片的絕對(duì)路徑 """file = open(pairs_txt_path)img_pairs_list,labels = [],[] while 1:img_pairs = []line = file.readline().replace('\n','') if line == '': breakline_list = line.split('\t') if len(line_list) == 3: img_pairs.append(img_path+'\\'+line_list[0]+'\\'+line_list[0]+'_'+('000'+line_list[1])[-4:]+'.jpg')img_pairs.append(img_path+'\\'+line_list[0]+'\\'+line_list[0]+'_'+('000'+line_list[2])[-4:]+'.jpg')labels.append(1) elif len(line_list) == 4:img_pairs.append(img_path+'\\'+line_list[0]+'\\'+line_list[0]+'_'+('000'+line_list[1])[-4:]+'.jpg')img_pairs.append(img_path+'\\'+line_list[2]+'\\'+line_list[2]+'_'+('000'+line_list[3])[-4:]+'.jpg')labels.append(0) else: continue img_pairs_list.append(img_pairs) return img_pairs_list,labels def roc(dist,labels):TP_list,TN_list,FP_list,FN_list,TPR,FPR = [],[],[],[],[],[] for t in range(180):threh = 0.1+t*0.01 TP,TN,FP,FN = 0,0,0,0 for i in range(len(dist)): if labels[i]==1 and dist[i]!=-1: if dist[i]<threh:TP += 1 else:FN += 1 elif labels[i]==0 and dist[i]!=-1: if dist[i]>=threh:TN += 1 else:FP += 1TP_list.append(TP)TN_list.append(TN)FP_list.append(FP)FN_list.append(FN)TPR.append(TP/(TP+FN))FPR.append(FP/(FP+TN)) return TP_list,TN_list,FP_list,FN_list,TPR,FPR if __name__ == '__main__':pairs_txt_path = 'C:/Users/thinkpad1/Desktop/image_set/lfw_funneled/pairs.txt'img_path = 'C:/Users/thinkpad1/Desktop/image_set/lfw_funneled'img_pairs_list,labels = get_img_pairs_list(pairs_txt_path,img_path) result,dist = face_verification(img_pairs_list) num_right, num_total = 0, 0num_total = len([r for r in result if r != -1])num_right = len([result[i] for i in range(len(result)) if result[i] == labels[i]]) print("人臉驗(yàn)證測(cè)試完畢")print("閾值為1.1,共%d對(duì)人臉,準(zhǔn)確率%2.4f%%"%(num_total, round(100*num_right/num_total,4))) TP_list,TN_list,FP_list,FN_list,TPR,FPR = roc(dist,labels)plt.plot(FPR,TPR,label='Roc')plt.plot([0, 1], [0, 1], '--', color=(0.6, 0.6, 0.6), label='Luck')plt.xlabel('FPR')plt.ylabel('TPR')plt.legend() plt.plot(np.linspace(0.1,1.89,180),TP_list,label='TP')plt.plot(np.linspace(0.1,1.89,180),TN_list,label='TN')plt.plot(np.linspace(0.1,1.89,180),FP_list,label='FP')plt.plot(np.linspace(0.1,1.89,180),FN_list,label='FN')plt.legend() 5 測(cè)試結(jié)果
在閾值1.1下測(cè)試準(zhǔn)確率為93.48%,這里沒有達(dá)到其宣稱的99%+的準(zhǔn)確率。
利用每對(duì)人臉距離,通過設(shè)置不同距離閾值,畫出ROC曲線,如下圖(左),將TP,TN,FP,FN的曲線也畫出來,可以佐證閾值在1.1時(shí),達(dá)到最好的分類效果(TP、TN最大,FP、FN最小)。
?
總結(jié)
以上是生活随笔為你收集整理的【facenet人脸识别】利用LFW数据集进行人脸比对测试的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。