人臉識(shí)別算法是指在檢測(cè)到人臉并定位面部關(guān)鍵特征點(diǎn)之后,主要的人臉區(qū)域就可以被裁剪出來(lái),經(jīng)過(guò)預(yù)處理之后,饋入后端的識(shí)別算法。識(shí)別算法要完成人臉特征的提取,并與庫(kù)存的已知人臉進(jìn)行比對(duì),完成最終的分類(lèi)。人臉識(shí)別算法的原理:系統(tǒng)輸入一張或者一系列含有未確定身份的人臉圖像,以及人臉數(shù)據(jù)庫(kù)中的若干已知身份的人臉圖象或者相應(yīng)的編碼,而其輸出則是一系列相似度得分,表明待識(shí)別的人臉的身份。
本教程操作環(huán)境:windows7系統(tǒng)、Dell G3電腦。
人臉識(shí)別(Facial Recognition),就是通過(guò)視頻采集設(shè)備獲取用戶的面部圖像,再利用核心的算法對(duì)其臉部的五官位置、臉型和角度進(jìn)行計(jì)算分析,進(jìn)而和自身數(shù)據(jù)庫(kù)里已有的范本進(jìn)行比對(duì),后判斷出用戶的真實(shí)身份。
人臉識(shí)別算法是指在檢測(cè)到人臉并定位面部關(guān)鍵特征點(diǎn)之后,主要的人臉區(qū)域就可以被裁剪出來(lái),經(jīng)過(guò)預(yù)處理之后,饋入后端的識(shí)別算法。識(shí)別算法要完成人臉特征的提取,并與庫(kù)存的已知人臉進(jìn)行比對(duì),完成最終的分類(lèi)。
人臉識(shí)別的算法有 4 種:基于人臉特征點(diǎn)的識(shí)別算法、基于整幅 人臉圖像的識(shí)別算法、基于模板的識(shí)別算法、利用神經(jīng)網(wǎng)絡(luò)進(jìn)行識(shí)別的算法。
人臉識(shí)別算法的原理:
系統(tǒng)輸入一般是一張或者一系列含有未確定身份的人臉圖像,以及人臉數(shù)據(jù)庫(kù)中的若干已知身份的人臉圖象或者相應(yīng)的編碼,而其輸出則是一系列相似度得分,表明待識(shí)別的人臉的身份。
人臉識(shí)別的三個(gè)經(jīng)典算法
1、Eigenfaces(特征臉)算法
Eigenfaces是在人臉識(shí)別的計(jì)算機(jī)視覺(jué)問(wèn)題中使用的一組特征向量的名稱(chēng),Eigenfaces是基于PCA(主成分分析)的,所以學(xué)習(xí)Eigenfaces需要我們了解PCA的原理。
基本思想
主成分分析(PCA)是一種矩陣的壓縮算法,在減少矩陣維數(shù)的同時(shí)盡可能的保留原矩陣的信息,簡(jiǎn)單來(lái)說(shuō)就是將 n×m的矩陣轉(zhuǎn)換成n×k的矩陣,僅保留矩陣中所存在的主要特性,從而可以大大節(jié)省空間和數(shù)據(jù)量。PCA的實(shí)現(xiàn)需要進(jìn)行降維,也就是將矩陣進(jìn)行變換,從更高的維度降到低的維度,然而PCA的降維離不開(kāi)協(xié)方差矩陣。方差是描述一維數(shù)據(jù)樣本本身相對(duì)于均值的偏離程度,是一種用來(lái)度量?jī)蓚€(gè)隨機(jī)變量關(guān)系的統(tǒng)計(jì)量,從角度來(lái)說(shuō),其夾角越小,值越大,方向越相近,也就是越正相關(guān)。協(xié)方差矩陣度量除了是兩個(gè)隨機(jī)變量的關(guān)系外,還是維度與維度之間的關(guān)系,而非樣本與樣本之間的關(guān)系。
學(xué)習(xí)一種新的東西,尤其是知識(shí),我們需要了解知識(shí)中的思想。我在了解和學(xué)習(xí)Eigenface算法時(shí)它的思想是圖像識(shí)別首先要選擇一個(gè)合適的子空間,將所有的圖像集中到這個(gè)子空間中,然后在這個(gè)子空間中衡量相似性或者進(jìn)行分類(lèi)學(xué)習(xí),再講子空間變換到另一個(gè)空間中,這樣的作用一是同一個(gè)類(lèi)別的圖像離得更近,二是不同的類(lèi)別的圖像會(huì)離得比較遠(yuǎn);這樣經(jīng)過(guò)線性分類(lèi)分開(kāi)的圖像在新空間就能容易分開(kāi)。同時(shí)特征臉技術(shù)會(huì)尋找人臉圖像分布的基本元素,即人臉圖像樣本集協(xié)方差矩陣的特征向量,以此來(lái)表征人臉圖像。人臉圖像的基本元素有很多,比如眼、面頰、唇等基本元素,這些特征向量在特征臉的圖像空間中對(duì)應(yīng)生成的子空間被稱(chēng)為子臉空間。
生成了子空間之后就要進(jìn)行空間構(gòu)造,那么如何進(jìn)行空間構(gòu)造呢?首先要尋找人臉的共性,其次是要尋找個(gè)體與共性的差異,還有就是要明白共性其實(shí)是空間,個(gè)體就是向量。利用協(xié)方差矩陣把目標(biāo)集中所有人臉圖像的特征值進(jìn)行分解,得到對(duì)應(yīng)的特征向量,這些特征向量就是“特征臉”。尋找特征向量的特性,將其進(jìn)行線性組合。在以每一個(gè)特征子臉為基的空間,每個(gè)人臉就是一個(gè)點(diǎn),這個(gè)點(diǎn)的坐標(biāo)就是每一個(gè)人臉在每個(gè)特征基下的的投影坐標(biāo)。
Eigenfaces算法過(guò)程
-
獲得人臉圖像數(shù)據(jù),將每一個(gè)人臉圖像矩陣按行串成一維,每個(gè)人臉就是一個(gè)向量;
-
將M個(gè)人臉在對(duì)應(yīng)維度上加起來(lái),然后求平均得到“平均臉”;
-
將每個(gè)圖像都減去平均臉向量;
-
計(jì)算協(xié)方差矩陣;
-
運(yùn)用Eigenfaces記性人臉識(shí)別;
算法實(shí)踐過(guò)程;
-
訓(xùn)練圖像
-
求出平均臉
-
獲得特征子臉
-
進(jìn)行圖像重構(gòu)
-
尋找相似度高的人臉圖像。
2、FisherFace算法
FisherFace是Fisher線性判別在人臉識(shí)別的應(yīng)用。線性判別分析(LDA)算法思想最早由英國(guó)統(tǒng)計(jì)與遺傳學(xué)家,現(xiàn)代統(tǒng)計(jì)科學(xué)的奠基人之一羅納德*費(fèi)舍爾(Ronald)提出。LDA算法使用統(tǒng)計(jì)學(xué)方法,嘗試找到物體間特征的一個(gè)線性組合,在降維的同時(shí)考慮類(lèi)別信息。通過(guò)該算法得到的線性組合可以用來(lái)作為一個(gè)線性分類(lèi)器或者實(shí)現(xiàn)降維。
基本思想
線性判別分析的基本思想是:將高維的模式樣本投影到低維最佳矢量空間,以達(dá)到抽取重要分類(lèi)信息和壓縮特征空間維度的效果,投影后保證模式樣本在新的子空間有最大的類(lèi)間距離、最小的類(lèi)內(nèi)距離,即模式在該空間中有最佳的可分離性。理論和特征臉里用到的Eigenfaces有相似之處,都是對(duì)原有數(shù)據(jù)進(jìn)行整體降維映射到低維空間的方法,fisherfaces和Eigenfaces都是從數(shù)據(jù)整體入手而不同于LBP提取局部紋理特征。
對(duì)降維后的樣本使用Fisher線性判別方法,確定一個(gè)最優(yōu)的投影方向,構(gòu)造一個(gè)一維的體征空間,將多維的人臉圖像投影到 fisherfaces特征空間,利用類(lèi)內(nèi)樣本數(shù)據(jù)形成一組特征向量,這組特征向量就代表了人臉的特征。
我們知道,該算法是在樣本數(shù)據(jù)映射到另外一個(gè)特征空間后,將類(lèi)內(nèi)距離最小化,類(lèi)間距離最大化。LDA算法可以用作降維,該算法的原理和PCA算法很相似,因此LDA算法也同樣可以用在人臉識(shí)別領(lǐng)域。通過(guò)使用PCA算法來(lái)進(jìn)行人臉識(shí)別的算法稱(chēng)為特征臉?lè)?,而使用LDA算法進(jìn)行人臉識(shí)別的算法稱(chēng)為費(fèi)舍爾臉?lè)ā?/p>
LDA和PCA相比:
- 相同:1、在降維的時(shí)候,兩者都使用了矩陣的特征分解思想;2、兩者都假設(shè)數(shù)據(jù)符合高斯分布。
- 不同:1、LDA是有監(jiān)督的降維方法,而PCA是無(wú)監(jiān)督的。2、如果說(shuō)數(shù)據(jù)是k維的,那么LDA只能降到(k-1)維度,而PCA不受此限制。3、從數(shù)學(xué)角度來(lái)看,LDA選擇分類(lèi)性能最好的投影方向,而PCA選擇樣本投影點(diǎn)具有最大方差的方向。
Fisherfaces算法和Eigenfaces算法相比:
-
相同:兩者均可以對(duì)數(shù)據(jù)進(jìn)行降維;兩者在降維時(shí)均使用了矩陣特征分解的思想。
-
不同:Fisherfaces是有監(jiān)督的降維方法,而是Eigenfaces無(wú)監(jiān)督的降維方法;Fisherfaces除了可以用于降維,還可以用于分類(lèi)。
值得一提的是,F(xiàn)isherFace算法識(shí)別的錯(cuò)誤率低于哈佛和耶魯人臉數(shù)據(jù)庫(kù)測(cè)試的Eigenfaces識(shí)別結(jié)果。
Fisherface算法流程
-
獲得人臉圖像數(shù)據(jù),然后求出人臉的均值。
-
觀察各個(gè)人臉的特征值。
-
進(jìn)行人臉鑒定,觀察人臉特征,判斷是否是個(gè)人。
-
最后進(jìn)行人臉識(shí)別。
3、LBPH(Local Binary Patter Histogram)算法
Local Binary Patterns Histograms即LBP特征的統(tǒng)計(jì)直方圖,LBPH將LBP(局部二值編碼)特征與圖像的空間信息結(jié)合在一起。如果直接使用LBP編碼圖像用于人臉識(shí)別。其實(shí)和不提取LBP特征區(qū)別不大,因此在實(shí)際的LBP應(yīng)用中,一般采用LBP編碼圖像的統(tǒng)計(jì)直方圖作為特征向量進(jìn)行分類(lèi)識(shí)別。
原始的LBP算子定義為在33的窗口內(nèi),以窗口中心像素為閾值,將相鄰的8個(gè)像素的灰度值與其進(jìn)行比較,若周?chē)袼刂荡笥诨虻扔谥行南袼刂?,則該像素點(diǎn)的位置被標(biāo)記為1,否則為0。這樣,33鄰域內(nèi)的8個(gè)點(diǎn)經(jīng)比較可產(chǎn)生8位二進(jìn)制數(shù)(通常轉(zhuǎn)換為十進(jìn)制數(shù)即LBP碼,共256種),即得到該窗口中心像素點(diǎn)的LBP值,并用這個(gè)值來(lái)反映該區(qū)域的紋理特征。
LBPH的維度: 采樣點(diǎn)為8個(gè),如果用的是原始的LBP或Extended LBP特征,其LBP特征值的模式為256種,則一幅圖像的LBP特征向量維度為:64256=16384維,而如果使用的UniformPatternLBP特征,其LBP值的模式為59種,其特征向量維度為:6459=3776維,可以看出,使用等價(jià)模式特征,其特征向量的維度大大減少,這意味著使用機(jī)器學(xué)習(xí)方法進(jìn)行學(xué)習(xí)的時(shí)間將大大減少,而性能上沒(méi)有受到很大影響。
基本思想
建立在LBPH基礎(chǔ)上的人臉識(shí)別法基本思想如下:首先以每個(gè)像素為中心,判斷與周?chē)袼鼗叶戎荡笮£P(guān)系,對(duì)其進(jìn)行二進(jìn)制編碼,從而獲得整幅圖像的LBP編碼圖像;再將LBP圖像分為個(gè)區(qū)域,獲取每個(gè)區(qū)域的LBP編碼直方圖,繼而得到整幅圖像的LBP編碼直方圖,通過(guò)比較不同人臉圖像LBP編碼直方圖達(dá)到人臉識(shí)別的目的,其優(yōu)點(diǎn)是不會(huì)受到光照、縮放、旋轉(zhuǎn)和平移的影響。
LBPH算法“人”如其名,采用的識(shí)別方法是局部特征提取的方法,這是與前兩種方法的最大區(qū)別。
LBPH 算法流程
-
LBP特征提?。焊鶕?jù)上述的均勻LBP算子處理原始圖像;
-
LBP特征匹配(計(jì)算直方圖):將圖像分為若干個(gè)的子區(qū)域,并在子區(qū)域內(nèi)根據(jù)LBP值統(tǒng)計(jì)其直方圖,以直方圖作為其判別特征。
4、算法的復(fù)現(xiàn)代碼
1)、EigenFaces算法
#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): ''' 載入圖像,灰度化處理,統(tǒng)一尺寸,直方圖均衡化 :param fileName: 圖像文件名 :param dsize: 統(tǒng)一尺寸大小。元組形式 :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: 包含訓(xùn)練數(shù)據(jù)集的圖像文件夾路徑 :return: 樣本矩陣,標(biāo)簽矩陣 ''' 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函數(shù),用于數(shù)據(jù)降維 :param dataMat: 樣本矩陣 :param dimNum: 降維后的目標(biāo)維度 :return: 降維后的樣本矩陣和變換矩陣 ''' # 均值化矩陣 meanMat = np.mat(np.mean(dataMat,1)).T print '平均值矩陣維度',meanMat.shape diffMat = dataMat-meanMat # 求協(xié)方差矩陣,由于樣本維度遠(yuǎn)遠(yuǎn)大于樣本數(shù)目,所以不直接求協(xié)方差矩陣,采用下面的方法 covMat = (diffMat.T*diffMat)/float(diffMat.shape[1]) # 歸一化 #covMat2 = np.cov(dataMat,bias=True) #print '基本方法計(jì)算協(xié)方差矩陣為',covMat2 print '協(xié)方差矩陣維度',covMat.shape eigVals, eigVects = np.linalg.eig(np.mat(covMat)) print '特征向量維度',eigVects.shape print '特征值',eigVals eigVects = diffMat*eigVects eigValInd = np.argsort(eigVals) eigValInd = eigValInd[::-1] eigValInd = eigValInd[:dimNum] # 取出指定個(gè)數(shù)的前n大的特征值 print '選取的特征值',eigValInd eigVects = eigVects/np.linalg.norm(eigVects,axis=0) #歸一化特征向量 redEigVects = eigVects[:,eigValInd] print '選取的特征向量',redEigVects.shape print '均值矩陣維度',diffMat.shape lowMat = redEigVects.T*diffMat print '低維矩陣維度',lowMat.shape return lowMat,redEigVects def compare(self,dataMat,testImg,label): ''' 比較函數(shù),這里只是用了最簡(jiǎn)單的歐氏距離比較,還可以使用KNN等方法,如需修改修改此處即可 :param dataMat: 樣本矩陣 :param testImg: 測(cè)試圖像矩陣,最原始形式 :param label: 標(biāo)簽矩陣 :return: 與測(cè)試圖片最相近的圖像文件名 ''' 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 '檢測(cè)樣本變換后的維度',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): ''' 預(yù)測(cè)函數(shù) :param dirName: 包含訓(xùn)練數(shù)據(jù)集的文件夾路徑 :param testFileName: 測(cè)試圖像文件名 :return: 預(yù)測(cè)結(jié)果 ''' testImg = cv2.imread(testFileName) dataMat,label = self.createImgMat(dirName) print '加載圖片標(biāo)簽',label ans = self.compare(dataMat,testImg,label) return ans if __name__ == '__main__': eigenface = EigenFace(20,50,(50,50)) print eigenface.predict('d:/face','D:/face_test/1.bmp')
2)、FisherFaces算法
#encoding=utf-8 import numpy as np import cv2 import os class FisherFace(object): def __init__(self,threshold,k,dsize): self.threshold = threshold # 閾值,暫未使用 self.k = k # 指定投影w的個(gè)數(shù) self.dsize = dsize # 統(tǒng)一尺寸大小 def loadImg(self,fileName,dsize): ''' 載入圖像,灰度化處理,統(tǒng)一尺寸,直方圖均衡化 :param fileName: 圖像文件名 :param dsize: 統(tǒng)一尺寸大小。元組形式 :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: 包含訓(xùn)練數(shù)據(jù)集的圖像文件夾路徑 :return: 包含樣本矩陣的列表,標(biāo)簽列表 ''' dataMat = np.zeros((10,1)) label = [] dataList = [] 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 index,filename in enumerate(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)) dataList.append(dataMat) label.append(subParent) return dataList,label def LDA(self,dataList,k): ''' 多分類(lèi)問(wèn)題的線性判別分析算法 :param dataList: 樣本矩陣列表 :param k: 投影向量k的個(gè)數(shù) :return: 變換后的矩陣列表和變換矩陣 ''' n = dataList[0].shape[0] W = np.zeros((n,self.k)) Sw = np.zeros((n,n)) Sb = np.zeros((n,n)) u = np.zeros((n,1)) N = 0 meanList = [] sampleNum = [] for dataMat in dataList: meanMat = np.mat(np.mean(dataMat,1)).T meanList.append(meanMat) sampleNum.append(dataMat.shape[1]) dataMat = dataMat-meanMat sw = dataMat*dataMat.T Sw += sw print 'Sw的維度',Sw.shape for index,meanMat in enumerate(meanList): m = sampleNum[index] u += m*meanMat N += m u = u/N print 'u的維度',u.shape for index,meanMat in enumerate(meanList): m = sampleNum[index] sb = m*(meanMat-u)*(meanMat-u).T Sb += sb print 'Sb的維度',Sb.shape eigVals, eigVects = np.linalg.eig(np.mat(np.linalg.inv(Sw)*Sb)) eigValInd = np.argsort(eigVals) eigValInd = eigValInd[::-1] eigValInd = eigValInd[:k] # 取出指定個(gè)數(shù)的前k大的特征值 print '選取的特征值',eigValInd.shape eigVects = eigVects/np.linalg.norm(eigVects,axis=0) #歸一化特征向量 redEigVects = eigVects[:,eigValInd] print '變換矩陣維度',redEigVects.shape transMatList = [] for dataMat in dataList: transMatList.append(redEigVects.T*dataMat) return transMatList,redEigVects def compare(self,dataList,testImg,label): ''' 比較函數(shù),這里只是用了最簡(jiǎn)單的歐氏距離比較,還可以使用KNN等方法,如需修改修改此處即可 :param dataList: 樣本矩陣列表 :param testImg: 測(cè)試圖像矩陣,最原始形式 :param label: 標(biāo)簽矩陣 :return: 與測(cè)試圖片最相近的圖像文件夾,也就是類(lèi)別 ''' testImg = cv2.resize(testImg,self.dsize) testImg = cv2.cvtColor(testImg,cv2.COLOR_RGB2GRAY) testImg = np.reshape(testImg,(-1,1)) transMatList,redVects = fisherface.LDA(dataList,self.k) testImg = redVects.T*testImg print '檢測(cè)樣本變換后的維度',testImg.shape disList = [] testVec = np.reshape(testImg,(1,-1)) sumVec = np.mat(np.zeros((self.dsize[0]*self.dsize[1],1))) for transMat in transMatList: for sample in transMat.T: disList.append( np.linalg.norm(testVec-sample)) print disList sortIndex = np.argsort(disList) return label[sortIndex[0]/9] def predict(self,dirName,testFileName): ''' 預(yù)測(cè)函數(shù) :param dirName: 包含訓(xùn)練數(shù)據(jù)集的文件夾路徑 :param testFileName: 測(cè)試圖像文件名 :return: 預(yù)測(cè)結(jié)果 ''' testImg = cv2.imread(testFileName) dataMat,label = self.createImgMat(dirName) print '加載圖片標(biāo)簽',label ans = self.compare(dataMat,testImg,label) return ans if __name__=="__main__": fisherface = FisherFace(10,20,(20,20)) ans = fisherface.predict('d:/face','d:/face_test/8.bmp') print ans
3)、LBPH算法
#encoding=utf-8 import numpy as np import os import cv2 class LBP(object): def __init__(self,threshold,dsize,blockNum): self.dsize = dsize # 統(tǒng)一尺寸大小 self.blockNum = blockNum # 分割塊數(shù)目 self.threshold = threshold # 閾值,暫未使用 def loadImg(self,fileName,dsize): ''' 載入圖像,灰度化處理,統(tǒng)一尺寸,直方圖均衡化 :param fileName: 圖像文件名 :param dsize: 統(tǒng)一尺寸大小。元組形式 :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 loadImagesList(self,dirName): ''' 加載圖像矩陣列表 :param dirName:文件夾路徑 :return: 包含最原始的圖像矩陣的列表和標(biāo)簽矩陣 ''' imgList = [] label = [] for parent,dirnames,filenames in os.walk(dirName): # print parent # print dirnames # print filenames for dirname in dirnames: for subParent,subDirName,subFilenames in os.walk(parent+'/'+dirname): for filename in subFilenames: img = self.loadImg(subParent+'/'+filename,self.dsize) imgList.append(img) # 原始圖像矩陣不做任何處理,直接加入列表 label.append(subParent+'/'+filename) return imgList,label def getHopCounter(self,num): ''' 計(jì)算二進(jìn)制序列是否只變化兩次 :param num: 數(shù)字 :return: 01變化次數(shù) ''' binNum = bin(num) binStr = str(binNum)[2:] n = len(binStr) if n < 8: binStr = "0"*(8-n)+binStr n = len(binStr) counter = 0 for i in range(n): if i != n-1: if binStr[i+1] != binStr[i]: counter += 1 else: if binStr[0] != binStr[i]: counter += 1 return counter def createTable(self): ''' 生成均勻?qū)?yīng)字典 :return: 均勻LBP特征對(duì)應(yīng)字典 ''' self.table = {} temp = 1 print type(temp) for i in range(256): if self.getHopCounter(i) <= 2: self.table[i] = temp temp += 1 else: self.table[i] = 0 return self.table def getLBPfeature(self,img): ''' 計(jì)算LBP特征 :param img:圖像矩陣 :return: LBP特征圖 ''' m = img.shape[0];n = img.shape[1] neighbor = [0]*8 featureMap = np.mat(np.zeros((m,n))) for y in xrange(1,m-1): for x in xrange(1,n-1): neighbor[0] = img[y-1,x-1] neighbor[1] = img[y-1,x] neighbor[2] = img[y-1,x+1] neighbor[3] = img[y,x+1] neighbor[4] = img[y+1,x+1] neighbor[5] = img[y+1,x] neighbor[6] = img[y+1,x-1] neighbor[7] = img[y,x-1] center = img[y,x] temp = 0 for k in range(8): temp += (neighbor[k] >= center)*(1<<k) featureMap[y,x] = self.table[temp] featureMap = featureMap.astype('uint8') # 數(shù)據(jù)類(lèi)型轉(zhuǎn)換為無(wú)符號(hào)8位型,如不轉(zhuǎn)換則默認(rèn)為float64位,影響最終效果 return featureMap def calcHist(self,roi): ''' 計(jì)算直方圖 :param roi:圖像區(qū)域 :return: 直方圖矩陣 ''' hist = cv2.calcHist([roi],[0],None,[59],[0,256]) # 第四個(gè)參數(shù)是直方圖的橫坐標(biāo)數(shù)目,經(jīng)過(guò)均勻化降維后這里一共有59種像素 return hist def compare(self,sampleImg,testImg): ''' 比較函數(shù),這里使用的是歐氏距離排序,也可以使用KNN,在此處更改 :param sampleImg: 樣本圖像矩陣 :param testImg: 測(cè)試圖像矩陣 :return: k2值 ''' testImg = cv2.resize(testImg,self.dsize) testImg = cv2.cvtColor(testImg,cv2.COLOR_RGB2GRAY) testFeatureMap = self.getLBPfeature(testImg) sampleFeatureMap = self.getLBPfeature(sampleImg) # 計(jì)算步長(zhǎng),分割整個(gè)圖像為小塊 ystep = self.dsize[0]/self.blockNum xstep = self.dsize[1]/self.blockNum k2 = 0 for y in xrange(0,self.dsize[0],ystep): for x in xrange(0,self.dsize[1],xstep): testroi = testFeatureMap[y:y+ystep,x:x+xstep] sampleroi =sampleFeatureMap[y:y+ystep,x:x+xstep] testHist = self.calcHist(testroi) sampleHist = self.calcHist(sampleroi) k2 += np.sum((sampleHist-testHist)**2)/np.sum((sampleHist+testHist)) print 'k2的值為',k2 return k2 def predict(self,dirName,testImgName): ''' 預(yù)測(cè)函數(shù) :param dirName:樣本圖像文件夾路徑 :param testImgName: 測(cè)試圖像文件名 :return: 最相近圖像名稱(chēng) ''' table = self.createTable() testImg = cv2.imread(testImgName) imgList,label = self.loadImagesList(dirName) k2List = [] for img in imgList: k2 = self.compare(img,testImg) k2List.append(k2) order = np.argsort(k2List) return label[order[0]] if __name__ == "__main__": lbp = LBP(20,(50,50),5) ans = lbp.predict('d:/face','d:/face_test/9.bmp') print ans
擴(kuò)展知識(shí):人臉識(shí)別算法研究的難點(diǎn)
人臉識(shí)別算法研究已久,在背景簡(jiǎn)單的情形下,大部分算法都能很好的處理。但是,人臉識(shí)別的應(yīng)用范圍頗廣,僅是簡(jiǎn)單圖像測(cè)試,是遠(yuǎn)遠(yuǎn)不能滿足現(xiàn)實(shí)需求的。所以人臉識(shí)別算法還是存在很多的難點(diǎn)。
光照
光照問(wèn)題是機(jī)器視覺(jué)中的老問(wèn)題,在人臉識(shí)別中的表現(xiàn)尤為明顯,算法未能達(dá)到使用的程度。
姿態(tài)
與光照問(wèn)題類(lèi)似,姿態(tài)問(wèn)題也是人臉識(shí)別研究中需要解決的一個(gè)技術(shù)難點(diǎn)。針對(duì)姿態(tài)的研究相對(duì)比較少,多數(shù)的人臉識(shí)別算法主要是針對(duì)正面,或接近正面的人臉圖像,當(dāng)發(fā)生俯仰或者左右側(cè)而比較厲害的情況下,人臉識(shí)別算法的識(shí)別率也將會(huì)急劇下降。
遮擋
對(duì)于非配合情況下的人臉圖像采集,遮擋問(wèn)題是一個(gè)非常嚴(yán)重的問(wèn)題,特別是在監(jiān)控環(huán)境下,往往被監(jiān)控對(duì)象都會(huì)帶著眼鏡﹑帽子等飾物,使得被采集出來(lái)的人臉圖像有可能不完整,從而影響了后面的特征提取與識(shí)別,甚至?xí)?dǎo)致人臉識(shí)別算法的失效。
年齡變化
隨著年齡的變化,面部外觀也在變化,特別是對(duì)于青少年,這種變化更加的明顯。對(duì)于不同的年齡段,人臉識(shí)別算法的識(shí)別率也不同。
圖像質(zhì)量
人臉圖像的來(lái)源可能多種多樣,由于采集設(shè)備的不同,得到的人臉圖像質(zhì)量也不同,特別是對(duì)于那些低分辨率﹑噪聲大﹑質(zhì)量差的人臉圖像如何進(jìn)行有效的人臉識(shí)別是個(gè)需要關(guān)注的問(wèn)題。同樣的,對(duì)于高分辨圖像,對(duì)人臉識(shí)別算法的影響也需要進(jìn)一步研究。
樣本缺乏
基于統(tǒng)計(jì)學(xué)習(xí)的人臉識(shí)別算法是人臉識(shí)別領(lǐng)域中的主流算法,但是統(tǒng)計(jì)學(xué)習(xí)方法需要大量的培訓(xùn)。由于人臉圖像在高維空間中的分布是一個(gè)不規(guī)則的流行分布,能得到的樣本只是對(duì)人臉圖像空間中的一個(gè)極小部分的采樣,如何解決小樣本下的統(tǒng)計(jì)學(xué)習(xí)問(wèn)題有待進(jìn)一步的研究。
大量數(shù)據(jù)
傳統(tǒng)人臉識(shí)別算法如PCA、LDA等在小規(guī)模數(shù)據(jù)中可以很容易進(jìn)行訓(xùn)練學(xué)習(xí)。但是對(duì)于大量數(shù)據(jù),這些方法其訓(xùn)練過(guò)程難以進(jìn)行,甚至有可能崩潰。
大規(guī)模人臉識(shí)別
隨著人臉數(shù)據(jù)庫(kù)規(guī)模的增長(zhǎng),人臉?biāo)惴ǖ男阅軐⒊尸F(xiàn)下降。