天天看點

MTCNN+facenet實作人臉識别系統實作流程項目目錄結建構立人臉資料圖庫MTCNN,Multi-task convolutional neural network(多任務卷積神經網絡)利用MTCNN網絡把人臉資料圖庫轉換為人臉特征庫(embedding庫)facenet進行人臉識别

國小期的實訓題目是實驗室進出人員身份識别和記錄學習時間,那麼基本功能是實作人臉識别。人臉識别其實又分為兩部分,人臉檢測和人臉識别,在本次部落格中,人臉檢測使用MTCNN模型,然後利用facenet進行人臉識别。

Github連結:https://github.com/ALittleLeo/FaceRcognization/tree/master

覺得有用的話請打個星!

目錄

系統實作流程

項目目錄結構

建立人臉資料圖庫

MTCNN,Multi-task convolutional neural network(多任務卷積神經網絡)

利用MTCNN網絡把人臉資料圖庫轉換為人臉特征庫(embedding庫)

facenet進行人臉識别

系統實作流程

1、建立人臉資料圖庫

2、搭建MTCNN網絡

3、利用MTCNN網絡把人臉資料圖庫轉換為人臉特征庫(embedding庫)

4、使用MTCNN網絡提取待檢測的人臉圖檔的特征

5、使用facenet比較待識别的人臉和人臉庫特征,繪制圖檔,得到最終結果

MTCNN+facenet實作人臉識别系統實作流程項目目錄結建構立人臉資料圖庫MTCNN,Multi-task convolutional neural network(多任務卷積神經網絡)利用MTCNN網絡把人臉資料圖庫轉換為人臉特征庫(embedding庫)facenet進行人臉識别

項目目錄結構

MTCNN+facenet實作人臉識别系統實作流程項目目錄結建構立人臉資料圖庫MTCNN,Multi-task convolutional neural network(多任務卷積神經網絡)利用MTCNN網絡把人臉資料圖庫轉換為人臉特征庫(embedding庫)facenet進行人臉識别

打開FaceNet Github位址: https://github.com/davidsandberg/facenet,把我們需要的檔案拷貝到自己獨立的工程中,(1)align檔案夾,(2)facenet.py檔案

