天天看點

[基于tensorflow的人臉檢測] 基于神經網絡的人臉檢測9——人臉檢測

1.前言

2.預處理

3.後處理

4.項目總結

正文:

1.前言

總結一下,目前為止做了什麼:在前面幾篇博文中,對資料進行了處理、搭建了神經網絡、訓練了神經網絡并進行了測試。在實際使用中,因為檢測的圖檔可能是整個人的圖像,是以需要從這些圖像中框出人臉的位置,這也是這個項目的目的。由于神經網絡隻能對一張含有人臉或者非人臉的圖檔進行判斷,是以在檢測一張圖檔時,需要先進行預處理。一張圖檔進行預處理以及神經網絡的判斷輸出後,可能會有很多個結果,是以還要進行後處理,找出最優解。

2.預處理

  • 滑動視窗

    由于一張圖檔可能有很多個部分組成(人臉、非人臉)。是以需要先對輸入的圖檔進行每部分的截取。滑動金字塔是按照固定的視窗大小在圖檔中滑動,進而得到很多個視窗,每個視窗都作為神經網絡的輸入。

    [基于tensorflow的人臉檢測] 基于神經網絡的人臉檢測9——人臉檢測

    上圖展示了滑動視窗将一張圖檔分為很多張子圖檔,除此之位,視窗還記錄了子圖檔在圖檔中的位置,最後可用于人臉标記。每張圖檔都輸入到訓練好的模型,如果神經網絡的輸出機率(神經網絡softmax輸出)大于我們設定的門檻值,就可以認為這張子圖檔是人臉部分,進行位置标記。

    下面是程式實作,函數傳回子視窗圖檔和對應的位置。

    import math 
    
    def slid_win(input_img, win_size_h, win_size_w, slid_step,other):
        """滑動視窗函數"""
        #輸入參數-輸入、視窗w、視窗h和步長
        #輸出滑動圖檔、滑動坐标(坐标格式:[y1,y2,x1,x2]
        sli_images = []
        locates = []
        image_h, image_w, _ = input_img.shape
        lim_w =  math.ceil((image_w-win_size_w)/ slid_step)
        lim_h = math.ceil((image_h-win_size_h)/slid_step)
        # print(lim_w, lim_h)
        for i in range(lim_h):
            strat_h = slid_step*i
            end_h = strat_h + win_size_h
            for j in range(lim_w):
                start_w = slid_step*j
                end_w = start_w + win_size_w
                # print(strat_h, end_h, start_w, end_w)
                if (end_h< image_h) or (end_w< image_w):
                    part_img = input_img[strat_h:end_h, start_w:end_w]
                    locate = [strat_h, end_h, start_w, end_w]
                    sli_images.append(part_img)
                    locates.append(locate)
                    # print(locate)
              
        #添加沒有滑動到的區域
        if  not isinstance(((image_w-win_size_w)/ slid_step), int): #判斷橫方向是不是為整數 不是标志有餘留的邊緣
            for i in range(lim_h): #周遊縱軸
                strat_h = slid_step*i
                end_h = strat_h + win_size_h
                start_w = image_w-win_size_w
                end_w = image_w
                part_img = input_img[strat_h:end_h, start_w:end_w]
                locate = [int(strat_h), int(end_h), int(start_w), int(end_w)]
                sli_images.append(part_img)
                # print(locate)
                locates.append(locate)
            
        if  not isinstance(((image_h-win_size_h)/ slid_step), int):#判斷縱方向是不是為整數 不是标志有餘留的邊緣
            for j in range(lim_w): #周遊橫軸
                start_w = slid_step*j
                end_w = start_w + win_size_w
                strat_h = image_h-win_size_h
                end_h = image_h
                part_img = input_img[strat_h:end_h, start_w:end_w]
                locate = [strat_h, end_h, start_w, end_w]
                sli_images.append(part_img)
                # print(locate)
                locates.append(locate)
        condition1 = not isinstance(((image_w-win_size_w)/ slid_step), int)
        condition2 = not isinstance(((image_h-win_size_h)/ slid_step), int)
        if condition1 and  condition2: #添加最後一張
            start_w = image_w-win_size_w
            end_w = image_w
            strat_h = image_h-win_size_h
            end_h = image_h
            part_img = input_img[strat_h:end_h, start_w:end_w]
            locate = [strat_h, end_h, start_w, end_w]
            sli_images.append(part_img)
            # print(locate)
            locates.append(locate) #格式y1 y2 x1 x2
                
        return sli_images, locates
               
  • 圖像金字塔

    雖然滑動視窗可以把一張圖檔中的人臉和非人臉分離出來,但是還會存在一個問題,因為滑動視窗的尺寸是固定的,是以會存在視窗大小和人臉大小不比對的情況。是以需要先對輸入的圖檔進行尺寸變換的操作,使得滑動視窗的大小總能和人臉大小互相比對。

    [基于tensorflow的人臉檢測] 基于神經網絡的人臉檢測9——人臉檢測
    (圖檔來自于百度圖檔)

3.後處理

經過了預處理并輸入到神經網絡,且進行位置标記,得到的圖檔是這樣的。

