Google Earth Engine – Handling Null Inside .map in Google Earth Engine

google-earth-enginenull

I want to map over an ImageCollection and calculate percentiles of a region. Some images are empty for my area of interest, due to cloud masking.

How do I handle something like:

if variable ==null :
  continue with next image

I prepared some code with the exact problem:

GEE code

Can the following normalize function be altered to incorporate the occasional null value?

var normalize = function(Im){
  var time = Im.get("system:time_start")
  var percentiles = Im.reduceRegion({
    reducer:ee.Reducer.percentile([10,90],["10","90"]),
    crs:proj.crs,
    crsTransform:proj.transform,
    maxPixels:1000000000
  })
  var p10 = ee.Number(percentiles.get("band_10"))
  print(p10,"p10")
  var p90 = ee.Number(percentiles.get("band_90"))
  print(p90,"p90")
  return Im.subtract(p10).divide(p90.subtract(p10)).set({"system:time_start":time})
}

Best Answer

There is not a great way to skip an image in the map function. However, you can use the ee.Algorithms.If function to control what happens when null is encountered. In your case, if all pixels in the region are masked, the reducer will return null. Instead of trying to do math operations with null, you can return a masked image (no attempt to normalize). Additionally, set an 'isNull' property so that you can filter on it once the normalize function has been mapped over the collection. Here is ee.Algorithms.If implemented in your snippet:

var normalize = function(Im){
  var time = Im.get("system:time_start");
  var percentiles = Im.reduceRegion({
    reducer:ee.Reducer.percentile([10,90],["10","90"]),
    crs:proj.crs,
    crsTransform:proj.transform,
    maxPixels:1000000000
  });
  
  var p10 = ee.Number(percentiles.get("band_10"));
  print(p10,"p10");
  var p90 = ee.Number(percentiles.get("band_90"));
  print(p90,"p90");
  
  var outImg = ee.Image(ee.Algorithms.If(
    p10, 
    Im.subtract(p10).divide(p90.subtract(p10)).set('isNull', false),
    ee.Image(0).selfMask().set('isNull', true)
  ));
  
  return outImg.set({"system:time_start":time});
};

If you wanted to filter the null images out of the collection do this:

var normCol = imgCol
  .select(["B1"], ["band"])
  .map(normalize);
  
var normColNotNull = normCol.filter(ee.Filter.eq('isNull', false));

Note that ee.Algorithms.If should be used with caution because it will always evaluate both the true and false alternatives, which takes extra time and resources.

Related Question