1. 程式人生 > >使用開源人臉特徵提取器進行臉部顏值評分

使用開源人臉特徵提取器進行臉部顏值評分

本文僅為模型應用實戰,而非顏值研究,所得結果僅供娛樂,僅供參考。

方法也僅供參考。

一般而言,資料量越大,結果越接近正常人審美。由於本次資料量較小,故僅為實驗。

使用環境:ubuntu14.04,opencv3.2.0,dlib19.6,python2.7

一、準備工作:

1、下載dlib庫,下載特徵提取模型。

該模型的作用是通過卷積神經網路產生128維的特徵向量,用以代表這張臉。網路輸入引數為人臉landmark的68個特徵點shape和整幅影象。可猜想網路特徵與人臉的68特徵點座標有關,在網路中進行歸一化並進一步處理,使得提出的特徵具有獨立、唯一性。

考慮到人臉的顏值與五官位置,拍照時的表情有關,故本網路可作為一種方案進行嘗試。

Dlib下載:

本模型原用於人臉識別,原型為CNN_ResNet。殘差網路是為了減弱在訓練過程中隨著網路層數增加而帶來的梯度彌散/爆炸的問題。該方法在LFW上進行人臉識別達到99.38%的準確率。

模型名稱:dlib_face_recognition_resnet_model_v1,迭代次數為10000,訓練時用了約300萬的圖片。輸入層的圖片尺寸是150。

下載地址:

提取特徵的網路模型地址:

landmark 68特徵點位置提取模型:

2、資料準備:準備不同型別的臉部影象,注意選用顏值不同的照片,該部分具有一定的主觀性,也是對最後評分影響最重要的一個環節,所以資料量應儘可能大,選用的影象儘可能典型。

我們設定6個分數,分別為:95,90,85,80,70,65

95分人數僅2人,其餘分數在15人左右。85人最多,約20人。資料符合正態分佈。

二、生成資料庫。

將整理好的圖片分別用資料夾包含好,每一個資料夾為一類顏值分數。在確保能夠檢測到臉的情況下,將每張圖片送入網路提取特徵,同時為其加入標籤,表示顏值所屬類別,為後續測試分類做好準備。

這樣每張圖就都已經生成了其對應的128個值和一個標籤。

三、基於最鄰近匹配的分數估計(類似KNN)

資料形式如下表所示:

資料庫資料儲存格式
新的測試圖片進入網路同樣得到128個值:
測試圖片資料形式
定義兩種衡量接近度的尺度(方式):
(1)歐氏距離:
歐氏距離

(2)基於線性組合係數的接近度表示:
我們將表1的資料矩陣進行轉置,得到如下表所示的矩陣:

樣本資料轉置矩陣

將以上矩陣設為A,測試圖片所形成的特徵列向量為b。


矩陣方程求解
A為128*n維,x為n維,b為128維。
則求得的x為b向量在A向量中每個列向量所具有的分量。即把測試圖片的特徵看作原有資料集中每個圖片特徵的線性組合。其係數越大的,則我們認為該係數所對應的資料庫中的圖片越接近測試圖片。
分別找到歐式距離最近的3個、線性組合中係數最大的三個,將這三個分別進行加權處理。

對歐式距離最接近的三張,我們找到對應的原資料(分數值),我們暫認為三者概率近似,以1:1:1的形式加權求和(這三張中可能有多張屬於同一顏值類別)。

對於使用線性組合方法的,取到這三張對應的而後使用權重的方法。

最後將2種方法結合,我們認為第二種方案更可信,以0.6權重加權,第一種方案,以0.4權重加權。
取歐式距離的前5張,進行類別投票以檢驗分數,若投票結果類別對應的分數值與之前求得分數相差較大,則將本次投票結果以一定的比例折算進入總分,調整原有分數,以防誤差過大。

測試圖片1測試圖片2
測試圖片3

四、拓展:加入性別識別
即準備男、女照片各約100張,應覆蓋不同年齡段,在樣本較少的情況下,(長得清秀的)男孩可能被誤認為女生。
分別打上標籤:0-女生,1-男生。
基於投票的分類,分別求測試圖與資料庫中特徵值距離的歐式距離、餘弦距離,取與特徵距離最近的10張,找到對應的原圖所屬性別,進行投票,多於半數(即大於10張)認為其為該性別。
資料結果如下:
歐式距離最近10張圖片的性別結果:[1,1,0,0,1,1,1,1,1,1]
餘弦距離最近10張圖片的性別結果:[1,1,1,0,0,1,1,1,1,1]
結果為:男性,置信度confidence=8*2/20=0.8
置信度表示本次結果的可信度,或根據先驗知識,求預測類別的概率。
基於投票的方案准確率較高。

性別測試結果
【注】測試和訓練圖片均源於網路。

還可以採用基於SVM的分類,關鍵程式碼:
clf=svm.SVC(C=1, kernel='rbf', gamma=1, decision_function_shape='ovr')
clf.fit(dataMat,np.uint8(labelMat))
face_descriptor_trans=face_descriptor_trans.reshape(1,-1)
print(clf.decision_function(dataMat))
score=clf.predict(face_descriptor_trans)

但在問題顏值計算中,分類結果始終為第三類,原因暫未知。且第三類中圖片數量略多於其他類別。
二分類問題有不錯的表現。

此外鄰近匹配法和分類思想也可用於表情識別等分類問題中。

---------------------------------關鍵程式碼-----------------------------------
歐氏距離與餘弦距離計算
def euler_dist(vector1, vector2):
X = np.vstack([vector1, vector2])
dist = pdist(X)
return dist

def cos(vector1, vector2):
dot_product = 0.0;
normA = 0.0;
normB = 0.0;
for a, b in zip(vector1, vector2):
dot_product += a * b
normA += a ** 2
normB += b ** 2
if normA == 0.0 or normB == 0.0:
return None
else:
return dot_product / ((normA * normB) ** 0.5)

矩陣轉換為列表,可用index進行索引:dist1 = list(dist)
對原dist進行排序操作 找到距離最近的索引號new_dist1 = sorted(dist)
score_1[j]=labelMat[np.uint8(loca_dist1[j])]
反查出對應的標籤是哪一類。

for i in range(0,num_select):
record_times[np.uint8(score_1[i])]=record_times[np.uint8(score_1[i])]+1
進行投票表決。
得分加權:
final_score=score[np.uint8(score_1[0])]0.333+score[np.uint8(score_1[1])]0.333+score[np.uint8(score_1[2])]*0.333