1.原始LBP
原始的LBP算子定义为在3*3的窗口内,以窗口中心像素为阈值,将相邻的8个像素的灰度值与其进行比较,若周围像素值大于中心像素值,则该像素点的位置被标记为1,否则为0。这样,3*3邻域内的8个点经比较可产生8位二进制数(通常转换为十进制数即LBP码,共256种),即得到该窗口中心像素点的LBP值,并用这个值来反映该区域的纹理信息。如下图所示:
代码
import cv2
import numpy as np
def LBP(img):
rows, cols = img.shape
dst = np.zeros((rows-2, cols-2), dtype=img.dtype)
for i in range(1, rows-1):
for j in range(1, cols-1):
center = img[i, j]
code = 0
code |= (img[i-1, j-1] > center) << 7
code |= (img[i-1, j] > center) << 6
code |= (img[i-1, j+1] > center) << 5
code |= (img[i, j+1] > center) << 4
code |= (img[i+1, j+1] > center) << 3
code |= (img[i+1, j] > center) << 2
code |= (img[i+1, j-1] > center) << 1
code |= (img[i, j-1] > center) << 0
dst[i-1, j-1] = code
return dst
img = cv2.imread(r'D:\papercode\experiment\2\deep-learning-for-image-processing-master\deep-learning-for-image-processing-master\amusement_0037.jpg', 0)
lbp = LBP(img)
cv2.imshow('LBP', lbp)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果:
2. 改进算法: 圆形LBP算法(Circular Local Binary Pattern)
基本的 LBP算子的最大缺陷在于它只覆盖了一个固定半径范围内的小区域,这显然不能满足不同尺寸和频率纹理的需要。为了适应不同尺度的纹理特征,并达到灰度和旋转不变性的要求,Ojala等对 LBP算子进行了改进,将 3×3邻域扩展到任意邻域,并用圆形邻域代替了正方形邻域,改进后的 LBP算子允许在半径为 R 的圆形邻域内有任意多个像素点。从而得到了诸如半径为R的圆形区域内含有P个采样点的LBP算子;
代码
import cv2
import numpy as np
def circular_lbp(img, radius, neighbors):
height, width = img.shape
lbp_img = np.zeros((height, width), np.uint8)
for i in range(radius, height - radius):
for j in range(radius, width - radius):
center = img[i, j]
code = 0
for k in range(neighbors):
x = i + int(radius * np.cos(2 * np.pi * k / neighbors))
y = j - int(radius * np.sin(2 * np.pi * k / neighbors))
if img[x, y] > center:
code += 1 << k
lbp_img[i, j] = code
return lbp_img
# 读取图像
img = cv2.imread(r'D:\papercode\experiment\2\deep-learning-for-image-processing-master\deep-learning-for-image-processing-master\amusement_0037.jpg', cv2.IMREAD_GRAYSCALE)
# 提取圆形LBP特征
lbp_img = circular_lbp(img, 1, 8)
# 显示图像
cv2.imshow('image', img)
cv2.imshow('LBP', lbp_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
其中,circular_lbp
函数实现了圆形LBP算子的计算,img
参数为输入图像,radius
参数为圆形邻域的半径,neighbors
参数为采样点的个数。函数返回一个与输入图像大小相同的LBP图像。
结果
3.CLBP(Completed Local Binary Pattern)
CLBP(Completed Local Binary Pattern)和圆形LBP(Circular Local Binary Pattern)都是LBP算子的扩展,它们的主要区别在于邻域的定义方式不同。
圆形LBP算子的邻域是以中心像素为圆心,以半径为R的圆上的P个像素点,这些像素点的位置坐标是通过等分圆周得到的。而CLBP算子的邻域是以中心像素为圆心,以半径为R的圆上的P个像素点和中心像素本身共P+1个像素点,这些像素点的位置坐标也是通过等分圆周得到的。
由于CLBP算子包含了中心像素本身,因此它对光照变化和噪声的鲁棒性更好,但是它的计算量也更大。而圆形LBP算子不包含中心像素本身,因此计算量较小,但是对光照变化和噪声的鲁棒性较差。
4.旋转不变LBP(Rotation Invariant LBP,RILBP)
RILBP是一种改进的局部二值模式(LBP)算法,它在LBP的基础上增加了旋转不变性。在LBP中,对于同一纹理,不同的旋转角度会导致不同的LBP特征,这会影响到纹理识别的准确性。而RILBP通过对LBP特征进行旋转不变处理,使得同一纹理在不同旋转角度下的LBP特征保持一致,从而提高了纹理识别的准确性。
代码
import cv2
import numpy as np
def rotation_invariant_lbp(img, P=8, R=1):
h, w = img.shape
lbp = np.zeros((h-2*R, w-2*R), dtype=np.uint8)
for i in range(R, h-R):
for j in range(R, w-R):
center = img[i, j]
values = []
for n in range(P):
x = i + int(R * np.cos(2 * np.pi * n / P))
y = j - int(R * np.sin(2 * np.pi * n / P))
values.append(img[x, y])
values = np.array(values)
values = values - center
values = np.where(values >= 0, 1, 0)
lbp[i-R, j-R] = np.sum(values * (2 ** np.arange(P)))
return lbp
# 其中,img为输入的灰度图像,P为采样点数,R为采样半径。
# 函数rotation_invariant_lbp返回的是旋转不变LBP特征图像。
# 读取图像
img = cv2.imread(r'D:\papercode\experiment\2\deep-learning-for-image-processing-master\deep-learning-for-image-processing-master\amusement_0037.jpg', cv2.IMREAD_GRAYSCALE)
# 计算旋转不变LBP特征
lbp = rotation_invariant_lbp(img)
# 显示结果
cv2.imshow('LBP', lbp)
cv2.waitKey(0)
cv2.destroyAllWindows()
5.方向性LBP(Directional LBP,DLBP)
DLBP是一种改进的LBP算法,它是基于LBP算法的基础上,引入了梯度信息,从而提高了LBP算法的鲁棒性和判别能力。DLBP算法的主要思想是将图像分成若干个小块,对每个小块进行LBP特征提取,并计算该小块内像素的梯度信息,将LBP特征和梯度信息进行融合,得到该小块的DLBP特征。DLBP算法的优点是可以有效地提高LBP算法的鲁棒性和判别能力,对于光照变化不均匀、噪声等情况下的图像处理具有较好的效果。
以下是DLBP算法的实现步骤:
1. 将图像分成若干个小块,对每个小块进行LBP特征提取。
2. 计算该小块内像素的梯度信息。
3. 将LBP特征和梯度信息进行融合,得到该小块的DLBP特征。
4. 将所有小块的DLBP特征进行拼接,得到整幅图像的DLBP特征。
代码
import cv2
import numpy as np
def DLBP(img, radius=1, neighbors=8):
h, w = img.shape
dst = np.zeros((h-2*radius, w-2*radius), dtype=np.uint8)
for i in range(radius, h-radius):
for j in range(radius, w-radius):
center = img[i, j]
value = 0
for k in range(neighbors):
x = i + int(radius * np.cos(2 * np.pi * k / neighbors))
y = j - int(radius * np.sin(2 * np.pi * k / neighbors))
if img[x, y] > center:
value += 2 ** k
dst[i-radius, j-radius] = value
return dst
def get_gradient(img):
grad_x = cv2.Sobel(img, cv2.CV_16S, 1, 0)
grad_y = cv2.Sobel(img, cv2.CV_16S, 0, 1)
gradx = cv2.convertScaleAbs(grad_x)
grady = cv2.convertScaleAbs(grad_y)
grad = cv2.addWeighted(gradx, 0.5, grady, 0.5, 0)
return grad
def get_DLBP(img, radius=1, neighbors=8):
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
grad = get_gradient(gray)
lbp = DLBP(gray, radius, neighbors)
dlbp = cv2.addWeighted(lbp, 0.5, grad, 0.5, 0)
return dlbp
# 读取图像
img = cv2.imread(r'D:\papercode\experiment\2\deep-learning-for-image-processing-master\deep-learning-for-image-processing-master\amusement_0037.jpg')
# 提取DLBP特征
dlbp = get_DLBP(img)
# 显示结果
cv2.imshow('DLBP', dlbp)
cv2.waitKey(0)
cv2.destroyAllWindows()
6.多尺度LBP(Multiscale LBP,MLBP)
MLBP是一种基于LBP的改进算法,它是由多个LBP特征组合而成的。相比于传统的LBP算法,MLBP可以更好地描述图像的纹理特征。下面是MLBP的实现步骤:
1.将图像分成若干个小块,对于每个小块,都计算出一个LBP特征。
2.将每个小块的LBP特征串联起来,得到一个长向量。
3.将所有小块的向量组合成一个矩阵,每行代表一个小块的向量。
4.对矩阵进行主成分分析(PCA),得到一个降维后的矩阵。
5.将降维后的矩阵中的每个元素都归一化到[0,1]的范围内。
6.将归一化后的矩阵中的每个元素都乘以一个权重系数,得到最终的MLBP特征。
代码
import cv2
import numpy as np
def mlbp(img, P, R, num_blocks):
# 将图像分成num_blocks x num_blocks个小块
h, w = img.shape[:2]
block_size = (w // num_blocks, h // num_blocks)
blocks = [img[i*block_size[1]:(i+1)*block_size[1], j*block_size[0]:(j+1)*block_size[0]] for i in range(num_blocks) for j in range(num_blocks)]
# 计算每个小块的LBP特征
lbp_blocks = [cv2.spatial_histogram(block, P, R, normalize=True) for block in blocks]
# 将所有小块的LBP特征串联起来
lbp_vector = np.concatenate(lbp_blocks)
# 将所有小块的LBP特征组成一个矩阵
lbp_matrix = np.reshape(lbp_vector, (num_blocks*num_blocks, -1))
# 对矩阵进行PCA降维
pca = cv2.PCA(n_components=0.95)
pca.fit(lbp_matrix)
lbp_matrix_pca = pca.transform(lbp_matrix)
# 归一化
lbp_matrix_norm = cv2.normalize(lbp_matrix_pca, None, 0, 1, cv2.NORM_MINMAX)
# 计算权重系数
weights = np.arange(num_blocks*num_blocks)
weights = np.exp(-weights)
# 计算MLBP特征
mlbp_feature = np.multiply(lbp_matrix_norm, weights.reshape(-1, 1))
mlbp_feature = np.sum(mlbp_feature, axis=0)
return mlbp_feature
# 读取图像
img = cv2.imread('test.jpg', cv2.IMREAD_GRAYSCALE)
# 计算MLBP特征
P = 8
R = 1
num_blocks = 4
mlbp_feature = mlbp(img, P, R, num_blocks)
# 输出MLBP特征
print(mlbp_feature)
7.加权LBP(Weighted LBP,W-LBP)
加权LBP(Local Binary Pattern)是一种用于图像处理的特征提取算法,它可以用于纹理分类、人脸识别等领域。加权LBP与传统的LBP相比,它引入了权重因子,可以更好地描述图像的纹理特征。下面是使用Python实现加权LBP的步骤:
1.将图像转换为灰度图像。
2.对于每个像素,计算其8个邻域像素与中心像素的差值,并将差值转换为二进制数。
3.根据二进制数计算加权值,加权值的计算公式为:$w_i=2^i$,其中$i$表示二进制数中1的个数。
4.将所有像素的加权值相加,得到该像素的加权LBP值。
5.将所有像素的加权LBP值组成一个向量,作为该图像的特征向量。
代码
import cv2
import numpy as np
# 定义计算加权LBP值的函数
def calc_weighted_lbp(img):
rows, cols = img.shape
dst = np.zeros((rows-2, cols-2), dtype=np.uint8)
for i in range(1, rows-1):
for j in range(1, cols-1):
binary = ''
center = img[i, j]
for m in [-1, 0, 1]:
for n in [-1, 0, 1]:
if m == 0 and n == 0:
continue
diff = img[i+m, j+n] - center
if diff >= 0:
binary += '1'
else:
binary += '0'
weight = 0
for k in range(len(binary)):
if binary[k] == '1':
weight += 2**k
dst[i-1, j-1] = weight
return dst
# 读取图像并转换为灰度图像
img = cv2.imread('test.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 计算加权LBP特征向量
lbp = calc_weighted_lbp(gray)
# 输出特征向量
print(lbp)
8.局部对比度模式LBP(Local Contrast Pattern,LCP)
LBP改进算法LCP是一种用于纹理特征提取的算法,它是LBP算法的改进版本。LBP算法是一种用于图像纹理特征提取的算法,它通过比较像素点与周围像素点的灰度值大小关系,将每个像素点转换为二进制数,从而提取图像的纹理特征。LCP算法在LBP算法的基础上,引入了旋转不变性和灰度不变性,使得算法更加稳健和准确。
LCP算法的具体步骤如下:
- 将图像分成若干个小区域,对每个小区域进行处理。
- 对于每个像素点,计算其与周围像素点的灰度值大小关系,并将结果转换为二进制数。
- 对于每个小区域,将其中的所有像素点的二进制数进行拼接,得到一个二进制数序列。
- 对于每个二进制数序列,将其进行旋转不变性处理,即将其按照字典序排序后,选择最小的一个作为该序列的代表。
- 对于每个小区域,将其代表序列的二进制数转换为十进制数,作为该小区域的纹理特征。
代码
import cv2
import numpy as np
def LCP(img):
# 将图像分成16个小区域
h, w = img.shape[:2]
h_step, w_step = h // 4, w // 4
features = []
for i in range(4):
for j in range(4):
# 对每个小区域进行处理
sub_img = img[i*h_step:(i+1)*h_step, j*w_step:(j+1)*w_step]
sub_feature = []
# 对每个像素点进行处理
for m in range(1, h_step-1):
for n in range(1, w_step-1):
center = sub_img[m, n]
binary = ''
for k in [(m-1, n-1), (m-1, n), (m-1, n+1), (m, n+1), (m+1, n+1), (m+1, n), (m+1, n-1), (m, n-1)]:
if sub_img[k] >= center:
binary += '1'
else:
binary += '0'
# 将二进制数转换为十进制数
sub_feature.append(int(binary, 2))
# 对代表序列进行旋转不变性处理
sub_feature.sort()
sub_feature = np.array(sub_feature)
min_feature = sub_feature
for k in range(1, 8):
sub_feature = np.roll(sub_feature, 1)
if (sub_feature < min_feature).all():
min_feature = sub_feature
# 将代表序列转换为十进制数,作为该小区域的纹理特征
features.append(min_feature.dot(2 ** np.arange(min_feature.size)[::-1]))
return features
# 读取图像
img = cv2.imread('test.jpg', 0)
# 提取纹理特征
features = LCP(img)
print(features)
从 skimage.feature导入
from skimage.feature import local_binary_pattern
import numpy as np
import cv2
# 读取图像
img = cv2.imread(r'D:\papercode\experiment\2\deep-learning-for-image-processing-master\deep-learning-for-image-processing-master\amusement_0037.jpg', 0)
# 计算LCP特征
radius = 3
n_points = 8 * radius
lcp = local_binary_pattern(img, n_points, radius)
# 将LCP特征转换为灰度图像
lcp = np.uint8((lcp / lcp.max()) * 255)
# 显示图像
cv2.imshow('LCP', lcp)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果:
参考: