LBP特征

匿名 (未验证) 提交于 2019-12-02 22:56:40

LBP是Local Binary Pattern(局部二值模式)的缩写,具有灰度不变性和旋转不变性等显著优点。由于该特征的简单易算性,虽然其总体效果不如Haar特征,但速度则快于Haar,所以也得到了广泛的使用。

LBP特征的描述

原始的LBP算子定义为在333*3的窗口内,以窗口中心像素为阈值,将相邻的8个像素的灰度值与其进行比较,若周围像素值大于等于中心像素值,则该像素点的位置被标记为1,否则为0。这样,333*3邻域内的8个点经比较可产生8位二进制数(通常转换为十进制数即LBP码,共256种),即得到该窗口中心像素点的LBP值,并用这个值来反映该区域的纹理信息。需要注意的是,LBP值是按照顺时针方向组成的二进制数。

LBP特征的圆形化改进

基本的 LBP算子的最大缺陷在于它只覆盖了一个固定半径范围内的小区域,这显然不能满足不同尺寸和频率纹理的需要。为了适应不同尺度的纹理特征,并达到灰度和旋转不变性的要求,Ojala等对 LBP 算子进行了改进,将 3×3邻域扩展到任意邻域,并用圆形邻域代替了正方形邻域,改进后的 LBP 算子允许在半径为 R 的圆形邻域内有任意多个像素点。从而得到了诸如半径为R的圆形区域内含有P个采样点的LBP算子,称为Extended LBP,也叫Circular LBP。

比如下图定了一个5x5的邻域:

上图内有八个黑色的采样点,每个采样点的值可以通过下式计算:

xp=xc+Rcos(2πpP)x_p = x_c+R\cos( \frac{2\pi p}{P} )

yp=ycRsin(2πpP)y_p = y_c-R\sin( \frac{2\pi p}{P} )

其中(xcyc)(x_c,y_c)为邻域中心点,(xpyp)(x_p,y_p)为某个采样点。通过上式可以计算任意个采样点的坐标,但是计算得到的坐标未必完全是整数,所以可以通过双线性插值来得到该采样点的像素值:

f(x,y)[1xx][f(0,0)f(0,1)f(1,0)f(1,1)][1yy]f(x,y)\approx \begin{bmatrix} 1-x & x \\ \end{bmatrix} \begin{bmatrix} f(0,0) & f(0,1)\\ f(1,0) & f(1,1) \end{bmatrix}\begin{bmatrix} 1-y\\ y \end{bmatrix}

几种不同半径不同采样点的LBP算子:

LBP旋转不变模式

下图中的8种 LBP 模式,对应的旋转不变的 LBP模式都是00001111,即 LBP值为 15:

Uniform Pattern LBP等价模式

一个LBP算子可以产生不同的二进制模式,对于半径为R的圆形区域内含有P个采样点的LBP算子将会产生2P2^P种模式。为了解决二进制模式过多的问题,提高统计性,Ojala提出了采用一种“等价模式”来对LBP算子的模式种类进行降维。

Ojala等认为,在实际图像中,绝大多数LBP模式最多只包含两次从1到0或从0到1的跳变。因此,Ojala将“等价模式”定义为:当某个LBP所对应的循环二进制数从0到1或从1到0最多有两次跳变时,该LBP所对应的二进制就称为一个等价模式类。如00000000(0次跳变),00000111(只含一次从0到1的跳变),10001111(先由1跳到0,再由0跳到1,共两次跳变)都是等价模式类, 除等价模式类以外的模式都归为另一类,称为混合模式类,例如10010111(共四次跳变)。。

通过这样的改进,模式数量由原来的2P2^P种减少为 P(P1)+2P ( P-1)+2种,其中PP表示邻域集内的采样点数。对于3×33×3邻域内8个采样点来说,二进制模式由原始的256种减少为58种, 他们对应的值按照从小到大分别编码为1-58,即它们在LBP特征图像中的灰度值为1-58,而除了等价模式类之外的混合模式类被编码为0,即它们在LBP特征中的灰度值为0,因此等价模式LBP特征图像整体偏暗。这使得特征向量的维数更少,并且可以减少高频噪声带来的影响。

