4 Les collections d’images dans GEE

Collections d’images

L’une des caractéristiques les plus puissantes de GEE est sa capacité de calcul en nuage ; vous pouvez traiter de nombreuses données simultanément.

Jusqu’à présent, nous avons eu une introduction rapide au travail avec des images individuelles dans GEE. Avec l’aide des ressources de Google, nous pouvons travailler avec une collection d’images. Nous aurons ainsi l’avantage d’accéder à toutes les données disponibles gratuitement dans GEE.

Par exemple, il existe la collection d’images Landsat-9. Dans la boîte de recherche, tapez « Landsat 9« , et vous avez alors deux options pour importer la collection d’images dans l’éditeur de code :

  1. Cliquez sur le « import » à côté de « USGS Landsat 9 Level 2, Collection 2, Tier 2 » (Figure 42);
    Figure 42 : Recherche de la collection Landsat 9 dans la boîte de recherche
  2. Vous pouvez voir une brève description de la collection d’images en cliquant sur « USGS Landsat 9 Level 2, Collection 2, Tier 2« . Ici, vous pouvez importer la collection d’images en copiant le « Collection Snippet » et en le collant dans l’éditeur de code ou en cliquant sur le bouton IMPORT dans le coin inférieur droit (Figure 43).
    Figure 43 : Importation grâce à l’extrait de code (« Snippet ») disponible dans la description

Donc après avoir chargé la collection d’images de « Landsat-9 Level 2, Collection 2, Tier 2« , votre éditeur de code ressemblerait à ceci (Figure 44) :

Figure 44 : Éditeur de code une fois la collection « Landsat-9 Level-2, Collection 2, Tier 2 » chargée

Comme vous le remarquez, la commande clé pour utiliser les collections d’images est ee.ImageCollection. Comme il est possible de le voir dans l’image précédente, il y a une erreur dans la Console causée par print(landsat9);, ce qui nous indique que GEE n’est pas en mesure de traiter plus de 5000 images simultanément. Un autre point critique est que, compte tenu de la collection massive d’images Landsat-9, il n’est pas possible de les visualiser en un seul affichage. Par conséquent, à la visualisation nous ne voyons seulement que les scènes les plus récentes prises par le satellite. Pour éviter l’erreur susmentionnée et être en mesure de traiter une grande quantité de données, nous devons réduire le nombre d’images existantes dans la collection en appliquant certains filtres.

Créer une mosaïque à partir d’une collection d’images

La création d’une mosaïque d’images est réalisée en utilisant une collection, puis en y appliquant une série de filtres spatiaux ou temporels afin de contraindre les images utilisées à répondre aux attentes de l’analyste.

L’exemple ci-dessous montre un mosaïque d’images Landsat-8 sur la région de Montréal entre les 1er et 18 mai 2022 (Figure 45). Comme vous pouvez l’observer, les images Landsat sont sujettes à la couverture nuageuse et la création d’une mosaïque ave GEE n’est pas garante d’une image 100% dégagée. C’est pourquoi nous verrons dans les prochaines sections, les méthodes à privilégier pour appliquer certains filtres spécifiques afin d’optimiser les images utilisées pour la mosaïque.

Figure 45 : Mosaïque Landsat-8 entre le 1er et le18 mai 2022 sur la région de Montréal.

Filtrer une collection d’images

Si, dans le panneau de gauche de l’onglet « Docs », vous ouvrez le filtre ee.Filter, vous verrez de nombreux types de filtres différents que vous pouvez appliquer à vos données pour obtenir l’image que vous souhaitez (Figure 46).

 

Figure 46 : Exemple de différents filtres disponibles dans GEE

Les filtres temporels

  1. ee.Filter.date(start, end)
    Filtre une collection par plage de dates.
    start(Date |Nombre| Chaîne) : La date de début (inclusive).
    end(Date |Numéro| Chaîne, optionnel) : La date de fin (exclusive).

    // Le filtre renverra les images acquises entre le 1er novembre 2020 et le 1er novembre 2022.

    var landsat8 = ee.ImageCollection(‘LANDSAT/LC08/C02/T1_L2’)

    .filter(ee.Filter.date(‘2020-11-01’, ‘2022-11-01’));

  2. ee.Filter.calendarRange(start, end, champ)
    Renvoie un filtre qui passe si l’horodatage de l’objet se situe dans la plage donnée d’un champ du calendrier.
    start(Integer) : La date de début de la période souhaitée (inclus).
    end(Integer, default : null) : La fin de la période souhaitée (inclus).
    field(String, default : « day_of_year ») : L’unité de mesure de la période. Les options sont : année, mois, heure, minute, jour de l’année, jour du mois et jour de la semaine.

    // Le premier filtre renvoie les images entre 2020 et 2022 et le second filtre s’assure que nous avons au moins une image de chaque mois.

    var landsat8 = ee.ImageCollection(‘LANDSAT/LC08/C02/T1_L2’)

    .filter(ee.Filter.calendarRange(2020, 2022,‘year’))

    .filter(ee.Filter.calendarRange(1, 12,‘month’));

  3. ee.Filter.dayOfYear(start, end)
    Renvoie un filtre qui passe si l’horodatage de l’objet se situe dans la plage de jours de l’année donnée.
    start(Integer) : Le début de la plage de jours souhaitée (inclusivement).
    end(Integer) : La fin de la plage de jours souhaitée (inclusivement).

    // Le filtre retournera les images entre 7 jours avant le 21 août (DOY 233) et 7 jours après.

    var landsat8 = ee.ImageCollection(‘LANDSAT/LC08/C02/T1_L2’)

    .filter(ee.Filter.dayOfYear(233 – 7, 233 + 7));

  4. ee.Filter.dateRangeContains(leftField, rightValue, rightField, leftValue)
    Crée un filtre unaire ou binaire qui passe si l’opérande de gauche, une plage de dates, contient l’opérande de droite, une date.
    leftField(String, default : null) : Un sélecteur pour l’opérande gauche. Il ne doit pas être spécifié si leftValue est spécifié.
    rightValue(Object, default : null) : La valeur de l’opérandede droite. Elle ne doit pas être spécifiée si rightField est spécifié.
    rightField(String, default : null) : Un sélecteur pour l’opérande de droite. Il ne doit pas être spécifié si rightValue est spécifié.
    leftValue(Object, default : null) : La valeur de l’opérande gauche. Elle ne doit pas être spécifiée si leftField est spécifié.

    // Le filtre retournera les images dont la date d’acquisition est égale à 2021-08-03.

    var landsat8 = ee.ImageCollection(‘LANDSAT/LC08/C02/T1_L2’)

    .filter(ee.Filter.dateRangeContains(null, null, ‘DATE_ACQUIRED’, ee.DateRange(‘2021-08-03’)));

    // Le filtre renvoie les images dont la date d’acquisition est comprise entre le 2018-01-01 et le 2018-05-01.

    var landsat8 = ee.ImageCollection(‘LANDSAT/LC08/C02/T1_L2’)

    .filter(ee.Filter.dateRangeContains(null, null, ‘DATE_ACQUIRED’, ee.DateRange(‘2018-01-01’, ‘2018-05-01’)));

