Customize Consent Preferences

We use cookies to help you navigate efficiently and perform certain functions. You will find detailed information about all cookies under each consent category below.

The cookies that are categorized as "Necessary" are stored on your browser as they are essential for enabling the basic functionalities of the site. ... 

Always Active

Necessary cookies are required to enable the basic features of this site, such as providing secure log-in or adjusting your consent preferences. These cookies do not store any personally identifiable data.

No cookies to display.

Functional cookies help perform certain functionalities like sharing the content of the website on social media platforms, collecting feedback, and other third-party features.

No cookies to display.

Analytical cookies are used to understand how visitors interact with the website. These cookies help provide information on metrics such as the number of visitors, bounce rate, traffic source, etc.

No cookies to display.

Performance cookies are used to understand and analyze the key performance indexes of the website which helps in delivering a better user experience for the visitors.

No cookies to display.

Advertisement cookies are used to provide visitors with customized advertisements based on the pages you visited previously and to analyze the effectiveness of the ad campaigns.

No cookies to display.

Google Earth Engine (GEE) Code to Calculate Moment Distance Index Normalized (MDIN) Using Sentinel-2 or LandSat Images

MDIN stands for Moment Distance Index Normalized, originally developed by Salas and Henebry (2013) and improved by Salas and Subburayalu (2019). We developed MDIN to improve the spatial-spectral classification of hyperspectral data for agricultural management systems. MDIN analyzes the full spectral curve across different wavelengths.

How it Works:

