原始LBP/Uniform LBP编程实现与直方图

此文章的完整代码网址:

https://blog.csdn.net/Mimido_luoluo/article/details/108445700

LBP直方图

1.1 LBP直方图数据记录的介绍

LBP可以提取图片的纹理特征并且保存为一系列数字。通常以某个像素点为中心,观察其八邻域是比中心像素大还是小,若以center表示为中心像素,以pixel(i)表示为center像素点的各个八邻域像素,其计算为:在这里插入图片描述

最后按顺序将这7个数字连在一起,可作为这个像素点的LBP特征值,最终,每个像素点的LBP特征值按照原像素的位置排列,可以表示成一个图片,即通常所使用的LBP图谱。图谱的每个像素值都是对应像素的LBP特征值,即8位二进制数,一般转换为0~255的十进制数字作为图谱的像素值。

但是实际使用时,例如分类器中使用的是LBP特征值中不同数值的个数。最简单的过程是,对一张图片提取LBP特征值后得到一系列0~ 255的数字,计算0~ 255各个数字的个数,再进行归一化处理后,便可送到分类器中使用,而这个结果用直方图比图谱表现得更为直观。

如果从一张图片得到256组数据,即256维的向量来作为分类器使用的数据,这样维度过小,能够提供的数据也会少,此时会缺失掉包括位置信息等很多的信息,导致分类的效果不理想。因此可以利用分块提取LBP特征值的方法,即将一张图片分成5×5份,或者16×16份等其他份数的多个小区域,再对每个区域进行LBP特征计算,这样每一个小的区域都会得到一个256维的向量,最后将这些小区域的向量都串联到一起,得到一个高维的大向量,此时分类的结果会更为准确。

由于分块处理图片提取LBP特征后,维度往往会很大,例如一个图片被分为5×5的小份,一共有25份,每个小份可以提取256维向量,此时,整张图片的LBP特征向量维数为5×5×256=6400维。因此需要进行降维处理,便用到Uniform LBP的概念,即LBP等价模式,可以保证在不失真的前提下,大大降低特征向量的维度。经过统计,LBP特征中Uniform LBP占85~90%,而Uniform LBP只有58维。不过,还需要加一维来表示那些不是Uniform LBP的向量,因此可以由256维降到59维,这个图片的LBP特征维数被降到5×5×59=1475维。

1.2 简单的LBP直方图

本部分通过使用python自行编写原始LBP特征提取的代码,对一张人脸图片进行LBP特征提取,最后将提取结果归一化为一个直方图。

使用到的库如下:
matplotlib.pyplot 2D绘图 直方图的绘制
numpy 矩阵计算 图片数据的计算
cv2 图像处理 读取图片并处理

本程序中,步骤为:
STEP 1:读取图片,将图片灰度化,这个过程称为预处理;
STEP 2:调用已写好的函数LBP_Cal(src), 计算图片的LBP特征值并保存为dst变量,直接使用cv2库的imshow函数来显示dst可以得到该图片的LBP图谱;
STEP 3:通过统计dst中各个数字出现的次数并且除以总次数从而归一化,保存为rate变量,此时调用matplotlib.pyplot库中的bar函数可以显示LBP直方图。

其中,LBP_Cal(src)是用来计算LBP特征的子函数,输入变量src是灰度图片,函数返回值是dst即LBP图谱。若以center作为计算的中心像素,以pixel(i)作为center的八邻域,八邻域以pixel(i)表示为:

pixel(1)pixel(2)pixel(3)
pixel(4)centerpixel(5)
pixel(6)pixel(7)pixel(8)

以i作为迭代变量,迭代值为1~8表示center的八邻域中8个像素,当i=9时结束循环。其计算过程为:
STEP 1:读取灰度图片,并以src(1,1)作为第一个中心像素center开始;
STEP 2:将迭代变量i设为1,记LBP中间计算向量为LBPtemp,初始值为0;
STEP 3:计算center的八邻域的第i个像素的LBP值,即pixel_LBP(i),并使LBPtemp的第(9-i)位数字等于pixel_LBP(i).
若i未迭代至i=9,则循环STEP2、STEP3.