Astuce

Si vous souhaitez reculer ou avancer dans le temps en fonction d’une date spécifique, vous devez utiliser ee.Date.advance pour cela. Nous vous montrons comment cela fonctionne à travers un exemple (Figure 47) :

Figure 47 : Utilisation de la fonction ee.DateAdvance

Les filtres spatiaux

Avant d’expliquer le fonctionnement des filtres spatiaux, nous devons savoir comment créer une géométrie et définir la région d’intérêt (ROI).

La création d’une région d’intérêt (ROI)

Avec les outils de géométrie

Afin d’importer des géométries dans votre script, vous pouvez les dessiner à l’écran. Pour créer des géométries, utilisez les outils de dessin de géométrie dans le coin supérieur gauche de l’affichage de la carte. Pour dessiner des points, utilisez l’icône de point de repère , pour dessiner des lignes, utilisez l’icône de ligne , pour dessiner des polygones, utilisez l’icône de polygone , pour dessiner des rectangles, utilisez l’icône de rectangle . Pour configurer les géométries importées dans votre script, cliquez sur l’icône , dans la section « Imports » de l’éditeur de code (Figure 48).

 

Figure 48 : Différentes géométries pour les ROI déterminées à partir des outils disponibles
Les entités géométriques et les collections d’entités géométriques

Les entités géométriques dotées d’attributs sont des objets Feature. Dans Earth Engine, une entité est déclinée sous la forme d’un fichier GeoJSON. GeoJSON est un format permettant d’encoder une variété de structures de données géographiques. Les collections d’entités sont stockées dans les objets FeatureCollection.

// Création d’une Feature Collection à partir d’une liste d’entités

var features = [

ee.Feature(ee.Geometry.Rectangle(30.01, 59.80, 30.59, 60.15), {name: ‘Voronoi’}),

ee.Feature(ee.Geometry.Point(-73.96, 40.781), {name: ‘Thiessen’}),

ee.Feature(ee.Geometry.Point(6.4806, 50.8012), {name: ‘Dirichlet’})

];

var fromList = ee.FeatureCollection(features);

print(fromList);

Le résultat de l’exécution du code ci-dessus génère le résultat suivant (Figure 49):

Figure 49 : Résultat de l’impression en console d’un FeatureDataset créé à partir d’une liste de Features

Earth Engine héberge une variété de jeux de données tabulaires pouvant être utilisés comme FeatureCollection. Pour charger un ensemble de données tabulaires, fournissez l’ID de la table au constructeur de FeatureCollection.

Par exemple, pour charger les données de la Frontière internationale à grande échelle (LSIB) (Figure 50) :

Figure 50 : Jeu de données tabulaires de données de frontières internationales utilisée en FeatureCollection

Une autre méthode utile de FeatureCollection est que vous pouvez créer une collection de points aléatoires dans une région spécifiée (Figure 51). Par exemple, cela pourrait nous être utile lorsque nous voulons rassembler des données d’entrainement pour former un algorithme d’apprentissage automatique; cela pourrait réduire considérablement le temps de préparation des données d’entraînement (nous aborderons ces sujets dans les sections suivantes).

Figure 51 : Création d’une collection de points aléatoires au sein d’un polygone
Lire un fichier externe comme entité géométrique ou collection d’entités géométriques

Pour télécharger et gérer des ensembles de données géospatiales, utilisez le gestionnaire de ressources dans l’éditeur de code. Le gestionnaire d’actifs se trouve dans l’onglet « Assets », sur le côté gauche de l’éditeur de code (Figure 52).

Figure 52 : Gestionnaire des « Assets » dans l’interface de code de Google Earth Engine

Astuce

Pour voir quelle part de votre quota d’actifs est utilisé, cliquez sur l’icône à côté de « users/username« .

Pour télécharger un fichier « Shapefile » à partir de l’éditeur de code, cliquez sur le bouton , puis sélectionnez « Shape files » dans la section « Table Upload ». Une boîte de dialogue de téléchargement similaire à la figure ci-dessous s’affichera (Figure 53).

Figure 53 : Fenêtre de téléchargement des données externes

Cliquez sur le bouton « SELECT » et naviguez vers un fichier Shapefile ou une archive Zip contenant un fichier Shapefile sur votre système de fichiers local. Donnez au tableau un ID « asset » approprié (qui n’existe pas déjà) dans votre dossier utilisateur. Cliquez sur « UPLOAD » pour lancer le téléchargement.

Après avoir lancé le téléchargement d’une table, une tâche d’ingestion de ressources est ajoutée au Gestionnaire de tâches, qui se trouve sous l’onglet « Tâches » à droite de l’éditeur de code. Une fois l’ingestion terminée, la cellule de la tâche devient bleue et le bien apparaît dans votre dossier utilisateur sous l’onglet « Assets » avec une icône .

