Skip to main content

Présentation rapide de l’utilisation de l’itérateur de cellule raster

Vous pouvez utiliser Raster Cell Iterator (Itérateur de cellule raster) pour effectuer une analyse raster personnalisée. Il permet de consulter les localisations individuelles des cellules raster, et procure un contrôle par itération pour interroger et modifier les valeurs des cellules raster, le tout dans un environnement Python.

Opérations de base à l’aide de l’itérateur de cellule raster

Cette section vous permettra d’acquérir une compréhension conceptuelle des opérations de base pouvant s’exécuter avec l’itérateur de cellule raster. Vous apprendrez à : créer un itérateur de cellule raster implicite, interroger et attribuer des valeurs aux cellules raster, créer un raster vide avec des métadonnées, indexer un objet raster et gérer la valeur NoData. Chaque section comprend des exemples de code qui illustrent comment utiliser l’itérateur de cellule raster depuis une fenêtre Python. Il est recommandé de lire ce document du début à la fin pour comprendre ces exemples de code.

Itérateur de cellule raster implicite

Un itérateur de cellule raster peut être invoqué implicitement sur un objet raster pour exécuter une itération à travers les index de ligne et de colonne d’un raster. L’exemple de code ci-dessous crée un objet raster nommé myRas à partir d’un jeu de données raster "myras" existant. Un itérateur de cellule raster implicite est défini sur l’objet raster qui énumère les paires d’index de ligne et de colonne à travers le raster dans une boucle. Dans l’itérateur, l’index de ligne i, l’index de colonne j et la valeur de cellule myRas[i,j] sont imprimés à chaque localisation de cellule. Voici un exemple d’interrogation d’une valeur de cellule à une localisation de cellule donnée en utilisant la notation d’index.

from arcpy.sa import *
myRas = Raster("myras")
for i,j in myRas:
 print(i, j, myRas[i,j])

Attribuer des valeurs aux cellules

À l’aide de l’itérateur de cellule raster, vous pouvez attribuer des valeurs aux cellules raster et ainsi modifier le jeu de données raster. Par défaut, les objets raster créés à partir d’un jeu de données raster existant comportent une propriété readOnly qui est définie sur True. Pour modifier les jeux de données raster, la propriété readOnly doit d’abord être définie sur False. Une fois les cellules raster modifiées, la méthode save() doit être appelée sur l’objet raster pour conserver ces modifications. Pour plus d’informations sur la propriété readOnly et l’enregistrement des rasters, reportez-vous à la rubrique d’aide relative aux objets Raster.

myRas.readOnly = False
for i,j in myRas:
 if myRas[i,j] == 0:
     myRas[i,j] = 128
myRas.save()

Création de rasters vides

La méthode getRasterInfo() vous permet de créer facilement un objet raster vide et de copier les métadonnées d’un objet raster existant. La méthode getRasterInfo() est appelée sur un objet raster existant, qui renvoie un objet rasterInfo() pour ce raster. L’objet rasterInfo() est ensuite transmis en tant que paramètre en entrée à la classe Raster() pour instancier un raster vide. L’objet raster vide présente les mêmes métadonnées que l’objet raster à partir duquel il est créé, mais possède la valeur NoData dans toutes les cellules raster. Les métadonnées raster comprennent notamment les propriétés suivantes : bandCount, taille de cellule, extent, spatialReference, pixelType et noDataValues. Lorsqu’un objet raster est créé à l’aide de la méthode getRasterInfo(), la propriété readOnly est définie par défaut sur False afin que des valeurs puissent être attribuées à cet objet raster vide.

outRas = Raster(myRas.getRasterInfo())

Vous pouvez également créer un objet de classe rasterInfo vide et renseigner les métadonnées raster en utilisant la méthode FromJSONString() sur l’objet rasterInfo(). Cet objet peut ensuite être utilisé pour créer un raster vide, comme illustré ci-dessous.

ri = arcpy.RasterInfo()
ri_as_jsonstring = '{"bandCount":1,' \
                '"extent":{"xmin":0,"ymin":0,"xmax":10,"ymax":10,"spatialReference":{"wkid":26912}},' \
                '"pixelSizeX":1,' \
                '"pixelSizeY":1,' \
                '"pixelType":"F32"}'
