I am struggling to understand the masking logic for MODIS snow cover data in the image selected in the code below (and many others like it).

Snow cover image In the image:

  • The black areas are "best" quality and NDSI_Snow_Cover = 0.
  • The blue areas are "OK" quality and NDSI_Snow_Cover = 0.
  • The transparent area in the center of the image is "OK" quality but the NDSI_Snow_Cover = "masked".
  • The purple areas in the upper right have some snow.

The QA bits are identical for the blue and transparent areas, so I don't understand why only the transparent area is masked.

Blue area:

  • NDSI_Snow_Cover: 0
  • NDSI_Snow_Cover_Basic_QA: 2 # (quality is "OK")
  • NDSI_Snow_Cover_Algorithm_Flags_QA: 128

Transparent area in the center:

  • NDSI_Snow_Cover: masked
  • NDSI_Snow_Cover_Basic_QA: 2
  • NDSI_Snow_Cover_Algorithm_Flags_QA: 128

The QA flag of "128" means that bit 7 is set. The documentation says:

SOLAR ZENITH SCREEN: BIT 7 This screen is utilized to identify low illumination conditions. When solar zenith angles exceed 70°, the low illumination challenges snow cover detection. As such, pixels with solar zenith angles > 70° are flagged by setting bit 7. This solar zenith mask is set across the entire swath. Note: night is defined as a solar zenith angle ≥ 85°. Night pixels are assigned a value '211' in the 'NDSI_Snow_Cover_Algorithm_Flags_QA' SDS and the 'NDSI_Snow_Cover' SDS.

So, both the blue and transparent areas have low illumination (not night), and the quality of both is "OK". Why is only one of the two areas masked, if the QA values are identical?

//Google Earth Engine javascript console
var study_area = ee.Geometry.BBox(103,41.5,113.5,47);

var snowdata = ee.ImageCollection('MODIS/006/MOD10A1')
      .map(function(image) { return image.clip(study_area); })

var n = snowdata.size();
var img_list = snowdata.toList(n);
var im = ee.Image(img_list.get(0));
Map.setCenter(114, 43, 6);

1 Answer 1


It turns out that Google Earth Engine splits the original MODIS NDSI_Snow_Cover band into two bands:

  1. NDSI_Snow_Cover. Contains only values from 0-100. All classes having values > 100 are masked out;
  2. NDSI_Snow_Cover_Class. Contains all values above 100. All values < 100 are masked out.

Annoyingly, Google Earth Engine uses the same name for their snow cover band ("NDSI_Snow_Cover") as the original data does, despite the Google version being truncated. So, to estimate snow cover and also count pixels in other classes (missing data, cloud, night, water, etc.), you must process both bands.

To rebuild the original NDSI_Snow_Cover band, you can use the rather obscure blend function:

def remake_ndsi_band(image): 
    snowband = image.select('NDSI_Snow_Cover') 
    classband = image.select('NDSI_Snow_Cover_Class')
    combinedband = snowband.blend(classband)
    return image.addBands(combinedband)

See GEE MOD10A1 documentation

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.