D. Divide and Sum (组合数、思维)

本文介绍了一种利用组合数学原理解决特定数组中元素最大差值的问题,并通过C++代码实现了解决方案。通过对数组进行排序并计算特定位置元素的差值,结合组合数的计算方法,有效地解决了该问题。

添加链接描述

对于任意分组可以发现其实差值是一样的,将绝对值拆开,会发现都是后面n个大的-前面n的小的。

看例子 a1 a2 a3 a4 a5 b1 b2 b3 b4 b5 (已按大小排序)

假设对于第一组 取了前面3个,后面2个,然后其从很小到大排序,后面一组只可能是取前面2个,后面3个,从大到小排序。那么对于第一组的前3个(顺序)与后面一组的前3个(逆序),必然是第一组的前三个都是a,后面一组的前三个都是b,然后对于第一组后两个,和后一组后两个,第一组后两个必然是b,后一组后两个必然是a。将绝对值去掉一组的差值就等于b1+b2+b3+b4+b5-a1-a2-a3-a4-a5,所有情况都是如此,将上例3化为k,2化为n-k就是普遍情况。然后总共有从2n个取出n个的情况,相乘即可。

#include<iostream>
#include<algorithm>
#define FAST ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
typedef long long ll;
const int Max = 1e6 + 5;
ll lst[Max];
ll Mod = 998244353;

ll f[Max];
ll qpow(ll a, ll b) {
	ll ans = 1, base = a;
	while (b) {
		if (b & 1) ans = ans * base % Mod;
		base = base * base % Mod;
		b >>= 1;
	}
	return ans;
}
void init() {
	f[0] = 1;
	for (int i = 1;i <= 1e6;i++) {
		f[i] = f[i - 1] * i % Mod;
	}
}
ll cal(ll n, ll m) {
	if (n < m) return 0;
	return 1ll * f[n] * qpow(f[m], Mod - 2) % Mod * qpow(f[n - m], Mod - 2) % Mod;
}

