ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

GEE土地利用监督分类全流程:从样本设计到精度验证

GEE土地利用监督分类全流程:从样本设计到精度验证 谷歌地球引擎Google Earth Engine简称GEE处理土地利用分类我这两年几乎每个月都要用上几次。无论是做城市扩张分析、农业种植结构提取还是给生态评估项目出基础底图GEE加监督分类这套组合基本上是绕不开的标配。这篇博文我打算把整个流程从数据准备、样本设计、分类器选型到精度验证、结果导出完整串一遍重点放在那些官方文档里不会明说的判断逻辑和容易踩坑的细节上。不管你是刚接触GEE的遥感方向研究生还是已经能用filterDate、clip但还不太确定样本怎么布、分类器参数怎么调的从业者这篇内容都能给你一个可以直接照做的方案。先说结论GEE做监督分类核心不在代码而在样本和特征。代码翻来覆去就是sample、train、classify这三板斧真正的差距在于你喂给分类器的训练样本够不够准、够不够均衡以及你给模型的波段特征能不能把地类区分开。这篇文章会顺着这个逻辑展开把每一步拆开讲清楚。1. 整体思路GEE为什么适合做土地利用监督分类1.1 监督分类的基本逻辑监督分类说白了就是“教机器认地物”。你先在影像上圈出几块你确定是水体的地方、确定是农田的地方、确定是城市的地方告诉算法“这些像素分别属于哪一类”算法从这些样本像素上学习光谱特征的分布规律然后拿这个规律去推测整幅影像上每一个像素属于哪一类。这里面有个关键概念叫特征空间。每个像素不只是一个颜色值它是很多波段数值组成的一个向量。比如Landsat-8有蓝、绿、红、近红外、两个短波红外这6个反射率波段那每个像素就是一个6维向量。水体在可见光波段反射率低、近红外波段更低而植被在近红外波段反射率高这些差异就是分类器做决策的依据。监督分类跟非监督分类的区别在于非监督分类比如K-Means、ISODATA是算法自己找数据中的聚类结构跑完你再给每个类贴标签监督分类是你要先给出带标签的样本算法学的是“某某标签对应的像素长什么样”。前者适合你对区域完全不了解的探索阶段后者适合你有明确分类体系、需要出精确成果的应用场景。土地利用分类绝大多数情况下是有明确体系的任务所以监督分类是主流的做法。1.2 GEE在这个任务里解决了什么核心痛点传统的土地利用分类流程是这样的先下载遥感影像可能几十个场景然后在一个能跑得动的桌面GIS软件里做大气校正、影像镶嵌、样本勾选、分类、后处理。这个过程最大的问题是数据管理和计算效率。如果研究区域跨好几景影像光是下载、拼接、裁剪就会消耗大量时间和硬盘空间如果做年度时序分析时间维度上的数据量更是天文数字。GEE的核心价值在于它把“数据存储、计算资源、算法库”三者捆在了一起。所有影像数据都在云端你的脚本直接在服务器端跑不需要把数据下载到本地。处理一整个省份的Landsat影像GEE在几秒到几十秒内就能完成。你写的是JavaScript或Python代码调用的却是谷歌数据中心里成千上万的CPU核心。这种方式让“大规模、多时相、长时序”的土地利用分类变成了一件门槛很低的事情。对于监督分类这个具体任务GEE还有一个优势你可以在交互式地图上直接勾选训练样本所见即所得样本做完直接喂给分类器反馈非常快。这种“边看边改”的交互方式比传统软件里“样本表和影像分离”的流程高效太多。1.3 整体技术路线从数据到成图的七个环节我们这次要做的完整流程我习惯拆成七个环节来规划确定研究区域和时间范围分类的目标区域在哪用什么时间窗口的影像。数据源选择与预处理选Landsat-8还是Sentinel-2做云掩膜、影像合成。特征构建在原始波段基础上加NDVI、NDWI等指数提升地类区分度。训练样本采集人工目视解译或者基于辅助数据生成带标签的样本点。样本拆分与分类器训练按一定比例拆成训练集和验证集训练随机森林等分类器。全图分类与后处理把训练好的模型应用到整个研究区必要时做平滑滤波。精度评估与结果导出用独立验证样本计算混淆矩阵、Kappa系数然后导出分类结果。这个流程看着常规但每个环节的选择都会直接影响最终精度。后面我按这个顺序详细展开。2. 数据源与特征构建分类精度的地基2.1 Landsat-8还是Sentinel-2尺度、时间与波段的取舍做土地利用分类第一步要选对影像源。现在最常用的就是Landsat-8/9和Sentinel-2两者各有适用场景。我从几个维度对比一下对比维度Landsat-8/9Sentinel-2空间分辨率多光谱30米全色15米可见光近红外10米红边和短波红外20米重返周期16天5天双星时间跨度2013年至今L8、2021年至今L92015年至今波段设置4个可见光/近红外2个短波红外有热红外4个10米波段6个20米波段有3个红边波段无热红外适合场景中尺度区域、长时序分析、温度相关研究小尺度精细分类、农业监测、植被参数反演我的经验是如果你做的是省级以上大范围、或者要做2015年以前的历史回溯选Landsat系列因为它的存档时间最长且连续如果你的研究区不大比如一个县或者一个流域又特别在意空间细节用Sentinel-2的10米分辨率做出来的图会干净很多。这篇文章的实操部分我用Landsat-8 Collection 2 Tier 1 Surface Reflectance数据来演示因为它在GEE里处理最简单、计算快而且对新手理解流程最友好。需要换Sentinel-2的话把影像集合的ID换掉特征波段做相应调整即可。2.2 光谱波段与指数的组合不要只用原始反射率很多教程跑到分类这一步就直接把原始6个波段丢进分类器。这样做能出结果但精度往往会差一口气。原因很简单有些地类的区分不能靠单一波段的绝对值而要靠波段之间的比值关系。举个例子水体和阴影在可见光波段的反射率都很低单看蓝、绿波段很难区分但水体在近红外波段的吸收比阴影更强这就让归一化差异水体指数NDWI成为区分水和阴影的利器。再比如植被覆盖度高的农田和自然林地原始波段形态相似但增强型植被指数EVI对高植被覆盖区更敏感加上它对大气和土壤背景的抗干扰能力经常能让两类分开。我在实际项目中常用的特征组合是6个原始反射率波段蓝、绿、红、近红外、短波红外1、短波红外2。3个光谱指数NDVI绿度、NDWI湿度/水体、EVI抗饱和植被指数。2个地形因子高程和坡度来自SRTM DEM数据。为什么加入地形因子因为土地利用分类不只是看植被和水体还要区分山地林地和山脚农田甚至阴坡和阳坡的植被长势完全不同。加上高程和坡度后分类器可以利用“地形位置”这个极强先验信息。在山区项目里加不加地形因子分类精度能差5到10个百分点。2.3 影像合成用“一年中最清爽的一帧”来分类还有一个容易忽略的问题到底用哪一天的影像分类单景影像往往有云、有阴影而且同一种地类在不同季节长相完全不同。我的做法是选一个物候相对稳定的时间窗口把窗口内的所有影像做中值合成。中值合成的意思是对每个像素取这个时间窗口内所有有效观测值的中位数作为最终值。这样既去掉了云和异常噪声又保留了这个时间段地物的普遍光谱状态。比如做华北平原的农耕区分类我通常会选5月到9月这个窗口因为这个时段植被覆盖度高、农田作物长势明显各地类光谱差异最大。代码实现上filterDate之后先map一个云掩膜函数再median()合成就能得到一幅干净的无云影像。如果没有做云掩膜直接median云和云的阴影虽然会被中值削弱但还是会有一部分残留在结果里所以云掩膜这一步不能省。3. 训练样本设计与分类器选型决定精度上限的关键3.1 样本点怎么采集才不坑自己这是整个监督分类流程里最需要耐心的环节。很多人把分类精度不高归结于算法不行实际上八成是样本出了问题。我梳理了几个必须遵守的原则。第一样本必须有代表性。每个类别的样本要覆盖该类别在整个研究区内的光谱变异范围。比如“林地”这个类别如果研究区里有针叶林、阔叶林、混交林它们的反射率差异明显你就不能只在一片针叶林里取样本必须在不同林分类型里都取。从这个意义上说样本的“面”比样本的“量”更重要。第二样本量要够但不要畸多。经验值是每个类别至少50到100个样本点类别多或者光谱变异大的地区要更多。样本太多也未必好如果同类样本之间高度相关相当于给分类器灌入了冗余信息反而可能造成过拟合。第三样本要尽量均匀分布。不要只集中在研究区一角应该铺满整个研究区。分类模型学的是光谱特征而同一个地类在不同区域因为土壤背景、大气状况、地形坡向的差异光谱会有漂移样本覆盖不全会导致没被覆盖到的地方分类出错。第四验证样本和训练样本必须独立。这一点我要特别强调。很多人图省事把同一批样本既拿去训练又拿去验证算出来的精度高得吓人整体精度动辄90%以上但一到真实应用就严重拉胯。正确的做法是先把样本整体做一次随机打乱比如按70%和30%的比例拆成训练集和验证集。如果样本量充裕更好的做法是训练样本和验证样本分别独立采集互不关联。3.2 分类器怎么选CART、随机森林、SVM的取舍逻辑GEE里内置了好几种监督分类器最常用的就是CART决策树、随机森林Random Forest和支持向量机SVM。三者的区别可以从学习方式上理解。CART就是一棵决策树它通过一系列“如果某波段大于某阈值就分到某类”的规则把特征空间切分出来。优点是训练速度极快、结果可解释缺点是单棵树的稳定性差——训练数据稍微变一点树的结构就变分类结果就会跟着波动。随机森林是很多棵决策树的集成每棵树用训练样本的一个随机子集和特征的一个随机子集来训练最后让所有树投票决定类别。它对噪声和过拟合的抗性比单棵树强很多训练速度也不算慢是GEE里做土地分类性价比最高的选择。SVM的思路是在特征空间里找一个“间隔最大”的超平面把不同类别分开。它对小样本、高维特征的表现很好但缺点是训练时间长对参数比如核函数类型、惩罚系数敏感调参成本高。我的使用经验是默认优先用随机森林它在绝大多数土地利用分类任务里精度和稳定性的平衡最好。CART可以用来做快速实验、看哪个特征对分类贡献大但出正式成果我不会用它。SVM只有在样本量不大比如几千个点以内且对精度有极致要求时才考虑样本量一大训练时间会让人崩溃。3.3 随机森林关键参数为什么是300棵树GEE的随机森林算法对应函数是ee.Classifier.smileRandomForest(numberOfTrees)。官方的默认参数比较保守实际使用中我一般手动设置几个关键参数。树的数量numberOfTrees我常用300。这个数值不是拍脑袋定的。理论上树越多模型越稳定但超过一定数量后边际收益急速递减训练时间和内存开销却线性增长。我用100、300、500做过对比100棵时精度略低一点300和500的精度几乎没有差别所以300是个性价比很好的折中值。其它几个参数也很关键minLeafPopulation叶子节点最少包含的样本数默认1。设得太小容易过拟合我一般设3或5。bagFraction每棵树用的样本比例默认0.5。这个参数让每棵树看到的样本不完全一样是随机森林能抗过拟合的关键一般不用动。maxNodes单棵树的最大节点数默认null也就是不限制。数据量大、特征多时可以限制一下比如设到200能明显加快训练速度。需要明白的是这些参数不是越复杂越好。随机森林本身就是“保持简单、依靠集成”的算法多数情况下用合理的默认值就能拿到不错的结果。3.4 特征重要性让模型告诉你哪些特征在干活GEE的分类器里有一个很实用的方法叫explain()它能输出分类器在训练时用到的各项配置。但如果我们用的是随机森林更值得看的其实是特征重要性。在GEE里可以用classifier.explain()获得也可以基于训练好的模型输出每个特征的重要性属性。我在项目里的做法是第一次训练跑完之后先去查看特征重要性排序如果发现某个指数或波段的贡献度长期垫底比如归一化差异水体指数在完全干旱区可能作用很小就会考虑把它从特征列表里去掉。这个做法的意义在于减少特征维度让模型更简洁、训练更快有时候反而能提升精度。这个环节不要省它能让你的分类项目从“能用”进步到“好用”。4. 完整代码实操一步步跑通GEE监督分类4.1 环境准备区域、影像与云掩膜打开 GEE Code Editorcode.earthengine.google.com左边的搜索框可以搜索区域、数据、示例脚本。这一段我们先把研究区、影像集合、云掩膜函数准备好。研究区域我这里先用一个点加缓冲区的方式演示方便直接运行。如果是实际项目你可以在左侧几何图形工具里画一个多边形或者上传自己的Shapefile通过Assets然后读取ee.FeatureCollection(你的资产ID)。// 定义研究区示例某地附近10公里范围 var studyArea ee.FeatureCollection(USDOS/LSIB_SIMPLE/2017) .filterMetadata(country_na, equals, China) .geometry() .centroid() .buffer(20000); // 实际使用请换成自己的矢量范围 Map.centerObject(studyArea, 10); Map.addLayer(studyArea, {color: red}, 研究区);然后是Landsat-8 Collection 2 Level-2地表反射率数据集的引入和云掩膜。Collection 2 Level-2的影像自带QA_PIXEL波段里面有云、云阴影、冰雪等质量标记我们通常只保留像素质量干净的部分。var l8 ee.ImageCollection(LANDSAT/LC08/C02/T1_L2); function maskL8Clouds(image) { var qa image.select(QA_PIXEL); var cloudBitMask 1 3; // 云 var cloudShadowBitMask 1 4; // 云阴影 var snowBitMask 1 5; // 雪 var mask qa.bitwiseAnd(cloudBitMask).eq(0) .and(qa.bitwiseAnd(cloudShadowBitMask).eq(0)) .and(qa.bitwiseAnd(snowBitMask).eq(0)); return image.updateMask(mask); }这段代码里的位运算可能对不熟悉二进制的人来说有点绕。简单解释QA_PIXEL是一个16位的整数每一位用0或1表示一种质量标志。比如第3位bit 3表示是否云第4位是否云阴影第5位是否雪。1 3是把1左移3位得到一个只有第3位是1的数字跟QA值做 bitwiseAnd 之后如果结果等于0就说明这一位没有被置1也就是没有云。三个条件用 and 串起来就得到了“无云无阴影无雪”的掩膜。接下来选择时间窗口并合成影像。这里我选择植被生长季的5月到9月并加上一个简单的缓冲区一年前后各多出一定天数让数据更充分。var startDate 2023-05-01; var endDate 2023-10-01; var image l8 .filterBounds(studyArea) .filterDate(startDate, endDate) .map(maskL8Clouds) .map(function(img) { // Collection 2 Level-2 地表反射率带有缩放系数 var scale 0.0000275; var offset -0.2; var optical img.select(SR_B[2-7]).multiply(scale).add(offset).copyProperties(img, [system:time_start]); return optical; }) .median() .clip(studyArea);在这里我先把SR_B2到SR_B7六个反射率波段做了定标处理。Collection 2 Level-2的原始DN值需要经过缩放才能变成实际的反射率范围大约0到1。这个线性缩放不影响随机森林分类器的相对比较但如果后面你要做阈值提取比如NDVI大于0.5算植被就必须先做这一步不然阈值毫无意义。4.2 光谱指数与地形特征组合出最终的特征列表接着构建NDVI、NDWI、EVI三个指数并引入SRTM地形数据。var ndvi image.normalizedDifference([SR_B5, SR_B4]).rename(NDVI); var ndwi image.normalizedDifference([SR_B3, SR_B5]).rename(NDWI); var evi image.expression( 2.5 * ((NIR - RED) / (NIR 6 * RED - 7.5 * BLUE 1)), { NIR: image.select(SR_B5), RED: image.select(SR_B4), BLUE: image.select(SR_B2) }).rename(EVI); var dem ee.Image(USGS/SRTMGL1_003).select(elevation); var slope ee.Terrain.slope(dem).rename(slope); // 合成最终特征影像 var featureImage image .addBands(ndvi) .addBands(ndwi) .addBands(evi) .addBands(dem) .addBands(slope); var featureBands [ SR_B2, SR_B3, SR_B4, SR_B5, SR_B6, SR_B7, NDVI, NDWI, EVI, elevation, slope ]; Map.addLayer(featureImage, {bands: [SR_B4, SR_B3, SR_B2], min: 0, max: 0.3}, 真彩色影像);有一个细节要注意normalizedDifference函数里两个波段的顺序。比如NDVI是近红外 - 红/近红外 红所以要写成[SR_B5, SR_B4]NDWI常见定义是用绿光和近红外即绿 - 近红外/绿 近红外所以是[SR_B3, SR_B5]。写反了结果完全不对这类小错误非常容易在熬夜写代码时出现建议把指数和波段对应关系先写在注释里。4.3 训练样本手工勾选变体与自动生成示例训练样本在GEE里有两种常见获取方式。一种是你直接在左侧地图工具里手动画点然后每个点通过属性赋类别标签另一种是用随机点生成工具再人工目视判别。我这里用第二种方式做一个可复现的示例。它的逻辑是在研究区内随机撒点然后基于高分辨率影像这里用Sentinel-2做参考和你的经验给每个点指定类别。当然实际项目更推荐你直接动笔圈画多边形把每个类别的地块完整勾出来再转成点这样样本更纯、边界更干净。// 方式1手工sampling——在Map上手动添加点并在属性里填class // 示例中用随机点近似实际使用请删掉这段随机点逻辑改为你的真实样本 var samples ee.FeatureCollection([ ee.Feature(ee.Geometry.Point([116.391, 39.907]), {class: 0}), // 水体 ee.Feature(ee.Geometry.Point([116.458, 39.931]), {class: 1}), // 建设用地 ee.Feature(ee.Geometry.Point([116.312, 39.883]), {class: 2}), // 农田 ee.Feature(ee.Geometry.Point([116.215, 39.975]), {class: 3}), // 林地 ee.Feature(ee.Geometry.Point([116.178, 40.021]), {class: 4}) // 裸地 ]);除了手工点我在项目里还有一种效率很高的做法先用非监督分类如K-Means跑一版初步结果然后基于初步结果来“指导”样本采集。比如非监督分类把一块区域分成5个光谱簇你对照高分辨率影像逐个确认这些簇分别对应什么地类然后把这些簇的代表性点直接吸收为监督分类的训练样本。这种方法比纯手工撒点快很多而且样本在光谱特征空间的代表性更均匀。无论用哪种方式最终都要确保每个样本点都带有class这个数值型属性。类别编号建议从0开始连续编号0, 1, 2, ...因为GEE的分类器对类别编号有连续性要求缺号会导致混淆矩阵显示不完整。4.4 拆分训练集/验证集与训练分类器样本准备好之后用randomColumn方法给每个样本分配一个0到1之间的随机数然后按0.7和0.3的比例拆分。var samplesWithRandom samples.randomColumn(random, 0); var trainingSet samplesWithRandom.filter(ee.Filter.lt(random, 0.7)); var validationSet samplesWithRandom.filter(ee.Filter.gte(random, 0.3));这里拆分的意义是训练集用来训练模型验证集用来评估模型在“没见过”的数据上的表现。如果验证精度和训练精度差距过大说明模型过拟合了。注意randomColumn如果不给随机种子第二个参数每次运行时生成的随机数不同结果会略有波动。如果你希望结果可复现就把种子固定下来比如randomColumn(random, 42)。接下来训练随机森林分类器。var classifier ee.Classifier.smileRandomForest({ numberOfTrees: 300, minLeafPopulation: 3, bagFraction: 0.5, seed: 42 }).train({ features: trainingSet, classProperty: class, inputProperties: featureBands });这一步是整个流程里最核心的“学习”环节。.train()会遍历训练集里每一个样本点提取对应位置上的特征波段值跟样本的类别标签放在一起交给随机森林算法训练出一组决策规则。训练完成后这个分类器对象就包含了全部的规则信息可以随时拿来对任意影像做分类。4.5 执行分类与结果可视化训练完成之后分类就简单了一句classify搞定。var classified featureImage.classify(classifier); var palette [ 1d6fd9, // 0 水体 d91d1d, // 1 建设用地 f0d94c, // 2 农田 2d8a3e, // 3 林地 9c7c5b // 4 裸地 ]; Map.addLayer(classified, {min: 0, max: 4, palette: palette}, 监督分类结果);这里有一个可视化上的小细节分类结果的调色板min和max一定要设置成类别编号的最小值和最大值不要用默认拉伸。如果不设GEE会按影像的直方图自动拉伸颜色结果就是不同类别显示的颜色完全错乱看起来一团糟。4.6 精度评估混淆矩阵、Kappa与各类精度分类结果做完之后最重要的一步是拿验证集算精度。做法是把验证集样本对应的实际类别和分类结果类别放在一起生成混淆矩阵。var validationClassified classified.sampleRegions({ collection: validationSet, properties: [class], scale: 30 }); var testAccuracy validationClassified.errorMatrix(class, classification); print(混淆矩阵, testAccuracy); print(总体精度, testAccuracy.accuracy()); print(Kappa系数, testAccuracy.kappa()); print(用户精度, testAccuracy.consumersAccuracy()); print(生产者精度, testAccuracy.producersAccuracy());混淆矩阵怎么读行通常代表参考类别真实类别列代表分类结果类别。对角线上的数字是分类正确的样本数非对角线上的数字是混淆的样本数。两类之间的混淆在矩阵里一目了然这是排查分类问题的第一手信息。几个精度指标的含义也需要理解清楚总体精度Overall Accuracy所有样本中分类正确的比例。Kappa系数排除了随机一致性的影响之后的一致性度量一般0.8以上算很好0.6到0.8算可用。生产者精度Producers Accuracy某个真实类别被正确识别的比例漏分类别的严重程度看它。用户精度Consumers Accuracy某个分类结果在真实世界里确实属于该类的比例误分类别的严重程度看它。实际项目中我会特别关注混淆矩阵里哪两类在互相混淆。比如农田和林地经常混那多半是物候期选择不当建设用地和裸地经常混那多半是光谱太接近需要考虑加纹理特征或者更换数据源。4.7 导出分类结果到本地方便制图分类结果在GEE里可以直接截图但正式成果需要导出到本地方便后续制图和分析。用Export.image.toDrive可以导出为GeoTIFF。Export.image.toDrive({ image: classified.int16(), description: LandUse_Classified_2023, folder: GEE_Export, scale: 30, crs: EPSG:4326, region: studyArea, maxPixels: 1e13 });导出的几个参数要注意classified.int16()是把分类结果的浮点标签转成整型文件体积会小很多也更符合分类产品的存储习惯scale要根据你的数据源分辨率设置Landsat是30米Sentinel-2如果是用10米波段分类就写10crs如果研究区在特定投影带内建议用当地的高斯-克吕格投影或UTM投影面积和形状畸变更小不过对于普通的分类图导出EPSG:4326也能用主要看下游制图软件的需求。启动导出任务后到右侧的Tasks面板点击Run等待处理完成后文件就会出现在你的Google Drive对应文件夹里。5. 常见问题与排查技巧实录5.1 分类结果“椒盐效应”明显怎么办椒盐效应就是分类结果图里的地类像撒了一层盐和胡椒明明是一大片连续农田结果图里却密密麻麻混杂着零星的林地、裸地像素。这个问题的本质是像素级分类忽略了空间上下文信息——每个像元独立判断类别没有考虑周围像元的类别。有两种解决方案。第一种是结果后处理对分类结果做众数滤波也就是用一个窗口计算中心像元周围像元的众数把中心像元的类别替换成众数类别。GEE里可以直接用focalModevar smoothed classified.focalMode(30, square, average);需要注意的是滤波窗口的大小要跟你允许的最小图斑面积匹配。30米分辨率影像用90米窗口做一次focalMode基本能抹掉大部分小碎斑但如果你要保留很小的地物比如宽度只有30米的水渠就不要用太大窗口。第二种更彻底的方案是在分类前使用面向对象的分割方法先对影像做分割把像素分成一个个对象再对每个对象做分类。这不仅解决椒盐效应还能保留地物边界但GEE里做分割计算量较大不是所有场景都适合。如果只是出一个基础图先用focalMode就够了。5.2 为什么我的分类结果里建设用地和裸地分不开建设用地和裸地的光谱特征确实非常接近——两者在可见光和短波红外波段都是高反射NDVI都很低。这个问题我经常遇到尤其在干旱半干旱区域。解决办法从两个方向入手。第一个方向是增加特征加入纹理特征比如用灰度共生矩阵GLCM计算纹理或者加入夜间灯光数据NPP/VIIRS因为建设用地有夜间灯光而裸地没有。第二个方向是改时间窗口如果研究区有季节性的植被变化建设用地全年不变而裸地可能在雨季长出稀疏植被用多个时相的影像做分类可以利用“时间轨迹”来区分它们。比如加入一个雨季NDVI和旱季NDVI的差值特征往往能显著改善。如果已经出了结果图且混分严重还可以在分类后加一个规则处理对“裸地”和“建设用地”这个两个类别叠加夜间灯光数据凡是灯光亮度超过一定阈值的裸地就重编码为建设用地。这种“分类后处理”的思路在实践中非常有效。5.3 训练时报错或内存溢出GEE有一个“用户内存限制”的概念每个计算任务可用内存是有限制的。当你处理大区域或者超高分辨率影像时很容易遇到User memory limit exceeded错误。这个报错信息对新手来说很吓人但解决办法其实不复杂。常见诱因和解决办法研究区太大特征影像的分辨率太高比如直接用Sentinel-2的10米处理整个省。解决缩小研究区或者先对影像做降采样或者分块处理后再拼接。导出时maxPixels设置太小。解决显式设置maxPixels: 1e13。样本数量太大导致训练过程内存暴涨。解决适当减少样本量或者在训练前用stratifiedSample对样本做分层抽样让每个类别的样本量控制在几百个以内。分类器训练时带入了太多波段或数据维度。解决精简特征用特征重要性排序删除贡献低的波段。遇到User memory limit exceeded我的排错顺序是先缩小region再降分辨率再减样本量最后才考虑换更简单的模型。80%的情况都能在前两步解决。5.4 验证精度虚高结果却不对这是一个比报错还隐蔽的问题。我接手过不少项目对方说“我们精度95%呢”但结果图明显不对——一条河道在中间断掉一个山头被划成荒地。问题几乎都出在同一个地方训练样本和验证样本不独立。前面说过如果验证样本就是从训练样本里随机抽出来的一部分那分类器“见过”这部分样本了验证精度自然虚高。这种情况下的总体精度没有参考意义。检验方法很简单看一下你的混淆矩阵里每个类别是不是都高得离谱比如都在95%以上如果是基本可以怀疑样本独立性出了问题。正确的做法是训练样本和验证样本分别采集各用各的。如果样本量不够至少也要用不同的地块分别采训练点和验证点不要在同一块地里面既采样做训练又采样做验证。5.5 不同年份分类结果不可比的坑如果你的项目要做多期土地利用变化分析还有一个大坑不同年份的影像由于太阳高度角、大气条件、物候差异反射率并不严格可比。这会导致你独立训练的两个年份分类器对“同一地物”的判断标准不一致变化分析的结论就不可靠。我的建议是如果做多年份对比尽量使用相同的影像源比如都用Landsat-8时间窗口尽量对齐比如都用6月到9月并且做相对辐射归一化让两年影像的反射率分布匹配到同一基准。更进一步的做法是把多年份影像放在同一个分类器里训练也就是把2018年、2021年、2023年的样本都放进同一个模型里让模型学会“跨年份不变的光谱特征”。这个策略在多期制图项目中效果显著。结尾一点个人体会做GEE土地利用分类这几年我最深的感触是这个任务的技术门槛其实在快速降低GEE把计算和数据都打包好了任何人都能靠教程在半天内跑出一个结果。但真正的分水岭不在写代码而在你对地物光谱、物候特征、区域背景的理解深度。你采样时有没有想过阴影里的水体怎么标你选时间窗口时知不知道这个区域的作物什么时候成熟这些知识才是决定成果质量的东西。所以我的建议是在GEE里跑流程的同时多花时间去看真彩色影像、看样本点的光谱曲线、跑完之后去野外或者用更高分辨率的影像抽查几个点。这个习惯比多调几次参数有用得多。如果你也在做类似的项目欢迎拿这篇里的流程做底子然后根据你的研究区特征去调整特征、样本和时间窗口——很快你就会有自己的一套成熟pipeline。
返回列表