LBP特征用于检测的原理

上述提取的LBP算子在每个像素点都可以得到一个LBP“编码”,那么,对一幅图像(记录的是每个像素点的灰度值)提取其原始的LBP算子之后,得到的原始LBP特征依然是“一幅图片”(记录的是每个像素点的LBP值)。

LBP的应用中,如纹理分类、人脸分析等,一般都不将LBP图谱作为特征向量用于分类识别,而是采用LBP特征谱的统计直方图作为特征向量用于分类识别。

例如:一幅100100100*100像素大小的图片,划分为1010=10010*10=100个子区域,也就有了101010*10个统计直方图,利用这101010*10个统计直方图,以及各种相似性度量函数,就可以判断两幅图像之间的相似性了。

MB-LBP特征

MB-LBP特征,全称为Multiscale Block LBP,在Traincascade级联目标训练检测中的LBP特征使用的就是MB-LBP。

将图像分成一个个小块(Block),每个小块再分为一个个的小区域(类似于HOG中的cell),小区域内的灰度平均值作为当前小区域的灰度值,与周围小区域灰度进行比较形成LBP特征,生成的特征称为MB-LBP。Block大小为333*3且小区域的大小为1时,就是原始的LBP特征,上图的Block大小为999*9,小区域的大小为333*3

作者对得到LBP特征又进行了均值模式编码,通过对得到的特征图求直方图,得到了LBP特征值0-255之间(0-255即直方图中的bin)的特征数量,通过对bin中的数值进行排序,通过权衡,将排序在前63位的特征值看作是等价模式类,其他的为混合模式类,总共64类,作者在论文中称之为SEMB-LBP(Statistically Effective MB-LBP )。类似于等价模式LBP,等价模式的LBP的等价模式类为58种,混合模式类1种,共59种。二者除了等价模式类的数量不同之外,主要区别在于:对等价模式类的定义不同,等价模式LBP是根据0-1的跳变次数定义的,而SEMB-LBP是通过对直方图排序得到的。

总结:MB-LBP有点类似于先将图像进行平滑处理,然后再求LBP特征。而SEMB-LBP是在MB-LBP进行编码后的图像。类似于等价模式LBP,先求LBP特征,再用等价模式进行编码。当Scale=3时,MB-LBP和SEMB-LBP就是LBP和等价模式LBP。

LBPH,图像的LBP特征向量

LBPH,Local Binary Patterns Histograms,即LBP特征的统计直方图,LBPH将LBP特征与图像的空间信息结合在一起。将LBP特征图像分成m个局部块,并提取每个局部块的直方图,然后将这些直方图依次连接在一起形成LBP特征的统计直方图,即LBPH。

一幅图像具体的计算LBPH的过程(以Opencv中的人脸识别为例):

  1. 计算图像的LBP特征图像。
  2. 将LBP特征图像进行分块,Opencv中默认将LBP特征图像分成8行8列64块区域
  3. 计算每块区域特征图像的直方图cell_LBPH,将直方图进行归一化,直方图大小为1numPatterns1*numPatterns
  4. 将每块区域的直方图按空间顺序依次排列成一行,形成LBP特征向量,大小为1(numPatterns64)1*(numPatterns*64)
  5. 用机器学习的方法对LBP特征向量进行训练,用来检测和识别目标

举例说明LBPH的维度:
采样点为8个,如果用的是原始的LBP或Extended LBP特征,其LBP特征值的模式为256种,则一幅图像的LBP特征向量维度为:64256=1638464*256=16384维,而如果使用的UniformPatternLBP特征,其LBP值的模式为59种,其特征向量维度为:6459=377664*59=3776维,可以看出,使用等价模式特征,其特征向量的维度大大减少,这意味着使用机器学习方法进行学习的时间将大大减少,而性能上没有受到很大影响。Opencv的人脸识别使用的是Extended LBP。

LBP算子的优缺点

优点:

  • 一定程度上消除了光照变化的问题
  • 具有旋转不变性
  • 纹理特征维度低,计算速度快

