基於kNN的人臉識別演算法
阿新 • • 發佈:2021-08-15
-
摘要:
本次實驗嘗試通過將人臉的影象轉化為特徵向量,然後訓練資料集,通過計算尤拉距離找到與待測人臉最接近的k個人臉,這樣對人臉進行歸類識別實現一個基於KNN 的人臉識別演算法,來達到人臉識別的入門級學習。
-
演算法簡介:
KNN演算法假設給定一個訓練資料集,其中的例項類別已定。分類時,對新的例項,根據其 k 個最近鄰的訓練例項的類別,通過多數表決等方式進行預測。因此,KNN演算法不具有顯式的學習過程。
KNN演算法實際上利用訓練資料集對特徵向量空間進行劃分,並作為其分類的“模型”。 k值的選擇、距離度量以及分類決策規則是k近鄰演算法的三個基本要素。 -
演算法流程:
1.假設有一個帶有標籤的樣本資料集(訓練樣本集),其中包含每條資料與所屬分類的對應關係。遍歷訓練資料集,計算預測樣本與其他每一個樣本點的距離,按照由近到遠排序。完成訓練得到訓練後的資料集After training Data Set
2.定義一個KNN引數k 值(1<=k<=20),表示納入投票決策的樣本數
3.輸入沒有標籤的新資料後,將新資料的每個特徵與樣本集中資料對應的特徵進行比較(進行測試集的測試)。
4.取前 k個樣本資料對應的分類標籤。求 k 個數據中出現次數最多的分類標籤作為新資料的分類。 -
實驗環境:
python版本為:python-3.8.1,所需執行庫有matplotlib、numpy及pillow
-
原始碼:
import matplotlib.pyplot as plt from PIL import Image, ImageFilter import numpy import heapq dataBase="data_base" persons=[] faces=[] for i in range(1, 41): persons.append("s" + str(i)) for i in range(1, 11): faces.append(str(i) + ".pgm") def parseImageToVector(path): """ 功能:將影象轉換為特徵向量 輸入:影象的路徑 返回值:特徵向量(numpy一維陣列) """ img = numpy.array(Image.open(path)) return img.flatten() def eularDistance(vec1, vec2): """ 功能:計算兩個特徵向量的eular距離 輸入:特徵向量1,2 返回值:尤拉距離 """ return numpy.sum(numpy.square(vec1-vec2)) def trainSetInitialization(faces): """ 功能:初始化訓練資料集 輸入:用作訓練集的人臉ID列表 返回值:初始化的資料集,(資料, 標籤, 影象)元組列表 """ trainSet = [] for person in persons: for face in faces: imgPath = dataBase + "/" + person + "/" + str(face) + ".pgm" imgVec = parseImageToVector(imgPath) trainSet.append((imgVec, person, str(face))) return trainSet def faceRecognition(face, trainSet, k): """ 功能:識別人臉,計算訓練資料集中的哪張臉與此臉相同(KNN實現) 輸入:face陣列中的測試臉,trainDataSet訓練後的資料,kNN引數 返回:資料集中最相同的面孔的標籤 """ heap = [] #小根堆,儲存(距離,標號,人臉)元組 neighbors = [] # 儲存前k個點的資訊 result = {} # { key : val } 表示一組k近鄰點中 { 標籤 : 標籤數量(1<=n<=k) } # 計算前k個最近的點,壓入小根堆heap for trainData in trainSet: # trainData[1]對應person標籤, trainData[0]對應該標籤下的某個特徵向量 heapq.heappush(heap, (eularDistance(face, trainData[0]), trainData[1], trainData[2]) ) # 找到前k個最近的點中數量最多的標籤,並加入結果result for i in range(k): first = heapq.heappop(heap) top = first[1] # 標籤 topImg = first[2] # 影象 neighbors.append((top, topImg)) if top in result: result[top] = result[top] + 1 else: result[top] = 1 maximum = (None, 0) for label in result: if result[label] > maximum[1]: maximum = (label, result[label]) # 顯示資訊 print("測試所屬標籤:" + maximum[0]) print("各標籤對應的數量" + str(result)) print("與目標k近鄰的人臉資訊:") for neighbor in neighbors: path = dataBase + "/" + neighbor[0] + "/" + neighbor[1] + ".pgm" print(path) print("-------------分界線--------------") return maximum[0] def main(): fault = 0 total = 0 kList = [] misclassificationRateList = [] for k in range(1, 21): for testIndex in range(1, 11): # 初始化訓練集 trainImages = [] for trainImage in range(1,11): trainImages.append(trainImage) trainImages.remove(testIndex) trainSet = trainSetInitialization(trainImages) # 測試 for person in persons: path = dataBase + "/" + person + "/" + str(testIndex) + ".pgm" faceVec = parseImageToVector(path) print("測試人臉的路徑:" + path) result = faceRecognition(faceVec, trainSet, k) if person != result: fault = fault + 1 total = total + 1 kList.append(k) misclassificationRateList.append(fault / total) print("misclassification rate:", fault / total) # 顯示影象 plt.plot(kList, misclassificationRateList, alpha=0.7) plt.xticks(kList, kList) plt.ylabel("Misclassification Rate") plt.show() if __name__ == "__main__": main()
-
實驗結果及分析: