[PYTHON] Accélérer l'algorithme de Zhang-Suen dans Numpy

introduction

Cliquez ici pour l'algorithme de Zhang-Suen Comme vous pouvez le voir en lisant le code lié, il est très lent car il est tourné dans une double boucle for. J'ai donc rendu possible le même traitement en utilisant uniquement la fonction universelle de Numpy.

Fonction universelle

Numpy fournit une fonction appelée fonction universelle qui renvoie un tableau des résultats de l'exécution d'opérations majeures sur chaque élément du tableau. Si vous utilisez cela, vous n'avez pas à passer par le processus d'extraction de chaque élément un par un et de le traiter. C'est rapide. Ce sera environ 20 à 30 fois plus rapide.

En traitement

Prétraitement

-Préparez une image binarisée avec le noir comme vrai et le blanc comme faux. Entourez l'extérieur avec Faux pour 1 pixel. -Pour chaque élément de la partie centrale, générer un tableau qui stocke les éléments du haut, du haut à droite, de la droite, du bas à droite, du bas, du bas à gauche, à gauche, en haut à gauche (Nommez-les respectivement P2 à P9)

#Une méthode pour remplir 1 pixel autour d'une image binaire avec False.
def padding(binary_image):
    row, col = np.shape(binary_image)
    result = np.zeros((row+2,col+2))
    result[1:-1, 1:-1] = binary_image[:, :]
    return result

def generate_mask(image):
    row, col = np.shape(image)
    p2 = np.zeros((row, col)).astype(bool)
    p3 = np.zeros((row, col)).astype(bool)
    p4 = np.zeros((row, col)).astype(bool)
    p5 = np.zeros((row, col)).astype(bool)
    p6 = np.zeros((row, col)).astype(bool)
    p7 = np.zeros((row, col)).astype(bool)
    p8 = np.zeros((row, col)).astype(bool)
    p9 = np.zeros((row, col)).astype(bool)
    #Vers le haut
    p2[1:row-1, 1:col-1] = image[0:row-2, 1:col-1]
    #En haut à droite
    p3[1:row-1, 1:col-1] = image[0:row-2, 2:col]
    #droite
    p4[1:row-1, 1:col-1] = image[1:row-1, 2:col]
    #En bas à droite
    p5[1:row-1, 1:col-1] = image[2:row, 2:col]
    #en dessous de
    p6[1:row-1, 1:col-1] = image[2:row, 1:col-1]
    #En bas à gauche
    p7[1:row-1, 1:col-1] = image[2:row, 0:col-2]
    #la gauche
    p8[1:row-1, 1:col-1] = image[1:row-1, 0:col-2]
    #en haut à gauche
    p9[1:row-1, 1:col-1] = image[0:row-2, 0:col-2]
    return (p2, p3, p4, p5, p6, p7, p8, p9)

Condition 1

** noir ** Le tableau d'origine est tel qu'il est.

condition1 = np.copy(image)

Condition 2

** Lorsque les pixels autour du pixel cible sont disposés dans l'ordre, il y a exactement un endroit où blanc → noir ** Cette condition signifie que lorsque vous regardez une adresse dans l'ordre P2, P3, P4, P5, P6, P7, P8, P9, P2, il y a exactement deux changements Vrai Faux.

#C'est une méthode pour juger s'il y a exactement un blanc → noir lorsque les pixels environnants sont disposés dans l'ordre.
def is_once_change(p_tuple):
    number_change = np.zeros_like(p_tuple[0])
    # P2~P9,Pour P2, comptez le nombre de vrais lorsque la somme logique exclusive des éléments adjacents est prise.
    for i in range(len(p_tuple) - 1):
        number_change = np.add(number_change, np.logical_xor(p_tuple[i], p_tuple[i+1]).astype(int))
    number_change = np.add(number_change, np.logical_xor(p_tuple[7], p_tuple[0]).astype(int))
    array_two = np.ones_like(p_tuple[0]) * 2
    return np.equal(number_change, array_two)

condition2 = is_once_change(p_tuple)

Condition 3