ri.fromJSONString(ri_as_jsonstring)
outRas = Raster(ri)

Indexation d’un objet raster

L’indexation d’un objet raster permet d’accéder en lecture et en écriture à une cellule spécifique dans un jeu de données raster. L’indexation peut être utilisée à l’intérieur ou à l’extérieur d’un itérateur de cellule raster.

Pour un raster monobande, un objet raster possède deux index, [i, j], qui sont respectivement les index de ligne et de colonne. Un minimum de deux index est nécessaire pour interroger et attribuer des valeurs. Tous les index sont en base zéro, et commencent à zéro. Les index de ligne ont une plage de valeurs, comprise entre 0 et n(lignes) - 1, où n(lignes) est le nombre de lignes dans le raster en question. De même, les index de colonne ont une plage de valeurs, comprise entre 0 et n(colonnes) - 1, où n(colonnes) est le nombre de colonnes dans le raster en question.

L’indexation commence dans l’angle supérieur gauche d’un jeu de données raster, où la cellule située la plus en haut à gauche présente l’index [0, 0] et la cellule située la plus en bas à droite présente l’index [n(lignes) - 1, n(colonnes) - 1].

Gestion des cellules NoData

Lorsqu’une cellule avec NoData est interrogée suivant la notation d’index, dans ou en dehors du contexte d’un itérateur de cellule raster, la valeur renvoyée dans Python est NaN. Par exemple, si l’on sait que myRas présente une valeur NoData pour la ligne et l’index de colonne [2, 2], l’interrogation de cette valeur de cellule renvoie NaN. Cela peut être vérifié par l’intermédiaire de la méthode math.isnan(), qui renvoie la valeur booléenne True pour cette cellule.

import math
math.isnan(myRas[2,2])
out: True

Si la valeur NaN est attribuée à une cellule dans Python, la cellule raster devient NoData, quel que soit le format ou l’objet NoDataValues pour ce jeu de données raster. Il s’agit de la méthode appropriée pour transformer une cellule en NoData. Par exemple, attribuer NaN à myRas au niveau de l’index de ligne et de colonne [3, 3] modifie cette cellule en NoData.

myRas[3,3] = math.nan

Il est recommandé de ne pas convertir une cellule en NoData en attribuant directement l’objet noDataValues de ce jeu de données raster à une cellule, mais plutôt de suivre la méthode décrite ci-dessus.

Opérations avancées à l’aide de l’itérateur de cellule raster

Cette section vous permettra d’acquérir une compréhension conceptuelle des opérations avancées pouvant s’exécuter avec l’itérateur de cellule raster. Vous apprendrez à créer un itérateur de cellule raster explicite pour exécuter une itération sur plusieurs rasters, et à utiliser les options padding et skipNoData. Vous découvrirez l’indexation de rasters multibandes et l’utiliserez dans un itérateur de cellule raster. Vous apprendrez à traiter différents types de pixels raster et à gérer les valeurs hors limite.

Itérateur de cellule raster explicite

Pour invoquer un itérateur de cellule raster, vous pouvez également utiliser un objet de classe RasterCellIterator explicite. Alors que l’itérateur implicite est idéal pour exécuter une itération sur un seul jeu de données raster, l’itérateur explicite est conçu pour exécuter une itération sur plusieurs rasters et est optimisé à cet effet. En itérant sur plusieurs rasters, vous pouvez effectuer des analyses avec des rasters en entrée dont les valeurs de cellule sont utilisées dans le calcul et des rasters en sortie sur lesquels les valeurs de cellule sont écrites pendant le calcul.

L’exemple suivant illustre l’utilisation de l’itérateur de cellule raster explicite pour exécuter une itération sur plusieurs rasters en entrée et en sortie. Les rasters en entrée myRas1 et myRas2 possèdent le même nombre de lignes et de colonnes et d’autres propriétés telles que la taille de cellule, l’étendue et la référence spatiale. Les rasters en sortie outRas1 et outRas2 sont créées à l’aide de l’objet de classe rasterInfo du premier raster en entrée. À chaque cellule raster, une opération focale est appliquée pour calculer les valeurs moyennes d’un voisinage de 3 cellules x 3 pour myRas1 et myRas2. À cette localisation de cellule, le raster outRas1 se voit attribuer une valeur de cellule comme minimum des moyennes et outRas2 une valeur de cellule comme maximum des moyennes.

