要求:在GEE平台上从1984年到2025年Landsat遥感数据用NDWI指数结合大津法OTUS阈值提取三峡水体面积然后根据面积反演水位
问题:在GEE平台上运行但出现报错不知道怎么纠正

// 1. 定义研究区 (Region of Interest)
// 请使用GEE自带的几何工具绘制您的湖泊/水库边界,并命名为 roi
var roi = ee.Geometry.Polygon([
[[116.0, 39.0],[116.5, 39.0], [116.5, 39.5],[116.0, 39.5]]
]);
Map.centerObject(roi, 10);
Map.addLayer(roi, {color: 'red'}, 'ROI', false);
// 2. 时间范围定义
var startYear = 1984;
var endYear = 2025;
var years = ee.List.sequence(startYear, endYear);
// 3. 大津法 (Otsu) 动态阈值计算函数
// 该函数通过直方图寻找类间方差最大的阈值
function otsu(histogram) {
var counts = ee.Array(ee.Dictionary(histogram).get('histogram'));
var means = ee.Array(ee.Dictionary(histogram).get('bucketMeans'));
var size = counts.length().get([0]);
var total = counts.reduce(ee.Reducer.sum(), [0]).get([0]);
var sum = means.multiply(counts).reduce(ee.Reducer.sum(), [0]).get([0]);
var mean = sum.divide(total);
var indices = ee.List.sequence(1, size).map(function(i) {
var aCounts = counts.slice(0, 0, i);
var aMeans = means.slice(0, 0, i);
var aSize = aCounts.reduce(ee.Reducer.sum(), [0]).get([0]);
var aMean = aMeans.multiply(aCounts).reduce(ee.Reducer.sum(), [0]).get([0]).divide(aSize);
var bSize = total.subtract(aSize);
var bMean = sum.subtract(aSize.multiply(aMean)).divide(bSize);
return aSize.multiply(bSize).multiply(aMean.subtract(bMean)).multiply(aMean.subtract(bMean));
});
return means.sort(indices).get([-1]);
}
// 4. Landsat 数据去云与NDWI计算函数
function getLandsatWater(year) {
var startDate = ee.Date.fromYMD(year, 1, 1);
var endDate = ee.Date.fromYMD(year, 12, 31);
// 合并 Landsat 5, 7, 8, 9 表面反射率数据
var l5 = ee.ImageCollection('LANDSAT/LT05/C02/T1_L2')
.filterBounds(roi).filterDate(startDate, endDate)
.map(function(img){ return img.rename(['B1','B2','B3','B4','B5','B6','B7','QA_PIXEL', 'QA_RADSAT', 'QA_AEROSOL', 'SR_ATMOS_OPACITY', 'SR_CLOUD_QA', 'ST_B6', 'ST_QA', 'ST_CDAD', 'ST_EMIS', 'ST_EMSD', 'ST_TRAD', 'ST_URAD', 'ST_ATRAN']).set('system:time_start', img.get('system:time_start')); });
var l7 = ee.ImageCollection('LANDSAT/LE07/C02/T1_L2')
.filterBounds(roi).filterDate(startDate, endDate)
.map(function(img){ return img.rename(['B1','B2','B3','B4','B5','B6','B7','B8','QA_PIXEL', 'QA_RADSAT', 'QA_AEROSOL', 'SR_ATMOS_OPACITY', 'SR_CLOUD_QA', 'ST_B6', 'ST_QA', 'ST_CDAD', 'ST_EMIS', 'ST_EMSD', 'ST_TRAD', 'ST_URAD', 'ST_ATRAN']).set('system:time_start', img.get('system:time_start')); });
var l8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2')
.filterBounds(roi).filterDate(startDate, endDate)
.map(function(img){ return img.rename(['B0','B1','B2','B3','B4','B5','B6','B7','B8','B9','B10','B11','QA_PIXEL', 'QA_RADSAT', 'QA_AEROSOL', 'ST_B10', 'ST_QA', 'ST_CDAD', 'ST_EMIS', 'ST_EMSD', 'ST_TRAD', 'ST_URAD', 'ST_ATRAN']).set('system:time_start', img.get('system:time_start')); });
var l9 = ee.ImageCollection('LANDSAT/LC09/C02/T1_L2')
.filterBounds(roi).filterDate(startDate, endDate)
.map(function(img){ return img.rename(['B0','B1','B2','B3','B4','B5','B6','B7','B8','B9','B10','B11','QA_PIXEL', 'QA_RADSAT', 'QA_AEROSOL', 'ST_B10', 'ST_QA', 'ST_CDAD', 'ST_EMIS', 'ST_EMSD', 'ST_TRAD', 'ST_URAD', 'ST_ATRAN']).set('system:time_start', img.get('system:time_start')); });
// 去云掩膜处理 (基于QA_PIXEL)
var maskClouds = function(image) {
var qa = image.select('QA_PIXEL');
var cloudBitMask = 1 << 3;
var cloudShadowBitMask = 1 << 4;
var mask = qa.bitwiseAnd(cloudBitMask).eq(0)
.and(qa.bitwiseAnd(cloudShadowBitMask).eq(0));
return image.updateMask(mask);
};
var merged = l5.merge(l7).merge(l8).merge(l9).map(maskClouds);
// 计算NDWI: (Green - NIR) / (Green + NIR)
// L5/7: Green=B2, NIR=B4; L8/9: Green=B3, NIR=B5
var withNDWI = merged.map(function(img) {
// 这里做了一个简单的波段判断处理,实际建议将波段名称统一重命名为 Green, NIR 等
var isL89 = img.bandNames().contains('B11');
var green = ee.Algorithms.If(isL89, img.select('B3'), img.select('B2'));
var nir = ee.Algorithms.If(isL89, img.select('B5'), img.select('B4'));
var ndwi = ee.Image(green).subtract(ee.Image(nir))
.divide(ee.Image(green).add(ee.Image(nir))).rename('NDWI');
return ndwi.set('system:time_start', img.get('system:time_start'));
});
// 使用年度中位数合成以减少季节波动和噪声
var annualNDWI = withNDWI.median().clip(roi);
// 生成直方图计算Otsu阈值
var histogram = annualNDWI.reduceRegion({
reducer: ee.Reducer.histogram(255, 2),
geometry: roi,
scale: 30,
maxPixels: 1e9
}).get('NDWI');
// 错误处理:如果没有有效像素,返回阈值 0
var threshold = ee.Algorithms.If(histogram, otsu(histogram), 0);
// 提取水体并计算面积 (平方公里)
var waterMask = annualNDWI.gt(ee.Number(threshold));
var waterArea = waterMask.multiply(ee.Image.pixelArea())
.reduceRegion({
reducer: ee.Reducer.sum(),
geometry: roi,
scale: 30,
maxPixels: 1e9
}).get('NDWI'); // 对应面积(平方米)
var areaKm2 = ee.Number(waterArea).divide(1e6); // 转换为平方公里
// 5. 水位反演 (核心经验公式占位符)
// 假设根据实测数据拟合得到的 水位(H) 与 面积(A) 的经验关系为: H = a * A^2 + b * A + c
// !!!请替换为您研究区的实际拟合参数!!!
var a = 0.005;
var b = 0.2;
var c = 105.0; // 基础水位高程
var estimatedWaterLevel = areaKm2.pow(2).multiply(a)
.add(areaKm2.multiply(b))
.add(c);
return ee.Feature(null, {
'Year': year,
'Otsu_Threshold': threshold,
'Water_Area_km2': areaKm2,
'Estimated_Level_m': estimatedWaterLevel
});
}
// 6. 遍历年份并获取结果
var yearlyResults = ee.FeatureCollection(years.map(getLandsatWater));
// 过滤掉因为影像缺失导致的空白数据 (如面积为0)
var validResults = yearlyResults.filter(ee.Filter.gt('Water_Area_km2', 0));
print('年度水体面积与水位反演结果:', validResults);
// 7. 导出数据为 CSV 格式至 Google Drive
Export.table.toDrive({
collection: validResults,
description: 'Water_Area_and_Level_1984_2025',
fileFormat: 'CSV',
selectors:['Year', 'Otsu_Threshold', 'Water_Area_km2', 'Estimated_Level_m']
});
// 8. 在控制台绘制面积折线图
var areaChart = ui.Chart.feature.byFeature(validResults, 'Year',['Water_Area_km2'])
.setOptions({
title: '1984-2025年水体面积变化趋势',
hAxis: {title: '年份', format: '####'},
vAxis: {title: '面积 (km²)'},
lineWidth: 2,
pointSize: 4
});
print(areaChart);
// 9. 在控制台绘制反演水位折线图
var levelChart = ui.Chart.feature.byFeature(validResults, 'Year',['Estimated_Level_m'])
.setOptions({
title: '1984-2025年反演水位变化趋势',
hAxis: {title: '年份', format: '####'},
vAxis: {title: '水位高程 (m)'},
colors: ['red'],
lineWidth: 2,
pointSize: 4
});
print(levelChart);