缺点:

  • 当光照变化不均匀时,各像素间的大小关系被破坏,对应的LBP算子也就发生了变化。
  • 通过引入旋转不变的定义,使LBP算子更具鲁棒性。但这也使得LBP算子丢失了方向信息。

计算原始LBP特征值

import cv2 import numpy as np  def origin_LBP(img):     dst = np.zeros(img.shape,dtype=img.dtype)     h,w=img.shape     for i in range(1,h-1):         for j in range(1,w-1):             center = img[i][j]             code = 0                           code |= (img[i-1][j-1] >= center) << (np.uint8)(7)               code |= (img[i-1][j  ] >= center) << (np.uint8)(6)               code |= (img[i-1][j+1] >= center) << (np.uint8)(5)               code |= (img[i  ][j+1] >= center) << (np.uint8)(4)               code |= (img[i+1][j+1] >= center) << (np.uint8)(3)               code |= (img[i+1][j  ] >= center) << (np.uint8)(2)               code |= (img[i+1][j-1] >= center) << (np.uint8)(1)               code |= (img[i  ][j-1] >= center) << (np.uint8)(0)                  dst[i-1][j-1]= code     return dst  gray = cv2.imread('C:/Users/Ivy/Desktop/a.jpg', cv2.IMREAD_GRAYSCALE) cv2.imshow('img', gray) org_lbp = origin_LBP(gray) cv2.imshow('org_lbp', org_lbp) cv2.waitKey(0) 

计算圆形LBP特征值

半径越小,图像纹理越精细, 邻域数目越小,图像亮度越低。

原始图 / 原始LBP / 圆形R1P8 / 圆形R3P8 / 圆形R3P6

import cv2 import numpy as np  def circular_LBP(img, radius=3, neighbors=8):     h,w=img.shape     dst = np.zeros((h-2*radius, w-2*radius),dtype=img.dtype)     for k in range(neighbors):         # 计算采样点对于中心点坐标的偏移量rx,ry         rx = radius * np.cos(2.0 * np.pi * k / neighbors)         ry = -(radius * np.sin(2.0 * np.pi * k / neighbors))         # 为双线性插值做准备         # 对采样点偏移量分别进行上下取整         x1 = int(np.floor(rx))         x2 = int(np.ceil(rx))         y1 = int(np.floor(ry))         y2 = int(np.ceil(ry))         # 将坐标偏移量映射到0-1之间         tx = rx - x1         ty = ry - y1         # 根据0-1之间的x,y的权重计算公式计算权重,权重与坐标具体位置无关,与坐标间的差值有关         w1 = (1-tx) * (1-ty)         w2 =    tx  * (1-ty)         w3 = (1-tx) *    ty         w4 =    tx  *    ty         for i in range(radius,h-radius):             for j in range(radius,w-radius):                 # 获得中心像素点的灰度值                 center = img[i,j]                 # 根据双线性插值公式计算第k个采样点的灰度值                 neighbor = img[i+y1,j+x1] * w1 + img[i+y2,j+x1] *w2 + img[i+y1,j+x2] *  w3 +img[i+y2,j+x2] *w4                 # LBP特征图像的每个邻居的LBP值累加,累加通过与操作完成,对应的LBP值通过移位取得                 dst[i-radius,j-radius] |= (neighbor>center)  <<  (np.uint8)(neighbors-k-1)     return dst  gray = cv2.imread('C:/Users/Ivy/Desktop/a.jpg', cv2.IMREAD_GRAYSCALE) cv2.imshow('img', gray) circul_1_8 = circular_LBP(gray,1,8) circul_3_8 = circular_LBP(gray,3,8) circul_3_6 = circular_LBP(gray,3,6) cv2.imshow('18', circul_1_8) cv2.imshow('38', circul_3_8) cv2.imshow('36', circul_3_6) cv2.waitKey(0) 

计算旋转不变圆形LBP特征值

原始图 / 原始LBP / 圆形R3P8 / 旋转不变R3P8

