land cover assemblage from primitives

Specify thresholds for each land cover class

step 1: add the image and primitives

var chl = ee.FeatureCollection("users/servirmekong/Vietnam/CHL_Boundary").geometry();

var plantations = ee.Image("users/servirmekong/Vietnam/primitives/plantations").rename('plantations')
var forest = ee.Image("users/servirmekong/Vietnam/primitives/forest").rename('forest')
var cropland = ee.Image("users/servirmekong/Vietnam/primitives/cropland").rename('cropland')
var urban = ee.Image("users/servirmekong/Vietnam/primitives/urban").rename('settlement')
var water = ee.Image("users/servirmekong/Vietnam/primitives/water").rename('water')

step 2: add all images to a single image

var primiImg = plantations.addBands(forest).addBands(cropland).addBands(urban).addBands(water)

step 3: Create as list of classes and define the thresholds

var primitives = ['forest','plantations','settlement','cropland',"water"];
var defaultThresholds = [70, 70, 70, 70,70,70];

var year = 2017
// container for the classified landclass image
var landClass = ee.Image();

step 4: add some ui objects

// ************************************************
// ui objects
// containers for sliders
var sliders = {};
// containers for inspected values
var valLabels = {};
// list of all selectable years
var availableYears = ['2017'];
// dropdown to select years
var yearList = ui.Select(availableYears, 'year', ''+year);
// checkbox to visualize primitives using thresholds
var primThresholds = ui.Checkbox({
  label:'Visualize primitive by thresholds',
  style:{'height':'18px','fontSize':'11px', 'padding':'4px', 'margin':'0px'}
});
// button to refresh display according to parameters
var refreshDisplay = ui.Button({
  label:'Refresh Display',
  onClick: refresh,
  style: {'fontSize':'11px', 'padding':'4px', 'margin':'0px'}
});
// button to export the current LandCover
var exportLC = ui.Button({
  label:'Export current landCover',
  onClick: exportHelper,
  style: {'fontSize':'11px', 'padding':'4px', 'margin':'0px'}
});

step 5: add function to reclassify the image

// function to reclassify stack image using decision tree
function reclassify(stackImage, decisionTree){
  var classifier = ee.Classifier.decisionTree(decisionTree);
  var landClass = stackImage.classify(classifier);
  return landClass;
}

step 6: add function to select primitive.

// client side list map function to change list of primitives
// to a list of images corresponding to the primitives
// also adds the primitives to the map
function getPrimitiveImages(primitive){
  var image = primiImg.select(primitive) //.multiply(0.01).rename(primitive);

  var primLayer = ui.Map.Layer(image, {max:100}, primitive, false, 1);
  if (primThresholds.getValue()){
    primLayer = ui.Map.Layer(image.gte(sliders[primitive].getValue()), {}, primitive, false, 1);
  }
  Map.layers().set(primitives.indexOf(primitive), primLayer);
  return image;
}

step 7: add the function to build the decision tree

// function to build decision tree from interface
function buildDecisionTree(){
  print(sliders)
  var values = {
    forest:sliders['forest'].getValue(),
    plantations:sliders['plantations'].getValue(),
    settlement:sliders['settlement'].getValue(),
    cropland:sliders['cropland'].getValue(),
    water:sliders['water'].getValue()
  }
  var DT = ['1) root 9999 9999 9999']
  var base = 1;
  for (var i = 0; i ='+values[primitives[i]]+' 9999 9999 '+(i+1)+' *');
    if(i == primitives.length-1){
      DT.push(''+b+') '+primitives[i]+'<'+values[primitives[i]]+' 9999 9999 0 *');
    }else DT.push(''+b+') '+primitives[i]+'<'+values[primitives[i]]+' 9999 9999 9999');
    base = b
  }
  return DT.join('\n')
}

step 8: function to start the process

// function to start the process
function process(year){
  var stackImage = ee.Image(primitives.map(getPrimitiveImages)) //.clip(nepalBounds);
  landClass = reclassify(stackImage, buildDecisionTree());
  var lcLayer = ui.Map.Layer(landClass.clip(chl), imageVisParam, 'land cover', true, 1);
  Map.layers().set(primitives.length, lcLayer);
}

step 9: function to add the legend

// function to add legend to the map
function addLegend(){
  var UTILS = require('users/khanalnishant/Algorithms:Utilities')
  var palette = imageVisParam.palette
  palette = palette.slice(1).concat(palette[0])
  var labels = primitives.concat('otherland')
  UTILS.addLegend(palette, labels,'Legend',{
    'position':'bottom-right',
    'padding':'8px 16px',
  });
}

step 10: function to inspect the maps

// function to add inspect panel to the map
function addInspect(){
  var panel = ui.Panel([], ui.Panel.Layout.Flow('vertical'),{maxHeight:'200px',position:'bottom-center'});
  var inspectLabel = ui.Label('Click to inspect primitive values',{'height':'18px','fontSize':'11px', 'padding':'0px', 'margin':'1px'});
  panel.add(inspectLabel)
  for (var i = 0; i <primitives.length;i++){
    var insLabel =  ui.Label(primitives[i],{'width':'60px','fontSize':'11px', 'padding':'0px', 'margin':'1px'});
    valLabels[primitives[i]] =  ui.Label('Click Map',{'fontSize':'11px', 'padding':'0px', 'margin':'1px'});
    var inspectSubPanel = ui.Panel([insLabel, valLabels[primitives[i]]], ui.Panel.Layout.Flow('horizontal'));
    panel.add(inspectSubPanel);
  }
  Map.add(panel)
}

step 11: fetch the values when the map is clicked.

// function to update the inspect section once map is clicked
function fetchValues(lonlat){
  var point = ee.Geometry.Point(lonlat.lon, lonlat.lat);
  var stack = ee.Image([]);
  for (var i=0; i<primitives.length;i++){
    var image = Map.layers().get(i).get('eeObject');
    stack = stack.addBands(image);
    valLabels[primitives[i]].setValue('updating values');
  }
  var pointSampled = stack.sample(point,30).first().evaluate(updateValues);
}

step 12: add function to update labels

//update the labels once the sampling is done
function updateValues(feature){
  // print(feature.properties);
  for (var i=0; i<primitives.length;i++){
    var value = parseFloat(feature.properties[primitives[i]]).toFixed(2)
    valLabels[primitives[i]].setValue(value);
  }
}

step 13: add function to export assemblage

// function to export current Land Cover
function exportHelper(){
  Export.image.toAsset({
    image:landClass.toInt8(),
    description:'LandCover-'+year,
    region:chl,
    scale:30,
    maxPixels:1e10
  })
}

step 14: add function to refresh the map after setting parameters.

// function to refresh display based on parameters
function refresh(){
  // get layer shown state
  var layers = Map.layers();
  var shownStat = layers.map(function(layer){
    return layer.getShown();
  });
  // get selected year
  year = yearList.getValue();
  // initiate the process
  process(year);
  // reassign the previous layer shown status
  layers = Map.layers();
  layers.map(function(layer){
    return layer.setShown(shownStat[layers.indexOf(layer)]);
  });
}

step 15: function to initialize

// function to initialize the application
function init(){
  var panel = ui.Panel([], ui.Panel.Layout.Flow('vertical'),{position:'bottom-left'});
  var yearLabel = ui.Label('Year',{'width':'30px','height':'18px','fontSize':'11px', 'margin':'15px 0px'});
  var yearSubPanel = ui.Panel([yearLabel, yearList], ui.Panel.Layout.Flow('horizontal'));
  panel.add(yearSubPanel);
  var sliderLabel = ui.Label('Adjust Probability Thresholds',{'height':'18px','fontSize':'11px', 'padding':'0px', 'margin':'1px'});
  panel.add(sliderLabel);
  for (var i = 0; i< primitives.length;i++){
    var label = ui.Label(primitives[i],{'width':'50px','height':'18px','fontSize':'11px', 'padding':'0px', 'margin':'1px'});
    sliders[primitives[i]] = ui.Slider({
      min:0,
      max:100,
      value:defaultThresholds[i],
      style:{'height':'18px','fontSize':'11px', 'padding':'0px', 'margin':'1px'}
    });
    var subPanel = ui.Panel([label, sliders[primitives[i]]], ui.Panel.Layout.Flow('horizontal'),{'padding':'4px'});
    panel.add(subPanel);
  }

  panel.add(primThresholds);
  panel.add(refreshDisplay);
  panel.add(exportLC)
  Map.add(panel);
  addLegend();
  addInspect();
  Map.onClick(fetchValues);
}

step 16: initialize the tool.

init();
var dec = buildDecisionTree()
print(dec)
process(year)

example

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s