Vous pouvez importer une ressource dans votre script en passant la souris sur le nom de la ressource dans le gestionnaire de ressources et en cliquant sur l’icône . Si vous cliquez sur le nom de la ressource, une boîte de dialogue contenant la description de la ressource apparaît. Vous pouvez également copier l’ID de la ressource dans un constructeur tel que Image, ImageCollection ou FeatureCollection.

var image = ee.Image(‘users/username/your_asset);

Créer une géométrie GeoJSON dans un script GEE

Pour commencer, vous devez copier-coller la chaîne GeoJSON dans son intégralité. Le reste du script analyse les caractéristiques, puis les renvoie lorsque la fonction est appelée depuis le script principal.

Pour la première partie, le script qui contient et analyse le fichier GeoJSON est présenté ci-dessous. Vous devez juste effacer le « // Coller la géométrie GeoJSON ici // » et coller votre fichier GeoJSON à la place.

var geojson =

// Coller la géométrie GeoJSON ici //

function fromGeoJSON(geojson) {var features = ee.FeatureCollection(geojson.features)

Object.keys(geojson).map(function(p) {if(p == ‘type’ || p == ‘features’) {return}

features = features.set(p, geojson[p])})

return features

}

var features = fromGeoJSON(geojson)

Map.addLayer(features)

Dans un exemple réel du Québec, nous avons créé une géométrie à partir du fichier GeoJSON contenant les polygones délimitant les bois de l’agglomération de Montréal (Figure 54). Vous pouvez accéder à ce fichier à partir d’ici.

Figure 54 : Fichier GeoJSON importé dans GEE représentant les secteurs boisés sur l’Île Bizard

La prise en compte de la topologie

Après avoir appris les moyens de créer les régions d’intérêt (ROI), il est temps d’aller de l’avant et d’apprendre à filtrer les collections d’images en les utilisant.

  1. ee.Filter.bounds(geometry, errorMargin)
    Crée un filtre qui passe si la géométrie de l’objet intersecte la géométrie donnée.
    Géométrie (ComputedObject|FeatureCollection|Geometry) : La géométrie, l’élément ou la collection à intersecter.
    errorMargin (ComputedObject|Number, facultatif) : Une marge d’erreur facultative. S’il s’agit d’un nombre, il est interprété comme des mètres.

    // Ce filtre va retourner les images qui seront en intersection avec la géométrie.

    var landsat8 = ee.ImageCollection(‘LANDSAT/LC08/C02/T1_L2’)

    .filter(ee.Filter. bounds(geometry));

    Attention

    Ce filtre renverra toute image qui a une intersection avec la géométrie que vous avez définie. Par conséquent, il ne couvre pas nécessairement tout le ROI.

    Ainsi, si nous voulons que la collection d’images renvoyée comprenne des images qui couvrent la totalité du ROI, nous devons utiliser le filtre suivant :

  2. ee.Filter.contains(leftField, rightValue, rightField, leftValue, maxError)
    Crée un filtre unaire ou binaire qui passe si la géométrie de gauche contient la géométrie de droite (les géométries vides ne sont contenues dans rien).
    leftField (Chaîne, par défaut : null) : Un sélecteur pour l’opérande gauche. Ne doit pas être spécifié si leftValue est spécifié.
    rightValue (Object, default : null) : La valeur de l’opérande de droite. Ne doit pas être spécifié si rightField est spécifié.
    rightField (String, default : null) : Un sélecteur pour l’opérande de droite. Ne doit pas être spécifié si rightValue est spécifié.
    leftValue (Object, default : null) : La valeur de l’opérande gauche. Ne doit pas être spécifié si leftField est spécifié.
    maxError (ErrorMargin, facultatif) : L’erreur maximale de reprojection autorisée pendant l’application du filtre.

    // Ce filtre va retourner les images qui couvrent entièrement la géométrie.

    var landsat8 = ee.ImageCollection(‘LANDSAT/LC08/C02/T1_L2’)

    .filter(ee.Filter. contains(‘.geo’, geometry));

    Attention

    Le filtre retournera les images qui couvrent toute la géométrie. La propriété ‘.geo‘ doit être incluse pour comparer les géométries des objets (Figure 55).
    Figure 55 : Filtre topologique « Contains » sélectionnant uniquement les images couvrant entièrement la ROI

    Et si nous souhaitons extraire une partie spécifique de l’image, telle que définie par une entité géométrique ? La fonction clip, présentée ci-dessous peut nous aider.

  3. .clip(geometry)
    Découpe une image sur une géométrie ou un objet.
    geometry (Feature|Geometry|Object) : La géométrie ou l’entité à découper.

    Astuce

    Cette méthode fonctionne sur une seule image, donc si vous voulez l’essayer avec une collection d’images, tout ce que vous avez à faire est de créer une fonction de découpage et de la faire correspondre à la collection d’images ; ainsi, elle passera par toutes les images et les découpera une par une (Figure 56).
    Figure 56 : Découpage d’une collection d’image à partir d’une entité géométrique de l’Île de Montréal

    Pour couper une collection d’images par une collection d’éléments au lieu d’un seul élément géométrique, il suffit de remplacer la méthode .clip par la méthode .clipToCollection comme dans la figure suivante (Figure 57).

    Figure 57 : Découpage d’une collection d’images en utilisant une collection d’entités géométriques

Filtrer les nuages

Lorsque nous utilisons l’imagerie optique, l’un des problèmes les plus apparents est celui des nuages. Dans cette partie, nous allons donc apprendre à filtrer les images avec des nuages en utilisant les propriétés de l’image (Figures 58 et 59).

Figure 58 : Propriété « CLOUD_PIXEL_PERCENTAGE » de la collection Sentinel-2 MSI, Level 2A

 

Figure 59 : Propriété « CLOUD_COVER » de la collection Landsat-8, Level 2, Collection 2, Tier 1

