LBP-Studiennotizen (3) --- Äquivalente Modusfunktionen (Code-Implementierung)

Es wird empfohlen, nach der Lektüre der LBP-Studiennotizen (1)         den folgenden Inhalt zu lesen, um den Einstieg zu erleichtern

1. Eine kurze Beschreibung des LBP-Äquivalentmodells

Als Algorithmus zur Bildtexturanalyse generiert der LBP-Operator während der Verarbeitung eine große Anzahl binärer Muster, was die Effizienz der Musterklassifizierung und -erkennung erheblich beeinträchtigt. Um dieses Problem zu lösen, schlug Ojala die Verwendung eines „äquivalenten Musters“ (Uniform Pattern) vor, um die Dimensionalität der Mustertypen des LBP-Operators zu reduzieren.

Insbesondere bezieht sich der LBP-Äquivalenzmodus auf die Codierung des Binärmodus in der LBP-Berechnung, sodass benachbarte Binärmodi in dieselbe Äquivalenzklasse eingeteilt werden, wenn bestimmte Bedingungen erfüllt sind. Auf diese Weise kann die übermäßige Anzahl binärer Muster in eine relativ kleine Anzahl äquivalenter Muster komprimiert werden, wodurch die Effizienz und Zuverlässigkeit des Algorithmus verbessert wird. Diese Strategie ist in praktischen Anwendungen weit verbreitet und wurde in vielen Bereichen des maschinellen Sehens angewendet, z. B. in der Gesichtserkennung, der Erkennung handschriftlicher Ziffern, der Erkennung von Hornhauttexturen usw.

2. Code-Implementierung (Schlüsselfunktionen und vollständiger Code)

1. Erhalten Sie äquivalente Modusfunktionen

# 获取图像的LBP原始模式特征
def lbp_basic(self, image_array):
    basic_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)[1]
            basic_array[i, j] = sum
    return basic_array


# 获取图像的LBP等价模式特征
def lbp_uniform(self, image_array):
    uniform_array = np.zeros(image_array.shape, np.uint8)
    basic_array = self.lbp_basic(image_array)
    width = image_array.shape[0]
    height = image_array.shape[1]
    for i in range(1, width - 1):
        for j in range(1, height - 1):
            k = basic_array[i, j] << 1
            if k > 255:
                k = k - 255
            xor = basic_array[i, j] ^ k #^是异或运算符,用于按位比较两个二进制数字,如果对应位上的数字不同,则该位的运算结果为1,否则为0
            num = self.calc_sum(xor)
            if num <= 2:
                uniform_array[i, j] = self.uniform_map[basic_array[i, j]]
            else:
                uniform_array[i, j] = 58
    return uniform_array

 Das Erhalten der ursprünglichen Modusfunktionen wurde in Anmerkung (1) vorgestellt und wird hier nicht wiederholt.

Bevor Sie die äquivalenten Mustermerkmale erhalten, rufen Sie zunächst die ursprünglichen Mustermerkmale ab und übergeben Sie sie an das basic_array in der Funktion lbp_uniform.

Durchlaufen Sie jeden Eigenwert von basic_array, verschieben Sie den Eigenwert um 1 Bit nach links (hier ist das Merkmal x2), führen Sie dann eine XOR-Operation mit dem ursprünglichen Eigenwert ohne Verschiebung durch, vergleichen Sie Bit für Bit, erhalten Sie eine neue Binärsequenz und berechnen Sie dann Wenn die Anzahl der Ziffern von 1 in der neuen Binärsequenz größer als zwei ist, werden sie alle in einen Modustyp eingeteilt, sodass ihre Pixelwerte alle gleich 58 sind. Wenn sie kleiner oder gleich sind 2. Ihre Pixelwerte basieren auf den charakteristischen Werten der Originaldaten. Weisen Sie als Schlüssel im uniform_map-Wörterbuch den dem Schlüssel entsprechenden Wert zu.

Exklusives ODER: Exklusives ODER (XOR) ist ein logischer Operator, der normalerweise zum Vergleichen der entsprechenden Bits zweier Binärzahlen verwendet wird. Wenn diese Bits unterschiedlich sind, ist das Ergebnis 1, andernfalls ist das Ergebnis 0. Sein Symbol ist normalerweise „^“.

