Classification LULC avec Sentinel-2 dans Google Earth Engine

Classification LULC avec Sentinel-2

Un guide complet pour la classification de l'occupation du sol (LULC) utilisant les données Sentinel-2 dans Google Earth Engine

Couverture complète

Toutes les étapes du processus de classification, de la préparation des données à l'évaluation des résultats.

Random Forest

Utilisation de l'algorithme Random Forest pour une classification robuste et précise.

Analyse complète

Inclut la validation, le calcul des superficies et l'exportation des résultats.

Code complet pour la classification LULC

// Étapes: échantillonnage, entraînement, validation, classification et visualisation
// -------------------------------- 
// 1. PRÉPARATION DES DONNÉES
// -------------------------------- 

// Définir la zone d'étude (à remplacer par votre propre geometry)
// Vous pouvez dessiner votre propre geometry en utilisant l'outil de dessin ou importer une limite administrative
var geometry = ee.Geometry.Rectangle([/* vos coordonnées */]);

// Charger la collection d'images Sentinel-2
var s2Collection = ee.ImageCollection('COPERNICUS/S2_SR')
  .filterDate('2023-01-01', '2023-12-31') // Ajustez la période selon vos besoins
  .filterBounds(geometry)
  .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 20));

// Créer une image composite médiane
var s2 = s2Collection.median();

// Sélectionner les bandes pertinentes et ajouter des indices spectraux
var bands = ['B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8', 'B8A', 'B11', 'B12'];

// Calculer les indices spectraux
var ndvi = s2.normalizedDifference(['B8', 'B4']).rename('NDVI');
var ndwi = s2.normalizedDifference(['B3', 'B8']).rename('NDWI');
var ndbi = s2.normalizedDifference(['B11', 'B8']).rename('NDBI');

// Ajouter les indices à l'image
var imageWithIndices = s2.select(bands).addBands(ndvi).addBands(ndwi).addBands(ndbi);

// -------------------------------- 
// 2. VISUALISATION DES COMPOSITIONS
// -------------------------------- 

// Composition en vraies couleurs
Map.addLayer(s2, {bands: ['B4', 'B3', 'B2'], min: 0, max: 3000}, 'RGB naturel');

// Composition en fausse couleur (proche infrarouge)
Map.addLayer(s2, {bands: ['B8', 'B4', 'B3'], min: 0, max: 3000}, 'Fausse couleur NIR', false);

// Composition SWIR
Map.addLayer(s2, {bands: ['B12', 'B8', 'B4'], min: 0, max: 3000}, 'SWIR', false);

// Visualisation des indices
Map.addLayer(ndvi, {min: -0.2, max: 0.8, palette: ['red', 'yellow', 'green']}, 'NDVI', false);
Map.addLayer(ndwi, {min: -0.8, max: 0.8, palette: ['white', 'blue']}, 'NDWI', false);
Map.addLayer(ndbi, {min: -0.6, max: 0.6, palette: ['green', 'white', 'red']}, 'NDBI', false);

// Centrer la carte sur la zone d'étude
Map.centerObject(geometry, 10);

// -------------------------------- 
// 3. COLLECTE DES DONNÉES D'ENTRAÎNEMENT
// -------------------------------- 

// OPTION 1: Collecte manuelle des points d'entraînement (méthode interactive)
// Utilisez l'outil de dessin pour créer des points et importez-les comme des variables
// Après avoir créé des points, importez-les comme 'urban_points', 'vegetation_points', etc.

/*
// Attribuer des classes aux collections de points
var urban = urban_points.map(function(feature) {
  return feature.set('class', 0);
});

var vegetation = vegetation_points.map(function(feature) {
  return feature.set('class', 1);
});

var water = water_points.map(function(feature) {
  return feature.set('class', 2);
});

var baresoil = baresoil_points.map(function(feature) {
  return feature.set('class', 3);
});

// Fusionner toutes les collections
var trainingPoints = urban.merge(vegetation).merge(water).merge(baresoil);
*/

// OPTION 2: Création programmatique de points d'entraînement (à des fins d'exemple)
// Cette approche est utile pour illustrer le code complet quand vous n'avez pas encore créé de points

// Définir des exemples de régions pour chaque classe (à remplacer par vos propres régions)
var urbanArea = ee.Geometry.Rectangle([/* coordonnées */]);
var vegetationArea = ee.Geometry.Rectangle([/* coordonnées */]);
var waterArea = ee.Geometry.Rectangle([/* coordonnées */]);
var baresoilArea = ee.Geometry.Rectangle([/* coordonnées */]);

// Créer des points aléatoires dans chaque région
var urban = ee.FeatureCollection.randomPoints(urbanArea, 50)
  .map(function(feature) { return feature.set('class', 0); });

var vegetation = ee.FeatureCollection.randomPoints(vegetationArea, 50)
  .map(function(feature) { return feature.set('class', 1); });

var water = ee.FeatureCollection.randomPoints(waterArea, 50)
  .map(function(feature) { return feature.set('class', 2); });

var baresoil = ee.FeatureCollection.randomPoints(baresoilArea, 50)
  .map(function(feature) { return feature.set('class', 3); });