int main()
{
	ll n;cin >> n;
	init();
	for (int i = 1;i <= 2*n;i++)cin >> lst[i];
	ll ans = 0;
	sort(lst + 1, lst + 1 + 2*n);
	for (int i = 1;i <= n;i++)
	{
		ans += lst[2 * n - i + 1] - lst[i];
	}
	ans = (ans % Mod * cal(n * 2, n)) % Mod;
	cout << ans << endl;
}
// ================= 1. 基础配置与数据源 ================= var CHIRPS = ee.ImageCollection("UCSB-CHG/CHIRPS/PENTAD"), soilData = ee.Image("OpenLandMap/SOL/SOL_TEXTURE-CLASS_USDA-TT_M/v02"), DEM = ee.Image("USGS/SRTMGL1_003"), aoi = ee.FeatureCollection("projects/ee-20241200080/assets/xiangjiang"); var analysisYear = 2020; var targetScale = 250; var exportRootFolder = "Lishui_" + analysisYear; var factorFolder = "RUSLE_Factors_Lishui"; var modulusFolder = "Erosion_Modulus_Lishui"; Map.centerObject(aoi, 9); Map.addLayer(aoi, {color: &#39;FF0000&#39;, fillColor: &#39;00000000&#39;}, &#39;澧水流域边界&#39;); var areaHectares = ee.Image.pixelArea().divide(10000).rename(&#39;area_ha&#39;); // ================= 2. 先计算所有RUSLE因子 ================= // K因子计算 function calculateK_Corrected(soilData, aoi) { var soilClip = soilData.clip(aoi); var K = soilClip.expression( "b(&#39;b0&#39;) == 1 ? 0.035 : b(&#39;b0&#39;) == 2 ? 0.040 : " + "b(&#39;b0&#39;) == 3 ? 0.045 : b(&#39;b0&#39;) == 4 ? 0.050 : " + "b(&#39;b0&#39;) == 5 ? 0.035 : b(&#39;b0&#39;) == 6 ? 0.048 : " + "b(&#39;b0&#39;) == 7 ? 0.055 : b(&#39;b0&#39;) == 8 ? 0.055 : " + "b(&#39;b0&#39;) == 9 ? 0.050 : b(&#39;b0&#39;) == 10 ? 0.025 : " + "b(&#39;b0&#39;) == 11 ? 0.010 : 0.04", {&#39;b0&#39;: soilClip.select(&#39;b0&#39;)} ).rename(&#39;K&#39;); return K.clip(aoi).unmask(0.045); } var K = calculateK_Corrected(soilData, aoi); // ================= R 因子计算(修正版 - 使用PENTAD数据正确聚合) ================= var months = ee.List.sequence(1, 12); var monthlyR = months.map(function(month) { month = ee.Number(month); var startDate = ee.Date.fromYMD(analysisYear, month, 1); var endDate = startDate.advance(1, &#39;month&#39;); // 使用PENTAD数据,但正确聚合为月数据 var monthlyPrecip = CHIRPS.filterDate(startDate, endDate) .select(&#39;precipitation&#39;) .sum() // 将候数据累加为月降雨量 .clip(aoi); // 章文波公式 var Ri = monthlyPrecip.expression( &#39;0.0585 * pow(P, 1.56)&#39;, { &#39;P&#39;: monthlyPrecip } ).rename(&#39;R&#39;); return Ri.set(&#39;month&#39;, month); }); var R_monthly = ee.ImageCollection(monthlyR); var R = R_monthly.sum().rename(&#39;R&#39;); // LS因子计算 var demClip = DEM.clip(aoi).resample(&#39;bilinear&#39;) .reproject({crs: &#39;EPSG:4326&#39;, scale: targetScale}); var slopeDeg = ee.Terrain.slope(demClip); var slopeRad = slopeDeg.multiply(Math.PI).divide(180); var flowAcc = ee.Image("WWF/HydroSHEDS/15ACC").clip(aoi) .resample(&#39;bilinear&#39;).reproject({crs: &#39;EPSG:4326&#39;, scale: targetScale}); var flowArea = flowAcc.multiply(ee.Number(targetScale).pow(2)); var slopeLength = flowArea.sqrt().min(300); var mExp = slopeRad.expression( "slope < 0.05 ? 0.2 : slope < 0.10 ? 0.3 : slope < 0.15 ? 0.4 : slope < 0.25 ? 0.5 : 0.6", {&#39;slope&#39;: slopeRad} ); var L = slopeLength.divide(22.13).pow(mExp).rename(&#39;L&#39;).unmask(1); var S = slopeRad.expression( "slope < 0.05 ? 10.8 * sin(slope) + 0.03 : " + "slope < 0.10 ? 16.8 * sin(slope) - 0.30 : " + "slope < 0.15 ? 21.9 * sin(slope) - 0.70 : " + "slope < 0.25 ? 31.6 * sin(slope) - 1.50 : " + "45.2 * sin(slope) - 2.50", {&#39;slope&#39;: slopeRad} ).rename(&#39;S&#39;).unmask(0.05); var LS = L.multiply(S).rename(&#39;LS&#39;) .updateMask(L.gt(0).and(S.gt(0))) .clip(aoi).unmask(0.1); // C因子计算 - 优化参数 var modisLulc = ee.ImageCollection("MODIS/006/MCD12Q1") .filterDate(ee.Date.fromYMD(analysisYear, 1, 1), ee.Date.fromYMD(analysisYear, 12, 31)) .first().select(&#39;LC_Type1&#39;).clip(aoi) .resample(&#39;bilinear&#39;).reproject({crs: &#39;EPSG:4326&#39;, scale: targetScale}); var modisNDVI = ee.ImageCollection(&#39;MODIS/006/MOD13Q1&#39;) .filterDate(ee.Date.fromYMD(analysisYear, 1, 1), ee.Date.fromYMD(analysisYear, 12, 31)) .filterBounds(aoi).select(&#39;NDVI&#39;); var monthlyC = ee.List.sequence(1, 12).map(function(month) { month = ee.Number(month); var monthStart = ee.Date.fromYMD(analysisYear, month, 1); var monthEnd = monthStart.advance(1, &#39;month&#39;); var monthNdviCol = modisNDVI.filterDate(monthStart, monthEnd); var monthNdvi = ee.Algorithms.If( monthNdviCol.size().gt(0), monthNdviCol.mean().clip(aoi), modisNDVI.filterDate(monthStart.advance(-1, &#39;month&#39;), monthEnd.advance(1, &#39;month&#39;)).mean().clip(aoi) ); monthNdvi = ee.Image(monthNdvi).multiply(0.0001).unmask(0.3); var FVC = monthNdvi.subtract(0.05).divide(0.75).clamp(0, 1); var cNdvi = FVC.expression("exp(-2.0 * fvc)", {&#39;fvc&#39;: FVC}).clamp(0.001, 1); // 调整系数 var cLulc = modisLulc.remap( ee.List.sequence(1, 17), [0.002, 0.003, 0.004, 0.006, 0.005, 0.020, 0.05, 0.10, 0.15, 0.22, 0.015, 0.45, 0.65, 0.35, 0.001, 0.001, 0.75], 0.35 ); return cNdvi.min(cLulc).clamp(0.001, 1).rename(&#39;C&#39;).set(&#39;month&#39;, month); }); var C_monthly = ee.ImageCollection(monthlyC); var C = C_monthly.mean().rename(&#39;C&#39;).clip(aoi).unmask(0.15); // 调整默认值 // P因子计算 - 优化参数 var lulcBaseP = ee.Dictionary({ 1: 0.02, 2: 0.02, 3: 0.02, 4: 0.02, 5: 0.02, 6: 0.035, 7: 0.09, 8: 0.15, 9: 0.22, 10: 0.28, 11: 0.001, 12: 0.65, 13: 0.90, 14: 0.45, 15: 0.001, 16: 0.001, 17: 0.65 }); var monthlyAdjust = ee.List([1.4, 1.35, 1.3, 1.25, 1.2, 1.1, 1.0, 0.9, 0.85, 0.8, 0.75, 0.7]); // 调整月度系数 var monthlyP = ee.List.sequence(1, 12).map(function(month) { month = ee.Number(month); var monthStart = ee.Date.fromYMD(analysisYear, month, 1); var monthEnd = monthStart.advance(1, &#39;month&#39;); var monthNdviCol = modisNDVI.filterDate(monthStart, monthEnd); var monthNdvi = ee.Algorithms.If( monthNdviCol.size().gt(0), monthNdviCol.mean().clip(aoi), modisNDVI.filterDate(monthStart.advance(-1, &#39;month&#39;), monthEnd.advance(1, &#39;month&#39;)).mean().clip(aoi) ); monthNdvi = ee.Image(monthNdvi).multiply(0.0001).unmask(0.3); var FVC = monthNdvi.subtract(0.05).divide(0.75).clamp(0, 1).pow(1.5); var baseP = modisLulc.remap(ee.List.sequence(1, 17), lulcBaseP.values(), 0.6); // 调整默认值 var adjust = ee.Image.constant(monthlyAdjust.get(month.subtract(1))); var slopeAdjustedP = baseP.multiply( ee.Image(1.0).expression( "1.0 * (slope < 8 ? 0.8 : slope < 20 ? 1.0 : slope < 35 ? 1.4 : 2.0)", {&#39;slope&#39;: slopeDeg} ) ); return slopeAdjustedP.multiply(adjust) .multiply(ee.Image(1).subtract(FVC).add(0.25)) // 调整系数 .clamp(0.15, 1.0) .rename(&#39;P&#39;) .set(&#39;month&#39;, month); }); var P_monthly = ee.ImageCollection(monthlyP); var P = P_monthly.mean().rename(&#39;P&#39;).clip(aoi).unmask(0.35); // 调整默认值 // ================= 3. 侵蚀模数计算 ================= function getMonthName(monthNum) { var monthNames = ee.List([&#39;一月&#39;, &#39;二月&#39;, &#39;三月&#39;, &#39;四月&#39;, &#39;五月&#39;, &#39;六月&#39;, &#39;七月&#39;, &#39;八月&#39;, &#39;九月&#39;, &#39;十月&#39;, &#39;十一月&#39;, &#39;十二月&#39;]); return ee.String(monthNames.get(ee.Number(monthNum).subtract(1))); } var K_250m = K.resample(&#39;bilinear&#39;).reproject({crs: &#39;EPSG:4326&#39;, scale: targetScale}); var LS_250m = LS.resample(&#39;bilinear&#39;).reproject({crs: &#39;EPSG:4326&#39;, scale: targetScale}); var monthlyErosionModulus = ee.List.sequence(1, 12).map(function(month) { month = ee.Number(month); var monthFilter = ee.Filter.eq(&#39;month&#39;, month); var monthR = R_monthly.filter(monthFilter).first().select(&#39;R&#39;); var monthC = C_monthly.filter(monthFilter).first(); var monthP = P_monthly.filter(monthFilter).first(); var monthR_fixed = monthR.unmask(0); var monthC_fixed = monthC.unmask(0.15); var monthP_fixed = monthP.unmask(0.35); var monthModulus = monthR_fixed.multiply(K_250m).multiply(LS_250m) .multiply(monthC_fixed).multiply(monthP_fixed).rename(&#39;Erosion_Modulus&#39;); var monthPixelModulus = monthModulus.divide(areaHectares).rename(&#39;Pixel_Erosion_Modulus&#39;); var monthResult = monthModulus.addBands(monthPixelModulus) .set(&#39;month&#39;, month).set(&#39;period_name&#39;, getMonthName(month)); return monthResult; }); var monthlyModulusCollection = ee.ImageCollection(monthlyErosionModulus); var annualModulus = monthlyModulusCollection.sum().select(&#39;Erosion_Modulus&#39;).rename(&#39;Annual_Modulus&#39;); var annualPixelModulus = annualModulus.divide(areaHectares).rename(&#39;Annual_Pixel_Modulus&#39;); // ================= 4. 可视化设置 ================= // 调整可视化范围以匹配新R因子计算 var modulusVis = { min: 0, max: 50, // 调整最大值 palette: [&#39;#f7fcf5&#39;,&#39;#e5f5e0&#39;,&#39;#c7e9c0&#39;,&#39;#a1d99b&#39;,&#39;#74c476&#39;,&#39;#41ab5d&#39;,&#39;#238b45&#39;,&#39;#006d2c&#39;,&#39;#00441b&#39;] }; var pixelModulusVis = { min: 0, max: 5, // 调整最大值 palette: [&#39;#f7fbff&#39;, &#39;#deebf7&#39;, &#39;#c6dbef&#39;, &#39;#9ecae1&#39;, &#39;#6baed6&#39;, &#39;#4292c6&#39;, &#39;#2171b5&#39;, &#39;#08519c&#39;, &#39;#08306b&#39;] }; // R因子可视化调整 var RVis = { min: 0, max: 2000, // 新公式下的合理范围 palette: [&#39;blue&#39;, &#39;cyan&#39;, &#39;green&#39;, &#39;yellow&#39;, &#39;red&#39;] }; // 侵蚀等级划分调整 - 只显示在区域内 var erosionLevels = annualModulus .where(annualModulus.lt(5), 1) .where(annualModulus.gte(5).and(annualModulus.lt(15)), 2) .where(annualModulus.gte(15).and(annualModulus.lt(30)), 3) .where(annualModulus.gte(30).and(annualModulus.lt(50)), 4) .where(annualModulus.gte(50).and(annualModulus.lt(100)), 5) .where(annualModulus.gte(100), 6) .rename(&#39;Erosion_Level&#39;) .clip(aoi); // 关键修改:只显示在区域内 var levelVis = { min: 1, max: 6, palette: [&#39;#d0f0fd&#39;,&#39;#b2df8a&#39;,&#39;#ffff99&#39;,&#39;#fdbf6f&#39;,&#39;#fb8072&#39;,&#39;#b2182b&#39;] }; // ================= 5. 完整的界面面板 ================= // 创建主控制面板 var controlPanel = ui.Panel({ style: { position: &#39;top-right&#39;, width: &#39;420px&#39;, // 增加宽度以容纳更多列 maxHeight: &#39;800px&#39;, stretch: &#39;vertical&#39; } }); // 标题 controlPanel.add(ui.Label(&#39;澧水流域土壤侵蚀分析系统 (湘江流域参数)&#39;, { fontWeight: &#39;bold&#39;, fontSize: &#39;18px&#39;, margin: &#39;0 0 10px 0&#39; })); // 年份选择器 var yearSelector = ui.Select({ items: [&#39;2000&#39;, &#39;2001&#39;, &#39;2002&#39;, &#39;2003&#39;, &#39;2004&#39;, &#39;2005&#39;], value: &#39;2001&#39;, onChange: function(year) { print(&#39;选择年份: &#39; + year); }, style: {width: &#39;100%&#39;, margin: &#39;5px 0&#39;} }); controlPanel.add(ui.Label(&#39;选择分析年份:&#39;, {margin: &#39;10px 0 5px 0&#39;})); controlPanel.add(yearSelector); // 参数信息面板 var paramPanel = ui.Panel({ style: { padding: &#39;8px&#39;, margin: &#39;8px 0&#39;, border: &#39;1px solid #4CAF50&#39;, backgroundColor: &#39;#f0f9f0&#39; } }); paramPanel.add(ui.Label(&#39;📊 参数设置说明&#39;, { fontWeight: &#39;bold&#39;, fontSize: &#39;12px&#39;, margin: &#39;0 0 5px 0&#39;, color: &#39;#2E7D32&#39; })); paramPanel.add(ui.Label(&#39;R因子范围: 2500-5000&#39;, {fontSize: &#39;11px&#39;, color: &#39;#555&#39;})); paramPanel.add(ui.Label(&#39;K因子范围: 0.001-0.07&#39;, {fontSize: &#39;11px&#39;, color: &#39;#555&#39;})); paramPanel.add(ui.Label(&#39;侵蚀模数范围: 0-100 t·hm⁻&sup2;·a⁻&sup1;&#39;, {fontSize: &#39;11px&#39;, color: &#39;#555&#39;})); controlPanel.add(paramPanel); // 月度因子统计面板 var monthlyFactorPanel = ui.Panel({ style: { padding: &#39;10px&#39;, margin: &#39;10px 0&#39;, border: &#39;1px solid #ddd&#39;, backgroundColor: &#39;#fff8f0&#39; } }); monthlyFactorPanel.add(ui.Label(&#39;月度因子统计&#39;, { fontWeight: &#39;bold&#39;, fontSize: &#39;14px&#39;, margin: &#39;0 0 8px 0&#39; })); // 创建月度因子表格的函数 function createMonthlyFactorTable() { // 清除现有内容(保留标题) while (monthlyFactorPanel.widgets().length > 1) { monthlyFactorPanel.remove(monthlyFactorPanel.widgets().get(1)); } var loadingLabel = ui.Label(&#39;正在计算月度因子数据...&#39;, {color: &#39;gray&#39;}); monthlyFactorPanel.add(loadingLabel); // 计算每个月的各因子平均值 var monthlyStats = ee.List.sequence(1, 12).map(function(month) { month = ee.Number(month); // 获取当月各因子 var monthFilter = ee.Filter.eq(&#39;month&#39;, month); var monthR = R_monthly.filter(monthFilter).first().select(&#39;R&#39;); var monthC = C_monthly.filter(monthFilter).first(); var monthP = P_monthly.filter(monthFilter).first(); var monthLS = LS; // LS因子不随月份变化 // 计算平均值 var rMean = monthR.reduceRegion({ reducer: ee.Reducer.mean(), geometry: aoi, scale: targetScale, maxPixels: 1e13 }).get(&#39;R&#39;); var cMean = monthC.reduceRegion({ reducer: ee.Reducer.mean(), geometry: aoi, scale: targetScale, maxPixels: 1e13 }).get(&#39;C&#39;); var pMean = monthP.reduceRegion({ reducer: ee.Reducer.mean(), geometry: aoi, scale: targetScale, maxPixels: 1e13 }).get(&#39;P&#39;); var kMean = K.reduceRegion({ reducer: ee.Reducer.mean(), geometry: aoi, scale: targetScale, maxPixels: 1e13 }).get(&#39;K&#39;); var lsMean = monthLS.reduceRegion({ reducer: ee.Reducer.mean(), geometry: aoi, scale: targetScale, maxPixels: 1e13 }).get(&#39;LS&#39;); // 计算当月侵蚀模数 var monthModulus = monthlyModulusCollection.filter(monthFilter).first(); var modulusMean = monthModulus.reduceRegion({ reducer: ee.Reducer.mean(), geometry: aoi, scale: targetScale, maxPixels: 1e13 }).get(&#39;Erosion_Modulus&#39;); return ee.Feature(null, { &#39;month&#39;: month, &#39;R&#39;: ee.Algorithms.If(ee.Algorithms.IsEqual(rMean, null), 0, rMean), &#39;C&#39;: ee.Algorithms.If(ee.Algorithms.IsEqual(cMean, null), 0.2, cMean), &#39;P&#39;: ee.Algorithms.If(ee.Algorithms.IsEqual(pMean, null), 0.4, pMean), &#39;K&#39;: ee.Algorithms.If(ee.Algorithms.IsEqual(kMean, null), 0.045, kMean), &#39;LS&#39;: ee.Algorithms.If(ee.Algorithms.IsEqual(lsMean, null), 1.0, lsMean), &#39;Modulus&#39;: ee.Algorithms.If(ee.Algorithms.IsEqual(modulusMean, null), 0, modulusMean), &#39;month_name&#39;: getMonthName(month) }); }); var monthlyStatsCollection = ee.FeatureCollection(monthlyStats); // 异步获取数据 monthlyStatsCollection.evaluate(function(stats) { monthlyFactorPanel.remove(loadingLabel); // 创建表格标题 var headerPanel = ui.Panel({ widgets: [ ui.Label(&#39;月份&#39;, {width: &#39;45px&#39;, fontWeight: &#39;bold&#39;, fontSize: &#39;10px&#39;}), ui.Label(&#39;R因子&#39;, {width: &#39;50px&#39;, fontWeight: &#39;bold&#39;, fontSize: &#39;10px&#39;}), ui.Label(&#39;C因子&#39;, {width: &#39;45px&#39;, fontWeight: &#39;bold&#39;, fontSize: &#39;10px&#39;}), ui.Label(&#39;P因子&#39;, {width: &#39;45px&#39;, fontWeight: &#39;bold&#39;, fontSize: &#39;10px&#39;}), ui.Label(&#39;K因子&#39;, {width: &#39;45px&#39;, fontWeight: &#39;bold&#39;, fontSize: &#39;10px&#39;}), ui.Label(&#39;LS因子&#39;, {width: &#39;45px&#39;, fontWeight: &#39;bold&#39;, fontSize: &#39;10px&#39;}), ui.Label(&#39;侵蚀模数&#39;, {width: &#39;60px&#39;, fontWeight: &#39;bold&#39;, fontSize: &#39;10px&#39;}) ], layout: ui.Panel.Layout.Flow(&#39;horizontal&#39;) }); monthlyFactorPanel.add(headerPanel); // 格式化数字函数 function formatNumber(value, decimals) { if (value === null || value === undefined) return &#39;-&#39;; var num = Number(value); return num.toFixed(decimals); } // 添加每月数据行 stats.features.forEach(function(feature, index) { var props = feature.properties; var rowPanel = ui.Panel({ widgets: [ ui.Label(props.month_name, {width: &#39;45px&#39;, fontSize: &#39;10px&#39;}), ui.Label(formatNumber(props.R, 0), {width: &#39;50px&#39;, fontSize: &#39;9px&#39;, color: &#39;#0066cc&#39;}), ui.Label(formatNumber(props.C, 3), {width: &#39;45px&#39;, fontSize: &#39;9px&#39;, color: &#39;#009900&#39;}), ui.Label(formatNumber(props.P, 3), {width: &#39;45px&#39;, fontSize: &#39;9px&#39;, color: &#39;#cc6600&#39;}), ui.Label(formatNumber(props.K, 4), {width: &#39;45px&#39;, fontSize: &#39;9px&#39;, color: &#39;#8B4513&#39;}), ui.Label(formatNumber(props.LS, 2), {width: &#39;45px&#39;, fontSize: &#39;9px&#39;, color: &#39;#FF4500&#39;}), ui.Label(formatNumber(props.Modulus, 1), {width: &#39;60px&#39;, fontSize: &#39;9px&#39;, color: &#39;#cc0000&#39;, fontWeight: &#39;bold&#39;}) ], layout: ui.Panel.Layout.Flow(&#39;horizontal&#39;) }); monthlyFactorPanel.add(rowPanel); }); // 添加年度平均值行 var annualR = R.reduceRegion({reducer: ee.Reducer.mean(), geometry: aoi, scale: targetScale, maxPixels: 1e13}).get(&#39;R&#39;); var annualC = C.reduceRegion({reducer: ee.Reducer.mean(), geometry: aoi, scale: targetScale, maxPixels: 1e13}).get(&#39;C&#39;); var annualP = P.reduceRegion({reducer: ee.Reducer.mean(), geometry: aoi, scale: targetScale, maxPixels: 1e13}).get(&#39;P&#39;); var annualK = K.reduceRegion({reducer: ee.Reducer.mean(), geometry: aoi, scale: targetScale, maxPixels: 1e13}).get(&#39;K&#39;); var annualLS = LS.reduceRegion({reducer: ee.Reducer.mean(), geometry: aoi, scale: targetScale, maxPixels: 1e13}).get(&#39;LS&#39;); var annualModulusMean = annualModulus.reduceRegion({reducer: ee.Reducer.mean(), geometry: aoi, scale: targetScale, maxPixels: 1e13}).get(&#39;Annual_Modulus&#39;); // 异步获取年度平均值 annualR.evaluate(function(rVal) { annualC.evaluate(function(cVal) { annualP.evaluate(function(pVal) { annualK.evaluate(function(kVal) { annualLS.evaluate(function(lsVal) { annualModulusMean.evaluate(function(mVal) { var summaryPanel = ui.Panel({ widgets: [ ui.Label(&#39;年度平均&#39;, {width: &#39;45px&#39;, fontSize: &#39;10px&#39;, fontWeight: &#39;bold&#39;}), ui.Label(formatNumber(rVal, 0), {width: &#39;50px&#39;, fontSize: &#39;9px&#39;, color: &#39;#0066cc&#39;, fontWeight: &#39;bold&#39;}), ui.Label(formatNumber(cVal, 3), {width: &#39;45px&#39;, fontSize: &#39;9px&#39;, color: &#39;#009900&#39;, fontWeight: &#39;bold&#39;}), ui.Label(formatNumber(pVal, 3), {width: &#39;45px&#39;, fontSize: &#39;9px&#39;, color: &#39;#cc6600&#39;, fontWeight: &#39;bold&#39;}), ui.Label(formatNumber(kVal, 4), {width: &#39;45px&#39;, fontSize: &#39;9px&#39;, color: &#39;#8B4513&#39;, fontWeight: &#39;bold&#39;}), ui.Label(formatNumber(lsVal, 2), {width: &#39;45px&#39;, fontSize: &#39;9px&#39;, color: &#39;#FF4500&#39;, fontWeight: &#39;bold&#39;}), ui.Label(formatNumber(mVal, 1), {width: &#39;60px&#39;, fontSize: &#39;9px&#39;, color: &#39;#cc0000&#39;, fontWeight: &#39;bold&#39;}) ], layout: ui.Panel.Layout.Flow(&#39;horizontal&#39;) }); monthlyFactorPanel.add(ui.Label(&#39;&#39;)); // 空行分隔 monthlyFactorPanel.add(summaryPanel); // 添加RUSLE公式说明 var formulaPanel = ui.Panel({ style: { padding: &#39;8px&#39;, margin: &#39;8px 0&#39;, border: &#39;1px solid #ddd&#39;, backgroundColor: &#39;#f8f8f8&#39; } }); formulaPanel.add(ui.Label(&#39;📐 RUSLE公式: A = R × K × LS × C × P&#39;, { fontWeight: &#39;bold&#39;, fontSize: &#39;11px&#39;, margin: &#39;0 0 4px 0&#39; })); formulaPanel.add(ui.Label(&#39;A: 土壤侵蚀模数 (t·hm⁻&sup2;·a⁻&sup1;)&#39;, {fontSize: &#39;10px&#39;, color: &#39;#555&#39;})); formulaPanel.add(ui.Label(&#39;R: 降雨侵蚀力因子&#39;, {fontSize: &#39;10px&#39;, color: &#39;#555&#39;})); formulaPanel.add(ui.Label(&#39;K: 土壤可蚀性因子&#39;, {fontSize: &#39;10px&#39;, color: &#39;#555&#39;})); formulaPanel.add(ui.Label(&#39;LS: 坡长坡度因子&#39;, {fontSize: &#39;10px&#39;, color: &#39;#555&#39;})); formulaPanel.add(ui.Label(&#39;C: 植被覆盖因子&#39;, {fontSize: &#39;10px&#39;, color: &#39;#555&#39;})); formulaPanel.add(ui.Label(&#39;P: 水土保持措施因子&#39;, {fontSize: &#39;10px&#39;, color: &#39;#555&#39;})); monthlyFactorPanel.add(formulaPanel); }); }); }); }); }); }); }); } // 月度因子详细分析按钮 var monthlyFactorButton = ui.Button({ label: &#39;显示月度因子详细数据&#39;, onClick: createMonthlyFactorTable, style: {margin: &#39;5px 0&#39;, width: &#39;100%&#39;, backgroundColor: &#39;#ff9800&#39;, color: &#39;white&#39;} }); monthlyFactorPanel.add(monthlyFactorButton); controlPanel.add(monthlyFactorPanel); // 图层控制面板 var layerControlPanel = ui.Panel({ style: { padding: &#39;10px&#39;, margin: &#39;10px 0&#39;, border: &#39;1px solid #ddd&#39;, backgroundColor: &#39;#f9f9f9&#39; } }); layerControlPanel.add(ui.Label(&#39;图层控制&#39;, { fontWeight: &#39;bold&#39;, fontSize: &#39;14px&#39;, margin: &#39;0 0 8px 0&#39; })); // 侵蚀模数图层控制 var erosionLayers = [ {name: &#39;年度侵蚀模数&#39;, layer: annualModulus, vis: modulusVis}, {name: &#39;像元侵蚀模数&#39;, layer: annualPixelModulus, vis: pixelModulusVis}, {name: &#39;侵蚀等级&#39;, layer: erosionLevels, vis: levelVis} ]; erosionLayers.forEach(function(layerInfo, index) { var checkbox = ui.Checkbox({ value: index === 0, onChange: function(checked) { if (checked) { Map.addLayer(layerInfo.layer, layerInfo.vis, layerInfo.name); } else { Map.layers().forEach(function(existingLayer, i) { if (existingLayer.getName() === layerInfo.name) { Map.remove(existingLayer); } }); } }, style: {margin: &#39;2px 5px&#39;} }); var label = ui.Label(layerInfo.name, {margin: &#39;2px 5px&#39;}); var row = ui.Panel({ widgets: [checkbox, label], layout: ui.Panel.Layout.Flow(&#39;horizontal&#39;) }); layerControlPanel.add(row); }); controlPanel.add(layerControlPanel); // 因子图层控制 var factorControlPanel = ui.Panel({ style: { padding: &#39;10px&#39;, margin: &#39;10px 0&#39;, border: &#39;1px solid #ddd&#39;, backgroundColor: &#39;#f9f9f9&#39; } }); factorControlPanel.add(ui.Label(&#39;因子图层&#39;, { fontWeight: &#39;bold&#39;, fontSize: &#39;14px&#39;, margin: &#39;0 0 8px 0&#39; })); var factorLayers = [ {name: &#39;R因子(降雨侵蚀力)&#39;, layer: R, vis: RVis}, {name: &#39;K因子(土壤可蚀性)&#39;, layer: K, vis: {min: 0, max: 0.07, palette: [&#39;white&#39;, &#39;lightbrown&#39;, &#39;brown&#39;, &#39;darkbrown&#39;]}}, {name: &#39;LS因子(地形)&#39;, layer: LS, vis: {min: 0, max: 25, palette: [&#39;white&#39;, &#39;lightgreen&#39;, &#39;green&#39;, &#39;yellow&#39;, &#39;orange&#39;, &#39;red&#39;]}}, {name: &#39;C因子(植被覆盖)&#39;, layer: C, vis: {min: 0, max: 1, palette: [&#39;darkgreen&#39;, &#39;green&#39;, &#39;yellow&#39;, &#39;red&#39;]}}, {name: &#39;P因子(水土保持)&#39;, layer: P, vis: {min: 0, max: 1, palette: [&#39;blue&#39;, &#39;cyan&#39;, &#39;yellow&#39;, &#39;red&#39;]}} ]; factorLayers.forEach(function(layerInfo) { var checkbox = ui.Checkbox({ value: false, onChange: function(checked) { if (checked) { Map.addLayer(layerInfo.layer, layerInfo.vis, layerInfo.name); } else { Map.layers().forEach(function(existingLayer, i) { if (existingLayer.getName() === layerInfo.name) { Map.remove(existingLayer); } }); } }, style: {margin: &#39;2px 5px&#39;} }); var label = ui.Label(layerInfo.name, {margin: &#39;2px 5px&#39;}); var row = ui.Panel({ widgets: [checkbox, label], layout: ui.Panel.Layout.Flow(&#39;horizontal&#39;) }); factorControlPanel.add(row); }); controlPanel.add(factorControlPanel); // 统计信息面板 var statsPanel = ui.Panel({ style: { padding: &#39;12px&#39;, margin: &#39;10px 0&#39;, border: &#39;1px solid #ccc&#39;, backgroundColor: &#39;#fff&#39; } }); statsPanel.add(ui.Label(&#39;年度统计结果&#39;, { fontWeight: &#39;bold&#39;, fontSize: &#39;16px&#39;, margin: &#39;0 0 10px 0&#39; })); // 更新统计信息的函数 function updateStatistics() { // 更新年度统计 updateAnnualStatistics(); // 更新月度因子表格 createMonthlyFactorTable(); } function updateAnnualStatistics() { // 清除现有统计内容(保留标题) while (statsPanel.widgets().length > 1) { statsPanel.remove(statsPanel.widgets().get(1)); } // 添加加载提示 var loadingLabel = ui.Label(&#39;正在计算统计信息...&#39;, {color: &#39;gray&#39;}); statsPanel.add(loadingLabel); // 侵蚀模数统计 var erosionStats = annualModulus.reduceRegion({ reducer: ee.Reducer.mean() .combine(ee.Reducer.min(), null, true) .combine(ee.Reducer.max(), null, true) .combine(ee.Reducer.median(), null, true), geometry: aoi, scale: targetScale, maxPixels: 1e13 }); // 各因子统计 var factorMeans = { R: R.reduceRegion({reducer: ee.Reducer.mean(), geometry: aoi, scale: targetScale, maxPixels: 1e13}).get(&#39;R&#39;), K: K.reduceRegion({reducer: ee.Reducer.mean(), geometry: aoi, scale: targetScale, maxPixels: 1e13}).get(&#39;K&#39;), LS: LS.reduceRegion({reducer: ee.Reducer.mean(), geometry: aoi, scale: targetScale, maxPixels: 1e13}).get(&#39;LS&#39;), C: C.reduceRegion({reducer: ee.Reducer.mean(), geometry: aoi, scale: targetScale, maxPixels: 1e13}).get(&#39;C&#39;), P: P.reduceRegion({reducer: ee.Reducer.mean(), geometry: aoi, scale: targetScale, maxPixels: 1e13}).get(&#39;P&#39;) }; // 使用evaluate异步获取结果 erosionStats.evaluate(function(erosionResult) { factorMeans.R.evaluate(function(rMean) { factorMeans.K.evaluate(function(kMean) { factorMeans.LS.evaluate(function(lsMean) { factorMeans.C.evaluate(function(cMean) { factorMeans.P.evaluate(function(pMean) { // 移除加载提示 statsPanel.remove(loadingLabel); function formatNumber(value, decimals) { if (value === null || value === undefined) return &#39;N/A&#39;; return Number(value).toFixed(decimals); } // 添加侵蚀模数统计 statsPanel.add(ui.Label(&#39;📊 侵蚀模数统计:&#39;, {fontWeight: &#39;bold&#39;, margin: &#39;8px 0 4px 0&#39;})); statsPanel.add(ui.Label(&#39; 平均值: &#39; + formatNumber(erosionResult.Annual_Modulus_mean, 1) + &#39; t·hm⁻&sup2;·a⁻&sup1;&#39;)); statsPanel.add(ui.Label(&#39; 最小值: &#39; + formatNumber(erosionResult.Annual_Modulus_min, 1) + &#39; t·hm⁻&sup2;·a⁻&sup1;&#39;)); statsPanel.add(ui.Label(&#39; 最大值: &#39; + formatNumber(erosionResult.Annual_Modulus_max, 1) + &#39; t·hm⁻&sup2;·a⁻&sup1;&#39;)); statsPanel.add(ui.Label(&#39; 中位数: &#39; + formatNumber(erosionResult.Annual_Modulus_median, 1) + &#39; t·hm⁻&sup2;·a⁻&sup1;&#39;)); // 添加各因子统计 statsPanel.add(ui.Label(&#39;🔬 各因子年度平均值:&#39;, {fontWeight: &#39;bold&#39;, margin: &#39;8px 0 4px 0&#39;})); statsPanel.add(ui.Label(&#39; R: &#39; + formatNumber(rMean, 0))); statsPanel.add(ui.Label(&#39; K: &#39; + formatNumber(kMean, 4))); statsPanel.add(ui.Label(&#39; LS: &#39; + formatNumber(lsMean, 2))); statsPanel.add(ui.Label(&#39; C: &#39; + formatNumber(cMean, 3))); statsPanel.add(ui.Label(&#39; P: &#39; + formatNumber(pMean, 3))); }); }); }); }); }); }); } // 添加更新统计按钮 var updateButton = ui.Button({ label: &#39;更新所有统计信息&#39;, onClick: updateStatistics, style: {margin: &#39;10px 0&#39;, width: &#39;100%&#39;} }); controlPanel.add(updateButton); controlPanel.add(statsPanel); // 时间序列图表面板 var chartPanel = ui.Panel({ style: { padding: &#39;10px&#39;, margin: &#39;10px 0&#39;, border: &#39;1px solid #ddd&#39; } }); chartPanel.add(ui.Label(&#39;时间序列分析&#39;, { fontWeight: &#39;bold&#39;, fontSize: &#39;14px&#39;, margin: &#39;0 0 8px 0&#39; })); // 月度侵蚀模数图表数据准备 var monthlyModulusStats = ee.List.sequence(1, 12).map(function(month) { month = ee.Number(month); var monthFilter = ee.Filter.eq(&#39;month&#39;, month); var monthImage = monthlyModulusCollection.filter(monthFilter).first(); var monthMeanModulus = monthImage.reduceRegion({ reducer: ee.Reducer.mean(), geometry: aoi, scale: targetScale, maxPixels: 1e13 }).get(&#39;Erosion_Modulus&#39;); monthMeanModulus = ee.Algorithms.If( ee.Algorithms.IsEqual(monthMeanModulus, null), 0, monthMeanModulus ); return ee.Feature(null, { &#39;month&#39;: month, &#39;modulus&#39;: ee.Number(monthMeanModulus), &#39;month_name&#39;: getMonthName(month) }); }); // 创建图表 var chartFeatures = ee.FeatureCollection(monthlyModulusStats); var modulusChart = ui.Chart.feature.byFeature({ features: chartFeatures, xProperty: &#39;month&#39;, yProperties: [&#39;modulus&#39;] }).setOptions({ title: analysisYear + &#39;年澧水流域月度土壤侵蚀模数&#39;, hAxis: {title: &#39;月份&#39;, gridlines: {count: 12}}, vAxis: {title: &#39;侵蚀模数 (t·hm⁻&sup2;·月⁻&sup1;)&#39;}, lineWidth: 3, pointSize: 5, series: {0: {color: &#39;#238b45&#39;}}, height: 200, chartArea: {width: &#39;85%&#39;, height: &#39;70%&#39;} }); // 将图表添加到面板 chartPanel.add(modulusChart); controlPanel.add(chartPanel); // 导出控制面板 var exportPanel = ui.Panel({ style: { padding: &#39;10px&#39;, margin: &#39;10px 0&#39;, border: &#39;1px solid #ddd&#39;, backgroundColor: &#39;#f0f8ff&#39; } }); exportPanel.add(ui.Label(&#39;数据导出&#39;, { fontWeight: &#39;bold&#39;, fontSize: &#39;14px&#39;, margin: &#39;0 0 8px 0&#39; })); var exportButton = ui.Button({ label: &#39;导出所有结果到Google Drive&#39;, onClick: function() { exportAllData(); var exportLabel = ui.Label({ value: &#39;✅ 导出任务已启动,请在Tasks面板查看进度&#39;, style: {color: &#39;green&#39;, margin: &#39;10px&#39;, backgroundColor: &#39;#f0fff0&#39;, padding: &#39;5px&#39;} }); controlPanel.add(exportLabel); setTimeout(function() { controlPanel.remove(exportLabel); }, 3000); }, style: {margin: &#39;5px 0&#39;, width: &#39;100%&#39;, backgroundColor: &#39;#4CAF50&#39;, color: &#39;white&#39;} }); exportPanel.add(exportButton); controlPanel.add(exportPanel); // 添加到地图 Map.add(controlPanel); // 初始化时更新统计信息 updateStatistics(); // ================= 6. 导出函数 ================= function exportAllData() { Export.image.toDrive({ image: annualModulus, description: &#39;Lishui_Annual_Erosion_Modulus_&#39; + analysisYear, folder: modulusFolder, scale: targetScale, region: aoi, maxPixels: 1e13, fileFormat: &#39;GeoTIFF&#39; }); Export.image.toDrive({ image: annualPixelModulus, description: &#39;Lishui_Annual_Pixel_Erosion_Modulus_&#39; + analysisYear, folder: modulusFolder, scale: targetScale, region: aoi, maxPixels: 1e13, fileFormat: &#39;GeoTIFF&#39; }); Export.image.toDrive({ image: erosionLevels, description: &#39;Lishui_Erosion_Levels_&#39; + analysisYear, folder: modulusFolder, scale: targetScale, region: aoi, maxPixels: 1e13, fileFormat: &#39;GeoTIFF&#39; }); for (var i = 0; i < 12; i++) { var month = i + 1; var monthImg = monthlyModulusCollection.filter(ee.Filter.eq(&#39;month&#39;, month)).first(); var monthCode = &#39;LS&#39; + analysisYear + &#39;_Month_&#39; + month; Export.image.toDrive({ image: monthImg.select(&#39;Pixel_Erosion_Modulus&#39;), description: monthCode, folder: exportRootFolder, scale: targetScale, region: aoi, maxPixels: 1e13, fileFormat: &#39;GeoTIFF&#39; }); } var factors = {&#39;R&#39;: R, &#39;K&#39;: K, &#39;LS&#39;: LS, &#39;C&#39;: C, &#39;P&#39;: P}; for (var factorName in factors) { Export.image.toDrive({ image: factors[factorName], description: &#39;Lishui_&#39; + factorName + &#39;_Factor_&#39; + analysisYear, folder: factorFolder, scale: targetScale, region: aoi, maxPixels: 1e13, fileFormat: &#39;GeoTIFF&#39; }); } print(&#39;✅ 所有导出任务已提交到Tasks面板&#39;); } // ================= 7. 图例和初始化 ================= // 侵蚀等级图例 var erosionLegend = ui.Panel({ style: { position: &#39;bottom-right&#39;, padding: &#39;8px 15px&#39;, backgroundColor: &#39;white&#39;, border: &#39;1px solid #ccc&#39; } }); erosionLegend.add(ui.Label(&#39;土壤侵蚀等级 (t·hm⁻&sup2;·a⁻&sup1;)&#39;, { fontWeight: &#39;bold&#39;, fontSize: &#39;14px&#39;, margin: &#39;0 0 6px 0&#39; })); var levelNames = [&#39;1: 微度侵蚀 (<5)&#39;, &#39;2: 轻度侵蚀 (5-15)&#39;, &#39;3: 中度侵蚀 (15-30)&#39;, &#39;4: 强度侵蚀 (30-50)&#39;, &#39;5: 极强度侵蚀 (50-100)&#39;, &#39;6: 剧烈侵蚀 (>100)&#39;]; var levelColors = [&#39;#d0f0fd&#39;, &#39;#b2df8a&#39;, &#39;#ffff99&#39;, &#39;#fdbf6f&#39;, &#39;#fb8072&#39;, &#39;#b2182b&#39;]; for (var i = 0; i < 6; i++) { var colorBox = ui.Label({style: {backgroundColor: levelColors[i], padding: &#39;8px&#39;, margin: &#39;0 0 4px 0&#39;, width: &#39;20px&#39;}}); var description = ui.Label({value: levelNames[i], style: {margin: &#39;0 0 4px 8px&#39;, fontSize: &#39;12px&#39;}}); var legendItem = ui.Panel({widgets: [colorBox, description], layout: ui.Panel.Layout.Flow(&#39;horizontal&#39;)}); erosionLegend.add(legendItem); } Map.add(erosionLegend); // 系统信息面板 - 更新R因子信息 var infoPanel = ui.Panel({ style: { position: &#39;bottom-left&#39;, padding: &#39;10px&#39;, margin: &#39;10px&#39;, backgroundColor: &#39;rgba(255,255,255,0.9)&#39;, border: &#39;1px solid #ccc&#39;, maxWidth: &#39;300px&#39; } }); infoPanel.add(ui.Label(&#39;系统信息&#39;, {fontWeight: &#39;bold&#39;, fontSize: &#39;14px&#39;, margin: &#39;0 0 8px 0&#39;})); infoPanel.add(ui.Label(&#39;🗓️ 分析年份: &#39; + analysisYear)); infoPanel.add(ui.Label(&#39;📐 空间分辨率: &#39; + targetScale + &#39;m&#39;)); infoPanel.add(ui.Label(&#39;📊 R因子公式: R = -8.12 + 0.562 × 降雨量&#39;)); infoPanel.add(ui.Label(&#39;🏔️ 流域特征: 山区地形复杂&#39;)); infoPanel.add(ui.Label(&#39;🌱 主要植被: 森林、农田&#39;)); infoPanel.add(ui.Label(&#39;🔍 侵蚀等级: 仅显示区域内&#39;)); Map.add(infoPanel); // 初始化显示 Map.addLayer(annualModulus, modulusVis, &#39;年度侵蚀模数&#39;); Map.addLayer(erosionLevels, levelVis, &#39;侵蚀等级&#39;); print(&#39;🎉 澧水流域土壤侵蚀分析系统已启动!(新R因子公式)&#39;); print(&#39;📍 R因子使用新公式: R = -8.12 + 0.562 × 降雨量&#39;); print(&#39;📊 侵蚀等级图层现在只显示在澧水流域区域内&#39;); print(&#39;💾 点击导出按钮保存结果&#39;); print(&#39;📈 点击"显示月度因子详细数据"查看每月各因子数值&#39;);对2000-2020年的数据进行mk检验并出图
最新发布
12-02
“// 定义研究区域和时间范围 var region = ee.FeatureCollection(&#39;projects/ee-yixuwei610/assets/hubei&#39;); var start2024 = &#39;2024-01-01&#39;; var end2024 = &#39;2024-12-31&#39;; var start2017 = &#39;2017-01-01&#39;; var end2017 = &#39;2017-12-31&#39;; // 加载2024年样本点 var samples2024 = ee.FeatureCollection("projects/ee-yixuwei610/assets/2024HBsamples") .filterBounds(region); // 哨兵2号数据预处理函数 function preprocessSentinel(image) { var qa = image.select(&#39;QA60&#39;); var cloudBitMask = 1 << 10; var cirrusBitMask = 1 << 11; var mask = qa.bitwiseAnd(cloudBitMask).eq(0) .and(qa.bitwiseAnd(cirrusBitMask).eq(0)); return image.updateMask(mask) .resample(&#39;bilinear&#39;) .select([&#39;B2&#39;,&#39;B3&#39;,&#39;B4&#39;,&#39;B5&#39;,&#39;B6&#39;,&#39;B7&#39;,&#39;B8&#39;,&#39;B11&#39;,&#39;B12&#39;]) .divide(10000); } // 获取2024年哨兵影像集 var sentinel2024 = ee.ImageCollection(&#39;COPERNICUS/S2_SR_HARMONIZED&#39;) .filterBounds(region) .filterDate(start2024, end2024) .map(preprocessSentinel) .median(); // 获取2017年哨兵影像集 var sentinel2017 = ee.ImageCollection(&#39;COPERNICUS/S2_SR_HARMONIZED&#39;) .filterBounds(region) .filterDate(start2017, end2017) .map(preprocessSentinel) .median(); // 定义波段列表 var bands = [&#39;B2&#39;,&#39;B3&#39;,&#39;B4&#39;,&#39;B5&#39;,&#39;B6&#39;,&#39;B7&#39;,&#39;B8&#39;,&#39;B11&#39;,&#39;B12&#39;]; // ==== 关键修复:确保值类型正确 ==== function safeSample(image, geom) { var sample = image.select(bands).sample(geom, 30); var defaultValues = bands.map(function(_) { return 0; }); // 确保返回数字类型字典 return ee.Dictionary( ee.Algorithms.If({ condition: sample.size().gt(0), trueCase: sample.first().toDictionary(), falseCase: ee.Dictionary.fromLists(bands, defaultValues) }) ); } // 光谱距离计算函数(修复值类型问题) function calculateSpectralDistances(feature) { var geom = feature.geometry(); // 获取2024年和2017年光谱值(确保为数字) var dict2024 = safeSample(sentinel2024, geom); var dict2017 = safeSample(sentinel2017, geom); // 创建光谱值数组(显式转换为数字) var arr2024 = ee.Array(ee.List(bands.map(function(band) { return ee.Number(dict2024.get(band)); // 关键修复:使用Number转换 }))); var arr2017 = ee.Array(ee.List(bands.map(function(band) { return ee.Number(dict2017.get(band)); // 关键修复:使用Number转换 }))); // 计算SAD(光谱角距离) var dotProduct = arr2024.multiply(arr2017).reduce(&#39;sum&#39;, [0]); var norm2024 = arr2024.pow(2).reduce(&#39;sum&#39;, [0]).sqrt(); var norm2017 = arr2017.pow(2).reduce(&#39;sum&#39;, [0]).sqrt(); var cosTheta = dotProduct.divide(norm2024.multiply(norm2017)); var SAD = cosTheta.acos().multiply(180).divide(Math.PI); // 计算ED(欧氏距离) var diff = arr2024.subtract(arr2017); var ED = diff.pow(2).reduce(&#39;sum&#39;, [0]).sqrt(); return feature.set({ &#39;SAD&#39;: SAD, &#39;ED&#39;: ED }); } // 动态阈值筛选函数 function applyDynamicThreshold(feature) { var landcover = feature.get(&#39;landcover&#39;); var thresholds = { &#39;water&#39;: {sad: 0.8, ed: 0.6}, &#39;forest&#39;: {sad: 1.0, ed: 1.0}, &#39;farmland&#39;: {sad: 1.5, ed: 1.4}, &#39;buildings&#39;: {sad: 2.0, ed: 1.8}, &#39;grassland&#39;: {sad:1.3, ed:1.2}, &#39;default&#39;: {sad: 1.2, ed: 1.1} }[landcover] || {sad: 1.2, ed: 1.1}; var dynamicSAD = ee.Number(5).multiply(thresholds.sad); var dynamicED = ee.Number(0.15).multiply(thresholds.ed); var SAD = ee.Number(feature.get(&#39;SAD&#39;)); var ED = ee.Number(feature.get(&#39;ED&#39;)); return feature.set({ &#39;thresh_SAD&#39;: dynamicSAD, &#39;thresh_ED&#39;: dynamicED, &#39;isStable&#39;: SAD.lte(dynamicSAD).and(ED.lte(dynamicED)) }); } // 主处理流程 var processedSamples = samples2024 .map(calculateSpectralDistances) .map(applyDynamicThreshold); // 筛选稳定样本点 var stableSamples = processedSamples.filter(ee.Filter.eq(&#39;isStable&#39;, true)); // 结果统计与可视化 print(&#39;总样本量 &#39;, samples2024.size()); print(&#39;稳定样本量 &#39;, stableSamples.size()); print(&#39;各类型稳定率 &#39;, stableSamples.aggregate_histogram(&#39;landcover&#39;)); Map.centerObject(region, 8); Map.addLayer(sentinel2024, {bands: [&#39;B8&#39;,&#39;B4&#39;,&#39;B3&#39;], min:0, max:0.3}, &#39;2024假彩色&#39;); Map.addLayer(sentinel2017, {bands: [&#39;B8&#39;,&#39;B4&#39;,&#39;B3&#39;], min:0, max:0.3}, &#39;2017假彩色&#39;); // 原代码错误:2999 Map.addLayer(stableSamples, {color: &#39;00FF00&#39;}, &#39;稳定样本&#39;, true); Map.addLayer(processedSamples.filter(ee.Filter.eq(&#39;isStable&#39;, false)), {color: &#39;FF0000&#39;}, &#39;不稳定样本&#39;, true); // 导出结果 Export.table.toDrive({ collection: stableSamples, description: &#39;Stable_Samples_2017&#39;, fileFormat: &#39;CSV&#39;, selectors: [&#39;SAD&#39;, &#39;ED&#39;, &#39;landcover&#39;, &#39;thresh_SAD&#39;, &#39;thresh_ED&#39;] });”报错“不稳定样本: Tile error: Error in map(ID=null): Number.lte, argument &#39;left&#39;: Invalid type. Expected type: Number. Actual type: Float<dimensions=1>. Actual value: [90.0]”
09-11
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_Rikka_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值