myRas1 = Raster("myras1")
myRas2 = Raster("myras2")
outRas1 = Raster(myRas1.getRasterInfo())
outRas2 = Raster(myRas1.getRasterInfo())
with RasterCellIterator({'rasters':[myRas1, myRas2, outRas1, outRas2]}) as rci:
 for i,j in rci:
     meanMyRas1 = (myRas1[i-1,j-1] + myRas1[i-1, j] + myRas1[i-1, j+1] + \
                   myRas1[i,j-1] + myRas1[i, j] + myRas1[i, j+1] + \
                   myRas1[i+1,j-1] + myRas1[i+1, j] + myRas1[i+1, j+1]) / 9
     meanMyRas2 = (myRas2[i-1,j-1] + myRas2[i-1, j] + myRas2[i-1, j+1] + \
                   myRas2[i,j-1] + myRas2[i, j] + myRas2[i, j+1] + \
                   myRas2[i+1,j-1] + myRas2[i+1, j] + myRas2[i+1, j+1]) / 9
     outRas1[i,j] = min(meanMyRas1, meanMyRas2)
     outRas2[i,j] = max(meanMyRas1, meanMyRas2)
outRas1.save()
outRas2.save()

Lorsque plusieurs rasters sont utilisés dans l’itérateur, le premier raster de la liste définit l’environnement d’analyse raster de l’itérateur. La référence spatiale, la taille de cellule et l’étendue de tous les autres rasters de la liste doivent correspondre à celles du premier raster. Si ces propriétés du deuxième raster et des suivants dans cette liste ne correspondent pas à celles du premier raster, l’environnement d’analyse du premier raster leur est appliqué. Il est recommandé de créer tous les rasters en sortie en utilisant l’objet rasterInfo() du premier raster afin qu’ils héritent de sa référence spatiale, de sa taille de cellule et de son étendue.

De plus, si vous souhaitez respecter les paramètres d’environnement, ils doivent être appliqués au premier raster de cette liste à l’aide de la fonction ApplyEnvironment avant de l’utiliser dans l’itérateur. L’exemple ci-dessous en offre une démonstration.

myRas1 = Raster("myras1")
myRas2 = Raster("myras2")
#Apply environment settings to myRas1
myRas1_env = arcpy.sa.ApplyEnvironment(myRas1)
outRas1_env = Raster(myRas1_env.getRasterInfo())
with RasterCellIterator({'rasters':[myRas1_env, myRas2, outRas1_env]}) as rci:
 for i,j in rci:
     meanMyRas1 = (myRas1_env[i-1,j-1] + myRas1_env[i-1, j] + myRas1_env[i-1, j+1] + \
                   myRas1_env[i,j-1] + myRas1_env[i, j] + myRas1_env[i, j+1] + \
                   myRas1_env[i+1,j-1] + myRas1_env[i+1, j] + myRas1_env[i+1, j+1]) / 9
     meanMyRas2 = (myRas2[i-1,j-1] + myRas2[i-1, j] + myRas2[i-1, j+1] + \
                   myRas2[i,j-1] + myRas2[i, j] + myRas2[i, j+1] + \
                   myRas2[i+1,j-1] + myRas2[i+1, j] + myRas2[i+1, j+1]) / 9
     outRas1_env[i,j] = min(meanMyRas1, meanMyRas2)
outRas1_env.save()

Option de remplissage

L’itérateur explicite comporte une option de remplissage. La marge de remplissage ne change en rien la sortie. Toutefois, elle améliore les performances en cas d’accès à des valeurs de cellule de voisinage pendant l’itération dans les emplacements de cellule. Par exemple, si une opération de voisinage comporte un noyau qui accède à des valeurs de cellule jusqu’à deux cellules de ligne ou deux cellules de colonne de l’emplacement de la cellule sous itération, prévoyez un remplissage de 2.

with RasterCellIterator({'rasters':[myRas1, outRas1], 'padding': 2}) as rci_padded:
 for i,j in rci_padded:
     outRas1[i,j] = (myRas1[i-2,j-2] + myRas1[i-2, j] + myRas1[i-2, j+2] + \
                   myRas1[i,j-2] + myRas1[i, j] + myRas1[i, j+2] + \
                   myRas1[i+2,j-2] + myRas1[i+2, j] + myRas1[i+2, j+2]) / 9
