1. 程式人生 > >用Python實現一個簡單的——人臉相似度對比

用Python實現一個簡單的——人臉相似度對比

近幾年來,興起了一股人工智慧熱潮,讓人們見到了AI的能力和強大,比如影象識別,語音識別,機器翻譯,無人駕駛等等。總體來說,AI的門檻還是比較高,不僅要學會使用框架實現,更重要的是,需要有一定的數學基礎,如線性代數,矩陣,微積分等。

幸慶的是,國內外許多大神都已經給我們造好“輪子”,我們可以直接來使用某些模型。今天就和大家交流下如何實現一個簡易版的人臉對比,非常有趣!

整體思路:

1、預先匯入所需要的人臉識別模型;

2、遍歷迴圈識別資料夾裡面的圖片,讓模型“記住”人物的樣子;

3、輸入一張新的影象,與前一步資料夾裡面的圖片比對,返回最接近的結果。

使用到的第三方模組和模型:

1、模組:os,dlib,glob,numpy;

2、模型:人臉關鍵點檢測器,人臉識別模型。

第一步:匯入需要的模型。

這裡解釋一下兩個dat檔案:

它們的本質是引數值(即神經網路的權重)。人臉識別算是深度學習的一個應用,事先需要經過大量的人臉影象來訓練。所以一開始我們需要去設計一個神經網路結構,來“記住”人類的臉。

對於神經網路來說,即便是同樣的結構,不同的引數也會導致識別的東西不一樣。在這裡,這兩個引數檔案就對應了不同的功能(它們對應的神經網路結構也不同):

shape_predictor.dat這個是為了檢測人臉的關鍵點,比如眼睛,嘴巴等等;dlib_face_recognition.dat是在前面檢測關鍵點的基礎上,生成人臉的特徵值。

所以後面使用dlib模組的時候,其實就是相當於,呼叫了某個神經網路結構,再把預先訓練好的引數傳給我們呼叫的神經網路。順便提一下,在深度學習領域中,往往動不動會訓練出一個上百M的引數模型出來,是很正常的事。

import os,dlib,glob,numpy
from skimage import io

# 人臉關鍵點檢測器
predictor_path = "shape_predictor.dat"
# 人臉識別模型、提取特徵值
face_rec_model_path = "dlib_face_recognition.dat"
# 訓練影象資料夾
faces_folder_path ='train_images' 

# 載入模型
detector = dlib.get_frontal_face_detector()
sp = dlib.shape_predictor(predictor_path)
facerec = dlib.face_recognition_model_v1(face_rec_model_path)

第二步:對訓練集進行識別。

在這一步中,我們要完成的是,對圖片資料夾裡面的人物影象,計算他們的人臉特徵,並放到一個列表裡面,為了後面可以和新的影象進行一個距離計算。關鍵地方會加上註釋,應該不難理解。

candidate = []         # 存放訓練集人物名字
descriptors = []       #存放訓練集人物特徵列表

for f in glob.glob(os.path.join(faces_folder_path,"*.jpg")):
    print("正在處理: {}".format(f))
    img = io.imread(f)
    candidate.append(f.split('\\')[-1].split('.')[0])
    # 人臉檢測
    dets = detector(img, 1)
    for k, d in enumerate(dets): 
        shape = sp(img, d)
        # 提取特徵
        face_descriptor = facerec.compute_face_descriptor(img, shape)
        v = numpy.array(face_descriptor) 
        descriptors.append(v)

print('識別訓練完畢!')

當你做完這一步之後,輸出列表descriptors看一下,可以看到類似這樣的陣列,每一個數組代表的就是每一張圖片的特徵量(128維)。然後我們可以使用L2正規化(歐式距離),來計算兩者間的距離。

舉個例子,比如經過計算後,A的特徵值是[x1,x2,x3],B的特徵值是[y1,y2,y3], C的特徵值是[z1,z2,z3]。

那麼由於A和B更接近,所以會認為A和B更像。想象一下極端情況,如果是同一個人的兩張不同照片,那麼它們的特徵值是不是應該會幾乎接近呢?知道了這一點,就可以繼續往下走了。 

第三步:處理待對比的圖片。

其實是同樣的道理,如法炮製,目的就是算出一個特徵值出來,所以和第二步差不多。然後再順便計算出新圖片和第二步中每一張圖片的距離,再合成一個字典型別,排個序,選出最小值,搞定收工!

try:
##    test_path=input('請輸入要檢測的圖片的路徑(記得加字尾哦):')
    img = io.imread(r".\test_images\test6.jpg")
    dets = detector(img, 1)
except:
    print('輸入路徑有誤,請檢查!')

dist = []
for k, d in enumerate(dets):
    shape = sp(img, d)
    face_descriptor = facerec.compute_face_descriptor(img, shape)
    d_test = numpy.array(face_descriptor) 
    for i in descriptors:                #計算距離
        dist_ = numpy.linalg.norm(i-d_test)
        dist.append(dist_)

# 訓練集人物和距離組成一個字典
c_d = dict(zip(candidate,dist))                
cd_sorted = sorted(c_d.items(), key=lambda d:d[1])
print ("識別到的人物最有可能是: ",cd_sorted[0][0])

這裡我用了一張“斷水流大師兄”林國斌的照片,識別的結果是,果然,是最接近黎明瞭(嘻嘻,我愛黎明)。但如果你事先在訓練影象集裡面有放入林國斌的照片,那麼出來的結果就是林國斌了。 

為什麼是黎明呢?我們看一下輸入圖片裡的人物最後與每個明星的距離,輸出列印一下:

{'劉亦菲': 0.5269014581137407,

'劉詩詩': 0.4779630331578229,

'唐藝昕': 0.45967444611419184,

'楊冪': 0.4753850256188804,

'迪麗熱巴': 0.5730399094704894,

'鄭秀妍': 0.40740137304879187,

'鄭秀晶': 0.45325515192940385,

'郭富城': 0.7624925709626963,

'黎明': 0.5925473299225084} 

沒錯,他和黎明的距離是最小的,所以和他也最像了!

原始碼及模型下載:https://download.csdn.net/download/m0_38106923/10772957