I am trying to perform PCA on MODIS imagery. I got my code to run using MODIS (it also worked for Landsat), but when I mask my MODIS collection the PCA fails. This had to do with missing values, as GEE doesn't run on sparse matrices.
Question: How do I mask bad pixels during a PCA? One can not mask before the PCA, so how can I mask pixels after PCA?
Here is my code. Extent is my ROI.
var dataset2019 = ee.ImageCollection('MODIS/006/MCD43A4').filter(ee.Filter.date('2018-12-01', '2019-04-20'));
var dataset2020 = ee.ImageCollection('MODIS/006/MCD43A4').filter(ee.Filter.date('2019-12-01', '2020-04-20'));
var modisCol = dataset2019.merge(dataset2020);
// Create a QA mask function
var filterqa = function(image){
var mask1 = image.select("BRDF_Albedo_Band_Mandatory_Quality_Band1").eq(0);
var mask2 = image.select("BRDF_Albedo_Band_Mandatory_Quality_Band2").eq(0);
var mask3 = image.select("BRDF_Albedo_Band_Mandatory_Quality_Band3").eq(0);
var mask4 = image.select("BRDF_Albedo_Band_Mandatory_Quality_Band4").eq(0);
var mask5 = image.select("BRDF_Albedo_Band_Mandatory_Quality_Band5").eq(0);
var mask6 = image.select("BRDF_Albedo_Band_Mandatory_Quality_Band6").eq(0);
var mask7 = image.select("BRDF_Albedo_Band_Mandatory_Quality_Band7").eq(0);
return image.updateMask(mask1).updateMask(mask2).updateMask(mask3).updateMask(mask4)
.updateMask(mask5).updateMask(mask6).updateMask(mask7);
};
// Preparing imagery for PCA
var PCA = function(image){
var image = image.select(['Nadir_Reflectance_Band1','Nadir_Reflectance_Band2',
'Nadir_Reflectance_Band3','Nadir_Reflectance_Band4',
'Nadir_Reflectance_Band5','Nadir_Reflectance_Band6',
'Nadir_Reflectance_Band7']);
var orig = image;
var region = Extent;
var scale = 500;
var bandNames = ['Nadir_Reflectance_Band1','Nadir_Reflectance_Band2',
'Nadir_Reflectance_Band3','Nadir_Reflectance_Band4','Nadir_Reflectance_Band5',
'Nadir_Reflectance_Band6','Nadir_Reflectance_Band7'];
var meanDict = image.reduceRegion({
reducer: ee.Reducer.mean(),
geometry: region,
scale: scale,
maxPixels: 1e9
});
var means = ee.Image.constant(meanDict.values(bandNames));
var centered = image.subtract(means);
var getNewBandNames = function(prefix) {
var seq = ee.List.sequence(1, 7);
return seq.map(function(b) {
return ee.String(prefix).cat(ee.Number(b).int());
});
};
// PCA function
var getPrincipalComponents = function(centered, scale, region) {
var arrays = centered.toArray();
var covar = arrays.reduceRegion({
reducer: ee.Reducer.centeredCovariance(),
geometry: region,
scale: scale,
maxPixels: 1e9
});
var covarArray = ee.Array(covar.get('array'));
var eigens = covarArray.eigen();
var eigenValues = eigens.slice(1, 0, 1);
var eigenVectors = eigens.slice(1, 1);
var arrayImage = arrays.toArray(1);
var principalComponents = ee.Image(eigenVectors).matrixMultiply(arrayImage);
var sdImage = ee.Image(eigenValues.sqrt())
.arrayProject([0]).arrayFlatten([getNewBandNames('sd')]);
return principalComponents.arrayProject([0])
.arrayFlatten([getNewBandNames('pc')])
.divide(sdImage);
};
var pcImage = getPrincipalComponents(centered, scale, region);
return ee.Image(image.addBands(pcImage));
};
var modisColClip = modisCol
.map(function(image){return(image.clip(Extent))})
.map(filterqa)
.map(PCA)
.sort('system:time_start');
print("modis",modisColClip);
This code produces a error due to the masking of pixels. How can I change this? I have tried to swap around the order of functions to map, but I don't want to conduct a PCA using QA bands, and if I ignore the QA bands, the filter function fails because there is no QA bands.
Any idea?