// Fusionner toutes les collections
var trainingPoints = urban.merge(vegetation).merge(water).merge(baresoil);

// -------------------------------- 
// 4. DIVISION EN ENSEMBLES D'ENTRAÎNEMENT ET DE VALIDATION
// -------------------------------- 

// Ajouter une colonne avec des nombres aléatoires
var withRandom = trainingPoints.randomColumn('random');

// Diviser en ensembles d'entraînement (70%) et validation (30%)
var split = 0.7;
var training = withRandom.filter(ee.Filter.lt('random', split));
var validation = withRandom.filter(ee.Filter.gte('random', split));

// Visualiser les points d'entraînement et de validation
Map.addLayer(training, {color: 'blue'}, 'Points d\'entraînement', false);
Map.addLayer(validation, {color: 'red'}, 'Points de validation', false);

// Afficher le nombre de points dans chaque ensemble
print('Nombre de points d\'entraînement:', training.size());
print('Nombre de points de validation:', validation.size());

// -------------------------------- 
// 5. ÉCHANTILLONNAGE DES VALEURS SPECTRALES
// -------------------------------- 

// Liste de toutes les bandes à utiliser pour la classification
var bandsToUse = bands.concat(['NDVI', 'NDWI', 'NDBI']);

// Échantillonner l'image aux emplacements des points d'entraînement
var trainingData = imageWithIndices.select(bandsToUse).sampleRegions({
  collection: training,
  properties: ['class'],
  scale: 20  // Résolution de Sentinel-2
});

// Échantillonner l'image aux emplacements des points de validation
var validationData = imageWithIndices.select(bandsToUse).sampleRegions({
  collection: validation,
  properties: ['class'],
  scale: 20
});

// -------------------------------- 
// 6. ENTRAÎNEMENT DU CLASSIFICATEUR
// -------------------------------- 

// Créer un classificateur Random Forest et l'entraîner
var classifier = ee.Classifier.smileRandomForest({
  numberOfTrees: 100,
  minLeafPopulation: 1,
  seed: 42
}).train({
  features: trainingData,
  classProperty: 'class',
  inputProperties: bandsToUse
});

// Obtenir des informations sur l'importance des variables (optionnel)
var importances = classifier.explain();
print('Importance des variables:', importances);

// -------------------------------- 
// 7. CLASSIFICATION DE L'IMAGE
// -------------------------------- 

// Appliquer le classificateur à l'image
var classified = imageWithIndices.select(bandsToUse).classify(classifier);

// Définir une palette de couleurs pour les classes
var palette = [
  '#FF0000',  // Rouge pour Urbain (classe 0)
  '#00FF00',  // Vert pour Végétation (classe 1)
  '#0000FF',  // Bleu pour Eau (classe 2)
  '#FFFF00'   // Jaune pour Sol nu (classe 3)
];

// Visualiser la classification
Map.addLayer(classified, {min: 0, max: 3, palette: palette}, 'Classification LULC');

// -------------------------------- 
// 8. VALIDATION ET ÉVALUATION DE LA PRÉCISION
// -------------------------------- 

// Classer les points de validation
var validationResult = validationData.classify(classifier);

// Créer une matrice de confusion
var confusionMatrix = validationResult.errorMatrix('class', 'classification');

// Afficher les résultats de précision
print('Matrice de confusion:', confusionMatrix);
print('Précision globale:', confusionMatrix.accuracy());
print('Précision du producteur:', confusionMatrix.producersAccuracy());
print('Précision de l\'utilisateur:', confusionMatrix.consumersAccuracy());
print('Coefficient Kappa:', confusionMatrix.kappa());

// -------------------------------- 
// 9. FILTRAGE POST-CLASSIFICATION (OPTIONNEL)
// -------------------------------- 

// Appliquer un filtre majoritaire pour réduire le bruit de classification
var filtered = classified.focal_mode({
  radius: 1.5,  // Rayon en pixels
  kernelType: 'circle',
  units: 'pixels'
});

// Visualiser la classification filtrée
Map.addLayer(filtered, {min: 0, max: 3, palette: palette}, 'Classification filtrée', false);

// -------------------------------- 
// 10. CALCUL DES STATISTIQUES DE SURFACE
// -------------------------------- 

// Calculer la superficie pour chaque classe
var areaImage = ee.Image.pixelArea().addBands(classified);
var areas = areaImage.reduceRegion({
  reducer: ee.Reducer.sum().group({
    groupField: 1,
    groupName: 'class',
  }),
  geometry: geometry,
  scale: 20,
  maxPixels: 1e9
});

// Afficher les résultats de superficie
print('Superficie par classe (m²):', areas);