Der Grund für k > 255 hier:

Nehmen Sie an, dass die eingehende Eigenwertmatrix des ursprünglichen Modus einen maximalen Eigenwert von 255 aufweist und die entsprechende Binärsequenz [1,1,1,1,1,1,1,1] ist. Wenn Sie dazu kein Urteil fällen Lassen Sie es einmal um ein Bit nach links verschieben, dann wird es 510, also [1,1,1,1,1,1,1,1,0], also die effektive Länge der Daten (1 als höchste Ziffer rechts) wird zu 9, unsere Binärsequenz besteht nur aus 8 Bits, also sei 510-255 = 255, um einen Berechnungsüberlauf zu vermeiden, wenn die 8 Pixel um das mittlere Pixel herum alle größer als das mittlere Pixel sind.

Der Grund für basic_array[i,j] ^ k:

Da der Hauptzweck der Verwendung des äquivalenten Modus darin besteht, die Umrissstreifen im Bild zu extrahieren und andere unwichtige Punkte auszuwählen, muss dieses Texturmerkmal in einem bestimmten Bereich kontinuierlich sein (es kann als Linie und dann als Grundlinie verstanden werden). muss kontinuierlich sein, es kann nicht jeweils ein Punkt sein), die Abstraktion ist [0,0,1,1,1,1,0,0], [1,1,1,1,1 ,1,1, 1], [0,0,0,0,0,0,0,0], [1,1,0,0,0,0,0,1], hier ist 1 kontinuierlich oder 0 muss kontinuierlich sein , so dass 0 zu 1 oder 1 zu 0 einmal springt und diese kontinuierliche Binärfolge nur 0 oder 2 Mal springen kann (in einer kreisförmigen Anordnung, Ende an Ende verbunden), werden wir es so ausdrücken Die entsprechenden Eigenwerte Die Binärdatei, die der Anzahl der Sprünge von weniger als 2 entspricht, wird als Schlüssel im Wörterbuch uniform_map verwendet (es gibt 58).

Wenn Sie dann diese Art von Binärsequenz erhalten möchten, mit der Sie beurteilen können, ob die Linientextur des Bildes kontinuierlich ist, besteht der einfachste Weg darin, eine XOR-Operation für den Originalmodus-Eigenwert und den durch Verschieben nach links erhaltenen Wert durchzuführen ein bisschen.

kontinuierlich:

 Diskontinuierlich:

 2. Ermitteln Sie die Dezimalzahl der Binärfolge

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

3. Ermitteln Sie die Ziffer 1 nach XOR

# 获取值r的二进制中1的位数
def calc_sum(self, r):
    num = 0
    while (r):
        r &= (r - 1)
        num += 1
    return num

4. Erstellen Sie ein äquivalentes Muster-Feature-Wörterbuch

def __init__(self):
    # uniform_map为等价模式的58种特征值从小到大进行序列化编号得到的字典  58种
    self.uniform_map = {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 6: 5, 7: 6, 8: 7, 12: 8, 14: 9, 15: 10, 16: 11, 24: 12, 28: 13,
                        30: 14, 31: 15, 32: 16, 48: 17, 56: 18, 60: 19, 62: 20, 63: 21, 64: 22, 96: 23, 112: 24,
                        120: 25, 124: 26, 126: 27, 127: 28, 128: 29, 129: 30, 131: 31, 135: 32, 143: 33, 159: 34,
                        191: 35, 192: 36, 193: 37, 195: 38, 199: 39, 207: 40, 223: 41, 224: 42, 225: 43, 227: 44,
                        231: 45, 239: 46, 240: 47, 241: 48, 243: 49, 247: 50, 248: 51, 249: 52, 251: 53, 252: 54,
                        253: 55, 254: 56, 255: 57}

 Die Schlüssel im Wörterbuch sind die Originalmodus-Eigenwerte, deren Anzahl an Sprüngen 2 nicht überschreitet, es gibt 58, und es gibt insgesamt 59 Modi, die äquivalent und unverändert sind, und diejenigen mit einer Anzahl von Sprüngen über 2 werden vereinheitlicht in einen Modus, und die den Schlüsseln entsprechenden Werte sind diese Der Pixelwert im Modus.

