在我们进行PCA进行分析之外,有时候想加载平方根的结果,但是显示无法正常展示,我们这里可以用一个绝对值来实现正常影像的加载

Srqt: Tile error: Array: Max (NaN) cannot be less than min (NaN).

对于在计算 PCA 时遇到此问题的人,我发现“数组:最大值(NaN)不能小于最小值(NaN)”错误的根本原因是负特征值。在某些情况下,您最终会得到非常非常小的负数(例如 -1e-13)并且调用它的 sqrt() 会导致此错误。据我了解,当您具有高度相关的输入波段并且最后几个特征值最终非常接近 0 时,就会发生这些情况。 

一个简单的解决方法是在求平方根之前对特征值调用 abs()。例如
var sdImage = ee.Image(eigenValues.abs(). sqrt())

 

代码:

// 一个演示错误的最小例子
// 阵列。最大(NaN)不能小于最小(NaN)。

// 运行脚本并检查任何像素以查看错误
// 当我们在有负数的数组上调用sqrt()时,就会发生这个错误。

var image = ee.Image("users/ujavalgandhi/temp/aerial_photo_clipped");
var geometry = image.geometry();
Map.addLayer(image, {}, 'Image');
Map.centerObject(image);

var projection = image.projection();
var scale = projection.nominalScale();

var texture = image.glcmTexture({size:5});
Map.addLayer(texture, {}, 'Texture')
var pca = PCA(texture).select(['pc1', 'pc2', 'pc3'])
Map.addLayer(pca, {}, 'PCA');

  
//************************************************************************** 
// 计算主成分的函数
// Code adapted from https://developers.google.com/earth-engine/guides/arrays_eigen_analysis
//************************************************************************** 
function PCA(maskedImage){
  var image = maskedImage.unmask()
  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: geometry,
    scale: scale,
    maxPixels: 1e10,
    tileScale: 16
  });
  print(meanDict)
  var means = ee.Image.constant(meanDict.values(bandNames));
  var centered = image.subtract(means);
  Map.addLayer(centered, {}, 'Centered')

  // 这个辅助函数返回一个新波段名称的列表。
  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());
    });
  };
  // 这个函数接受平均中心的图像、一个比例尺和一个要进行分析的区域。 
// 它将区域内的区域内的主成分(PC)作为一个新图像。
  var getPrincipalComponents = function(centered, scale, region) {
    // 将图像的波段折叠成每个像素的一维阵列。
    var arrays = centered.toArray();
    
    // 计算区域内各条带的协方差。
    var covar = arrays.reduceRegion({
      reducer: ee.Reducer.centeredCovariance(),
      geometry: geometry,
      scale: scale,
      maxPixels: 1e10,
      tileScale: 16
    });

    //得到 "数组 "协方差结果,并将其转换为一个数组。
    // 这代表了该区域内的带与带之间的协方差。
    var covarArray = ee.Array(covar.get('array'));
    Map.addLayer(ee.Image(covarArray), {}, 'Covar')
    // 进行特征分析,将数值和向量切开。
    var eigens = covarArray.eigen();

    // 这是一个P长度的特征值向量。
    var eigenValues = eigens.slice(1, 0, 1);
   
    // 这是一个PxP矩阵,行中有特征向量。
    var eigenVectors = eigens.slice(1, 1);

    // 将数组图像转换为二维数组,用于矩阵计算。
    var arrayImage = arrays.toArray(1);
    Map.addLayer(arrayImage, {}, 'Array image')

    // 左边的图像阵列与特征向量矩阵相乘。
    var principalComponents = ee.Image(eigenVectors).matrixMultiply(arrayImage);
    Map.addLayer(ee.Image(eigenValues), {}, 'eigen')
    Map.addLayer(ee.Image(eigenValues.sqrt()), {}, 'Srqt')
    Map.addLayer(ee.Image(eigenValues.abs().sqrt()), {}, 'Abs Srqt')

    // 将特征值的平方根变成P波段图像。
    var sdImage = ee.Image(eigenValues.abs().sqrt())
      .arrayProject([0]).arrayFlatten([getNewBandNames('sd')]);


    // 将PC变成P波段图像,按SD进行归一化处理。
    return principalComponents
      // 扔掉一个不需要的维度,[[]] ->[]。
      .arrayProject([0])
      // 使一个波段的阵列图像成为多波段的图像,[] -> 图像。
      .arrayFlatten([getNewBandNames('pc')])
      // 将PC按其SD归一化。
      .divide(sdImage);
  };
  var pcImage = getPrincipalComponents(centered, scale, geometry);
  return pcImage.mask(maskedImage.mask());
}