** 2 ou plus et 6 ou moins de noir autour du pixel cible ** Cette condition signifie que le nombre de vrais de P2, P3, P4, P5, P6, P7, P8, P9 est de 2 ou plus et de 6 ou moins pour une certaine adresse.

#Cette méthode compte le nombre de pixels noirs autour d'elle et détermine si elle est de 2 ou plus et de 6 ou moins.
def is_black_pixels_appropriate(p_tuple):
    number_of_black_pxels = np.zeros_like(p_tuple[0])
    array_two = np.ones_like(p_tuple[0]) * 2
    array_six = np.ones_like(p_tuple[0]) * 6
    for p in p_tuple:
        number_of_black_pxels = np.add(number_of_black_pxels, p.astype(int))
    greater_two = np.greater_equal(number_of_black_pxels, array_two)
    less_six = np.less_equal(number_of_black_pxels, array_six)
    return np.logical_and(greater_two, less_six)

condition3 = is_black_pixels_appropriate(p_tuple)

Condition 4, condition 5

** Au moins un des pixels en haut, en bas, à gauche et à droite du pixel cible est blanc ** Vérifiez qu'au moins une des valeurs P2, P4, P6, P8 correspondantes pour le pixel cible est False.

#Une méthode qui renvoie le produit logique pour tous les arguments donnés.
def multi_logical_and(*args):
    result = np.copy(args[0])
    for arg in args:
        result = np.logical_and(result, arg)
    return result
condition4 = np.logical_not(multi_logical_and(p_tuple[0], p_tuple[2], p_tuple[4]))

Code source

Je vais mettre le code de l'ensemble du processus.

ZhangSuen.py


import numpy as np

#Une méthode qui renvoie le produit logique pour tous les arguments donnés.
def multi_logical_and(*args):
    result = np.copy(args[0])
    for arg in args:
        result = np.logical_and(result, arg)
    return result

#Une méthode pour remplir 1 pixel autour d'une image binaire avec False.
def padding(binary_image):
    row, col = np.shape(binary_image)
    result = np.zeros((row+2,col+2))
    result[1:-1, 1:-1] = binary_image[:, :]
    return result

#Le contraire du rembourrage
def unpadding(image):
    return image[1:-1, 1:-1]

#Renvoie un tableau contenant des informations sur les pixels autour de ce pixel.
def generate_mask(image):
    row, col = np.shape(image)
    p2 = np.zeros((row, col)).astype(bool)
    p3 = np.zeros((row, col)).astype(bool)
    p4 = np.zeros((row, col)).astype(bool)
    p5 = np.zeros((row, col)).astype(bool)
    p6 = np.zeros((row, col)).astype(bool)
    p7 = np.zeros((row, col)).astype(bool)
    p8 = np.zeros((row, col)).astype(bool)
    p9 = np.zeros((row, col)).astype(bool)
    #Vers le haut
    p2[1:row-1, 1:col-1] = image[0:row-2, 1:col-1]
    #En haut à droite
    p3[1:row-1, 1:col-1] = image[0:row-2, 2:col]
    #droite
    p4[1:row-1, 1:col-1] = image[1:row-1, 2:col]
    #En bas à droite
    p5[1:row-1, 1:col-1] = image[2:row, 2:col]
    #en dessous de
    p6[1:row-1, 1:col-1] = image[2:row, 1:col-1]
    #En bas à gauche
    p7[1:row-1, 1:col-1] = image[2:row, 0:col-2]
    #la gauche
    p8[1:row-1, 1:col-1] = image[1:row-1, 0:col-2]
    #en haut à gauche
    p9[1:row-1, 1:col-1] = image[0:row-2, 0:col-2]
    return (p2, p3, p4, p5, p6, p7, p8, p9)

#C'est une méthode pour juger s'il y a exactement un blanc → noir lorsque les pixels environnants sont disposés dans l'ordre.
def is_once_change(p_tuple):
    number_change = np.zeros_like(p_tuple[0])
    # P2~P9,Pour P2, comptez le nombre de vrais lorsque la somme logique exclusive des éléments adjacents est prise.
    for i in range(len(p_tuple) - 1):
        number_change = np.add(number_change, np.logical_xor(p_tuple[i], p_tuple[i+1]).astype(int))
    number_change = np.add(number_change, np.logical_xor(p_tuple[7], p_tuple[0]).astype(int))
    array_two = np.ones_like(p_tuple[0]) * 2

    return np.equal(number_change, array_two)