LBPtemp的赋值使用了按位逻辑与移位算法。首先计算好pixel_LBP(i)后将pixel_LBP(i)左移(8-i)位,表示第i个相邻像素的LBP值,再与LBPtemp进行按位或操作。例如,i=1时,计算邻域pixel(1)的LBP值为1,则pixel_LBP(1)=1,将其左移(8-1=7)位,得到数字为pixel_LBP(1)=10000000,此时的1处于该数字的从右向左第八位,由于LBPtemp的初始值为00000000,按位或操作得到LBPtemp=10000000,此时pixel(1)的LBP计算过程完毕。

基于上述过程,便可编写出原始LBP特征的python代码。此代码的运行结果如下:
在这里插入图片描述
在这里插入图片描述

1.3 图像分块后得到的LBP直方图

该程序仍然使用上述简单LBP直方图算法,预处理过程中需先将图片进行分割。
由于图片大小为512×512,为计算方便将图片分为8×8共64块,其中一块的大小为64×64.其分块示意图如图1.3.1.
在这里插入图片描述

对一个小区域进行LBP特征提取后,可以得到LBP值共64×64=4096个,而全图片共64个相同的小区域,因此LBP值共有4096×64=262144个。
由于维度过多,运算庞大,在这里不做直方图图片。

下图是运行结果的数据大小:
在这里插入图片描述
这个4096×64的数组是整个图片的所有LBP特征值。一个小区域64×64个特征值,将所有小区域的特征值矩阵按列合并,共64个小区域,因此该数组的行数为64×64 = 4096,而列数则不变,仍是64列。制作直方图时,以64×64为一个迭代单位,一次迭代制作一个共有256个长方体的直方图,共迭代64次,因此直方图的横坐标共256×64 = 16384个数据点,即16384个长方体,而上节所述的简单方法仅256个。相比于256维的LBP特征,16384维的LBP特征能提供相对更多的信息,但是这并不利于分类器运算速度的提升。

1.4 Uniform LBP的实现

Uniform LBP等价模式的原理是,根据跳变来确定是哪一类。
等价模式类为,计算0到1或1到0的跳变,跳变0次、跳变1次、跳变2次,共有58个情况;跳变超过2次的,称为其他情况,是1个情况,因此LBP特征变为58+1=59维。

若8个数字都一样,即0000 0000与1111 1111,跳变次数为0;
若8个数字中有1个0,则根据0不同位置,有8种组合,即0111 1111、1011 1111、1101 1111、1110 1111、1111 0111、1111 1011、1111 1101、1111 1110;
若8个数字中有2个0,若要保证跳变不超过2次,这两个0只能是相邻的,因此也是有8种组合:0011 1111、1001 1111、1100 1111、1110 0111、1111 0011、1111 1001、1111 1100、0111 1110;
若8个数字中有3个0、4个0、…、7个0,这些0都要相邻,才能保证跳变不超过2次,因此,每种情况都有8种组合,从而,以上情况共有8×7=56种。

综上所有情况相加,2+56=58种。其余情况则统称为混合类,统统放到同一维中,即第59维。这59种类别中,前58种按照二进制数所对应的值按照从小到大编码为1~58,第59类则编码为0.

对一个图片,首先计算其LBP特征值。然后观察每一个LBP特征值都属于哪一类别,之后,将该位置的数字改为类别数。例如,0000 0000对应第1类、0000 0001对应第2类、… 、1111 1111对应第58类,而1010 1101之类则对应第0类。最后得到的是一张由类别编码数替换后的灰色图片。如果将各个数字进行计数,便可总结成一个维度为59的直方图。

本算法的python实现流程如下:
STEP 1:读取图片并转换为灰度图像;
STEP 2:将灰度图像输入到子函数uniform_LBP(img)中,进行计算;
STEP 3:将得到的uniform_LBP值进行归一化处理并做成直方图。

