时间序列谐波分析法(Harmonic Analysis of Time Series,HANTS)是平滑和滤波两种方法的综合,它能够充分利用遥感图像存在时间性和空间性的特点,将其空间上的分布规律和时间上的变化规律联系起来。时间序列谐波分解法进行影像重构时充分考虑了植被生长周期性和数据本身的双重特点,能够用代表不同生长周期的植被频率曲线重新构建时序NDVI影像,真实反映植被的周期性变化规律。时间序列谐波分析法是对快速傅立叶变换的改进,它不仅可以去除云污染点,而且对时序图像的要求不象快速傅立叶变换(FFT)那么严格,它可以是不等时间间隔的影像。因此同快速傅立叶变换相比,HANTS在频率和时间系列长度的选择上具有更大的灵活性。时间序列谐波分析法进行时序影像的重构也是基于云对NDVI的负值影响,但是它与最大值去除云污染的影响是两个完全不同的方法。它是首先通过傅立叶变换得到非零频率的振幅和相位,然后将所有的点进行最小二次方拟合。通过观测资料与拟合曲线的比较,对于那些明显低于拟合曲线的点被作为云污染点通过把它们的权重赋为零而拒绝参与曲线的拟合。建立在剩余点上进行新的曲线拟合,通过这种反复进行的迭代过程实现图像的重构。
HANTS的核心算法是最小二乘法和傅立叶变换,通过最小二乘法的迭代拟合去除时序NDVI值中受云污染影响较大的点,借助于傅立叶在时间域和频率域的正反变换实现曲线的分解和重构,从而达到时序遥感影像去云重构的目的。
var geometry = /* color: #0b4a8b */ee.Geometry.Polygon(
[[[111.87324431288253, 31.332281491028226],
[112.12592985975753, 29.384319886249077],
[113.19709685194503, 29.298127184229514],
[113.98261931288253, 30.15675555545011],
[113.31272952219614, 31.754288216446177]]]);
var reCollection = jianghan.filterBounds(geometry);
var outsideLine = ee.Image()
.toByte()
.paint({
featureCollection:reCollection,
color:0,
width:1
});
Map.centerObject(table3, 8);
Map.addLayer(outsideLine,{color:'000000'},"outsideLine");
var Sentinel2 = ee.ImageCollection('COPERNICUS/S2_SR');
// var roi = ee.Geometry.Point([112.7814535832465,30.090882792239622]);
var roi = ee.Feature(
ee.Geometry.Rectangle(112.73934073725333, 30.083476861006016, 112.74044580736746, 30.083880697610432),
{label: 'Shrimp_rice_field'});
// Map.centerObject(roi, 10);
使用此函数为计算NDVI,并把NDVI、time和constant变量添加到 Sentinel -2 图像中
// 此字段包含以毫秒为单位的UNIX时间
var timeField = 'system:time_start';
// 计算NDVI
var addVariables = function(image) {
// 计算自纪元以来的小数年时间
var date = ee.Date(image.get(timeField));
var years = date.difference(ee.Date('1970-01-01'), 'year');
// 返回添加了波段的图像
return image
// 添加NDVI波段
.addBands(image.normalizedDifference(['B8', 'B4']).rename('NDVI')).float()
// 添加time波段
.addBands(ee.Image(years).rename('t').float())
// 添加constant波段
.addBands(ee.Image.constant(1));
};
// 去除云,添加变量并过滤到感兴趣的区域。
var filteredLandsat = Sentinel2
.filterBounds(jianghan)
.filterMetadata('CLOUDY_PIXEL_PERCENTAGE',"less_than",30)
.filterDate('2019-02-23', '2022-12-31')
.map(addVariables)
.map(function(image) {
var edge = image.lt(-30.0);
var maskedImage = image.mask().and(edge.not());
return image.updateMask(maskedImage).clip(jianghan);
})
// .map(maskS2clouds)
;
print('filteredLandsat',filteredLandsat);
// Name of the dependent variable.
var dependent = ee.String('NDVI');
// Use these independent variables in the harmonic regression.
var harmonicIndependents = ee.List(['constant', 't', 'cos', 'sin']);
// Add harmonic terms as new image bands.
var harmonicLandsat = filteredLandsat.map(function(image) {
var timeRadians = image.select('t').multiply(2 * Math.PI);
var sinCoeff = timeRadians.sin();
var cosCoeff = timeRadians.cos();
var phase = cosCoeff.atan2(sinCoeff);
var amplitude = cosCoeff.hypot(sinCoeff);
return image
.addBands(sinCoeff.rename('cos'))
.addBands(cosCoeff.rename('sin'))
.addBands(phase.rename('phase'))//相位角
.addBands(amplitude.rename('amplitude'));//振幅;
});
// The output of the regression reduction is a 4x1 array image.
var harmonicTrend = harmonicLandsat
.select(harmonicIndependents.add(dependent))
.reduce(ee.Reducer.linearRegression(harmonicIndependents.length(), 1));
// Turn the array image into a multi-band image of coefficients.
var harmonicTrendCoefficients = harmonicTrend.select('coefficients')
.arrayProject([0])
.arrayFlatten([harmonicIndependents]);
print('harmonicTrendCoefficients',harmonicTrendCoefficients);
// Compute fitted values.
var fittedHarmonic = harmonicLandsat.map(function(image) {
return image.addBands(
image.select(harmonicIndependents)
.multiply(harmonicTrendCoefficients)
.reduce('sum')
.rename('fitted'))
;
});
print('fittedHarmonic',fittedHarmonic);
// Plot the fitted model and the original data at the ROI.
print(ui.Chart.image.series({
imageCollection:fittedHarmonic.select(['NDVI','fitted']),
region:roi,
xProperty: 'system:time_start',
reducer:ee.Reducer.mean(),
scale: 10
}) .setSeriesNames(['NDVI', 'HANTS'])
.setOptions({
title: 'Harmonic model: original and fitted values',
lineWidth: 1,
pointSize: 3,
}));
// Compute phase and amplitude.
var NDVI_phase = harmonicTrendCoefficients.select('cos').atan2(
harmonicTrendCoefficients.select('sin'));
var NDVI_amplitude = harmonicTrendCoefficients.select('cos').hypot(
harmonicTrendCoefficients.select('sin'));
var NDVI_Max = harmonicTrendCoefficients.select('cos').reduce('max');
// Use the HSV to RGB transform to display phase and amplitude
var rgb = NDVI_phase.unitScale(-Math.PI, Math.PI).addBands(
NDVI_amplitude.multiply(2.5)).addBands(
ee.Image(1)).hsvToRgb();
print('rgb',rgb);
Map.addLayer(rgb, {}, 'phase (hue), amplitude (saturation)');
参考文档:https://blog.sciencenet.cn/blog-466120-508372.html