
1. 先说重点这套数据解决了什么问题做欧洲尺度的农业遥感最头疼的一件事就是地物类别不够细。全球通用的土地覆盖产品像 ESA WorldCover 那种能告诉你哪块是农田、哪块是森林但没人告诉你这块农田种的是玉米还是油菜。如果只是宏观看一下够用一旦进入作物种植结构分析、补贴核查、产量估算这类业务场景粒度完全不够。EUCROPMAP 2018 就是为这个缺口设计的。它由欧洲委员会联合研究中心Joint Research Centre简称 JRC发布基于 Sentinel-1 和 Sentinel-2 时序影像生产空间分辨率 10 米覆盖整个欧洲把地表划分为 21 类。注意谷歌地球引擎GEE上直接搜索 EUCROPMAP 往往找不到官方托管的影像集合但数据可以从 JRC 官网下载后上传到 GEE 处理。标题里“Google Earth EngineGEE——欧洲10米分辨率土地分类21种分类EUCROPMAP 2018 数据”这个表述实际对应的就是这条“官网下载 GEE 上传分析”的完整链路。给不熟悉的朋友说人话你可以把它理解成一张覆盖全欧洲的“农作物地图”每个 10 米×10 米的像素都被贴上一个标签告诉大家这里是什么。这张图能支撑的需求场景包括国家或大区尺度的作物种植面积统计特定作物的空间分布提取比如找出所有向日葵田多年度种植结构变化分析需要配合 2019、2020 等年份数据与气象、土壤数据叠加做适宜性评估作为样本点生成工具辅助训练更精细的分类模型。这篇文章面向的读者是已经在 GEE 里跑过一些基础代码、想上手处理大区域土地分类数据但被“怎么把外部数据弄进 GEE”“坐标系怎么整”“类别编号怎么对应”这类问题卡住的人。我会把从下载、预处理、上传到计算的完整路径讲清楚顺手把这条路上几个坑填平。2. 21 类到底是什么分类体系和生产思路2.1 分类体系不是空泛的“土地利用”而是细化到作物类型EUCROPMAP 2018 的 21 类包含两个层次农业用地内的具体作物类型和非农业用地覆盖类型。下面这份映射表是我在实际处理中整理出来的不同分发版本的字段名可能略有差异类别编号类别名称说明1夏季谷物以春小麦、春大麦为主2玉米整个欧洲的粒用玉米和青贮玉米3冬季谷物冬小麦、冬大麦、黑麦等4油菜冬油菜为主少量春油菜5向日葵通常夏季播种6根茎类作物马铃薯、甜菜等7苜蓿多年生豆科牧草8其他豆类豌豆、蚕豆等9草地/牧场永久性草地非轮作10果园苹果、梨、核果类11葡萄园酿酒葡萄和鲜食葡萄12橄榄园地中海沿岸典型作物13休耕地当年未种植14其他多年生作物坚果、其他浆果类15温室/大棚设施农业用地16林地所有森林类型17水域河流、湖泊、水库18城市建成区不透水面为主19其他土地裸地、岩石等20湿地永久性沼泽21其他作物无法归入上述类别的作物提示类别编号在不同年份的 EUCROPMAP 产品中可能有调整。比如 2019 年份的编码和 2018 就不完全一致下载后第一件事是打开类别说明文档核对而不是想当然拿去年的表去套。后面第 4 节会专门讲这个坑。这套分类体系生产时核心思路是把 Sentinel-1 的 SAR 后向散射时间序列和 Sentinel-2 的光谱指数时间序列拼接成特征张量再用随机森林训练。JRC 训练时用了大量 LUCAS 实地调查点作为样本这是它能覆盖 21 类的主要原因——纯靠遥感光谱很难稳定区分小麦和大麦这种光谱相近的作物必须有足够的样本支撑。2.2 分辨率、坐标系和瓦片组织三个必须较真的硬指标官方数据采用的投影是 ETRS89 / LAEA Europe即 EPSG:3035。这是欧洲标准的等积投影好处是面积变形小做面积统计时非常友好。但问题也来了EPSG:3035 不是 Web Mercator直接扔进 GEE 的 WGS84 逻辑里不做重投影处理会出现错位和面积误差。分辨率方面EPSG:3035 投影下的真实地面分辨率是 10 米这是等积投影下的定义如果强行转成 EPSG:4326经纬度每个像素的经度方向实际宽度随纬度变化不再是严格的 10 米。所以很多人在 GEE 里计算面积时喜欢靠scale10参数一算在 DGG 投影下误差不明显但放到欧洲这么靠北的地区误差能到百分之几到百分之十几后面专门展开。数据瓦片组织上JRC 官网按地理格网分块提供下载一块大约是 2°×2°经纬度格网全欧洲有几百个 GeoTIFF 文件。如果你只做某个国家可以只下载覆盖那个国家的几个瓦片如果做全欧洲那得写脚本批量拉取手动点击不太现实。3. 从官网下载到上传 GEE我实测过的一条完整链路3.1 下载前必须先做的分块规划很多人第一步就栽在这直接挑感兴趣的瓦片下下了十几个 GeoTIFF然后发现相邻瓦片之间投影、分辨率、像素对齐都没问题但上传时 GEE 单资产有大小限制一块 2°×2° 的 10 米数据全欧洲范围内面积大点的地方一个瓦片就能到 1GB 以上单个资产上传容易失败或超限。我的建议是下载前先想清楚研究区在研究区矢量边界上叠加 JRC 的瓦片格网确定需要哪些瓦片下载后先用 GDAL 合并gdal_merge.py或gdalbuildvrt再按行政边界裁剪一次压缩体积如果合并后仍超过 GEE 单资产限制就按 1°×1° 或按国别切成多块分别上传。JRC 官网下载支持按瓦片选择也提供整个欧洲的完整 GeoTIFF 下载入口。我做某国项目时通常是下载覆盖该国及其周边缓冲区的约 20 到 30 个瓦片合并后裁剪大概 2GB 左右转成 Cloud Optimized GeoTIFF 后上传 GEE 就非常顺。3.2 用 GDAL 做合并、重投影和裁剪在本地处理时我常用的工具是 GDAL 命令行和 QGIS。核心命令如下。假设瓦片下载到tiles/目录# 用 VRT 合并速度快不产生中间文件 gdalbuildvrt eucropmap_merged.vrt tiles/*.tif # 裁剪到研究区范围用 GeoJSON 或 Shapefile gdalwarp -cutline study_area.geojson -crop_to_cutline \ -dstnodata 0 -overwrite \ eucropmap_merged.vrt eucropmap_cropped.tif # 转成 Cloud Optimized GeoTIFF方便 GEE 读取 gdal_translate -co TILEDYES -co COMPRESSDEFLATE -co PREDICTOR2 \ eucropmap_cropped.tif eucropmap_cropped_cog.tif注意几个细节原数据有空值区域合并时建议显式设置-dstnodata 0。原产品的背景值一般是 0但要确认一下你下载的版本里背景是不是0有的版本可能用255或65535这种标记搞错了后续面积统计会多出一大块“第 0 类”。不需要提前重投影到 EPSG:4326。GEE 上传时支持保留原始投影上传后 GEE 会自动按需求重投影提前转反而容易引入插值误差。如果你在 QGIS 里处理需要检查属性表是否保留了类别字段。EUCROPMAP 的单波段 GeoTIFF像素值就是类别编码没有额外属性表所以 GDAL 处理后通常就是一个 Int16/UInt8 单波段文件。3.3 GEE 上传参数这里踩过的坑比想象中多上传数据到 GEE 的入口是Assets → New → Image upload。很多人在这里手滑参数没填对几何位置错得离谱。规范的填法Asset ID建议用projects/你的项目/assets/eucropmap_2018_v1这种层次化命名方便后续管理多个版本Source files选择刚才生成的 COG 文件Coordinate reference system下拉框里如果找不到EPSG:3035选择EPSG:3035自定义输入或者直接留空让 GEE 从 GeoTIFF 内部读取投影信息。留空通常更靠谱因为 GDAL 写入的投影信息是完整的FiletypeGeoTIFF。上传后先在 GEE 里检查一下var cropMap ee.Image(projects/your-project/assets/eucropmap_2018_v1); print(cropMap.projection()); print(cropMap.bandNames()); Map.addLayer(cropMap, {min: 0, max: 21}, EUCROPMAP 2018);如果投影显示EPSG:3035波段名是b1或classification那就成功了一大半。假如这里发现几何位置偏移到海里去了基本是 GeoTIFF 内部坐标参考信息丢失重新用 GDAL 写一遍投影信息。4. GEE 里最容易集体翻车的地方类别映射与面积统计4.1 不要凭记忆写类别映射表这是我在帮某团队排查结果“整体不对”时最常见的病根。EUCROPMAP 的类别编号并不是按我在第 2 节列表那种顺序简单排列的而是按照 JRC 内部定义编码。具体表现是有人把分类结果按 1 到 21 的连续数值猜测了含义画出来的图里水域占满整个阿尔卑斯山草地变城市结论完全反了。正确做法到 JRC 数据下载页面找到该年份的类别说明文档通常是一个 Excel 或 PDF确认类别编号和名称的对应关系在 GEE 里把cropMap的直方图打出来统计 0 到 21 各个类别的像素数先排除背景值问题再写下映射代码。类别映射代码示例var classNames [ {value: 1, name: summer_cereals}, {value: 2, name: maize}, // 这里必须根据官方文档逐一填写不要照抄其他来源的编号 ]; var remap cropMap.remap( [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21] );这段代码看着什么都没做但实际作用是确认了类别取值范围和个数。如果下载的版本类别数不是 21或者某类缺失remap会直接报错比后面统计时发现莫名其妙多一类的排查成本低得多。4.2 面积统计别用像素数乘以 100 糊弄自己10 米分辨率每个像素面积是 100 平方米很多人直接数像素数乘 100觉得精度够了。这个做法在投影变形小的低纬度地区勉强说得过去在欧洲高纬度用 EPSG:3035 原始投影算误差不算大但如果数据被重投影到 Web MercatorEPSG:3857或直接以 4326 坐标系跑每个像素对应的地面面积在南北方向上差别很大。正确做法是结合ee.Image.pixelArea()它能返回每个像素的真实球面面积。统计某类总面积的标准写法var areaImage cropMap.eq(2).multiply(ee.Image.pixelArea()); var totalArea areaImage.reduceRegion({ reducer: ee.Reducer.sum(), maxPixels: 1e13, scale: 10, bestEffort: true, geometry: studyRegion }); print(总面积单位平方米, totalArea.get(classification));关键点reduceRegion里的scale参数填多少取决于你希望计算在什么分辨率下进行。如果源数据是 EPSG:3035 的 10 米这里填10没问题如果进行了reproject或reduceRegion未指定crsGEE 可能默认在 WGS84 下按scale取样导致面积统计偏差。稳妥做法是指定crs参数为原始投影var totalArea areaImage.reduceRegion({ reducer: ee.Reducer.sum(), maxPixels: 1e13, crs: cropMap.projection(), scale: 10, geometry: studyRegion });我测过一个中等国家的玉米面积用crs: cropMap.projection()的计算结果和官方提供的参考统计相差不到 2%而直接用默认投影计算误差能到 8% 以上。对于面积统计类任务这已经不是可以忽略的误差了。4.3 可视化样式让分类图不辣眼睛的设计小技巧EUCROPMAP 输出到地图上如果不设置 paletteGEE 默认的灰度渲染会让 21 类完全分不清。建议初始化一个可视化参数对象var visParams { min: 1, max: 21, palette: [ #ffff00, // 夏季谷物 #ff9900, // 玉米 #ccff33, // 冬季谷物 #99ff99, // 油菜 #ffcc00, // 向日葵 #996633, // 根茎类 #cccc99, // 苜蓿 #ccffcc, // 其他豆类 #cc9966, // 草地/牧场 #33cc00, // 果园 #993399, // 葡萄园 #3399ff, // 橄榄园 #cccccc, // 休耕地 #666600, // 其他多年生 #ffcccc, // 温室 #003300, // 林地 #0000ff, // 水域 #ff0000, // 城市 #808080, // 其他土地 #00ffff, // 湿地 #ffffcc // 其他作物 ] }; Map.addLayer(cropMap, visParams, EUCROPMAP 2018 Vis);配色没有统一标准但有序原则是作物类用黄绿暖色系非植被类用灰蓝冷色系城市用醒目的红色/深色水体用蓝色。这样图面第一眼就能看出农业区分布而不是一堆色块挤在一起。5. 上传后的实际应用从画图到出结论5.1 指定区域、指定类别一键统计最常用的需求是某国的某省2020 年玉米种植面积是多少。这需要 2018 年 EUCROPMAP 不能直接回答但如果你做的是同区域 2018 年的基准数据可以先跑通流程var country ee.FeatureCollection(FAO/GAUL/2015/level1) .filter(ee.Filter.eq(ADM1_NAME, 某省名字)); var cornArea cropMap.eq(2) .multiply(ee.Image.pixelArea()) .reduceRegion({ reducer: ee.Reducer.sum(), geometry: country.geometry(), crs: cropMap.projection(), scale: 10, bestEffort: true }); print(cornArea);顺便说一句GAUL 数据集在 GEE 里有时会被标记为 deprecated但 2015 版还能访问。如果图省事用它没问题如果做正式报告建议用你本地更准确的行政区边界上传为ee.FeatureCollection。5.2 把 EUCROPMAP 当作样本标签源来用很多人不知道EUCROPMAP 的价值不只是出图它还能当“免费的训练样本库”。做法是提取某一类别比如葡萄园的像素随机生成采样点把这些点和对应的 Sentinel-2 影像块配对作为训练数据集训练自己的分类模型因为 EUCROPMAP 本身有误差采样时最好加一个“纯度筛选”比如只保留类别置信度高的斑块——不过 2018 版本没有附带逐像素置信度波段一种替代方法是剔除小斑块连接组分分析后面积小于一定阈值的斑块不要。这个思路在我做作物精细分类时非常实用节省了大量野外采样时间。代价是模型有系统误差的风险因为标签本身继承了 EUCROPMAP 的错分噪声所以如果预算允许至少要用一部分独立实地验证点做精度评估。5.3 与 2019、2020 年份数据叠加做变化检测如果你手头有其他年份的 EUCROPMAP 版本可以直接做作物结构变化矩阵var map2019 ee.Image(projects/your-project/assets/eucropmap_2019_v1); var change cropMap.multiply(100).add(map2019); var changeCounts change.reduceRegion({ reducer: ee.Reducer.frequencyHistogram(), geometry: studyRegion, crs: cropMap.projection(), scale: 10, maxPixels: 1e13 }); print(changeCounts);变化矩阵里值由“2018 类别 × 100 2019 类别”构成。例如 2018 是 2玉米、2019 是 3冬季谷物变化值为 203。这个思路可以搬到任意两个年份上用来快速找出耕地“改种”的热点区域。实际跑的时候内存占用很大建议按区域分块统计或者用reduceRegion时指定tileScale参数比如tileScale: 4减少单线程任务量避免 GEE 内存超限。6. 结尾说几个我用下来的体会第一次跑 EUCROPMAP 全流程时我最大的感受是“地图产品永远比你想象的更需要较真”。分辨率、投影、类别编号、背景值任何一环错了结果都不对而且很多时候不是整体报错而是安静地错——你看着图觉得挺像那么回事直到量化统计才发现偏差。所以养成一个习惯拿到任何新数据第一件事不是急着分析而是打直方图、查投影、看边界、数类别个数把“数据体检”做扎实。再分享一个小技巧上传大文件的时候别一次把所有瓦片合成一个 GB 级大文件建议按瓦片原样先传 4 到 5 块测试确认 GEE 端读取没问题再批量传剩余的。这样万一某一步出问题排查成本低得多。最后EUCROPMAP 这类产品在欧洲以外区域没有覆盖如果你做的是其他大洲的同类分析思路可以照搬但数据源得换。常用替代品包括 FAO 的 WaPOR、IIASA 的耕地产品以及基于 GEE 上现有的 WorldCereal 数据集。核心方法论是一样的先摸清分类体系和坐标系再做重采样和统计分析。这套流程打通之后你会发现处理任何大区域土地分类数据本质上都是同一套打怪路径。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。