0

I want to calculate PCA for the image Landsat 5 but i get this error User memory limit exceeded, I know it's because the memory but i don't know how can i resolve this problem.

This is my code :

var geometry = 
    /* color: #ffffff */
    /* displayProperties: [
      {
        "type": "rectangle"
      }
    ] */
    geometry;
var l5coll_1994 = ee.ImageCollection("LANDSAT/LT05/C02/T1_L2")
.filterMetadata('CLOUD_COVER','less_than', 1)
.filterBounds(geometry)
.filterDate('1994-01-01', '1994-12-31');
print('Number of images in collection:', l5coll_1994.size());
// Convert the image collection to a single multi-band image. Note that image ID
// ('system:index') is prepended to band names to delineate the source images.
var img = l5coll_1994.toBands();
print('Collection to bands', img);

Map.addLayer(img.clip(geometry), {bands: ['LT05_201035_19941220_SR_B3', 'LT05_201035_19941220_SR_B2', 'LT05_201035_19941220_SR_B1'],min:4150.84015306147, max: 16008.850707153584,gamma:0.7}, 'True Color');

// calcu PCA:
function PCA(maskedImage){
  var image = maskedImage.unmask()
  var scale = 30;
  var region = geometry;
  var bandNames = image.bandNames();
  // Mean center the data to enable a faster covariance reducer
  // and an SD stretch of the principal components.
  var meanDict = image.reduceRegion({
    reducer: ee.Reducer.mean(),
    geometry: region,
    scale: scale,
    maxPixels: 1e9,
    bestEffort: true,
    tileScale: 16
  });
  var means = ee.Image.constant(meanDict.values(bandNames));
  var centered = image.subtract(means);
  // This helper function returns a list of new band names.
  var getNewBandNames = function(prefix) {
    var seq = ee.List.sequence(1, bandNames.length());
    return seq.map(function(b) {
      return ee.String(prefix).cat(ee.Number(b).int());
    });
  };
  // This function accepts mean centered imagery, a scale and
  // a region in which to perform the analysis.  It returns the
  // Principal Components (PC) in the region as a new image.
  var getPrincipalComponents = function(centered, scale, region) {
    // Collapse the bands of the image into a 1D array per pixel.
    var arrays = centered.toArray();
    
    // Compute the covariance of the bands within the region.
    var covar = arrays.reduceRegion({
      reducer: ee.Reducer.centeredCovariance(),
      geometry: region,
      scale: scale,
      maxPixels: 1e11,
      bestEffort: true,
      tileScale: 16
    });

    // Get the 'array' covariance result and cast to an array.
    // This represents the band-to-band covariance within the region.
    var covarArray = ee.Array(covar.get('array'));

    // Perform an eigen analysis and slice apart the values and vectors.
    var eigens = covarArray.eigen();

    // This is a P-length vector of Eigenvalues.
    var eigenValues = eigens.slice(1, 0, 1);
    
    // Compute Percentage Variance of each component
    var eigenValuesList = eigenValues.toList().flatten()
    var total = eigenValuesList.reduce(ee.Reducer.sum())
    var percentageVariance = eigenValuesList.map(function(item) {
      return (ee.Number(item).divide(total)).multiply(100).format('%.2f')
    })
    // This will allow us to decide how many components capture
    // most of the variance in the input
    print('Percentage Variance of Each Component', percentageVariance)
    // This is a PxP matrix with eigenvectors in rows.
    var eigenVectors = eigens.slice(1, 1);
    // Convert the array image to 2D arrays for matrix computations.
    var arrayImage = arrays.toArray(1);

    // Left multiply the image array by the matrix of eigenvectors.
    var principalComponents = ee.Image(eigenVectors).matrixMultiply(arrayImage);

    // Turn the square roots of the Eigenvalues into a P-band image.
    var sdImage = ee.Image(eigenValues.sqrt())
      .arrayProject([0]).arrayFlatten([getNewBandNames('sd')]);

    // Turn the PCs into a P-band image, normalized by SD.
    return principalComponents
      // Throw out an an unneeded dimension, [[]] -> [].
      .arrayProject([0])
      // Make the one band array image a multi-band image, [] -> image.
      .arrayFlatten([getNewBandNames('pc')])
      // Normalize the PCs by their SDs.
      .divide(sdImage);
  };
  var pcImage = getPrincipalComponents(centered, scale, region);
  return pcImage.mask(maskedImage.mask());
}
var pca = PCA(img).select(['pc1', 'pc2', 'pc3']);
var composite = img.addBands(pca)  
Map.addLayer(pca.clip(geometry), {bands: ['pc1', 'pc2', 'pc3']}, 'pca')
Map.addLayer(composite.clip(geometry), {bands: ['LT05_201035_19941220_SR_B3', 'LT05_201035_19941220_SR_B2', 'LT05_201035_19941220_SR_B1'],min:7529,max:21920,gamma:1.4}, 'pca_Composite')

This is the link to the code:

https://code.earthengine.google.com/095114674df53496caad966b166906ea

Or someone knows how i can optimize the memory.

5
  • You are putting all imagery for a year into a single, multi-band, image and calculating PCA for that image. I've never seen that done before, and it sounds a bit strange to me. That doesn't necessarily mean that it's wrong though. Is this how you intended to do this? Not to generate a median composite and get the PCA for it, or to calculate the PCA for every image in the collection and combine the results somehow? Commented Aug 29, 2022 at 14:51
  • Please include a link to the Code Editor script (use the Get Link button), and make sure you have shared all assets used in the script. How expensive this is to calculate depends very much on the size of your region and it's missing in your code snippet. Commented Aug 29, 2022 at 14:53
  • Yes i was searching to calculate the PCA for a year into a single image.
    – Hafsa
    Commented Aug 29, 2022 at 17:48
  • honestly i don't know it's true or not but i think it's logical .
    – Hafsa
    Commented Aug 29, 2022 at 17:52
  • Please if you know something about it ,thanks for sharing it with me.
    – Hafsa
    Commented Aug 29, 2022 at 17:56

1 Answer 1

1

If you run it with the profiler you will see that the calls to ee.Image.arrayProject are the memory hog. One approach is to try to flatten the array without projecting (assign labels for 2 dimensions). The other thing that you should do (and works in this case) is to not include all (12!) of the QA bands in the PCA.

// SELECT ONLY THE REFLECTANCE AND THERMAL BANDS.
var img = l5coll_1994.select('SR_B.').toBands();

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.