MODIS cloud masking

Create a cloud free MODIS composite

 

Use the code below or follow this link.


// import data
var collection = ee.ImageCollection("MODIS/MOD09A1")

// Define dates
var iniDate = ee.Date.fromYMD(2010,1,1);
var endDate = ee.Date.fromYMD(2010,1,31);

// bands
var modisBands = ['sur_refl_b03','sur_refl_b04','sur_refl_b01','sur_refl_b02','sur_refl_b06','sur_refl_b07'];
var lsBands = ['blue','green','red','nir','swir1','swir2'];

// helper function to extract the QA bits
function getQABits(image, start, end, newName) {
 // Compute the bits we need to extract.
 var pattern = 0;
 for (var i = start; i <= end; i++) {
 pattern += Math.pow(2, i);
 }
 // Return a single band image of the extracted QA bits, giving the band
 // a new name.
 return image.select([0], [newName])
 .bitwiseAnd(pattern)
 .rightShift(start);
}

// A function to mask out cloudy pixels.
function maskQuality(image) {
 // Select the QA band.
 var QA = image.select('StateQA');
 // Get the internal_cloud_algorithm_flag bit.
 var internalQuality = getQABits(QA,8, 13, 'internal_quality_flag');
 // Return an image masking out cloudy areas.
 return image.updateMask(internalQuality.eq(0));
}

// create cloud free composite
var noCloud = collection.filterDate(iniDate,endDate)
 .map(maskQuality)
 .select(modisBands,lsBands);

// create composite with clouds
var Cloud = collection.filterDate(iniDate,endDate)
 .select(modisBands,lsBands);

// vis parameters
var visParams = {bands:['red','green','blue'],min:0,max:3000,gamma:1.3};

// add the cloud free composite
Map.addLayer(noCloud.median(),visParams,'MODIS Composite');

// add the cloud composite
Map.addLayer(Cloud.median(),visParams,'MODIS Composite clouds');

 

4 comments

  1. Hi there, thank you for this very helpful tutorial!

    I am new to Google Earth Engine and JavaScript for that matter, so am therefore trying to understand the method and functions you use a bit better. Two questions:
    1) Why is the mask created from pixels where internalQuality= 0? It is my understanding that the highest quality, least cloudy images will have bits equal to zero therefore when the .bitwiseAnd(pattern) is performed, it is only pixels equal to 0 that you want to keep. I am clearly misunderstanding something however as your code does remove clouds. Could you possible explain how the both the .bitwiseAnd(pattern) and also .rightShift(Start) work in this application?

    2) I’ve noticed that in regions not masked by the function there can still be a different shade to the resultant image, the result of different values for red/green/blue in the noCloud layer. I can’t figure out a pattern to the change in values however. I would think that as this is a cloud mask, only pixels with clouds will be altered while those without will be left with the same values as before in all bands. Can you explain what is occurring here? Some regions values do remain the same as well.

    I hope these questions are not too rudimentary. I’m trying to understand this method in hopes of applying to different bits in both QA and State QA bands.

    Thank you for any input you can offer.

    Like

  2. I added a new post with the bitmask. hope that helps answering your question.

    The difference in color is caused by the median function at the end. for the no cloud image the median is taken from the cloud free imagecollection.

    Like

  3. Hello.

    I would like to use MOD09A1 to clip bands 1 and 2 of the MOD09GQ product by removing the clouds.

    I could not modify the scope of the “getQABits” and “maskQuality” functions.

    The error occurs because the above functions are global and do not find the metadata (‘StateQA’) in the MOD09GQ product.

    Would you help me out of this ? Thanks and we look forward to your reply.

    ________________________________________________________________________

    // import data
    var collectionMOD09A1 = ee.ImageCollection(“MODIS/MOD09A1”)
    var collectionMOD09GQ = ee.ImageCollection(“MODIS/MOD09GQ”)

    // Define dates
    var iniDate = ee.Date.fromYMD(2010,1,1);
    var endDate = ee.Date.fromYMD(2010,1,31);
    //DayOfYear

    // bands
    var modisBandsMOD09A1 = [‘sur_refl_b03′,’sur_refl_b04′,’sur_refl_b01′,’sur_refl_b02′,’sur_refl_b06′,’sur_refl_b07’];
    var modisBandsMOD09GQ = [‘sur_refl_b01′,’sur_refl_b02’];

    var lsBandsMOD09A1 = [‘blue’,’green’,’red’,’nir’,’swir1′,’swir2′];
    var lsBandsMOD09GQ = [‘red’,’nir’];

    // helper function to extract the QA bits
    var getQABits = function getQABits(modisBandsMOD09A1, start, end, newName) {
    // Compute the bits we need to extract.
    var pattern = 0;
    for (var i = start; i <= end; i++) {
    pattern += Math.pow(2, i);
    }
    // Return a single band image of the extracted QA bits, giving the band
    // a new name.
    return modisBandsMOD09A1.select([0], [newName])
    .bitwiseAnd(pattern)
    .rightShift(start);
    }
    // A function to mask out cloudy pixels.
    var maskQuality = function maskQuality(modisBandsMOD09A1) {
    // Select the QA band.
    var QA = modisBandsMOD09A1.select('StateQA');
    // Get the internal_cloud_algorithm_flag bit.
    var internalQuality = getQABits(QA,8, 13, 'internal_quality_flag');
    // Return an image masking out cloudy areas.
    return modisBandsMOD09A1.updateMask(internalQuality.eq(0));
    }

    // create cloud free composite
    var noCloudMOD09A1 = collectionMOD09A1.filterDate(iniDate,endDate)
    .map(maskQuality)
    .select(modisBandsMOD09A1,lsBandsMOD09A1);

    var noCloudMOD09GQ = collectionMOD09GQ
    .filterDate(iniDate,endDate)
    .map(maskQuality)
    .select(modisBandsMOD09GQ,lsBandsMOD09GQ);

    // create composite with clouds
    var CloudMOD09A1 = collectionMOD09A1.filterDate(iniDate,endDate)
    .select(modisBandsMOD09A1,lsBandsMOD09A1);

    var CloudMOD09GQ = collectionMOD09GQ.filterDate(iniDate,endDate)
    .select(modisBandsMOD09GQ,lsBandsMOD09GQ);

    // vis parameters
    var visParamsMOD09A1 = {bands:['red','green','blue'],min:0,max:3000,gamma:1.3};

    var visParamsMOD09GQ = {bands:['red','nir','red'],min:0,max:3000,gamma:1.3};

    // add the cloud free composite
    Map.addLayer(noCloudMOD09A1.median(),visParamsMOD09A1,'MOD09A1 Composite');
    Map.addLayer(noCloudMOD09GQ.median(),visParamsMOD09GQ,'MOD09GQ Composite');

    // add the cloud composite
    Map.addLayer(CloudMOD09A1.median(),visParamsMOD09A1,'MOD09A1 Composite clouds');
    Map.addLayer(CloudMOD09GQ.median(),visParamsMOD09GQ,'MOD09GQ Composite clouds');

    Like

Leave a Reply