[基于tensorflow的人臉檢測] 基于神經網絡的人臉檢測9——人臉檢測

一點也不美觀,也沒有達到效果。這主要是由于門檻值的設定(達到門檻值就框出人臉)、滑動視窗步長和比例因子所造成的。是以這裡需要進行非極大值抑制(NMS)處理,下面是NMS的算法思想。

[基于tensorflow的人臉檢測] 基于神經網絡的人臉檢測9——人臉檢測

NMS簡單的說就是對框進行合并,合并的基準是機率最大對應的視窗。如果一個視窗和機率最大對應的視窗重疊面積足夠大,就進行消除,隻保留機率值最大所對應的視窗。根據這個思想進行程式編寫如下。

def compuet_iou(rect1, rect2):
    """計算兩個矩形的IOU"""
    #rect是矩形的四個坐标 左上角和右下角坐标 rect = [x1,y1,x2,y2]
    area1 = (rect1[3] - rect1[1]) * (rect1[2] - rect1[0])
    area2 = (rect2[3] - rect2[1]) * (rect2[2] - rect2[0])
    all_area = area1 + area2
    x1 = max(rect1[0], rect2[0])
    y1 = max(rect1[1], rect2[1])
    x2 = min(rect1[2], rect2[2])
    y2 = min(rect1[3], rect2[3])
    h = max(0, y2 - y1)
    w = max(0, x2 - x1)
    overlap = h * w
    #判斷等于1情況
    try :
        iou = overlap/(all_area - overlap)
    except:
        iou = 1
    else : 
        iou = overlap/(all_area - overlap)

    return iou

def max_prop(locates, props):
    """取最大機率的nms"""
    #輸入參數:所有超過門檻值的滑動窗位置、滑動視窗對應門檻值
    #輸出 算法留下來的框位置
    temp_locates = []
    temp_prop = []
    final_locates = []
    return_locates = []
    second_locates = []
    second_prop = []
    for i in range(len(locates)): #周遊目前所有框
        
        temp_locate = [locates[i][2],locates[i][0],locates[i][3],locates[i][1]]
        temp_locates.append(temp_locate)
        temp_prop.append(props[i])
        
        for j in range(len(locates)):
            now_locate = [locates[j][2],locates[j][0],locates[j][3],locates[j][1]]
            iou = compuet_iou(temp_locate,now_locate) #計算iou
            if iou>0.3 and iou<1: #門檻值設定
                temp_locates.append(now_locate)
                temp_prop.append(props[j])
                
        second_locates.append(temp_locates)
        second_prop.append(temp_prop)
        temp_locates = [] #清零 下一次儲存
        temp_prop = []
    
    for k in range(len(second_locates)):
        area = []
        for l in range(len(second_locates[k])):
            area.append(second_prop[k][l]) #存儲機率值
        max_index = area.index(max(area)) #取最大機率
        final_locates.append(second_locates[k][max_index])#取最大機率對應的框
    # #整理清單 删除相同元素
    for final_locate in final_locates:
        if not final_locate in return_locates:
            return_locates.append(final_locate)
            
    return return_locates #return_locates #格式[x1,y1,x2,y2]
           

4.項目總結

至此,整個人臉檢測項目就完成了。從資料處理到神經網絡搭建、訓練與測試,再到一張人臉圖檔的測試以及一張圖檔的測試。下面是這個項目的步驟總結。

  1. 确定資料集 --> 處理得到訓練、驗證以及測試的圖檔
  2. 搭建神經網絡 --> 用1中的圖檔進行訓練 --> 得到分類器模型
  3. 圖檔輸入 --> 圖像金字塔 --> 滑動視窗 --> 送入2中得到的分類器模型分類 --> 輸出機率值并标記視窗 --> 非極大值抑制 --> 框出人臉
步驟 備注
确定資料集 FDDB或WIDER FACE或其他
處理得到訓練、驗證以及測試的圖檔 該内容在FDDB資料集處理、WIDER FACE資料集處理、資料集的标簽生成中,資料也在其中。
搭建神經網絡 按照 神經網絡的搭建的架構進行搭建
用1中的圖檔進行訓練 設定學習率和訓練次數等參數進行訓練。訓練神經網絡中的訓練架構為了加快速度設定了比較小的batch、圖檔和訓練次數(實際使用時,并不是使用這麼小的batch、圖檔和訓練次數得到模型),可以自主進行選擇調節
得到分類器模型 訓練搭建好的神經網絡得到的模型。我的模型在這裡擷取人臉檢測模型密碼:f3vzk8
圖檔輸入 選擇一張圖檔或者視訊的一幀
圖像金字塔 本篇博文
滑動視窗 本篇博文
送入分類器模型分類 用驗證神經網絡中的圖檔驗證程式進行圖檔輸入,其中的輸出為經過softmax後的機率值。(用于本博文中滑動視窗輸入,輸出的機率值與門檻值比較)
輸出機率值并标記視窗 輸出機率值指的是softmax輸出,當這個值超出自己設定的門檻值時就進行标記
非極大值抑制 本篇博文,經過非極大值抑制後的輸出就是最終人臉檢測結果