banniere

Le portail francophone de la géomatique


Toujours pas inscrit ? Mot de passe oublié ?
Nom d'utilisateur    Mot de passe              Toujours pas inscrit ?   Mot de passe oublié ?

Annonce

Rencontres QGIS 2025

L'appel à participation est ouvert jusqu'au 19 janvier 2025!

#1 Wed 05 July 2023 03:09

BorelPaul
Juste Inscrit !
Date d'inscription: 4 Jul 2023
Messages: 3

QGIS: Detection de classes entourees par une autre classe

Bonjour, je poste ce message pour obtenir de l'aide sur un problème que j'ai actuellement.

J'ai un raster qui représente 4 classes d'occupation du sol (représenté par 4 valeurs) :
Classe A = 1
Classe B = 2
Classe C = 3
Classe D = 4

Mon raster est très grand (10000 x 10000 pixels)

J'aimerais changer la valeur des pixels de la classe D (=4) lorsqu'elle est entièrement entourée par des pixels de la classe C (=3).

J'ai essayé de faire des sélections classiques en vectorisant mon raster avec "sélection par localisation" avec le mode 'contient' mais cela ne fonctionne pas car la couche l'entoure et ne la contient pas.
Je me suis dit aussi qu'en récupérant les contours de mes polygones de ma classe C(=3) je pourrais reformer de nouveaux polygones "complets" ou "sans trous" qui me permettrais de sélectionner mes polygones de classe D(=4) avec la sélection par localisation mais je n'y parviens pas, les contours interne sont toujours récupérer (j'ai utilisé r.contour de GRASS)

J'ai aussi essayé en conservant le raster mais les manipulations de rasters sont souvent très longues donc cela ne peut pas être appliqué dans mon cas..

Merci beaucoup déjà de lire ce post et j'espère que vous aurez des pistes à me proposer !

Dernière modification par BorelPaul (Wed 05 July 2023 10:14)

Hors ligne

 

#2 Fri 07 July 2023 09:25

BorelPaul
Juste Inscrit !
Date d'inscription: 4 Jul 2023
Messages: 3

Re: QGIS: Detection de classes entourees par une autre classe

Alors je suis passé sous python pour essayer de trouver une solution et j'ai fait ça ! (au cas où si quelqu'un se pose la question)
Le code n'est surement pas parfait mais il fonctionne (pour exemple il traite un raster de 10 000px * 10 000px en environ 8 minutes, même si cela dépend beaucoup de la quantité de pixels à modifier et la complexité des données).
Si vous avez des suggestions pour des modifications futures ou des remarques je suis preneur !

Ce code crée des groupes de pixels collé les un aux autres (dans mon exemple il groupe les pixels égal à 4) et ensuite calcule le pourcentage de pixels d'une autre valeur autour de chacun des groupes, au dessus d'un certain pourcentage (dans mon exemple 60% de pixel égal à 3) il change la valeur des pixels vers une valeur prédéfinie (dans mon exemple 3).

Code:

import rasterio
import numpy as np
from tqdm import tqdm
import os

# Chemin vers le dossier contenant les fichiers raster
dossier_source = r'chemin/vers/votre/dossier'

# Liste des fichiers raster à traiter
liste = ['chemin/vers/votre/fichier1.tif', 'chemin/vers/votre/fichier2.tif']

for fichier in liste:
    # Chemin vers le fichier de sortie modifié
    output_raster_path = fichier[:-4] + "_modifie.tif"
    
    # Passe si un fichier de sortie de même nom a déjà été généré
    if os.path.exists(output_raster_path):
        print(output_raster_path + " existe déjà !")
        continue
    
    # Lire le raster
    with rasterio.open(fichier) as src:
        # Lire les données raster
        raster_data = src.read(1)

        # Copier les données raster pour effectuer les modifications
        modified_raster_data = raster_data.copy()

        # Tableau pour stocker les groupes
        group_table = np.zeros_like(raster_data, dtype=np.int32)

        # Dictionnaire pour stocker les coordonnées des pixels de contour pour chaque groupe
        contour_pixels = {}

        # Valeur de groupe initial
        current_group = 1

    # Parcourir tous les pixels du raster en utilisant un parcours en profondeur (DFS) itératif
    def dfs(i, j, current_group):
        stack = [(i, j)]
        while stack:
            i, j = stack.pop()
            if (0 <= i < raster_data.shape[0] and
                    0 <= j < raster_data.shape[1] and
                    raster_data[i, j] == 4 and
                    group_table[i, j] == 0):
                group_table[i, j] = current_group
                contour_pixels[current_group].append((i, j))

                # Ajouter les voisins non marqués à la pile
                stack.extend([
                    (i, j-1),  # Gauche
                    (i-1, j-1),  # Haut gauche
                    (i-1, j),  # Haut
                    (i-1, j+1),  # Haut droite
                    (i, j+1),  # Droite
                    (i+1, j+1),  # Bas droite
                    (i+1, j),  # Bas
                    (i+1, j-1)  # Bas gauche
                ])

    # Parcourir tous les pixels du raster
    for i in tqdm(range(raster_data.shape[0]), desc='Processing'):
        for j in range(raster_data.shape[1]):
            if raster_data[i, j] == 4 and group_table[i, j] == 0:
                current_group += 1
                contour_pixels[current_group] = []  # Initialiser la liste des pixels de contour pour ce groupe
                dfs(i, j, current_group)

    # Parcourir les groupes pour vérifier le pourcentage de pixels voisins des pixels de contour
    for group, pixels in tqdm(contour_pixels.items(), desc='Processing contours'):
        contour_array = np.array(pixels)
        contour_i, contour_j = contour_array[:, 0], contour_array[:, 1]

        # Obtenir les indices des voisins (les 8 voisins)
        neighbors_i = np.array([contour_i-1, contour_i-1, contour_i-1, contour_i, contour_i, contour_i+1, contour_i+1, contour_i+1])
        neighbors_j = np.array([contour_j-1, contour_j, contour_j+1, contour_j-1, contour_j+1, contour_j-1, contour_j, contour_j+1])

        # Filtrer les voisins valides
        valid_neighbors = np.logical_and(
            np.logical_and(neighbors_i >= 0, neighbors_i < raster_data.shape[0]),
            np.logical_and(neighbors_j >= 0, neighbors_j < raster_data.shape[1])
        )
        neighbors_i = neighbors_i[valid_neighbors]
        neighbors_j = neighbors_j[valid_neighbors]

        # Obtenir les valeurs des voisins
        neighbor_values = raster_data[neighbors_i, neighbors_j]

        # Compter les voisins ayant la valeur 3
        imper_neighbors = np.count_nonzero(neighbor_values == 3)

        # Compter les voisins ayant une valeur différente de 4 pour obtenir le nombre total de voisins
        total_neighbors = np.count_nonzero(neighbor_values != 4)

        # Calculer le pourcentage
        percentage = (imper_neighbors * 100) / total_neighbors

        if percentage > 60:
            # Changer les valeurs des pixels du groupe de 4 à 3 dans raster_data
            group_indices = np.where(group_table == group)
            raster_data[group_indices] = 3

    # Enregistrer le raster modifié
    with rasterio.open(output_raster_path, 'w', **src.meta) as dst:
        dst.write(raster_data, 1)

print("Programme terminé")

Dernière modification par BorelPaul (Fri 07 July 2023 10:12)

Hors ligne

 

Pied de page des forums

Powered by FluxBB