(1) Distance Calculation: The index calculates the distance of each band’s reflectance from two “pivots” within the spectral curve: the left pivot and the right pivot. (2) Normalization: These distances are normalized to create a value between -1 and 1.

    Below is the simplified code for calculating MDIN using a Sentinel-2 image on the Google Earth Engine (GEE) platform.

    //Get the boudary of your study area.  
    var ohio = ee.FeatureCollection('TIGER/2018/States')
      .filter(ee.Filter.eq('NAME', 'Ohio'));
    
    // Function to calculate MDIN for Sentinel-2 imagery.  
    // If you want to use LandSat bands, make sure to change/edit the bands below.  
    var calculateMDIN = function(image) {
      // Define wavelengths for Sentinel-2 bands (in nanometers)
      var wavelengths = {
        'B2': 490,   // Blue (LP - Left Pivot)
        'B3': 560,   // Green
        'B4': 665,   // Red
        'B5': 705,   // Red Edge 1
        'B6': 740,   // Red Edge 2
        'B7': 783,   // Red Edge 3
        'B8': 842,   // NIR
        'B8A': 865,  // Red Edge 4
        'B11': 1610, // SWIR 1
        'B12': 2190  // SWIR 2 (RP - Right Pivot)
      };
      
      // Get all bands for calculation
      var allBands = ['B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8', 'B8A', 'B11', 'B12'];
    
      // Calculate MDLP (Left Pivot to Right Pivot)
      // If using LandSat, change Sentinel-2 [B2] with the first band of LandSat.
      var mdlpSum = ee.Image(0);
      allBands.forEach(function(band) {
        var reflectance = image.select(band).subtract(image.select(allBands).reduce(ee.Reducer.mean())); // Centralize reflectance
        var wavelengthPosition = ee.Number(wavelengths[band]);
        var leftPivotDiff = wavelengthPosition.subtract(wavelengths['B2']); // Distance from LP
        
        // Hypotenuse: sqrt(ρ² + (i-λLP)²)
        var distanceLP = reflectance.pow(2).add(leftPivotDiff.pow(2)).sqrt();
        mdlpSum = mdlpSum.add(distanceLP);
      });
    
      // Calculate MDRP (Right Pivot to Left Pivot)
      // If using LandSat, change Sentinel-2 [B12] with the last band of LandSat.
      var mdrpSum = ee.Image(0);
      allBands.forEach(function(band) {
        var reflectance = image.select(band).subtract(image.select(allBands).reduce(ee.Reducer.mean())); // Centralize reflectance
        var wavelengthPosition = ee.Number(wavelengths[band]);
        var rightPivotDiff = ee.Number(wavelengths['B12']).subtract(wavelengthPosition); // Distance from RP
        
        // Hypotenuse: sqrt(ρ² + (λRP-i)²)
        var distanceRP = reflectance.pow(2).add(rightPivotDiff.pow(2)).sqrt();
        mdrpSum = mdrpSum.add(distanceRP);
      });
    
      // Normalize MDLP and MDRP
      var normalizedMDLP = mdlpSum.divide(mdlpSum.add(mdrpSum));
      var normalizedMDRP = mdrpSum.divide(mdlpSum.add(mdrpSum));
      
      // Calculate MDIN = (MDRP - MDLP)/(MDRP + MDLP)
      var mdin = normalizedMDRP.subtract(normalizedMDLP).rename('MDIN');
    
      return image.addBands(mdin);
    };
    
    
    // Get Sentinel-2 collection for summer 2023. Change the dates depending on your study dates. 
    var s2Collection = ee.ImageCollection('COPERNICUS/S2_SR')
      .filterDate('2023-05-01', '2023-06-30')
      .filterBounds(ohio.geometry())
      .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 10));
    
    // Calculate MDIN for each image
    var mdinCollection = s2Collection.map(calculateMDIN);
    
    // Calculate the mean MDIN across all images
    var meanMDIN = mdinCollection.select('MDIN').mean();
    
    // Clip to Ohio boundary
    var mdinOhio = meanMDIN.clip(ohio);
    
    // Calculate MDIN statistics for visualization
    var mdinStats = mdinOhio.reduceRegion({
      reducer: ee.Reducer.max(),
      geometry: ohio.geometry(),
      scale: 1000,
      maxPixels: 1e9
    });
    
    // Get the maximum MDIN value
    var maxMDIN = ee.Number(mdinStats.get('MDIN'));
    print('Maximum MDIN:', maxMDIN);
    
    // Create a palette with 20 colors
    var palette = [
      '#0000FF', '#0033FF', '#0066FF', '#0099FF', '#00CCFF',
      '#00FFFF', '#33FFCC', '#66FF99', '#99FF66', '#CCFF33',
      '#FFFF00', '#FFCC00', '#FF9900', '#FF6600', '#FF3300',
      '#FF0000', '#CC0033', '#990066', '#660099', '#3300CC'
    ];
    
    // Visualization parameters with 20 categories
    var mdinVis = {
      min: 0,
      max: maxMDIN.getInfo(),
      palette: palette
    };
    
    // Center map on Ohio
    Map.centerObject(ohio, 7);
    
    // Add layers
    Map.addLayer(mdinOhio, mdinVis, 'Average Summer MDIN Ohio');
    Map.addLayer(ohio.style({color: 'black', fillColor: '00000000'}), {}, 'Ohio boundary');
    
    // Add a legend for the 20 categories
    var createCategoricalLegend = function(palette, min, max, categories) {
      var legend = ui.Panel({
        style: {
          position: 'bottom-right',
          padding: '8px 15px'
        }
      });
    
      // Legend title
      var legendTitle = ui.Label({
        value: 'MDIN Categories',
        style: {
          fontWeight: 'bold',
          fontSize: '16px',
          margin: '0 0 4px 0',
          padding: '0'
        }
      });
    
      legend.add(legendTitle);
    
      // Create rows for each category
      var step = (max - min) / categories;
      for (var i = 0; i < categories; i++) {
        var value = (min + i * step).toFixed(2) + ' to ' + (min + (i + 1) * step).toFixed(2);
        var colorBox = ui.Label({
          style: {
            backgroundColor: palette[i],
            padding: '8px',
            margin: '0 0 4px 0'
          }
        });
        var description = ui.Label({
          value: value,
          style: {margin: '0 0 4px 6px'}
        });
        legend.add(ui.Panel([colorBox, description], ui.Panel.Layout.Flow('horizontal')));
      }
    
      return legend;
    };
    
    // Add the categorical legend to the map
    var legend = createCategoricalLegend(palette, 0, maxMDIN.getInfo(), 20);
    Map.add(legend);
    
    // Add a chart showing MDIN values over time
    var chart = ui.Chart.image.series({
      imageCollection: mdinCollection.select('MDIN'),
      region: ohio.geometry(),
      reducer: ee.Reducer.mean(),
      scale: 1000
    }).setOptions({
      title: 'Average MDIN Values Over Summer 2023',
      vAxis: {title: 'MDIN'},
      hAxis: {title: 'Date'},
      trendlines: {0: {}}
    });
    
    print(chart);

    If you use the code above or apply MDIN, kindly use this citation:

    Salas, EAL and Subburayalu, SK (2019). Modified shape index for object-based random forest image classification of agricultural systems using airborne hyperspectral datasets. PLoS ONE 14(3): e0213356. https://doi.org/10.1371/journal.pone.0213356

    Leave a Reply

    Your email address will not be published. Required fields are marked *

    three × 2 =

    This site uses Akismet to reduce spam. Learn how your comment data is processed.