Выполнение PCA для изображения поверх коллекции изображений в Google Earth Engine - PullRequest
1 голос
/ 17 июня 2020

Мне нужно выполнить PCA для каждого изображения над коллекцией изображений. Затем я хочу сохранить только ось 1 компонента Principle и добавить это как полосу к каждому изображению в моей коллекции изображений. В конечном итоге я хочу экспортировать файл .csv с местоположениями выборки GPS в заголовках строк и идентификатором изображения в виде заголовков столбцов со средним значением оси 1 компонента Принципа в качестве значений. Идея этого заключается в том, что я хочу использовать прокси (спектральную неоднородность) для дальнейшего статистического анализа в R.

Вот код, который у меня есть на данный момент:

//Create an test image to extract information to be used during PCA
var testImage =ee.Image('LANDSAT/LC08/C01/T1_SR/LC08_168080_20130407')
.select(['B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
        ['Blue', 'Green', 'Red', 'NIR', 'SWIR1', 'SWIR2']);

// Define variables for PCA
var region = Extent;
var scale = testImage.projection().nominalScale();
var bandNames = testImage.bandNames();
Map.centerObject(region);

// Function for performing PCA
function doPCA(image){
  // This code is from https://code.earthengine.google.com/7249153a8a0f5c79eaf562ed45a7adad
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);

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

// [START principal_components]
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 (pcImage);
}

// map PCA function over collection
var PCA = LandsatCol.map(function(image){return doPCA(image)});
print('pca', PCA);

Extent - это моя рентабельность инвестиций, а LandsatCol - это предварительно обработанная коллекция изображений. Код здесь вызывает ошибку при попытке сопоставить PCA с коллекцией изображений (вторая последняя строка кода). Ошибка гласит: «Массив: требуется параметр 'values'».

Есть предложения, как с этим бороться? И как добавить ось 1 компонента Principle в качестве полосы для каждого изображения в коллекции изображений?

1 Ответ

0 голосов
/ 18 июня 2020

Я разобрался. Ошибка «Массив: требуется параметр 'values'» была связана с разреженными матрицами, которые были результатом фильтрации, отсечения и уточнения областей внутри для выполнения PCA. Earth Engine не может работать с разреженными матрицами.

Вот рабочий код. LandsatCol - это моя коллекция предварительно обработанных изображений.

// Display AOI
var point = ee.Geometry.Point([30.2261, -29.458])
Map.centerObject(point,10);

// Prepairing imagery for PCA
var Preped = LandsatCol.map(function(image){
  var orig = image;
  var region = image.geometry();
  var scale = 30;
  var bandNames = ['Blue', 'Green', 'Red', 'NIR', 'SWIR1', 'SWIR2'];
  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, 6);
  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));
});
print("PCA imagery: ",Preped);

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...