LBP study notes (2) --- rotation invariant mode features (code implementation)

        It is recommended to read the following content after reading the LBP study notes (1) to make it easier to get started

1. A brief description of the LBP rotation invariant model

The rotation-invariant local binary pattern refers to the feature representation with rotation invariance by performing rotation-invariant processing on the LBP feature on the basis of the local binary pattern (LBP) feature. Because the LBP feature has the advantages of grayscale invariance and rotation invariance, it has been widely used in the fields of image processing and computer vision.

The rotation-invariant LBP features can be calculated by the equivalent mode method and the rotation-invariant weight method. The number of equivalent modes of LBP features can be obtained by the method of equivalent modes, thereby eliminating the influence of image rotation on feature extraction. With the rotation-invariant weight method, different weights can be assigned to the pixels around the reference point to suppress some rotation-invariant effects.

When the rotation invariant mode is not used, the LBP feature calculation is simple, but it will be affected by factors such as image rotation and grayscale changes, resulting in inaccurate feature extraction. Using the rotation invariant mode can avoid the interference of these factors and improve the robustness of LBP features in practical application scenarios.

2. Code implementation (key functions and complete code)

1. Traversing pixels to obtain rotation invariant pattern features

# 获取图像的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 is the binary sequence obtained after the grayscale image of the original image is processed by the LBP original feature algorithm

revolve_key is the smallest decimal number obtained by sum after continuous rotation

Then use revolve_key as the key of the revolve_map dictionary, and assign its corresponding value (ie pixel value) to revolve_array[i,j]

2. Obtain the binary sequence of the comparison value of the eight fields

# 图像的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

 Note (1) with diagram

3. Continuously rotate the binary sequence to get the minimum decimal value of the binary sequence

# 获取二进制序列进行不断环形旋转得到新的二进制序列的最小十进制值
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)

 The incoming arr is the sum in calute_basic_lbp, a binary sequence, and circle.extend (arr) is to add the same sequence after the circle sequence, so that every 8 elements are traversed as a group, and after traversing eight groups, you can see The result is that the sequence is constantly rotating and finally returns to the original sequence arrangement. The while loop calculates the decimal number of each binary sequence, adds it to the values ​​list and returns the smallest decimal number. (<< is a bit left shift operator, the function is to shift the value to the left bit_num, if the value of circle[i+j] is 3, bit_num is 3, then this line of code will increase the value of sum by 24)

4. Create a dictionary of 36 features in rotation invariant mode

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}

 After the eight-bit binary number is continuously rotated, there are only 36 types of decimals, so these 36 types of decimal values ​​are used as the keys of the dictionary, and the values ​​corresponding to the keys are pixel values ​​(0~35)

5. Complete code

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)


3. Summary

        The extraction of LBP rotation-invariant mode features is a little more troublesome than the extraction of original mode features, mainly through continuous rotation of the binary sequence of original mode features to obtain its minimum decimal number and use it as a feature value, and in 3 *3 In the pixel neighborhood, compare the central pixel with the surrounding 8 pixels to get the minimum decimal number of the binary sequence is only 36, so as long as these 36 modes are clear, the extraction of LBP rotation invariant mode features is basically solved

If there is any mistake, please correct me!

Guess you like

Origin blog.csdn.net/qq_66036911/article/details/130330313