5. Vollständiger Code

import numpy as np
import cv2
from PIL import Image
from pylab import *


class LBP:
    def __init__(self):
        # uniform_map为等价模式的58种特征值从小到大进行序列化编号得到的字典  58种
        self.uniform_map = {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 6: 5, 7: 6, 8: 7, 12: 8,14: 9, 15: 10, 16: 11, 24: 12, 28: 13, 30: 14, 31: 15, 32: 16, 48: 17, 56: 18, 60: 19, 62: 20, 63: 21, 64: 22, 96: 23, 112: 24,120: 25, 124: 26, 126: 27, 127: 28, 128: 29, 129: 30, 131: 31, 135: 32,143: 33, 159: 34, 191: 35, 192: 36, 193: 37, 195: 38, 199: 39, 207: 40,223: 41, 224: 42, 225: 43, 227: 44, 231: 45, 239: 46, 240: 47, 241: 48,243: 49, 247: 50, 248: 51, 249: 52, 251: 53, 252: 54, 253: 55, 254: 56,255: 57}

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


    # 获取值r的二进制中1的位数
    def calc_sum(self, r):
        num = 0
        while (r):
            r &= (r - 1)
            num += 1
        return num

    # 获取图像的LBP原始模式特征
    def lbp_basic(self, image_array):
        basic_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)[1]
                basic_array[i, j] = sum
        return basic_array


    # 获取图像的LBP等价模式特征
    def lbp_uniform(self, image_array):
        uniform_array = np.zeros(image_array.shape, np.uint8)
        basic_array = self.lbp_basic(image_array)
        width = image_array.shape[0]
        height = image_array.shape[1]
        for i in range(1, width - 1):
            for j in range(1, height - 1):
                k = basic_array[i, j] << 1
                if k > 255:
                    k = k - 255
                xor = basic_array[i, j] ^ k #^是异或运算符,用于按位比较两个二进制数字,如果对应位上的数字不同,则该位的运算结果为1,否则为0
                num = self.calc_sum(xor)
                if num <= 2:
                    uniform_array[i, j] = self.uniform_map[basic_array[i, j]]
                else:
                    uniform_array[i, j] = 58
        return uniform_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_basic_hist(self, img_array):
        self.show_hist(img_array, [256], [0, 256])

    # 绘制图像等价模式LBP特征的归一化统计直方图
    def show_uniform_hist(self, img_array):
        self.show_hist(img_array, [60], [0, 60]) #[60]把像素值区间分成60部分,[0, 60]像素值区间

    # 显示图像
    def show_image(self, image_array):
        plt.imshow(image_array, cmap='Greys_r')
        plt.show()

if __name__ == '__main__':
    image = cv2.imread('F:/in_picture/001.png')
    image_array = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) #BGR格式图像转灰度图像
    lbp = LBP()
    plt.imshow(image_array, cmap='Greys_r')  # 去掉参数就是热量图了
    plt.title('Original')
    plt.show()

    # 获取图像原始LBP特征,并显示其统计直方图与特征图像
    basic_array = lbp.lbp_basic(image_array)
    lbp.show_basic_hist(basic_array)
    lbp.show_image(basic_array)

    #获取图像等价模式LBP特征,并显示其统计直方图与特征图像
    uniform_array=lbp.lbp_uniform(image_array)
    lbp.show_uniform_hist(uniform_array)
    lbp.show_image(uniform_array)

3. Zusammenfassung

Der äquivalente invariante Modus verwendet hauptsächlich die XOR-Logikoperation, um die kontinuierlichen Zeilen herauszufiltern. Vor der Ausführung der XOR-Operation müssen die Daten verarbeitet werden, um einen Berechnungsüberlauf zu vermeiden.

Wenn es einen Fehler gibt, korrigieren Sie mich bitte!

Supongo que te gusta

Origin blog.csdn.net/qq_66036911/article/details/130335915
Recomendado
Clasificación