结果:

 

 

 

 

 

 函数:

matrixMultiply(image2)
返回图像1和图像2中每一对匹配频段的矩阵乘法A * B。如果图像1或图像2只有一个波段,那么它将被用来对付另一个图像中的所有波段。如果图像有相同数量的条带,但名字不一样,它们就按自然顺序成对使用。输出的带子以两个输入中较长的命名,或者如果它们的长度相等,则以图像1的顺序命名。输出像素的类型是输入类型的联合。

参数。
this:image1 (图像)。
左边操作数带的图像。

image2 (图像)。
右边的操作带所取的图像。

返回。图像

ee.Reducer.centeredCovariance()
创建一个还原器,将一些相同长度为N的一维数组还原成一个形状为NxN的协方差矩阵。警告:这个还原器要求数据已经被平均居中。

没有参数。
返回。减速器

glcmTexture(size, kernel, average)
从每个波段的每个像素周围的灰度共现矩阵计算出纹理指标。灰度共现矩阵是对图像中不同的像素亮度值(灰度)组合出现频率的一种列表。它计算值为X的像素在特定方向和距离上与值为Y的像素相邻的次数,然后从这个表格中得出统计数据。

这个实现计算Haralick提出的14个GLCM度量,以及Conners提出的4个额外度量。输入要求是整数值的。

如果定向平均开启,输出由每个输入带的18个带组成,如果没有,则由内核中每个方向对的18个带组成。

ASM:f1,角秒矩;测量重复对的数量

CONTRAST: f2, 对比度;测量图像的局部对比度

CORR:f3,相关度;测量像素对之间的相关度

VAR:f4,方差;测量灰度分布的分散程度

IDM:f5,反差矩;测量同质性

SAVG:f6,平均数之和

SVAR: f7, 总方差

SENT: f8, 熵的总和

ENT: f9, 熵。衡量灰度分布的随机性

DVAR: f10, 差分方差

DENT: f11, 差分熵

IMCORR1: f12, 信息测量的Corr. 1

IMCORR2: f13, Corr.的信息度量。2

MAXCORR: f14, 最大修正系数。系数。(不计算)

DISS:异质性

INERTIA: 惯性

SHADE: 聚类阴影

PROM: 聚类的突出性

更多信息可以在这两篇论文中找到。Haralick等,"Textural Features for Image Classification",http://doi.org/10.1109/TSMC.1973.4309314 和Conners等,Segmentation of a high-resolution urban scene using texture operators",http://doi.org/10.1016/0734-189X(84)90197-X。

参数。
this:image(图像)。
要计算纹理度量的图像。

size(整数,默认为1)。
在每个GLCM中包含的邻域的大小。

kernel(内核,默认为空)。
指明计算GLCM的x和y偏移的内核。除中心像素外,只要在同一方向和距离上还没有计算过GLCM,就会为内核中的每个非零像素计算GLCM。例如,如果东边和西边的任何一个或两个像素都被设置了,就只计算1个(水平)GLCM。内核从左到右、从上到下进行扫描。默认是一个3x3的正方形,产生4个GLCM,偏移量分别为(-1,-1)、(0,-1)、(1,-1)和(-1,0)。

average(布尔值,默认为true)。
如果为真,则对每个度量的方向带进行平均。

返回。图像

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