import cv2 import numpy as np  def rotation_invariant_LBP(img, radius=3, neighbors=8):     h,w=img.shape     dst = np.zeros((h-2*radius, w-2*radius),dtype=img.dtype)     for k in range(neighbors):         # 计算采样点对于中心点坐标的偏移量rx,ry         rx = radius * np.cos(2.0 * np.pi * k / neighbors)         ry = -(radius * np.sin(2.0 * np.pi * k / neighbors))         # 为双线性插值做准备         # 对采样点偏移量分别进行上下取整         x1 = int(np.floor(rx))         x2 = int(np.ceil(rx))         y1 = int(np.floor(ry))         y2 = int(np.ceil(ry))         # 将坐标偏移量映射到0-1之间         tx = rx - x1         ty = ry - y1         # 根据0-1之间的x,y的权重计算公式计算权重,权重与坐标具体位置无关,与坐标间的差值有关         w1 = (1-tx) * (1-ty)         w2 =    tx  * (1-ty)         w3 = (1-tx) *    ty         w4 =    tx  *    ty         for i in range(radius,h-radius):             for j in range(radius,w-radius):                 # 获得中心像素点的灰度值                 center = img[i,j]                 # 根据双线性插值公式计算第k个采样点的灰度值                 neighbor = img[i+y1,j+x1] * w1 + img[i+y2,j+x1] *w2 + img[i+y1,j+x2] *  w3 +img[i+y2,j+x2] *w4                 # LBP特征图像的每个邻居的LBP值累加,累加通过与操作完成,对应的LBP值通过移位取得                 dst[i-radius,j-radius] |= (neighbor>center)  <<  (np.uint8)(neighbors-k-1)     # 进行旋转不变处理     for i in range(dst.shape[0]):         for j in range(dst.shape[1]):             currentValue = dst[i,j]             minValue = currentValue;             for k in range(1, neighbors):                 # 循环左移                 temp = (np.uint8)(currentValue>>(neighbors-k)) |  (np.uint8)(currentValue<<k)                 if temp < minValue:                     minValue = temp                              dst[i,j] = minValue          return dst         gray = cv2.imread('C:/Users/Ivy/Desktop/a.jpg', cv2.IMREAD_GRAYSCALE) cv2.imshow('img', gray) rotation_invariant = rotation_invariant_LBP(gray,3,8) cv2.imshow('ri', rotation_invariant) cv2.waitKey(0) 

计算Uniform Pattern LBP特征值

原始图 / 圆形R3P8 / 旋转不变R3P8 / UPLBP,R3P8 / UPLBP,R3P8增强亮度显示

import cv2 import numpy as np  def uniform_pattern_LBP(img,radius=3, neighbors=8):     h,w=img.shape     dst = np.zeros((h-2*radius, w-2*radius),dtype=img.dtype)     # LBP特征值对应图像灰度编码表,直接默认采样点为8位     temp = 1     table =np.zeros((256),dtype=img.dtype)     for i in range(256):         if getHopTimes(i)<3:             table[i] = temp             temp+=1     # 是否进行UniformPattern编码的标志     flag = False     # 计算LBP特征图     for k in range(neighbors):         if k==neighbors-1:             flag = True                # 计算采样点对于中心点坐标的偏移量rx,ry         rx = radius * np.cos(2.0 * np.pi * k / neighbors)         ry = -(radius * np.sin(2.0 * np.pi * k / neighbors))         # 为双线性插值做准备         # 对采样点偏移量分别进行上下取整         x1 = int(np.floor(rx))         x2 = int(np.ceil(rx))         y1 = int(np.floor(ry))         y2 = int(np.ceil(ry))         # 将坐标偏移量映射到0-1之间         tx = rx - x1         ty = ry - y1         # 根据0-1之间的x,y的权重计算公式计算权重,权重与坐标具体位置无关,与坐标间的差值有关         w1 = (1-tx) * (1-ty)         w2 =    tx  * (1-ty)         w3 = (1-tx) *    ty         w4 =    tx  *    ty         # 循环处理每个像素         for i in range(radius,h-radius):             for j in range(radius,w-radius):                 # 获得中心像素点的灰度值                 center = img[i,j]                 # 根据双线性插值公式计算第k个采样点的灰度值                 neighbor = img[i+y1,j+x1] * w1 + img[i+y2,j+x1] *w2 + img[i+y1,j+x2] *  w3 +img[i+y2,j+x2] *w4                 # LBP特征图像的每个邻居的LBP值累加,累加通过与操作完成,对应的LBP值通过移位取得                 dst[i-radius,j-radius] |= (neighbor>center)  <<  (np.uint8)(neighbors-k-1)                 # 进行LBP特征的UniformPattern编码                 if flag:                     dst[i-radius,j-radius] = table[dst[i-radius,j-radius]]     return dst               def getHopTimes(data):     '''     计算跳变次数     '''     count = 0;     binaryCode = "{0:0>8b}".format(data)           for i in range(1,len(binaryCode)):         if binaryCode[i] != binaryCode[(i-1)]:             count+=1     return count  gray = cv2.imread('C:/Users/Ivy/Desktop/a.jpg', cv2.IMREAD_GRAYSCALE) cv2.imshow('img', gray) uniform_pattern = uniform_pattern_LBP(gray,3,8) cv2.imshow('up', uniform_pattern) cv2.waitKey(0) 