Comment parvenir à filtrer les images en utilisant ces propriétés précalculées par les fournisseurs d’images ? Trois avenues s’offrent à nous :

  1. ee.Filter.lt(nom, opérateur, valeur)
    Filtre sur les métadonnées afin d’identifier les images pour lesquelles la valeur est plus basse que la valeur seuil donnée.
    name (Chaîne) : Le nom de la propriété sur laquelle le filtre doit porter.
    value (Object) : La valeur seuil à comparer.
    OU
    ee.Filter.LessThan(leftField, rightValue, rightField, leftValue)
    Crée un filtre unaire ou binaire qui passe si l’opérande gauche est inférieur à l’opérande droit.
    leftField(String, default : null) : Un sélecteur pour l’opérande gauche. Ne doit pas être spécifié si leftValue est spécifié.
    rightValue(Object, default : null) : La valeur de l’opérande de droite. Ne doit pas être spécifié si rightField est spécifié.
    rightField(String, default : null) : Un sélecteur pour l’opérande de droite. Ne doit pas être spécifié si rightValue est spécifié.
    leftValue(Object, default : null) : La valeur de l’opérande gauche. Ne doit pas être spécifié si leftField est spécifié.

    // Pour les images Landsat-8

    var landsat8 = ee.ImageCollection(‘LANDSAT/LC08/C02/T1_L2’).filter(ee.Filter. lt(‘CLOUD_COVER’, 10));

    // ou

    var landsat8 = ee.ImageCollection(‘LANDSAT/LC08/C02/T1_L2’).filter(ee.Filter.lessThan(‘CLOUD_COVER’, 10));

    // Pour les images Sentinel-2

    var landsat8 = ee.ImageCollection(‘COPERNICUS/S2_SR’).filter(ee.Filter. lt(‘CLOUDY_PIXEL_PERCENTAGE’, 10));

    // ou

    var landsat8 = ee.ImageCollection(‘COPERNICUS/S2_SR’).filter(ee.Filter.lessThan(‘CLOUDY_PIXEL_PERCENTAGE’, 10));

    Astuce

    Vous pouvez utiliser ces types de filtres (greaterThan, greaterThanOrEquals, gt, gte, lessThanOrEquals, lte, neq, notEquals, and, or, eq, equals) pour filtrer tout type de métadonnées telles que l’orbite et la rangée des images (‘WRS_PATH’, ‘WRS_ROW’).

    Astuce

    Vous pouvez utiliser ‘CLOUD_COVER_LAND’ pour filtrer les nuages dans les images Landsat. Cette statistique porte uniquement sur la proportion de nuages détectée aux endroits où il n’y a pas d’eau.
  2. .sort(propriété, ascending)
    Trie une collection en fonction de la propriété spécifiée.
    propriété (Chaîne) : La propriété à trier.
    ascending (booléen, facultatif) : Indique si le tri doit être effectué par ordre croissant ou décroissant. La valeur par défaut est true (ascendant).

    // The filter will return images which have the least cloud coverage.

    var landsat8 = ee.ImageCollection(‘LANDSAT/LC08/C02/T1_L2’). sort(‘CLOUD_COVER’)).first();

    Et si l’on souhaite obtenir les dix images avec le moins de couvert nuageux ?
    Voici comment s’y prendre :

    var landsat8 = ee.ImageCollection(‘LANDSAT/LC08/C02/T1_L2’).sort(‘CLOUD_COVER’, false).limit(10);

    // Pour les images Sentinel-2 il suffit de remplacer ‘CLOUD_COVER’ avec ‘CLOUDY_PIXEL_PERCENTAGE’.

  3. .median()
    Réduit une collection d’images en calculant la médiane de toutes les valeurs à chaque pixel à travers la pile de toutes les bandes correspondantes. Cela a l’avantage de supprimer les nuages (qui ont une valeur élevée) et les ombres (qui ont une valeur faible). Les bandes sont appariées par nom.

    // Le filtre renvoie une image dont chaque pixel est la valeur médiane pour chaque bande.

    var landsat8 = ee.ImageCollection(‘LANDSAT/LC08/C02/T1_L2’).median();

    Astuce

    La médiane renvoie une seule image, et non une collection d’images. Elle est principalement utilisée à des fins de visualisation et pour créer une mosaïque sans nuage de collections d’images.
    Figure 60 : Impact de la médiane sur une collection d’images

    Astuce

    Plus la plage de temps utilisée dans le filtrage temporel est longue, moins l’image médiane sera nuageuse.

    Attention

    Il existe de nombreux autres réducteurs que vous pouvez utiliser sur votre collection d’images, tels que sum, max, min, mean, etc. Par exemple, sum réduit une collection d’images en calculant la somme de toutes les valeurs à chaque pixel à travers la pile de toutes les bandes correspondantes.

Masquer les nuages

Dans cette section, nous divisons le masquage des nuages en trois parties pour une meilleure compréhension et aussi pour être spécifique aux données. Il faut différencier le fait de filtrer la collection versus le fait de détecter et masquer les nuages dans une image.

Attention

Si vous utilisez un pourcentage de nuages très faible pour filtrer les nuages (par exemple 10 %), vous perdrez un grand nombre d’images simplement parce qu’elles avaient peut-être une couverture nuageuse de 20 %. En outre, le plus important est que vous ne réussirez peut-être pas à trouver une image sans nuage (moins de 10 %) pendant toute une année dans certains endroits. Tout cela nous amène à utiliser des techniques de masquage des nuages pour notre collection d’images.

Sur l’imagerie Landsat

ee.Algorithms.Landsat.simpleCloudScore(image)

Calcule un score simple de probabilité de nuage dans la plage [0, 100] en utilisant une combinaison de luminosité, de température et de NDSI. Selon cette méthode, si un pixel a un score de nuages de 100, cela signifie que le pixel est couvert par des nuages avec une probabilité de 100 %. L’image utilisée doit être une image TOA (Top of the atmosphere, soit exoatmosphérique) et non une image radiométriquement corrigée.