其中,子函数uniform_LBP(img)中,首先建立了一个长度为8的数列Code,用以记录8位二进制数的每一位数字,即8位的特征值,方便后来的计算跳变次数;以row和col作为图片的行列迭代变量,建立for双循环遍历图片的各个中心像素,row和col的范围都是1~511;以dst作为输出变量,输出的是一个59维的均值LBP图谱。

STEP 1:计算src[row,col]像素的LBP特征值,并且保存到Code变量中;
STEP 2:设置记录跳变的变量count=0,以i=0,1,…,8为迭代变量,从i=0开始遍历数列Code,若发生跳变,则变量count加1,当i=8时停止迭代;
STEP 3:若count > 2,则令输出dst[row,col]=0;若count ≤ 2,则寻找该LBP值属于1~58的哪一个类别,并且将该类别号作为输出dst[row,col]的值。

若row和col均未迭代到511,则循环步骤STEP 1~STEP 3. 最终此函数输出dst数组。

基于上述过程,可以写出Uniform LBP的python运行代码,输入图1.2.1图片,其运行结果如下:
在这里插入图片描述

由此可见,Uniform LBP的确相当大地降了维度,在不失真的条件下使计算量大大减少,以下是原始LBP直方图和Uniform LBP直方图的对比:在这里插入图片描述
从组合对比图中可以看出来,直方图中,虽然Uniform LBP的结果维度很少,是59维,但是大致的数据分布是相似的,并未过多地失真;而图谱中,由于0~59像素值的灰度图整体上是偏暗的,但是纹理特征与原始LBP图谱的纹理特征相同,也没有过多的失真现象出现。

  • 9
    点赞
  • 60
    收藏
    觉得还不错? 一键收藏
  • 17
    评论
好的,以下是我使用Python代码实现上述要求的过程: ```python import cv2 import numpy as np from matplotlib import pyplot as plt # 载入原始图像 img = cv2.imread('image.jpg', cv2.IMREAD_GRAYSCALE) # 生成3幅不同亮度的图像 img1 = cv2.add(img, 50) img2 = cv2.add(img, 100) img3 = cv2.add(img, 150) # 生成4幅图像的LBP图像和LBP直方图 images = [img, img1, img2, img3] histograms = [] for i, image in enumerate(images): # 计算LBP图像 lbp = cv2.LBP(image, 8, 2, cv2.LBP_UNIFORM) # 计算LBP直方图 hist, _ = np.histogram(lbp.ravel(), bins=256, range=(0, 255)) # 将LBP直方图归一化 hist = hist.astype("float") hist /= (hist.sum() + 1e-7) # 将LBP直方图添加到列表中 histograms.append(hist) # 显示LBP图像和LBP直方图 plt.subplot(2, 4, i+1), plt.imshow(lbp, cmap='gray') plt.title('LBP Image %d' % (i+1)) plt.subplot(2, 4, i+5), plt.plot(hist) plt.title('LBP Histogram %d' % (i+1)) # 计算误差值(MSE) mse1 = np.mean((histograms[0] - histograms[1])**2) mse2 = np.mean((histograms[0] - histograms[2])**2) mse3 = np.mean((histograms[0] - histograms[3])**2) print('MSE 1: %f' % mse1) print('MSE 2: %f' % mse2) print('MSE 3: %f' % mse3) plt.show() ``` 请注意,此处我使用了Python中的matplotlib库来显示生成的LBP图像和LBP直方图。如果您没有安装该库,请先使用以下命令安装: ```bash pip install matplotlib ``` 另外,我假设您已经将原始图像保存在名为“image.jpg”的文件中,并将其放置在当前工作目录中。如果您的文件名或路径不同,请相应地更改代码中的文件名和路径。 运行上述代码后,您将会看到4幅图像的LBP图像和LBP直方图,以及3幅图像的LBP直方图原始图像LBP直方图的MSE值。
评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值