outRas1.save()

Ignorer l’option NoData

L’itérateur explicite a la capacité d’ignorer complètement les cellules NoData, au lieu de les traiter par cellule. Utilisez la clé skipNoData pour fournir une liste de rasters déterminant quelles cellules raster sont ignorées par l’itérateur. Pour une cellule donnée, si l’un des rasters de cette liste comporte une valeur NoData, cette cellule est ignorée. Puisque l’état des cellules NoData dans ces rasters peut changer au cours d’une itération, que les cellules soient ignorées ou non varie selon l’état des rasters à chaque cellule, à mesure de leur visite par l’itérateur. Le principal avantage de cette option est l’amélioration des performances lors de l’itération sur des jeux de données raster de faible densité, puisque de nombreuses cellules NoData n’ont plus besoin d’être visitées.

Dans l’exemple suivant, un raster streamRas de faible densité n’a des valeurs qu’aux cellules représentant des cours d’eau, et NoData partout ailleurs. Un raster de direction de flux, flowDirRas, comporte des valeurs partout dans l’étendue du raster, sans aucune cellule NoData. En utilisant l’itérateur de cellule raster pour extraire les valeurs raster de direction de flux le long des cellules d’écoulement, vous pouvez utiliser la clé skipNoData de sorte que seules les cellules d’écoulement avec des valeurs soient visitées par l’itérateur, ce qui réduit le nombre total de cellules visitées.

streamRas = Raster("streams")
flowDirRas = Raster("flowdir")
outRas = Raster(flowDirRas.getRasterInfo())
with RasterCellIterator({'rasters':[streamRas, flowDirRas, outRas],'skipNoData':[flowDirRas, streamRas]}) as rci_skip:
 for i,j in rci_skip:
     outRas[i,j] = flowDirRas[i,j]
outRas.save()

Indexation des rasters multibandes

Dans le cas des rasters multibandes, vous pouvez fournir deux ou trois index. Les différences de comportement entre eux sont présentées ci-dessous.

Si deux index sont fournis, ils sont interprétés comme des index de lignes et de colonnes, et un tuple de valeurs est renvoyé depuis chaque bande pour l’index [row, column] spécifié. Par exemple, un raster multibande « mbras » de trois bandes peut être interrogé avec deux index, disons [2,2]. Ces index sont interprétés comme des index de lignes et de colonnes, et les valeurs de chacune des trois bandes sont renvoyées sous forme de tuple.

multibandRas = Raster("mbras")
multibandRas[2,2]
out: (4,5,6)

Si trois index sont spécifiés, ils sont interprétés comme des index [band, row, column], et la valeur de cellule est renvoyée pour l’emplacement de cellule de cette bande, ligne et colonne. L’index de bande est en base zéro et sa plage de valeurs pour un raster multibande est déterminée par 0 à n(bandes) - 1, où n(bandes) correspond au nombre total de bandes.

multibandRas[0,2,2]
out: 4

Gestion des valeurs hors limite

Tous les rasters ont un type de pixel et une profondeur de bits correspondante. Reportez-vous à la rubrique Capacité de profondeur de bits pour les pixels des jeux de données raster pour une liste complète des profondeurs de bits et de la plage de valeurs que chaque cellule peut contenir. Lorsqu’une valeur est attribuée à une cellule raster qui dépasse la plage des valeurs acceptées pour sa profondeur de bits, une situation hors limite se produit. Dans de tels cas, la cellule se voit attribuer NoData. Par exemple, le type de pixel d’un objet raster myRas1 est 'U8', qui est un entier non signé 8 bits. Ce raster peut contenir des valeurs entières comprises entre 0 et 255. Si la valeur 260 est attribuée à une cellule dans myRas1, la valeur NoData est attribuée. Après cette affectation, l’interrogation de la valeur dans cette cellule a pour effet de renvoyer NaN.

myRas1 = Raster("myras1")
myRas1Info = myRas1.getRasterInfo()
pixelType_MyRas1 = myRas1Info.getPixelType()
print(pixelType_MyRas1)
out: 'U8'
myRas1[3,3] = 260
math.isnan(myRas1[3,3])
out: True