Dans l’exemple ci-dessous, nous spécifions un pourcentage maximum pour les pixels nuageux de 10%. Ensuite, nous écrivons une fonction qui calcule le score de nuage pour chaque pixel de l’image et, en fonction du seuil que nous avons défini, elle renvoie uniquement les pixels dont le pourcentage de nuage est inférieur au seuil établi. La dernière étape de la fonction consiste à mettre à jour l’image originale et à masquer les pixels reconnus comme nuageux en utilisant updateMask et en lui passant le masque déjà créé. Ensuite, nous utilisons map pour exécuter la fonction que nous avons définie sur une collection d’images (Figure 61). Nous conservons toujours la ROI sur Montréal des scripts précédents.

var max_pixel_percentage = 10;

var cloudless = function (image){

var cloud_score = ee.Algorithms.Landsat.simpleCloudScore(image);

var mask = cloud_score.select([‘cloud’]).lt(max_pixel_percentage);

var masked = image.updateMask(mask);

return masked;

};

var cloudy_l8 = ee.ImageCollection(‘LANDSAT/LC08/C02/T1_TOA’).filter(ee.Filter.bounds(montreal)).filter(ee.Filter.date(‘2019-01-01’, ‘2021-01-01’));

var cloudmasked_l8 = cloudy_l8.map(cloudless);

var vis = {‘bands’: [‘B4’,‘B3’, ‘B2’], ‘min’:0.04, ‘max’:0.17};

Map.addLayer(cloudy_l8.median(), vis, ‘Landsat-8 Image Collection Median (Cloudy)’);

Map.addLayer(cloudmasked_l8.median(), vis, ‘Landsat-8 Image Collection Median (Cloud Masked)’);

// Dans les lignes ci-dessous nous compilons une liste des cinq premières images de la collection et utilisons la cinquième pour la visualisation. Notez qu’il faut préalablement utiliser ee.Image() afin de la convertir en image GEE pour l’affichage.

Map.addLayer(ee.Image(cloudy_l8.toList(5).get(4)), vis, ‘Landsat-8 Image (Cloudy)’);

Map.addLayer(ee.Image(cloudmasked_l8.toList(5).get(4)), vis, ‘Landsat-8 Image (Cloud Masked)’);

Figure 61 : Calcul du masque de nuages sur les images Landsat

Sur l’imagerie Sentinel-2

Afin de masquer les nuages dans les images Sentinel-2, nous utilisons un autre jeu de données disponible gratuitement dans GEE appelé « Sentinel-2 : Cloud Probability« .

L’exemple ci-dessous présente l’approche sur la région de Québec (Figure 62).

var s2_cloudProbe = ee.ImageCollection(‘COPERNICUS/S2_CLOUD_PROBABILITY’).filter(ee.Filter.bounds(quebec)).filter(ee.Filter.date(‘2019-05-01’, ‘2021-01-01’));

var s2_toa = ee.ImageCollection(‘COPERNICUS/S2’).filter(ee.Filter.bounds(quebec)).filter(ee.Filter.date(‘2019-05-01’, ‘2021-01-01’));

var max_pixel_percentage = 20;

// Les deux collections d’images proviennent de l’imagerie Sentinel-2, ce qui signifie que nous pouvons trouver les mêmes identifiants d’images pour une mesure spécifique du temps. La fonction ‘maskClouds’ prendra chaque image de la collection ‘Sentinel-2 : Cloud Probability’ et filtrera les images de la collection d’images TOA (Top of Atmosphere) sur la base de leur propriété ‘system:index’ qui indique les identifiants des images.

var maskClouds = function (image){

var mask = s2_cloudProbe.filter(ee.Filter.equals({leftField: ‘system:index’, rightValue: image.get(‘system:index’)})).first();

return image.updateMask(mask.gt(max_pixel_percentage).not());

}

var s2CloudMasked = s2_toa.map(maskClouds);

Figure 62 : Calcul du masque de nuages sur les images [pb_glossary id="310"]Sentinel-2[/pb_glossary]

Méthode générale

Pour masquer les nuages avec une approche plus « générale », vous pouvez utiliser le masque binaire créé sur la base de la « bande d’évaluation de la qualité » (QA) dans le jeu de données. Cette approche n’est pas limité à l’imagerie Landsat ou Sentinel-2. L’autre avantage d’apprendre cette méthode générale est que vous serez également en mesure de masquer l’ombre des nuages, la neige, l’eau, etc.

Tout d’abord, nous devons savoir comment trouver cette bande dans les ensembles de données. La bande d’évaluation de la qualité (QA) porte des noms différents selon le jeu de données. Quelques exemples sont présentés dans les figures suivantes (Figure 63, 64 et 65).

Figure 63 : Masque QA pour les données Sentinel-2

 

Figure 64 : Masque QA pour les données MODIS

 

Figure 65 : Masque QA pour les données Landsat-5

