Google Earth Engine – Download NASA’s Black Marble VNPA2 Nighttime Light Data

data-qualityexportgoogle-earth-engine

I want to download images from NASA's Black Marble nighttime light (NTL) using Google Earth Engine. The product can be found here. Before downloading them I need to check the pixel's quality using the QF Cloud Mask. More specifically, from the table under the Bitmask for QF_Cloud_Mask I need:

  1. Bit 0: Day/Night: 0: Night
  2. Bits 1-3: Land/Water Background: 1: Land no Desert
  3. Bits 4-5: Cloud Mask Quality: 3: High
  4. Bits 6-7: Cloud Detection Results & Confidence Indicator: 0: Confident Clear
  5. Bit 8: Shadow Detected: 0: No
  6. Bit 9: Cirrus Detection (IR) (BTM15 – BTM16): 0: No cloud
  7. Bit 10: Snow/Ice Surface: 0: No Snow/Ice

From the Mandatory_Quality_Flag Class Table:

  • 0 High-quality, Persistent nighttime lights

From the Snow_Flag Class Table:

  • 0 No Snow/Ice

Based on the above information, I did:

// Here I'm trying to set the Bits according to table 'Bitmask for QF_Cloud_Mask'
var mask_vnpa2_img = function(image) {
  var LandWaterBackground = (1 << 3);
  var CloudMaskQuality = (3 << 5);
  var CloudDetectionResultsConfidenceIndicator = (0 << 7);
  var ShadowDetected = (0 << 8);
  var CirrusDetection = (0 << 9);
  var SnowIceSurface = (0 << 10);

  // Get the pixel QA band
  var qa = image.select('QF_Cloud_Mask');

  var mask = qa
    .bitwiseAnd(LandWaterBackground).eq(0)
    .and(qa.bitwiseAnd(CloudMaskQuality).eq(0))
    .and(qa.bitwiseAnd(CloudDetectionResultsConfidenceIndicator).eq(0))
    .and(qa.bitwiseAnd(ShadowDetected).eq(0))
    .and(qa.bitwiseAnd(CirrusDetection).eq(0))
    .and(qa.bitwiseAnd(SnowIceSurface).eq(0));

  // Mask image with clouds and shadows
  return image.updateMask(mask);
};

var dataset = ee.ImageCollection('NOAA/VIIRS/001/VNP46A2').filter(
  ee.Filter.date('2018-06-01', '2018-06-30'));

// 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'],
};

Map.setCenter(-79.4, 43.1, 8);
// Day/Night Band (DNB)
// NightTime Light (NTL)
Map.addLayer(brdf, brdfVis, 'DNB_BRDF_Corrected_NTL');

If I remove the code from line 1 to 24 and plot the results I don't see any difference meaning that the QA mask I applied isn't correct. Here is the table (shp) I am using.

How can I apply the QA mask to the collection before I export the image?

Best Answer

Maybe you messed up the bit fiddling? I've got a little utility function that I always use, so I don't have to think about it every time:

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


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

https://code.earthengine.google.com/a7be3d668841043a7d0daa9de406d0b7