计算MB-LBP特征值

ԭʼͼ / ԭʼLBP / MBLBP 3 / MBLBP 9 / MBLBP 15

import cv2 import numpy as np  def multi_scale_block_LBP(img,scale):     h,w= img.shape          # 定义并计算积分图像     cellSize = int(scale / 3)     offset = int(cellSize / 2)     cellImage = np.zeros((h-2*offset, w-2*offset),dtype=img.dtype)            for i in range(offset,h-offset):         for j in range(offset,w-offset):             temp = 0;             for m in range(-offset,offset+1):                 for n in range(-offset,offset+1):                       temp += img[i+n,j+m]                              temp /= (cellSize*cellSize);             cellImage[i-int(cellSize/2),j-int(cellSize/2)] = np.uint8(temp)                   dst = origin_LBP(cellImage)     return dst  gray = cv2.imread('C:/Users/Ivy/Desktop/a.jpg', cv2.IMREAD_GRAYSCALE) cv2.imshow('img', gray) mb_3 = multi_scale_block_LBP(gray,3)   mb_9 = multi_scale_block_LBP(gray,9)   mb_15 = multi_scale_block_LBP(gray,15)   cv2.imshow('mb_3', mb_3) cv2.imshow('mb_9', mb_9) cv2.imshow('mb_15', mb_15) cv2.waitKey(0) 

计算图像的LBPH特征向量

def getLBPH(img_lbp,numPatterns,grid_x,grid_y,normed):     '''     计算LBP特征图像的直方图LBPH     '''     h,w=img_lbp.shape     width = int(w / grid_x)     height = int(h / grid_y)     # 定义LBPH的行和列,grid_x*grid_y表示将图像分割的块数,numPatterns表示LBP值的模式种类     result = np.zeros((grid_x * grid_y,numPatterns),dtype=float)     resultRowIndex = 0     # 对图像进行分割,分割成grid_x*grid_y块,grid_x,grid_y默认为8     for i in range(grid_x):         for j in range(grid_y):             # 图像分块             src_cell = img_lbp[i*height:(i+1)*height,j*width:(j+1)*width]             # 计算直方图             hist_cell = getLocalRegionLBPH(src_cell,0,(numPatterns-1),True)             #将直方图放到result中             result[resultRowIndex]=hist_cell             resultRowIndex+=1     return np.reshape(result,(-1))  def getLocalRegionLBPH(src,minValue,maxValue,normed):     '''     计算一个LBP特征图像块的直方图     '''     data = np.reshape(src,(-1))     # 计算得到直方图bin的数目,直方图数组的大小     bins = maxValue - minValue + 1;     # 定义直方图每一维的bin的变化范围     ranges = (float(minValue),float(maxValue + 1))     hist, bin_edges = np.histogram(src, bins=bins, range=ranges, normed=normed)     return hist  uniform_pattern = uniform_pattern_LBP(gray,3,8) lbph = getLBPH(uniform_pattern,59,8,8,True) 
文章来源: LBP特征
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!