Les exemples suivants présentent l’approche à prendre pour masquer les nuages en utilisant la bande QA, d’abord par un exemple facile à comprendre avec l’imagerie Landsat-5, puis nous passons à un niveau supérieur en utilisant l’imagerie MODIS.

  1. Exemple avec Landsat-5 (Figure 66)

    var maskout_func = function(image){

    // Tout d’abord, consultez les gammes de bits dans les catalogues. Comme vous pouvez le voir sur les figures précédentes, les nuages et les ombres des nuage sont respectivement dans les bits 3 et 4. La fonction ‘bitwiseAnd’ extrait les bits spécifiques du masque de bits (QA).

    var qa = image.select(‘QA_PIXEL’);

    var cloud = qa.bitwiseAnd(1<<3);

    var cloud_shadow = qa.bitwiseAnd(1<<4);

    // Le « 0 » dans un masque représente les pixels que nous voulons masquer. Ainsi, lorsque nous utilisons ‘neq’ (c’est-à-dire non égal) pour les valeurs 0, nous obtenons les pixels ayant la valeur 1. La fonction ‘or’ fonctionne comme un opérateur d’union. Cela signifie que si l’une des conditions est vraie, elle sera retournée comme sortie.

    var mask = (cloud.neq(0)).or(cloud_shadow.neq(0));

    return image.updateMask(mask.eq(0));};

    var unmasked_l5 = ee.ImageCollection(‘LANDSAT/LT05/C02/T1_L2’).filter(ee.Filter.bounds(montreal)).filter(ee.Filter.date(‘2009-05-01’, ‘2011-01-01’));

    var masked_l5 = unmasked_l5.map(maskout_func);

    Figure 66 : Résultat du processus de masquage des nuages à partir des données de la bande QA
  2. Exemple avec MODIS
    Cet exemple est un peu plus compliqué que le précédent bien qu’il ait une plus grande portée de généralisation et puisse être appliqué à n’importe quel ensemble de données ayant un masque binaire QA. Nous avons étendu nos méthodes de masquage des nuages à ce niveau car les masques de bits ne sont pas toujours identiques. Dans la figure suivante, on voit que les caractéristiques du masque QA de MODIS présente une gamme de bits pour le masquage des nuages et de leur ombre contrairement à Landsat-5 où pour les nuages l’on faisait directement appel aux bits 3 et 4 (Figures 67 et 68).
    Figure 67 : Comparaison des bandes QA de Landsat-5 et MODIS

     // Nous utilisons une fonction utilitaire pour extraire des bits spécifiques du masque QA. Ce que nous avons ici est une plage de bits et ‘fromBit’ est le premier nombre de la plage et ‘toBit’ est le dernier nombre de la plage

    function bitwiseExtract(value, fromBit, toBit) {

    if (toBit === undefined) toBit = fromBit

    var maskSize = ee.Number(1).add(toBit).subtract(fromBit)

    var mask = ee.Number(1).leftShift(maskSize).subtract(1)

    return value.rightShift(fromBit).bitwiseAnd(mask)}

     

    function maskQuality(image) {

    // Selectionner la bande QA

    var QA = image.select(StateQA);

    // Ici, on peut spécifier le bit de départ et celui d’arrivée.

    var cloud = bitwiseExtract(QA ,0 , 1);

    var cloud_shadow = bitwiseExtract(QA ,2);

    // Retourner une image masquée pour les ombres de nuages et les nuages

    return image.updateMask(cloud.eq(0)).updateMask(cloud_shadow.eq(0));

    }

    var modis = ee.ImageCollection(‘MODIS/061/MOD09A1’).filterDate(2009-05-01′, ‘2011-01-01′).filterBounds(quebec);

    var modis_masked = modis.map(maskQuality)

    Figure 68 : Masque de nuages et d’ombres de nuages tiré de la bande QA de MODIS appliqué à la région de Québec

    Astuce

    Comme mentionné, vous pouvez appliquer cette méthode sur n’importe quel ensemble de données contenant la bande QA. Toutefois, dans l’imagerie Sentinel-2, si vous utilisez le masque binaire QA, le masque des nuages aura une résolution spatiale de 60 m, tandis que l’utilisation du jeu de données « Sentinel-2 Cloud Probability » vous donnera un masque des nuages de 10 m.

    Pour une meilleure compréhension et plus d’explications sur les bitmasks et la façon de les utiliser pour masquer une image, vous pouvez consulter cette page (en anglais).

Autres transformations

  1. De la réflectance exoatmosphérique (TOA) de Sentinel-2 à la réflectance de surface (SR)
    Comme vous le remarquez par la mise en évidence dans la figure ci-dessous (Figure 69), la réflectance de surface (SR) de l’imagerie Sentinel-2 (c’est-à-dire le niveau 2A) n’est pas produite pour le globe entier.
    Figure 69 : Informations de collection indiquant que la couverture niveau L2 de [pb_glossary id="310"]Sentinel-2[/pb_glossary] n’est pas globale.

    Ainsi, nous utiliserons ici une technique développée par Yin et al. (2022) dans GEE pour convertir le TOA de Sentinel-2 en SR au cas où vous auriez besoin de ces données qui ne sont pas disponibles dans le catalogue de données de GEE (Figure 70).

    // Notez l’importation du code de l’utilisateur « marcyinfeng »

    var sr_func = require(‘users/marcyinfeng/utils:SIAC’);

    var toa2sr = function(image){return sr_func.get_sur(image).multiply(10000).toInt();};

    var s2_toa = ee.ImageCollection(‘COPERNICUS/S2’).filter(ee.Filter.bounds(montreal)).filter(ee.Filter.date(‘2019-05-01’, ‘2021-01-01’));

    var s2_sr = s2_toa.map(toa2sr);

    Figure 70 : Résultat de l’application de l’algorithme de correction atmophérique de Yin et al. (2022) sur les données [pb_glossary id="310"]Sentinel-2[/pb_glossary] de la Ville de Québec
  2. De l’imagerie brute Landsat vers le composite TOA
    L’exemple présenté ci-dessous permet de calculer un composite Landsat TOA à partir d’une collection de scènes Landsat brutes. Il applique un étalonnage TOA standard, puis attribue un score de nuages à chaque pixel à l’aide de l’algorithme SimpleLandsatCloudScore. Il sélectionne la gamme la plus basse possible de scores de nuages en chaque point, puis calcule les valeurs de percentile par bande à partir des pixels acceptés pour reconstituer un composite sans nuages (Figure 71).

    // L’intrant à la fonction « simpleComposite » est la donnée Landsat brute

    var l8_filtered = ee.ImageCollection(‘LANDSAT/LC08/C02/T1’).filter(ee.Filter.bounds(montreal)).filter(ee.Filter.date(‘2019-05-01’, ‘2021-01-01’));

    var viz1 = {bands:[‘B4’,‘B3’,‘B2’], min:4637, max:15346};

    Map.addLayer(l8_filtered, viz1, ‘Landsat-8 Image Collection’);

    // .

    var composite = ee.Algorithms.Landsat.simpleComposite({

    collection: l8_filtered,

    asFloat: true

    });

    // Display a composite with a band combination chosen from: https://landsat.usgs.gov/how-do-landsat-8-band-combinations-differ-landsat-7-or-landsat-5 satellite-data

    var viz2 = {bands: [‘B6’, ‘B5’, ‘B4’], max: [0.3, 0.4, 0.3]};

    Map.addLayer(composite, viz2, ‘ee.Algorithms.Landsat.simpleComposite’);

    Figure 71 : Composite TOA construit à partir des données Landsat et de la fonction .Landsat.simpleComposite

