人臉識別經典演算法實現(三)——LBP演算法
阿新 • • 發佈:2019-01-09
第三種演算法稱之為LBP演算法,這個演算法的思路與PCA和Fisher有很大不同,他是考慮區域性特徵運算元,並不是全域性考慮。
這種演算法定義了一種LBP特徵,這種特徵與我們經常見到的Haar特徵、HoG特徵沒有啥太大不同,都是特徵運算元,只是演算法不同。因此,我們按照理解特徵運算元一類的演算法去理解LBP就可以了。
注意,LBP對關照不敏感,為什麼?因為LBP運算元是一種相對性質的數量關係,相比於PCA或者Fsiher,直接使用灰度值去參與運算,LBP更能反映出的是一種變化趨勢。
最後一次當個搬運工
http://blog.csdn.net/feirose/article/details/39552977,LBP運算元寫的不算太清楚,但是整個演算法的完整流程講明白了,而且最後如何判定的直方圖交叉核和卡方檢驗都有說明。
http://blog.csdn.net/pi9nc/article/details/18623971,這個部落格的LBP運算元說得很好,而且有opencv的例程。
注意,這裡的樣本影象組織形式與前面兩個演算法又有不同,因為他不需要把影象變成列向量,因此影象矩陣不需要做什麼處理就可以加入列表備用了。
程式碼如下:
#encoding=utf-8 import numpy as np import os import cv2 class LBP(object): def __init__(self,threshold,dsize,blockNum): self.dsize = dsize # 統一尺寸大小 self.blockNum = blockNum # 分割塊數目 self.threshold = threshold # 閾值,暫未使用 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 loadImagesList(self,dirName): ''' 載入影象矩陣列表 :param dirName:資料夾路徑 :return: 包含最原始的影象矩陣的列表和標籤矩陣 ''' 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): ''' 計算二進位制序列是否只變化兩次 :param num: 數字 :return: 01變化次數 ''' 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): ''' 生成均勻對應字典 :return: 均勻LBP特徵對應字典 ''' 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): ''' 計算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') # 資料型別轉換為無符號8位型,如不轉換則預設為float64位,影響最終效果 return featureMap def calcHist(self,roi): ''' 計算直方圖 :param roi:影象區域 :return: 直方圖矩陣 ''' hist = cv2.calcHist([roi],[0],None,[59],[0,256]) # 第四個引數是直方圖的橫座標數目,經過均勻化降維後這裡一共有59種畫素 return hist def compare(self,sampleImg,testImg): ''' 比較函式,這裡使用的是歐氏距離排序,也可以使用KNN,在此處更改 :param sampleImg: 樣本影象矩陣 :param testImg: 測試影象矩陣 :return: k2值 ''' testImg = cv2.resize(testImg,self.dsize) testImg = cv2.cvtColor(testImg,cv2.COLOR_RGB2GRAY) testFeatureMap = self.getLBPfeature(testImg) sampleFeatureMap = self.getLBPfeature(sampleImg) # 計算步長,分割整個影象為小塊 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): ''' 預測函式 :param dirName:樣本影象資料夾路徑 :param testImgName: 測試影象檔名 :return: 最相近影象名稱 ''' 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