// Convertir les résultats en hectares et créer un tableau plus lisible
var classAreas = ee.List(areas.get('groups'));
var classAreasList = classAreas.map(function(item) {
  var areaDict = ee.Dictionary(item);
  var classNumber = areaDict.get('class');
  var area = ee.Number(areaDict.get('sum')).divide(10000); // Conversion en hectares
  
  // Déterminer le nom de la classe
  var className;
  if (classNumber.equals(0)) {
    className = 'Urbain';
  } else if (classNumber.equals(1)) {
    className = 'Végétation';
  } else if (classNumber.equals(2)) {
    className = 'Eau';
  } else {
    className = 'Sol nu';
  }
  
  return ee.Dictionary({
    'Classe': className,
    'Superficie (ha)': area.format('%.2f')
  });
});

print('Superficie par classe (ha):', classAreasList);

// -------------------------------- 
// 11. EXPORTATION DES RÉSULTATS
// -------------------------------- 

// Exporter la classification vers Google Drive
Export.image.toDrive({
  image: classified,
  description: 'LULC_Classification',
  folder: 'GEE_Exports',
  region: geometry,
  scale: 20,
  maxPixels: 1e9
});

// Exporter les points d'entraînement pour une utilisation future
Export.table.toDrive({
  collection: trainingPoints,
  description: 'LULC_Training_Points',
  fileFormat: 'GeoJSON'
});

// -------------------------------- 
// 12. AJOUT D'UNE LÉGENDE (FACULTATIF)
// -------------------------------- 

// Créer un panneau pour la légende
var legend = ui.Panel({
  style: {
    position: 'bottom-left',
    padding: '8px 15px'
  }
});

// Ajouter un titre à la légende
var legendTitle = ui.Label({
  value: 'Légende LULC',
  style: {
    fontWeight: 'bold',
    fontSize: '16px',
    margin: '0 0 4px 0',
    padding: '0'
  }
});
legend.add(legendTitle);

// Créer et ajouter les éléments de la légende
var makeRow = function(color, name) {
  var colorBox = ui.Label({
    style: {
      backgroundColor: color,
      padding: '8px',
      margin: '0 0 4px 0'
    }
  });
  var description = ui.Label({
    value: name,
    style: {margin: '0 0 4px 6px'}
  });
  return ui.Panel({
    widgets: [colorBox, description],
    layout: ui.Panel.Layout.Flow('horizontal')
  });
};

legend.add(makeRow('#FF0000', 'Urbain (0)'));
legend.add(makeRow('#00FF00', 'Végétation (1)'));
legend.add(makeRow('#0000FF', 'Eau (2)'));
legend.add(makeRow('#FFFF00', 'Sol nu (3)'));

// Ajouter la légende à la carte
Map.add(legend);
                    
1

Préparation des données

  • Définition de la zone d'étude
  • Chargement des images Sentinel-2
  • Filtrage temporel et spatial
  • Calcul des indices spectraux (NDVI, NDWI, NDBI)
2

Visualisation

  • Compositions RGB naturel
  • Fausse couleur NIR
  • Composition SWIR
  • Visualisation des indices
3

Collecte des données d'entraînement

  • Option manuelle (outil de dessin)
  • Option programmatique (exemple)
  • Attribution des classes
4

Division des données

  • Séparation 70% entraînement / 30% validation
  • Randomisation des points
  • Visualisation des ensembles
5

Entraînement du classificateur

  • Configuration du Random Forest
  • 100 arbres, seed=42
  • Analyse d'importance des variables
6

Classification et validation

  • Application du modèle
  • Matrice de confusion
  • Métriques de précision
  • Filtrage post-classification
7

Analyse et exportation

Calcul des superficies

  • Conversion en hectares
  • Résultats par classe

Exportation

  • Classification vers Google Drive
  • Points d'entraînement en GeoJSON
  • Ajout de légende interactive

Légende des classes LULC

Couleurs des classes

  • Urbain (classe 0)
  • Végétation (classe 1)
  • Eau (classe 2)
  • Sol nu (classe 3)

Palettes des indices

  • NDVI: [-0.2 à 0.8]
  • NDWI: [-0.8 à 0.8]
  • NDBI: [-0.6 à 0.6]

Notes importantes

Configuration initiale

  • Vous devez définir votre propre geometry pour délimiter la zone d'étude.
  • Dans la partie "OPTION 1", utilisez l'outil de dessin du Code Editor pour créer des points d'entraînement.
  • Importez les points comme variables: urban_points, vegetation_points, etc.
  • Décommentez la section correspondante dans le code.

Points d'entraînement

  • Pour l'échantillonnage manuel: dessinez vos points avec l'outil de dessin.
  • L'OPTION 2 avec des points générés automatiquement est fournie pour démarrer rapidement.
  • Définissez des zones représentatives pour chaque classe dans l'option programmatique.

Paramètres du modèle

  • Ajustez les paramètres du classificateur Random Forest selon vos besoins.
  • Nombre d'arbres, profondeur, etc. peuvent être optimisés.
  • La seed=42 assure la reproductibilité des résultats.

Exportation

  • Modifiez le dossier de destination dans Google Drive si nécessaire.
  • Adaptez la résolution (scale) selon vos besoins.
  • Le format GeoJSON est recommandé pour les points d'entraînement.

Astuce

Ce code est immédiatement opérationnel dans Google Earth Engine et peut être facilement adapté à d'autres régions d'étude ou personnalisé selon vos besoins spécifiques.