Les « Reducers », ou réductions statistiques

Avec l’aide du calcul parallèle dans GEE, nous pouvons calculer des statistiques sur de grandes quantités de données en utilisant les reducer.

Les Reducers sur les collections d’images

Un reducer peut permettre, par exemple, de calculer la médiane d’une série chronologique d’images représentée par une collection d’images. Pour réduire une ImageCollection, utilisez imageCollection.reduce. Cela réduit la collection d’images à une image individuelle, comme illustré dans la figure qui suit (Figure 72).

 

Figure 72 : Schématisation du fonctionnement du « reducer » sur une collection d’images

Plus précisément, la sortie est calculée pixel par pixel, de sorte que chaque pixel de la sortie est composé de la valeur médiane de toutes les images collectées à cet endroit, comme dans la figure qui suit. Remarquez le suffixe s’étant ajouté au nom des bandes de l’image résultante (Figure 73).

Figure 73 : Application de la fonction reducer sur une collection d’images Sentinel-2 avec pour paramètre la médiane

Les reducers sur une image

L’application du reducer sur des images n’est pas différente des collections d’images, sauf que les bandes de l’image sont en entrée du reducer plutôt que les images de la collection. La sortie est également une image dont le nombre de bandes est égal au nombre de sorties du reducer.

Par exemple, pour calculer le maximum pour les bandes RVB sélectionnées d’une imagerie Landsat-8, on peut utiliser le reducer. Comme on peut le remarquer dans la figure suivante (Figure 74), contrairement au cas de la collection d’images, le reducer ne renvoie qu’une bande pour les valeurs maximales des pixels parmi les trois bandes RVB.

Figure 74 : Application de « reduce » sur une image Landsat-8 afin d’en tirer la statistique sur la valeur maximale de pixel RVB

Les reducers sur une région, l’équivalent de statistiques zonales

Pour obtenir des statistiques sur les valeurs des pixels dans une région d’une image, utilisez la méthode reduceRegion.

Voici une représentation schématique de cette méthode (Figure 75).

Figure 75 : Vue schématique du fonctionnement de la fonction « reduceRegion« 

Il est possible de traiter l’entièreté de l’image comme étant une région. Dans ce cas, l’algorithme nous fournira la valeur calculée pour toute la bande, par exemple la moyenne de chaque bande, tel que présenté dans l’image ci-dessous (Figure 76).

Figure 76 : Application du reduceRegion sur l’entièreté d’une image

Cependant, l’utilité principale de la fonction reduceRegion est bien sur d’utiliser des géométries prédéfinies afin d’extraire des statistiques zonales propres à chacune des régions. Pour se faire, il faut ajouter un attribut « geometry » dans la fonction reduceRegion qui pointe vers la featureCollection d’intérêt (Figure 77).

Figure 77 : Utilisation du reduceRegion à partir d’une géométrie

Combiner les reducers

Si vous souhaitez effectuer plus d’un calcul statistique, vous devez utiliser plusieurs réducteurs imbriqués. L’exemple présenté dans la figure ci-dessous démontre comment combiner plusieurs réducteurs et les appliquer sur une image (Figure 78). Il existe une large gamme de reducer, pour en savoir plus, recherchez ee.Reducer dans « Docs ».

Figure 78 : Utilisation de reducer multiples sur une image

Production de graphiques

