转自:https://blog.csdn.net/freedom098/article/details/52088179
第三种算法称之为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