2

I am working with Black Marble VNPA2 nighttime light daily product. Before I export any image I check the pixel's quality and I remove any 'bad' pixels from the collection. But by removing the bad quality pixels, in many cases the area of interest, for a particular day, has very little coverage (most of the area is empty/nan values).

Using Google Earth Engine, how can I print the days, (starting from January 1st until the last day of December 2018) where the pixel coverage of my study area is equal or greater than 80%? By pixel coverage I mean, the remaining pixels after removing the bad quality ones.

Here is the code for removing the bad quality pixels:

// Here I'm trying to set the Bits according to table 'Bitmask for QF_Cloud_Mask'
var mask_vnpa2_img = function(image) {
  var qa = image.select('QF_Cloud_Mask');
  var landWaterBackground = bitwiseExtract(qa, 1, 3)
  var cloudMaskQuality = bitwiseExtract(qa, 4, 5)
  var cloudDetectionResultsConfidenceIndicator = bitwiseExtract(qa, 6, 7)
  var shadowDetected = bitwiseExtract(qa, 8)
  var cirrusDetection = bitwiseExtract(qa, 9)
  var snowIceSurface = bitwiseExtract(qa, 10)

  var mask = ee.Image(1)
    .and(landWaterBackground.eq(1)) // Land no Desert
    .and(cloudMaskQuality.eq(3)) // High
    .and(cloudDetectionResultsConfidenceIndicator.eq(0)) // Confident Clear
    .and(shadowDetected.eq(0)) // No
    .and(cirrusDetection.eq(0)) // No cloud
    .and(snowIceSurface.eq(0)) // No Snow/Ice
    
  return image.updateMask(mask);
};

// Project the image to Mollweide.
var wkt = ' \
  PROJCS["World_Mollweide", \
    GEOGCS["GCS_WGS_1984", \
      DATUM["WGS_1984", \
        SPHEROID["WGS_1984",6378137,298.257223563]], \
      PRIMEM["Greenwich",0], \
      UNIT["Degree",0.017453292519943295]], \
    PROJECTION["Mollweide"], \
    PARAMETER["False_Easting",0], \
    PARAMETER["False_Northing",0], \
    PARAMETER["Central_Meridian",0], \
    UNIT["Meter",1], \
    AUTHORITY["EPSG","54009"]]';

var proj_mollweide = ee.Projection(wkt);

var dataset = ee.ImageCollection('NOAA/VIIRS/001/VNP46A2')
  .filterDate('2018-01-01', '2018-01-02')
  .map(mask_vnpa2_img)
  .filterBounds(table)
  .select('DNB_BRDF_Corrected_NTL')
  .median()
  .clip(table)
  .reproject({
                crs: proj_mollweide,
                scale: 500
                  });

print(dataset)

// Bidirectional Reflectance Distribution Function (BRDF)
var brdf = dataset.select('DNB_BRDF_Corrected_NTL');
var brdfVis = {
  min: 0,
  max: 100,
  palette: ['black', 'purple', 'cyan', 'green', 'yellow', 'red', 'white'],
};


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)
}

Export.image.toDrive({
image: brdf,
description: 'ntl',
scale: 500, //100 for Band10
maxPixels: 1000000000000,
region: table,
folder: 'Landsat-5'
});

And the shp of my study area.

1 Answer 1

3

First of all, you are mixing methods from ee.Image objects and ee.ImageCollection. For this reason, I guess you probably considered the median determination for your dataset because your first approach didn't work. Several methods must be used in the mask_vnpa2_img function instead to be applied in dataset. It now looks as follows. Observe that I also added a concise file name in the return.

var mask_vnpa2_img = function(image) {
  var qa = image.select('QF_Cloud_Mask');
  var landWaterBackground = bitwiseExtract(qa, 1, 3)
  var cloudMaskQuality = bitwiseExtract(qa, 4, 5)
  var cloudDetectionResultsConfidenceIndicator = bitwiseExtract(qa, 6, 7)
  var shadowDetected = bitwiseExtract(qa, 8)
  var cirrusDetection = bitwiseExtract(qa, 9)
  var snowIceSurface = bitwiseExtract(qa, 10)

  var mask = ee.Image(1)
    .and(landWaterBackground.eq(1)) // Land no Desert
    .and(cloudMaskQuality.eq(3)) // High
    .and(cloudDetectionResultsConfidenceIndicator.eq(0)) // Confident Clear
    .and(shadowDetected.eq(0)) // No
    .and(cirrusDetection.eq(0)) // No cloud
    .and(snowIceSurface.eq(0)); // No Snow/Ice
  
  var date = image.get("system:time_start");
  
  return image.set('fileName', ee.String('image_').cat(ee.Date(date).format('YYYY-MM-DD')))
              .reproject({crs: proj_mollweide, scale: 500})
              .clip(table)
              .updateMask(mask);

};

For trying out if my approach works, I considered all January month of 2018 (31 days) and an arbitrary area in USA. The newImg function computes the areas of each masked images and uses the criterion "equal or greater than 80%" of all area (corresponding to table polygon) for selecting and exporting only the desired images. This looks as follows:

var brdf_list = brdf.toList(brdf.size());

var total_area = ee.Image.pixelArea().reduceRegion({
    reducer: ee.Reducer.sum(),
    geometry: table,
    scale: 500,
    maxPixels: 1e13
    
  });

var newImg = brdf_list.map(function (img) {
  
  var area = ee.Image.pixelArea().mask(ee.Image(img).gte(0)).reduceRegion({
    reducer: ee.Reducer.sum(),
    geometry: table,
    scale: 500,
    maxPixels: 1e13
    
  });
  
  var crit = ee.Number(area.get('area')).divide(total_area.get('area'));
  
  return ee.Algorithms.If(crit.gt(0.8), img, -1);
  
}).removeAll([-1]);

print(newImg);

newImg = ee.ImageCollection(newImg);

var first = newImg.first();

Map.addLayer(first, imageVisParam, 'brdf');

var exportImage = function(image, fileName) {
  Export.image.toDrive({
    image: image.first(),
    description: fileName,
    scale: 500, //100 for Band10
    maxPixels: 1000000000000,
    region: table,
    folder: 'Landsat-5'
  });
};

newImg.aggregate_array('fileName').evaluate(function (fileNames) {
  fileNames.forEach(function(fileName) {
    var image = brdf
      .filter(ee.Filter.eq('fileName', fileName));
    
    print(fileName);
    
    exportImage(image, fileName);

  });
});

After running the complete code, at the GEE code editor, I got following result. Only 11 images (of 31 possibles) have an area of non masked pixels of 80 %; as it can be observed in Tasks tab to be uploaded to Google Drive. The image observed at the picture is the first one of the corresponding series.

enter image description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.