Dans cette section, l’objectif est de dessiner des graphiques à partir des données produites par nos codes. Chaque fonction accepte un type de données spécifique et comprend des méthodes permettant de réduire les données au format tabulaire selon différentes dispositions.

  1. ui.Chart.image.series
    Avec cette méthode, la date de l’image est tracée sur l’axe des x en fonction de la propriété system:time_start. Les bandes d’images définissent les séries. Les valeurs de l’axe des Y sont la réduction des images, par date, pour une seule région. La figure ci-dessous présente un résultat pour une série d’images avec les statistiques pour les bandes b1, b2 et b3 (Figure 78).

    Figure 78 : Graphique de l’évolution des bandes B1 B2 et B3 pour des images à 3 dates différentes

     

    Dans l’exemple qui suit, nous filtrons la collection d’images de réflectance de surface Landsat-8, puis nous calculons le NDVI pour chaque image de la collection. Nous dessinons ensuite un graphique basé sur la valeur moyenne des NDVI calculés dans une géométrie que nous avons définie précédemment. Pour le graphique, GEE prendra chaque NDVI et calculera la valeur moyenne des pixels NDVI à l’intérieur de la géométrie et retournera une seule valeur moyenne pour la région (Figure 79).

    var landsat8 = ee.ImageCollection(‘LANDSAT/LC08/C02/T1_L2’).filter(ee.Filter.date(‘2021-01-01’, ‘2022-01-01’)).filter(ee.Filter.bounds(geometry)).filter(ee.Filter.lessThan(‘CLOUD_COVER’, 20));

    var ndvi = landsat8.map(function(image){var index = image.normalizedDifference([‘SR_B5’, ‘SR_B4’]);

    return index.copyProperties(image, [‘system:time_start’]); // la propriété ‘system:time_start’est copié car elle est utilisée en axe X.

    });

    var chart = ui.Chart.image.series({imageCollection: ndvi, region: geometry, reducer: ee.Reducer.mean(),scale: 30, // résolution spatiale des images utilisées

    xProperty: ‘system:time_start’});

    print(chart);

    Figure 79 : Génération d’un graphique de l’évolution du NDVI dans une région au sud de la Ville de Québec
  2. ui.Chart.image.seriesByRegion
    Cette fonction fonctionne comme la précédente mais avec une différence. Dans cette fonction, les séries sont définies par des régions. En utilisant cette méthode, vous devez rassembler toutes vos géométries sous forme de FeatureCollection et leur attribuer une étiquette (figure 80).

    Figure 80 : Graphique présentant l’évolution d’un signal en fonction de régions r1, r2 et r3

    Dans l’exemple suivant, nous avons une collection d’entités composée de quelques géométries définies sur des zones forestières et des terres cultivées dans le sud de la ville de Québec. Nous voulons mesurer la valeur moyenne dans ces deux classes et voir la différence NDVI dans le temps en dessinant un graphique utilisant les valeurs moyennes (Figure 81).

    var landsat8 = ee.ImageCollection(‘LANDSAT/LC08/C02/T1_L2’).filter(ee.Filter.date(‘2021-01-01’, ‘2022-01-01’)).filter(ee.Filter.bounds(geometry))

    .filter(ee.Filter.lessThan(‘CLOUD_COVER’, 50));

    var ndvi = landsat8.map(function(image){var index = image.normalizedDifference([‘SR_B5’, ‘SR_B4’]);return index.rename(‘NDVI’).copyProperties(image, [‘system:time_start’]); // Nous renommons la bande résultante NDVI afin d’être en mesure d’avoir cette information sur le graphique.

    });

    var regions = ee.FeatureCollection([ee.Feature(ee.Geometry(geometry1), {label: ‘forest’}), ee.Feature(ee.Geometry(geometry2), {label: ‘cropfield’})]);

    var chart = ui.Chart.image.seriesByRegion({imageCollection: ndvi, regions: regions, reducer: ee.Reducer.mean(), band: ‘NDVI’,

    scale:30, xProperty:‘system:time_start’, seriesProperty: ‘label’});

    print(chart);

    Figure 81 : Extraction de l’évolution du NDVI par catégorie dans un secteur de l’ouest de la ville de Lévis

    Astuce

    Vous pouvez modifier le titre des axes et bien plus encore avec .setOptions. Il existe ici un guide très détaillé que vous pouvez utiliser pour personnaliser vos graphiques. L’exemple ci-dessous vous permet de voir comment il est possible d’ajuster les éléments d’affichage d’un graphique.

    var chart = ui.Chart.image.seriesByRegion({imageCollection: ndvi, regions: regions, reducer: ee.Reducer.mean(), band: ‘NDVI’,

    scale:30, xProperty:‘system:time_start’, seriesProperty: ‘label’})

    .setOptions({title: ‘NDVI Mean Values For Forest and Cropfield’, hAxis: {title: ‘Date’, titleTextStyle: {italic: false, bold: true}},

    vAxis: {title: ‘NDVI Mean Value’, titleTextStyle: {italic: false, bold: true}},});

    Le résultat obtenu est le suivant (Figure 82) :

    Figure 82 : Ajustement des paramètres d’affichage d’un graphe présentant l’évolution du NDVI pour des zones boisées et en culture.

Exporter une image

Vous pouvez exporter les images de Earth Engine au format GeoTIFF ou TFRecord.

Vers Google Drive

Pour exporter une image vers Google Drive, utilisez la fonction Export.image.toDrive.

var landsat8 = ee.ImageCollection(‘LANDSAT/LC08/C02/T1_L2’).filter(ee.Filter.date(‘2021-01-01’, ‘2022-01-01’)).filter(ee.Filter.contains(‘.geo’, montreal.geometry()))

.filter(ee.Filter.lessThan(‘CLOUD_COVER’, 10));

var ndvi = landsat8.map(function(image){var index = image.normalizedDifference([‘SR_B5’, ‘SR_B4’]); return index.rename(‘NDVI’);});

Export.image.toDrive({

image: ndvi, //nom de la variable

description: ‘NDVI_Landsat-8’, // le nom que vous souhaitez pour votre données sur le Drive

folder: ‘GEE/EXPORT’, // Dossier sur votre Drive ou exporter l’image

region: montreal, scale: 30,

crs: ‘EPSG: 4326’, // CRS de sortie (Système de coordonnées)

maxPixels: 1e13, // Paramètre impliquant un nombre maximal de pixel en sortie, principalement pour la gestion de mémoire (ajuster au besoin).

});

Après avoir cliqué sur le bouton « Run », vous verrez une nouvelle tâche apparaître dans l’onglet du gestionnaire de tâches sur le côté droit de votre éditeur de code (Figure 83).

Figure 83 : Gestionnaire de tâches avec une tâche d’exportation en attente

Une fenêtre de confirmation s’affiche si vous cliquez sur le bouton « Run » (Figure 84).

Figure 84 : Fenêtre « pop-up » qui s’affiche lorsque vous lancez une tâche d’exportation à partir du gestionnaire de tâches

Vous devez alors cliquer sur le bouton « Run » dans la fenêtre qui s’affiche, et le processus d’exportation commencera.

Astuce

Si les données sont trop volumineuses pour être exportées et que vous voulez les diviser en tuiles, il existe une option (fileDimensions) que vous pouvez utiliser. Disons que nous voulons diviser nos données en tuiles de 512×512 pixels. Voici comment y arriver :

Export.image.toDrive({

image: ndvi, //nom de la variable

description: ‘NDVI_Landsat-8’, //le nom que vous souhaitez pour votre données sur le Drive

folder: ‘GEE/EXPORT’, // Dossier sur votre Drive ou exporter l’image

region: montreal,

scale: 30,

crs: ‘EPSG: 4326’, // CRS de sortie (Système de coordonnées)

maxPixels: 1e13, // Paramètre impliquant un nombre maximal de pixel en sortie, principalement pour la gestion de mémoire (ajuster au besoin).

fileDimensions: 512, // dimension des tuiles de sortie désirée

skipEmptyTiles: true // paramètre indiquant s’il faut oui ou non exporter les tuiles vides

});

 

definition

Licence

Symbole de License Creative Commons Attribution - Pas d’utilisation commerciale 4.0 International

Maitriser le développement sous Google Earth Engine Copyright © 2023 by Charles Gignac, Maryam Rahimzad et Saeid Homayouni is licensed under a License Creative Commons Attribution - Pas d’utilisation commerciale 4.0 International, except where otherwise noted.

Partagez ce livre