最近研究了一下人臉識別,發現裡面很有門道啊,我是初入,還不是很理解,只能到時看看論壇,到處學習啊。感謝各位先人的帖子和代碼。本帖部分原創,部分借用,如有雷同,純屬巧合!!!
首先需要2個第三方的庫
opencv-python、numpy
安裝完成後,可以編程了,還是先說明一下需要的算法:
特徵子臉技術的基本思想是:從統計的觀點,尋找人臉圖像分布的基本元素,即人臉圖像樣本集協方差矩陣的特徵向量,以此近似地表徵人臉圖像。這些特徵向量稱為特徵臉(Eigenface)。
實際上,特徵臉反映了隱含在人臉樣本集合內部的信息和人臉的結構關係。將眼睛、面頰、下頜的樣本集協方差矩陣的特徵向量稱為特徵眼、特徵頜和特徵唇,統稱特徵子臉。特徵子臉在相應的圖像空間中生成子空間,稱為子臉空間。計算出測試圖像窗口在子臉空間的投影距離,若窗口圖像滿足閾值比較條件,則判斷其為人臉。
基於特徵分析的方法,也就是將人臉基準點的相對比率和其它描述人臉臉部特徵的形狀參數或類別參數等一起構成識別特徵向量,這種基於整體臉的識別不僅保留了人臉部件之間的拓撲關係,而且也保留了各部件本身的信息,而基於部件的識別則是通過提取出局部輪廓信息及灰度信息來設計具體識別算法。現在Eigenface(PCA)算法已經與經典的模板匹配算法一起成為測試人臉識別系統性能的基準算法;而自1991年特徵臉技術誕生以來,研究者對其進行了各種各樣的實驗和理論分析,FERET'96測試結果也表明,改進的特徵臉算法是主流的人臉識別技術,也是具有最好性能的識別方法之一。
該方法是先確定眼虹膜、鼻翼、嘴角等面像五官輪廓的大小、位置、距離等屬性,然後再計算出它們的幾何特徵量,而這些特徵量形成一描述該面像的特徵向量。其技術的核心實際為「局部人體特徵分析」和「圖形/神經識別算法。」這種算法是利用人體面部各器官及特徵部位的方法。如對應幾何關係多數據形成識別參數與資料庫中所有的原始參數進行比較、判斷與確認。Turk和Pentland提出特徵臉的方法,它根據一組人臉訓練圖像構造主元子空間,由於主元具有臉的形狀,也稱為特徵臉 ,識別時將測試 圖像投影到主元子空間上,得到一組投影係數,和各個已知人的人臉圖像比較進行識別。Pentland等報告了相當好的結果,在 200個人的 3000幅圖像中得到 95%的正確識別率,在FERET資料庫上對 150幅正面人臉象只有一個誤識別。但系統在進行特徵臉方法之前需要作大量預處理工作如歸一化等。
在傳統特徵臉的基礎上,研究者注意到特徵值大的特徵向量 (即特徵臉 )並不一定是分類性能好的方向,據此發展了多種特徵 (子空間 )選擇方法,如Peng的雙子空間方法、Weng的線性歧義分析方法、Belhumeur的FisheRFace方法等。事實上,特徵臉方法是一種顯式主元分析人臉建模,一些線性自聯想、線性壓縮型BP網則為隱式的主元分析方法,它們都是把人臉表示為一些向量的加權和,這些向量是訓練集叉積陣的主特徵向量,Valentin對此作了詳細討論。總之,特徵臉方法是一種簡單、快速、實用的基於變換係數特徵的算法,但由於它在本質上依賴於訓練集和測試集圖像的灰度相關性,而且要求測試圖像與訓練集比較像,所以它有著很大的局限性。
基於KL 變換的特徵人臉識別方法
基本原理:
KL變換是圖象壓縮中的一種最優正交變換,人們將它用於統計特徵提取,從而形成了子空間法模式識別的基礎,若將KL變換用於人臉識別,則需假設人臉處於低維線性空間,且不同人臉具有可分性,由於高維圖象空間KL變換後可得到一組新的正交基,因此可通過保留部分正交基,以生成低維人臉空間,而低維空間的基則是通過分析人臉訓練樣本集的統計特性來獲得,KL變換的生成矩陣可以是訓練樣本集的總體散布矩陣,也可以是訓練樣本集的類間散布矩陣,即可採用同一人的數張圖象的平均來進行訓練,這樣可在一定程度上消除光線等的幹擾,且計算量也得到減少,而識別率不會下降。
下面開始編程,過程中發現pcv好複雜啊,增加了些列印,方便調試用。
#encoding=utf-8
import numpy as np
import cv2
import os
class EigenFace(object):
def __init__(self,threshold,dimNum,dsize):
self.threshold = threshold # 閾值暫未使用
self.dimNum = dimNum
self.dsize = dsize
def loadImg(self,fileName,dsize):
'''''
載入圖像,灰度化處理,統一尺寸,直方圖均衡化
:param fileName: 圖像文件名
:param dsize: 統一尺寸大小。元組形式
:return: 圖像矩陣
'''
img = cv2.imread(fileName)
retImg = cv2.resize(img,dsize)
retImg = cv2.cvtColor(retImg,cv2.COLOR_RGB2GRAY)
retImg = cv2.equalizeHist(retImg)
# cv2.imshow('img',retImg)
# cv2.waitKey()
return retImg
def createImgMat(self,dirName):
'''''
生成圖像樣本矩陣,組織形式為行為屬性,列為樣本
:param dirName: 包含訓練數據集的圖像文件夾路徑
:return: 樣本矩陣,標籤矩陣
'''
dataMat = np.zeros((10,1))
label = []
for parent,dirnames,filenames in os.walk(dirName):
# print parent
# print dirnames
# print filenames
index = 0
for dirname in dirnames:
for subParent,subDirName,subFilenames in os.walk(parent+'/'+dirname):
for filename in subFilenames:
img = self.loadImg(subParent+'/'+filename,self.dsize)
tempImg = np.reshape(img,(-1,1))
IF index == 0 :
dataMat = tempImg
else:
dataMat = np.column_stack((dataMat,tempImg))
label.append(subParent+'/'+filename)
index += 1
return dataMat,label
def PCA(self,dataMat,dimNum):
'''''
PCA函數,用於數據降維
:param dataMat: 樣本矩陣
:param dimNum: 降維後的目標維度
:return: 降維後的樣本矩陣和變換矩陣
'''
# 均值化矩陣
meanMat = np.mat(np.mean(dataMat,1)).T
print u'平均值矩陣維度',meanMat.shape
diffMat = dataMat-meanMat
# 求協方差矩陣,由於樣本維度遠遠大於樣本數目,所以不直接求協方差矩陣,採用下面的方法
covMat = (diffMat.T*diffMat)/float(diffMat.shape[1]) # 歸一化
#covMat2 = np.cov(dataMat,bias=True)
#print '基本方法計算協方差矩陣為',covMat2
print u'協方差矩陣維度',covMat.shape
eigVals, eigVects = np.linalg.eig(np.mat(covMat))
print u'特徵向量維度',eigVects.shape
print u'特徵值',eigVals
eigVects = diffMat*eigVects
eigValInd = np.argsort(eigVals)
eigValInd = eigValInd[::-1]
eigValInd = eigValInd[:dimNum] # 取出指定個數的前n大的特徵值
print u'選取的特徵值',eigValInd
eigVects = eigVects/np.linalg.norm(eigVects,axis=0) #歸一化特徵向量
redEigVects = eigVects[:,eigValInd]
print u'選取的特徵向量',redEigVects.shape
print u'均值矩陣維度',diffMat.shape
lowMat = redEigVects.T*diffMat
print u'低維矩陣維度',lowMat.shape
return lowMat,redEigVects
def compare(self,dataMat,testImg,label):
'''''
比較函數,這裡只是用了最簡單的歐氏距離比較,還可以使用KNN等方法,如需修改修改此處即可
:param dataMat: 樣本矩陣
:param testImg: 測試圖像矩陣,最原始形式
:param label: 標籤矩陣
:return: 與測試圖片最相近的圖像文件名
'''
testImg = cv2.resize(testImg,self.dsize)
testImg = cv2.cvtColor(testImg,cv2.COLOR_RGB2GRAY)
testImg = np.reshape(testImg,(-1,1))
lowMat,redVects = self.PCA(dataMat,self.dimNum)
testImg = redVects.T*testImg
print u'檢測樣本變換後的維度',testImg.shape
disList = []
testVec = np.reshape(testImg,(1,-1))
for sample in lowMat.T:
disList.append(np.linalg.norm(testVec-sample))
print disList
sortIndex = np.argsort(disList)
return label[sortIndex[0]]
def predict(self,dirName,testFileName):
'''''
預測函數
:param dirName: 包含訓練數據集的文件夾路徑
:param testFileName: 測試圖像文件名
:return: 預測結果
'''
testImg = cv2.imread(testFileName)
dataMat,label = self.createImgMat(dirName)
print u'加載圖片標籤',label
ans = self.compare(dataMat,testImg,label)
return ans
if __name__ == '__main__':
eigenface = EigenFace(200,500,(500,500))
print eigenface.predict('d:/face/11.bmp','D:/face1/1.bmp')
免責聲明:本文轉自電子發燒友論壇,傳播僅為學習交流,版權歸原作者所有,如有侵權,請聯繫刪除