目錄說明:

  • align檔案夾中包含三個mtcnn要用到的模型檔案,以及搭建mtcnn網絡的檔案 

    detect_face.py

    ,這裡面的東西在facenet的項目中的都可以找到
  • dataset檔案夾中主要存放資料,包括images(人臉資料圖庫),emb(人臉特征庫),test_images(測試圖檔)
  • models檔案夾中存放facenet預訓練模型(連結: https://pan.baidu.com/s/1l16K7EktS6EO4a4pVNXvsQ 提取碼: rvtv )
  • utils是工具類檔案夾,用于檔案讀寫,圖檔相關操作。
  • predict.py是進行人臉識别的入口
  • create_dataset.py用于将人臉資料圖庫轉換為人臉特征庫

建立人臉資料圖庫

MTCNN+facenet實作人臉識别系統實作流程項目目錄結建構立人臉資料圖庫MTCNN,Multi-task convolutional neural network(多任務卷積神經網絡)利用MTCNN網絡把人臉資料圖庫轉換為人臉特征庫(embedding庫)facenet進行人臉識别

人臉圖檔放在dataset/images檔案夾下,每個子目錄放同一個人的照片,以子目錄名作為人名,上圖所示胡歌和周傑倫

MTCNN,Multi-task convolutional neural network(多任務卷積神經網絡)

MTCNN+facenet實作人臉識别系統實作流程項目目錄結建構立人臉資料圖庫MTCNN,Multi-task convolutional neural network(多任務卷積神經網絡)利用MTCNN網絡把人臉資料圖庫轉換為人臉特征庫(embedding庫)facenet進行人臉識别

正如上圖所示,該MTCNN由3個網絡結構組成(P-Net,R-Net,O-Net)。

           Proposal Network (P-Net):該網絡結構主要獲得了人臉區域的候選視窗和邊界框的回歸向量。并用該邊界框做回歸,對候選視窗進行校準,然後通過非極大值抑制(NMS)來合并高度重疊的候選框。

Refine Network (R-Net):該網絡結構還是通過邊界框回歸和NMS來去掉那些false-positive區域。

隻是由于該網絡結構和P-Net網絡結構有差異,多了一個全連接配接層,是以會取得更好的抑制false-positive的作用。

Output Network (O-Net):該層比R-Net層又多了一層卷基層,是以處理的結果會更加精細。作用和R-Net層作用一樣。但是該層對人臉區域進行了更多的監督,同時還會輸出5個地标(landmark)。

(詳細介紹等後面再寫)

github上的facenet工程在實作facent的時候,為了便于測試,mtcnn也一放在了工程檔案中,在工程中的位置是

align/detect_face.py

 ,它的參數模型也儲存在align檔案夾下,分别是

det1.npy,det2.npy,det3.npy

,它的用法便是先将網絡搭建出來,定位input中的人臉的位置,然後傳回自己設定的固定大小的臉部crop,然後再将其輸入facenet就ok了,其作用就是人臉檢測+定位+對齊。

代碼實作

1、加載網絡檔案,搭建MTCNN網絡

def create_mtcnn(sess, model_path):
    if not model_path:
        model_path,_ = os.path.split(os.path.realpath(__file__))

    with tf.variable_scope('pnet'):
        data = tf.placeholder(tf.float32, (None,None,None,3), 'input')
        pnet = PNet({'data':data})
        pnet.load(os.path.join(model_path, 'det1.npy'), sess)
    with tf.variable_scope('rnet'):
        data = tf.placeholder(tf.float32, (None,24,24,3), 'input')
        rnet = RNet({'data':data})
        rnet.load(os.path.join(model_path, 'det2.npy'), sess)
    with tf.variable_scope('onet'):
        data = tf.placeholder(tf.float32, (None,48,48,3), 'input')
        onet = ONet({'data':data})
        onet.load(os.path.join(model_path, 'det3.npy'), sess)
        
    pnet_fun = lambda img : sess.run(('pnet/conv4-2/BiasAdd:0', 'pnet/prob1:0'), feed_dict={'pnet/input:0':img})
    rnet_fun = lambda img : sess.run(('rnet/conv5-2/conv5-2:0', 'rnet/prob1:0'), feed_dict={'rnet/input:0':img})
    onet_fun = lambda img : sess.run(('onet/conv6-2/conv6-2:0', 'onet/conv6-3/conv6-3:0', 'onet/prob1:0'), feed_dict={'onet/input:0':img})
    return pnet_fun, rnet_fun, onet_fun
           

2、使用MTCNN進行人臉檢測,傳回人臉框和人臉的五個特征點

bboxes, landmarks = detect_face.detect_face(image, self.minsize, self.pnet, self.rnet, self.onet, self.threshold, self.factor)




def detect_face(img, minsize, pnet, rnet, onet, threshold, factor):
    """Detects faces in an image, and returns bounding boxes and points for them.
    img: input image
    minsize: minimum faces' size
    pnet, rnet, onet: caffemodel
    threshold: threshold=[th1, th2, th3], th1-3 are three steps's threshold
    factor: the factor used to create a scaling pyramid of face sizes to detect in the image.
    """
    factor_count=0
    total_boxes=np.empty((0,9))
    points=np.empty(0)
    h=img.shape[0]
    w=img.shape[1]
    minl=np.amin([h, w])
    m=12.0/minsize
    minl=minl*m
    # create scale pyramid
    scales=[]
    while minl>=12:
        scales += [m*np.power(factor, factor_count)]
        minl = minl*factor
        factor_count += 1

    # first stage
    for scale in scales:
        hs=int(np.ceil(h*scale))
        ws=int(np.ceil(w*scale))
        im_data = imresample(img, (hs, ws))
        im_data = (im_data-127.5)*0.0078125
        img_x = np.expand_dims(im_data, 0)
        img_y = np.transpose(img_x, (0,2,1,3))
        out = pnet(img_y)
        out0 = np.transpose(out[0], (0,2,1,3))
        out1 = np.transpose(out[1], (0,2,1,3))
        
        boxes, _ = generateBoundingBox(out1[0,:,:,1].copy(), out0[0,:,:,:].copy(), scale, threshold[0])
        
        # inter-scale nms
        pick = nms(boxes.copy(), 0.5, 'Union')
        if boxes.size>0 and pick.size>0:
            boxes = boxes[pick,:]
            total_boxes = np.append(total_boxes, boxes, axis=0)

    numbox = total_boxes.shape[0]
    if numbox>0:
        pick = nms(total_boxes.copy(), 0.7, 'Union')
        total_boxes = total_boxes[pick,:]
        regw = total_boxes[:,2]-total_boxes[:,0]
        regh = total_boxes[:,3]-total_boxes[:,1]
        qq1 = total_boxes[:,0]+total_boxes[:,5]*regw
        qq2 = total_boxes[:,1]+total_boxes[:,6]*regh
        qq3 = total_boxes[:,2]+total_boxes[:,7]*regw
        qq4 = total_boxes[:,3]+total_boxes[:,8]*regh
        total_boxes = np.transpose(np.vstack([qq1, qq2, qq3, qq4, total_boxes[:,4]]))
        total_boxes = rerec(total_boxes.copy())
        total_boxes[:,0:4] = np.fix(total_boxes[:,0:4]).astype(np.int32)
        dy, edy, dx, edx, y, ey, x, ex, tmpw, tmph = pad(total_boxes.copy(), w, h)

    numbox = total_boxes.shape[0]
    if numbox>0:
        # second stage
        tempimg = np.zeros((24,24,3,numbox))
        for k in range(0,numbox):
            tmp = np.zeros((int(tmph[k]),int(tmpw[k]),3))
            tmp[dy[k]-1:edy[k],dx[k]-1:edx[k],:] = img[y[k]-1:ey[k],x[k]-1:ex[k],:]
            if tmp.shape[0]>0 and tmp.shape[1]>0 or tmp.shape[0]==0 and tmp.shape[1]==0:
                tempimg[:,:,:,k] = imresample(tmp, (24, 24))
            else:
                return np.empty()
        tempimg = (tempimg-127.5)*0.0078125
        tempimg1 = np.transpose(tempimg, (3,1,0,2))
        out = rnet(tempimg1)
        out0 = np.transpose(out[0])
        out1 = np.transpose(out[1])
        score = out1[1,:]
        ipass = np.where(score>threshold[1])
        total_boxes = np.hstack([total_boxes[ipass[0],0:4].copy(), np.expand_dims(score[ipass].copy(),1)])
        mv = out0[:,ipass[0]]
        if total_boxes.shape[0]>0:
            pick = nms(total_boxes, 0.7, 'Union')
            total_boxes = total_boxes[pick,:]
            total_boxes = bbreg(total_boxes.copy(), np.transpose(mv[:,pick]))
            total_boxes = rerec(total_boxes.copy())

    numbox = total_boxes.shape[0]
    if numbox>0:
        # third stage
        total_boxes = np.fix(total_boxes).astype(np.int32)
        dy, edy, dx, edx, y, ey, x, ex, tmpw, tmph = pad(total_boxes.copy(), w, h)
        tempimg = np.zeros((48,48,3,numbox))
        for k in range(0,numbox):
            tmp = np.zeros((int(tmph[k]),int(tmpw[k]),3))
            tmp[dy[k]-1:edy[k],dx[k]-1:edx[k],:] = img[y[k]-1:ey[k],x[k]-1:ex[k],:]
            if tmp.shape[0]>0 and tmp.shape[1]>0 or tmp.shape[0]==0 and tmp.shape[1]==0:
                tempimg[:,:,:,k] = imresample(tmp, (48, 48))
            else:
                return np.empty()
        tempimg = (tempimg-127.5)*0.0078125
        tempimg1 = np.transpose(tempimg, (3,1,0,2))
        out = onet(tempimg1)
        out0 = np.transpose(out[0])
        out1 = np.transpose(out[1])
        out2 = np.transpose(out[2])
        score = out2[1,:]
        points = out1
        ipass = np.where(score>threshold[2])
        points = points[:,ipass[0]]
        total_boxes = np.hstack([total_boxes[ipass[0],0:4].copy(), np.expand_dims(score[ipass].copy(),1)])
        mv = out0[:,ipass[0]]

        w = total_boxes[:,2]-total_boxes[:,0]+1
        h = total_boxes[:,3]-total_boxes[:,1]+1
        points[0:5,:] = np.tile(w,(5, 1))*points[0:5,:] + np.tile(total_boxes[:,0],(5, 1))-1
        points[5:10,:] = np.tile(h,(5, 1))*points[5:10,:] + np.tile(total_boxes[:,1],(5, 1))-1
        if total_boxes.shape[0]>0:
            total_boxes = bbreg(total_boxes.copy(), np.transpose(mv))
            pick = nms(total_boxes.copy(), 0.7, 'Min')
            total_boxes = total_boxes[pick,:]
            points = points[:,pick]
                
    return total_boxes, points
           

利用MTCNN網絡把人臉資料圖庫轉換為人臉特征庫(embedding庫)

MTCNN+facenet實作人臉識别系統實作流程項目目錄結建構立人臉資料圖庫MTCNN,Multi-task convolutional neural network(多任務卷積神經網絡)利用MTCNN網絡把人臉資料圖庫轉換為人臉特征庫(embedding庫)facenet進行人臉識别

執行create_dataset.py,程式會加載預訓練模型,把人臉資料圖轉換成embedding特征,儲存到dataset/emb檔案夾下。如下圖所示。

MTCNN+facenet實作人臉識别系統實作流程項目目錄結建構立人臉資料圖庫MTCNN,Multi-task convolutional neural network(多任務卷積神經網絡)利用MTCNN網絡把人臉資料圖庫轉換為人臉特征庫(embedding庫)facenet進行人臉識别

faceEmbedding.npy為人臉特征檔案庫,name.txt是對應的特征标簽。

facenet進行人臉識别

方法

       facenet通過CNN将人臉映射到歐式空間的特征向量上,計算不同圖檔人臉特征的距離,通過相同個體人臉的距離總是小于不同個體 人臉·的距離這一先驗知識訓練網絡(詳細介紹後續補充)。

代碼實作,執行predict.py。流程:加載人臉特征資料庫,提取待識别的人臉的特征與人臉資料庫中的資訊逐一比較。

# 初始化facenet
face_net=face_recognition.facenetEmbedding(model_path)

pred_emb=face_net.get_embedding(face_images)
pred_name,pred_score=compare_embadding(pred_emb, dataset_emb, names_list)




class facenetEmbedding:
    def __init__(self,model_path):
        self.sess = tf.InteractiveSession()
        self.sess.run(tf.global_variables_initializer())
        # Load the model
        facenet.load_model(model_path)
        # Get input and output tensors
        self.images_placeholder = tf.get_default_graph().get_tensor_by_name("input:0")
        self.tf_embeddings = tf.get_default_graph().get_tensor_by_name("embeddings:0")
        self.phase_train_placeholder = tf.get_default_graph().get_tensor_by_name("phase_train:0")

    def  get_embedding(self,images):
        feed_dict = {self.images_placeholder: images, self.phase_train_placeholder: False}
        embedding = self.sess.run(self.tf_embeddings, feed_dict=feed_dict)
        return embedding
    def free(self):
        self.sess.close()


def compare_embadding(pred_emb, dataset_emb, names_list,threshold=0.65):
    '''
        将待識别的人臉特征向量與人臉資料庫進行比較
        :param pred_emb: 待識别的人臉
        :param dataset_emb: 人臉資料庫特征向量
        :param threshold: 置信門檻值,小于說明是同一個人,大于說明不是同一個人
        :return:預測人名,預測分值
        '''
    # 為bounding_box 比對标簽
    pred_num = len(pred_emb)
    dataset_num = len(dataset_emb)
    pred_name = []
    pred_score=[]
    for i in range(pred_num):
        dist_list = []
        for j in range(dataset_num):
            dist = np.sqrt(np.sum(np.square(np.subtract(pred_emb[i, :], dataset_emb[j, :]))))
            dist_list.append(dist)
        min_value = min(dist_list)
        pred_score.append(min_value)
        if (min_value > threshold):
            pred_name.append('unknow')
        else:
            pred_name.append(names_list[dist_list.index(min_value)])
    return pred_name,pred_score

           

效果:

MTCNN+facenet實作人臉識别系統實作流程項目目錄結建構立人臉資料圖庫MTCNN,Multi-task convolutional neural network(多任務卷積神經網絡)利用MTCNN網絡把人臉資料圖庫轉換為人臉特征庫(embedding庫)facenet進行人臉識别

胡歌和周傑倫的照片在人臉資料庫中,可是識别,成龍的不在,是以不能識别。

繼續閱讀