#Cette méthode compte le nombre de pixels noirs autour d'elle et détermine si elle est de 2 ou plus et de 6 ou moins.
def is_black_pixels_appropriate(p_tuple):
    number_of_black_pxels = np.zeros_like(p_tuple[0])
    array_two = np.ones_like(p_tuple[0]) * 2
    array_six = np.ones_like(p_tuple[0]) * 6
    for p in p_tuple:
        number_of_black_pxels = np.add(number_of_black_pxels, p.astype(int))
    greater_two = np.greater_equal(number_of_black_pxels, array_two)
    less_six = np.less_equal(number_of_black_pxels, array_six)
    return np.logical_and(greater_two, less_six)

def step1(image, p_tuple):
    #Condition 1
    condition1 = np.copy(image)
    
    #Condition 2
    condition2 = is_once_change(p_tuple)
    
    #Condition 3
    condition3 = is_black_pixels_appropriate(p_tuple)
    
    #Condition 4
    condition4 = np.logical_not(multi_logical_and(p_tuple[0], p_tuple[2], p_tuple[4]))
    
    #Condition 5
    condition5 = np.logical_not(multi_logical_and(p_tuple[2], p_tuple[4], p_tuple[6]))
    
    return np.logical_xor(multi_logical_and(condition1, condition2, condition3, condition4, condition5), image)
    
def step2(image, p_tuple):
    #Condition 1
    condition1 = np.copy(image)
    
    #Condition 2
    condition2 = is_once_change(p_tuple)
    
    #Condition 3
    condition3 = is_black_pixels_appropriate(p_tuple)
    
    #Condition 4
    condition4 = np.logical_not(np.logical_and(p_tuple[0], np.logical_and(p_tuple[2], p_tuple[6])))
    
    #Condition 5
    condition5 = np.logical_not(np.logical_and(p_tuple[0], np.logical_and(p_tuple[4], p_tuple[6])))
    
    return np.logical_xor(multi_logical_and(condition1, condition2, condition3, condition4, condition5), image)

#Cette méthode renvoie une image binarisée sous forme de ligne fine.
def ZhangSuen(image):
    
    image = padding(image)
    
    while True:
        old_image = np.copy(image)

        p_tuple = generate_mask(image)
        image = step1(image, p_tuple)
        p_tuple = generate_mask(image)        
        image = step2(image, p_tuple)
        
        if (np.array_equal(old_image, image)):
            break
            
    return unpadding(image)


Recommended Posts

Accélérer l'algorithme de Zhang-Suen dans Numpy
où de numpy
Implémenter l'algorithme PRML en Python (presque uniquement Numpy)
Spécification d'axe avec NumPy
Algorithme génétique en python
Algorithme en Python (méthode Bellman-Ford, Bellman-Ford)
Algorithme en Python (Dijkstra)
Installez numpy dans Visual Studio 2019
Algorithme en Python (jugement premier)
Imiter Numpy de Python en C #
Produit matriciel en python numpy
Reproduire la méthode de division mutuelle euclidienne en Python
Algorithme en Python (dichotomie)
Implémenter l'algorithme de Dijkstra en python
Algorithme en Python (recherche de priorité de largeur, bfs)
Algorithme de tri et implémentation en Python
Mettez python, numpy, opencv3 dans ubuntu14
Ecrire des algorithmes A * (A-star) en Python
Carte auto-organisée dans la version Python NumPy
Développons un algorithme d'investissement avec Python 2
[Numpy] Appeler savetxt () en mode ajout
Algorithme en Python (recherche de priorité en profondeur, dfs)
Implémentation d'un algorithme simple en Python 2
Algorithme (arborescence de segments) en Python (s'entraîner)
Exécutez un algorithme simple en Python
Inverser le tableau booléen numpy dans tilda