Se recomienda leer el siguiente contenido después de leer las notas del estudio LBP (1) para que sea más fácil comenzar
1. Una breve descripción del modelo invariante de rotación LBP
El patrón binario local invariable en rotación se refiere a la representación de características con invariancia en rotación al realizar un procesamiento invariable en rotación en la característica LBP sobre la base de la característica de patrón binario local (LBP). Debido a que la función LBP tiene las ventajas de la invariancia de escala de grises y la invariancia de rotación, se ha utilizado ampliamente en los campos del procesamiento de imágenes y la visión artificial.
Las características LBP de rotación invariable se pueden calcular mediante el método de modo equivalente y el método de ponderación de rotación invariable. El número de modos equivalentes de características LBP se puede obtener mediante el método de modos equivalentes, eliminando así la influencia de la rotación de la imagen en la extracción de características. Con el método de peso de rotación invariable, se pueden asignar diferentes pesos a los píxeles alrededor del punto de referencia para suprimir algunos efectos de rotación invariable.
Cuando no se usa el modo de rotación invariable, el cálculo de la característica LBP es simple, pero se verá afectado por factores como la rotación de la imagen y los cambios en la escala de grises, lo que resultará en una extracción de características imprecisa. El uso del modo invariable de rotación puede evitar la interferencia de estos factores y mejorar la solidez de las características de LBP en escenarios de aplicación práctica.
2. Implementación de código (funciones clave y código completo)
1. Travesía de píxeles para obtener características de patrones invariantes de rotación
# 获取图像的LBP旋转不变模式特征
def lbp_revolve(self, image_array):
revolve_array = np.zeros(image_array.shape, np.uint8)
width = image_array.shape[0]
height = image_array.shape[1]
for i in range(1, width - 1):
for j in range(1, height - 1):
sum = self.calute_basic_lbp(image_array, i, j)[0]
revolve_key = self.get_min_for_revolve(sum)
revolve_array[i, j] = self.revolve_map[revolve_key]
return revolve_array
sum es la secuencia binaria obtenida después de que el algoritmo de características originales LBP procese la imagen en escala de grises de la imagen original
revolve_key es el número decimal más pequeño obtenido por la suma después de una rotación continua
Luego use revolve_key como la clave del diccionario revolve_map y asigne su valor correspondiente (es decir, valor de píxel) a revolve_array[i,j]
2. Obtenga la secuencia binaria del valor de comparación de los ocho campos
# 图像的LBP原始特征计算算法:将图像指定位置的像素与周围8个像素比较
# 比中心像素大的点赋值为1,比中心像素小的赋值为0,返回得到的二进制序列
def calute_basic_lbp(self, image_array, i, j):
sum = []
num = 0
if image_array[i - 1, j - 1] > image_array[i, j]:
sum.append(1)
num += 2 ** 0
else:
sum.append(0)
if image_array[i - 1, j] > image_array[i, j]:
sum.append(1)
num += 2 ** 1
else:
sum.append(0)
if image_array[i - 1, j + 1] > image_array[i, j]:
sum.append(1)
num += 2 ** 2
else:
sum.append(0)
if image_array[i, j - 1] > image_array[i, j]:
sum.append(1)
num += 2 ** 3
else:
sum.append(0)
if image_array[i, j + 1] > image_array[i, j]:
sum.append(1)
num += 2 ** 4
else:
sum.append(0)
if image_array[i + 1, j - 1] > image_array[i, j]:
sum.append(1)
num += 2 ** 5
else:
sum.append(0)
if image_array[i + 1, j] > image_array[i, j]:
sum.append(1)
num += 2 ** 6
else:
sum.append(0)
if image_array[i + 1, j + 1] > image_array[i, j]:
sum.append(1)
num += 2 ** 7
else:
sum.append(0)
return sum, num
Nota (1) con diagrama
3. Gire continuamente la secuencia binaria para obtener el valor decimal mínimo de la secuencia binaria
# 获取二进制序列进行不断环形旋转得到新的二进制序列的最小十进制值
def get_min_for_revolve(self, arr):
values = []
circle = arr
circle.extend(arr)
for i in range(0, 8):
j = 0
sum = 0
bit_num = 0
while j < 8:
sum += circle[i + j] << bit_num
bit_num += 1
j += 1
values.append(sum)
return min(values)
El arr entrante es la suma en calute_basic_lbp, una secuencia binaria, y circle.extend (arr) es agregar la misma secuencia después de la secuencia del círculo, de modo que cada 8 elementos se recorren como un grupo, y después de recorrer ocho grupos, puede ver El resultado es que la secuencia gira constantemente y finalmente vuelve a la disposición de la secuencia original. El ciclo while calcula el número decimal de cada secuencia binaria, lo agrega a la lista de valores y devuelve el número decimal más pequeño. (<< es un operador de desplazamiento de bit a la izquierda, la función es desplazar el valor a la izquierda bit_num, si el valor de circle[i+j] es 3, bit_num es 3, entonces esta línea de código aumentará el valor de sum por 24)
4. Cree un diccionario de 36 características en modo de rotación invariable
def __init__(self):
# revolve_map为旋转不变模式的36种特征值从小到大进行序列化编号得到的字典
self.revolve_map = {0: 0, 1: 1, 3: 2, 5: 3, 7: 4, 9: 5, 11: 6, 13: 7, 15: 8, 17: 9, 19: 10, 21: 11, 23: 12, 25: 13,
27: 14, 29: 15, 31: 16, 37: 17, 39: 18, 43: 19, 45: 20, 47: 21, 51: 22, 53: 23, 55: 24, 59: 25,
61: 26, 63: 27, 85: 28, 87: 29, 91: 30, 95: 31, 111: 32, 119: 33, 127: 34, 255: 35}
Después de que el número binario de ocho bits se rota continuamente, solo hay 36 tipos de decimales, por lo que estos 36 tipos de valores decimales se utilizan como claves del diccionario, y los valores correspondientes a las claves son valores de píxeles. (0~35)
5. Código completo
import numpy as np
import cv2
from PIL import Image
from pylab import *
class LBP:
def __init__(self):
# revolve_map为旋转不变模式的36种特征值从小到大进行序列化编号得到的字典
self.revolve_map = {0: 0, 1: 1, 3: 2, 5: 3, 7: 4, 9: 5, 11: 6, 13: 7, 15: 8, 17: 9, 19: 10, 21: 11, 23: 12, 25: 13, 27: 14, 29: 15, 31: 16, 37: 17, 39: 18, 43: 19, 45: 20, 47: 21, 51: 22, 53: 23,55: 24,59: 25, 61: 26, 63: 27, 85: 28, 87: 29, 91: 30, 95: 31, 111: 32, 119: 33, 127: 34, 255: 35}
# 图像的LBP原始特征计算算法:将图像指定位置的像素与周围8个像素比较
# 比中心像素大的点赋值为1,比中心像素小的赋值为0,返回得到的二进制序列
def calute_basic_lbp(self, image_array, i, j):
sum = []
num = 0
if image_array[i - 1, j - 1] > image_array[i, j]:
sum.append(1)
num += 2 ** 0
else:
sum.append(0)
if image_array[i - 1, j] > image_array[i, j]:
sum.append(1)
num += 2 ** 1
else:
sum.append(0)
if image_array[i - 1, j + 1] > image_array[i, j]:
sum.append(1)
num += 2 ** 2
else:
sum.append(0)
if image_array[i, j - 1] > image_array[i, j]:
sum.append(1)
num += 2 ** 3
else:
sum.append(0)
if image_array[i, j + 1] > image_array[i, j]:
sum.append(1)
num += 2 ** 4
else:
sum.append(0)
if image_array[i + 1, j - 1] > image_array[i, j]:
sum.append(1)
num += 2 ** 5
else:
sum.append(0)
if image_array[i + 1, j] > image_array[i, j]:
sum.append(1)
num += 2 ** 6
else:
sum.append(0)
if image_array[i + 1, j + 1] > image_array[i, j]:
sum.append(1)
num += 2 ** 7
else:
sum.append(0)
return sum, num
# 获取二进制序列进行不断环形旋转得到新的二进制序列的最小十进制值
def get_min_for_revolve(self, arr):
values = []
circle = arr
circle.extend(arr)
for i in range(0, 8):
j = 0
sum = 0
bit_num = 0
while j < 8:
sum += circle[i + j] << bit_num
bit_num += 1
j += 1
values.append(sum)
return min(values)
# 获取图像的LBP旋转不变模式特征
def lbp_revolve(self, image_array):
revolve_array = np.zeros(image_array.shape, np.uint8)
width = image_array.shape[0]
height = image_array.shape[1]
for i in range(1, width - 1):
for j in range(1, height - 1):
sum = self.calute_basic_lbp(image_array, i, j)[0]
revolve_key = self.get_min_for_revolve(sum)
revolve_array[i, j] = self.revolve_map[revolve_key]
return revolve_array
# 绘制指定维数和范围的图像灰度归一化统计直方图
def show_hist(self, img_array, im_bins, im_range):
# 直方图的x轴是灰度值,y轴是图片中具有同一个灰度值的点的数目, [img_array]原图像图像格式为uint8或float32,[0]0表示灰度,None无掩膜
hist = cv2.calcHist([img_array], [0], None, im_bins, im_range)
hist = cv2.normalize(hist, hist).flatten() # 对计算出来的直方图数据进行归一化处理,并将结果扁平化为1D数组
# print(hist)
plt.plot(hist, color='r')
plt.xlim(im_range) # 设置X轴的取值范围
plt.show()
# 绘制图像旋转不变LBP特征的归一化统计直方图
def show_revolve_hist(self, img_array):
self.show_hist(img_array, [36], [0, 36])
# 显示图像
def show_image(self, image_array):
plt.imshow(image_array, cmap='Greys_r')
plt.show()
if __name__ == '__main__':
image = cv2.imread('F:/out_picture/train/001.jpg')
image_array = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
lbp = LBP()
plt.imshow(image_array, cmap='Greys_r') # 去掉参数就是热量图了
plt.title('Original')
plt.show()
#获取图像旋转不变LBP特征,并显示其统计直方图与特征图像
revolve_array = lbp.lbp_revolve(image_array)
lbp.show_revolve_hist(revolve_array)
lbp.show_image(revolve_array)