武大CLCD更新到2025年了,这个国产土地覆盖数据集圈子里应该已经传开了。CLCD全称China Land Cover Dataset,目前是少有的连续41年、30米分辨率的土地利用/土地覆盖栅格产品,覆盖1985—2025年,作者团队按行政区切好了全国整幅tiff和分省tiff。搞城乡规划、生态评估、双碳测算、农业区划的人,从读研写论文到做生产项目,大概率都绕不开它。这篇直接讲清楚这版数据更新在哪、拿到tiff之后怎么验证、怎么裁剪、怎么按点位提取栅格值、长时序分析有哪些坑,以及我这些年使用CLCD攒下来的经验。
1. 这版数据到底更新了什么
1.1 从1985到2025,41年意味着什么
很多刚接触遥感数据的人对“41年”没有概念,觉得不就是加了几个年份吗。实际上这是国内土地覆盖产品里时间跨度最大、分辨率最高、更新最勤的序列之一。
1985年这个起点选得很好。那年中国很多城市化进程刚起步,后续所有的大规模变化都被完整记录:90年代沿海扩张、2000年后中西部开发、2010年后的国家级新区、近年来的生态修复和耕地保护行动。有了41年连续数据,你才能回答“某个区域这40年到底怎么变的”这种核心问题,而不是只有两三期快照。
从数据处理角度说,新增年份不是简单拼一块。CLCD官方团队基于Landsat系列影像(Landsat 5/7/8/9)逐年生产,时间序列越长,跨传感器一致性越重要。我对比过上一版和这版,早期年份的像元类别发生了少量修正,因为每次更新都会把前面年份用新算法重跑一遍。这意味着你下载整套1985—2025时,拿到的不是一个一个年代孤立拼接的产物,而是一套经过时空一致性校正、前后可比的序列。做趋势分析的人最怕换来换去前后口径不一,CLCD这种“整套重跑”的做法才是正确姿势。
1.2 30米分辨率在实际应用中的表现
30米分辨率在城市尺度能勉强看到街区,在区域尺度已经非常够用。Landsat卫星原始分辨率的限制决定了国产大范围土地覆盖产品通常都是30米起步,CLCD能把全国连续长系列做到30米,靠的是Google Earth Engine海量算力支撑下的逐像元合成与随机森林分类。
实际使用中30米能支持什么?比如提取城市不透水面,30米栅格能识别城中村、大型工业区、新建道路,但细窄巷弄和小区内部道路会有混合像元问题。做县域或省级土地利用变化分析时,30米完全够;做村级或地块尺度的精细分析,建议配合高分影像做局地校正。你如果拿CLCD算一个乡镇的建设用地面积,会出现边界锯齿和细碎图斑,不能直接当矢量的不动产登记数据用,要明白这类产品和专业测绘数据之间天然存在尺度差。
1.3 分类体系与文件构成
CLCD把土地覆盖分为9大类:农田、森林、灌木、草地、水体、裸地、不透水面、湿地、冰雪。不同发布渠道的栅格里,类别编码略有区别。常见的是1~9对应上述类别,0或255作为背景/无效值;也有版本按官方重新整理的编码用10、20、30递增。我每次下载后第一件事就是打开随数据的说明文档确认编码表,绝不让代码里写死一组数字跑到底。
文件构成上,官方发布通常给两类:一个全国范围的完整tiff,以及按省级行政区裁剪好的分省tiff。全国整幅tiff在WGS84地理坐标系下覆盖范围很大,单期约1~2GB。分省tiff把范围切到省界以内,数据量小、加载快,适合按省做研究的同学。
提示:这类数据集的分省结果一般是按行政边界矩形裁剪或按边界精准裁剪,文件命名可能是“CLCD_2025_省份名.tif”。拿到手先看范围是否带省外像元,带外像元在统计面积前一定要掩膜掉。
2. 拿到tiff之后先搞懂这三件事
2.1 全国图与分省图怎么选
做全国尺度的分析,直接下载全国整幅。全国图加载慢、波段计算时间长,但好处是无缝,不需要处理省界拼接问题。做单个省或市级分析,分省图更轻便。但分省图有一个隐藏问题:部分版本的分省图是按省份矩形范围裁的,四周带一圈邻省像元;还有的版本分省图坐标边界和省界Shapefile存在几米到几十米的偏移。如果你用省界矢量去严格裁剪后再统计面积,就会省下很多麻烦。
多年实操下来我的建议是:做省级统计,直接用全国图 + 省级行政边界矢量裁剪;做全省快速出图预览,才用现成的分省tiff。不要把现成“分省”当成干干净净的“省域数据”,先验证再使用。
2.2 先读元数据,再谈分析
拿到tiff第一步不是打开看颜色,而是读元数据。用gdalinfo最直接:
gdalinfo CLCD_2025.tif重点看四行:
- Driver是否为GTiff;
- Size是不是30米分辨率对应的行列数;
- Coordinate System是什么坐标系;
- Band的NoData值是什么。
我在实际项目就踩过坐标系坑。CLCD全国图是WGS84经纬度坐标,但很多自然生态类分析要求等积投影,面积统计要在Albers或Lambert投影下做。如果你拿WGS84的栅格直接算像元面积,纬度越高面积误差越大,因此一旦涉及面积,必须投影后再统计。
2.3 栅格数据在区域分析里的扩展性
不少人问CLCD能不能直接用于高程相关的分析,这里要区分清楚:CLCD输出的是土地覆盖类别,不是高程。很多人拿“土地利用tiff”和“高程tiff”混着操作,我经常看到“如何根据tiff提取区域内高程点”这类需求。实际业务中,如果你手上有一张DEM高程tiff,在区域内按采样点提取高程值是常规操作;如果你只有CLCD土地覆盖tiff,按点位提取出来的就不是高程,而是该位置的覆盖类别值。两种tiff虽然都叫栅格,但内容语义完全不同,先分清数据类型再选工具,否则结果就是错的。
这类“从栅格按点位提取值”的操作,本质上是一套通用方法,下面第3节直接给完整实操。
3. 实操:从tiff里提取我想要的区域数据
3.1 环境准备和快速检查
推荐一套很稳定的Python环境组合:rasterio读栅格、geopandas读矢量、matplotlib出图,配合GDAL命令行工具做裁剪投影。先建环境:
conda create -n clcd python=3.11 conda activate clcd pip install rasterio geopandas matplotlib读取并快速查看属性:
import rasterio from rasterio.plot import show tif_path = "CLCD_2025.tif" with rasterio.open(tif_path) as src: print(src.profile) print(src.crs) print(src.bounds) data = src.read(1) show(data, cmap="tab20")输出里确认了坐标系、分辨率、行列数,再做后续。
3.2 按行政区裁剪全国图
拿到全国图后做区域分析,我习惯用gdalwarp完成裁剪。假设你有一个省级行政边界Shapefile,命令如下:
gdalwarp -cutline 省界.shp \ -crop_to_cutline \ -dstnodata 0 \ -overwrite \ CLCD_2025.tif CLCD_2025_省裁剪.tif几个参数说明:
-cutline指定矢量边界;-crop_to_cutline让输出范围贴合边界外接矩形,并且边界外像元裁掉;-dstnodata 0把无数据区域统一设成0,后面统计时才能准确排除;- 不加
-t_srs,输出坐标系默认跟输入一致。
裁剪完后再用gdalinfo检查一遍范围和像元值分布。如果你的矢量是其他坐标系,gdalwarp会自动处理投影转换,但最好提前统一好,减少边界锯齿。
3.3 从tiff提取区域内点位的栅格值
先分清需求再操作。如果你要提取的是某个土地覆盖类别值,用rasterio的采样功能;如果你要提取的是高程值,则是读入一张DEM tiff,用同样的采样方法。这里我把两种场景都写出来,通用性很强。
第一种场景:给定一批经纬度点,提取CLCD分类值。
import rasterio import pandas as pd points_df = pd.read_csv("采样点.csv") # 包含 lon, lat 两列 with rasterio.open("CLCD_2025.tif") as src: coords = [(lon, lat) for lon, lat in zip(points_df["lon"], points_df["lat"])] values = list(src.sample(coords)) points_df["clcd_value"] = [v[0] for v in values] points_df.to_csv("采样点_带覆盖类型.csv", index=False)第二种场景:点位在区域外或落在无效像元上,结果可能为0或255。建议采样后先做一遍清洗,排除无效值再进入统计。
第三种场景:从高程tiff提取高程点。原理完全一样,把tif路径换成DEM文件,提取的值就是高程。很多问“根据tiff提取区域内高程点”的人,实际操作到这里就跑通了。
如果你想批量提取的是一个多边形区域内所有像元,而不是散点,可以先裁剪再统计,或者结合rasterio的window读取局部数据。对小范围区域,我经常直接按矢量bounds读取,不加载整幅图,速度快很多。
3.4 重分类与面积统计
提取到类别值以后,常规操作是重分类和面积统计。例如只看不透水面变化:
import numpy as np import rasterio with rasterio.open("CLCD_2025_省裁剪.tif") as src: data = src.read(1).astype(np.float32) profile = src.profile # 假设不透水面类别编码为7,按官方说明调整 impervious_mask = np.where(data == 7, 1, 0).astype(np.int16) # 计算像元面积前先投影到等积坐标系 # 实际操作中应使用gdalwarp先把tif转为Albers投影,再算面积 cell_area_m2 = 30 * 30 pixel_count = impervious_mask.sum() area_km2 = pixel_count * cell_area_m2 / 1e6 print(f"不透水面面积约: {area_km2:.2f} km2")这里特别要提醒:如果不投影就直接算面积,WGS84的0.00027度像元并不是30米乘30米,纬度不同实际地面尺寸差距很大。正确流程是先用gdalwarp转成Albers等积投影,或者用rasterio配合pyproj做逐像元面积校正。很多误差很大的统计结果,源头就是这一步。
4. 长时序分析的正确打开方式
4.1 年份命名与批次不一致问题
CLCD经历了多个版本批次,文件名有时带v01、v1.0,有时带年份后缀。下载整批数据后,我建议先把所有年份整理成统一命名规范,例如:
CLCD_{年份}.tif然后写一个批量读取脚本,因为不同批次数据的压缩方式、NoData值可能有差异。我在实践中遇到过一个年份的tif背景值是0,另一年份背景值是255,不处理就叠加统计,趋势直接失真。建议写一段代码统一规范化所有年份的无效像元,再进入分析。
4.2 变化检测与趋势分析
连续41年的序列最常做两类事:变化检测与趋势分析。变化检测可以用像元级的转移矩阵,例如统计某个区域哪些年份森林变农田、农田变建设用地。
典型脚本思路:
import numpy as np # 读取 2000 年和 2025 年两张裁剪后的图 with rasterio.open("CLCD_2000_省.tif") as src: d2000 = src.read(1) with rasterio.open("CLCD_2025_省.tif") as src: d2025 = src.read(1) valid = (d2000 != 0) & (d2025 != 0) transition = (d2000[valid].astype(int) * 100) + d2025[valid].astype(int) unique, counts = np.unique(transition, return_counts=True) # 比如 102 表示类别1变成类别2,具体含义对照编码表这种“先合并编码再看转移”的方法,比逐类比较更清晰。聚类之后,对每个转移组合做面积统计,得到区域土地利用转移矩阵,这是任何土地利用变化分析的核心输出。
趋势分析上,建议先计算每年各类别面积,再做回归或其他趋势方法。CLCD适合做年度序贯比较,因为它是一年一期,不是五六年一期,可以支撑像元级的Sen+MK检验。41年足够跑出一个统计上更稳健的显著性结果,这是很多稀薄时序数据做不到的。
4.3 精度与验证
CLCD官方公开的精度在多数年份保持在80%以上,不同土地覆盖类别精度差异比较大,不透水面和农田通常比较稳,湿地、冰雪这类过渡性地物容易混淆。做研究写论文时,我建议自己再抽验证样本,找高分辨率影像做目视判读,统计混淆矩阵,不要直接引用官方精度数据。原因是官方验证样本分布和你的研究区范围大概率不同,区域迁移后精度会有变化。
30米分辨率产品还有一个通病:混合像元。城乡交错带的农田与建设用地混杂,不透水面占比低的像元容易被分类成农田,这是训练样本和光谱特征共同造成的系统性偏差。做城市扩张研究时,建议把连续多年不透水面比例做低通滤波,去除单年份“闪烁”现象。
5. 常见问题速查与避坑清单
5.1 坐标系和投影
CLCD全国图常见坐标系是WGS84经纬度。做面积统计、距离量算、空间叠加时,全部转到Albers投影或UTM分区投影。偷懒的做法是用gdalwarp批量转换:
gdalwarp -t_srs EPSG:32650 CLCD_2025.tif CLCD_2025_UTM50.tifEPSG:32650是WGS84 UTM 50N,适合中国中东部区域;全国尺度分析建议EPSG:6933(WGS84 Albers全球等积投影)或其他中国常用Albers投影。
5.2 像元值与背景值
不要用“0”当普通类别,要确认NoData和背景值。我见过同学把0当成裸地统计,得出一个地区有几十万公顷裸地,实际那是背景值。每次换版本我都建议跑一行唯一值统计:
import rasterio from collections import Counter with rasterio.open("CLCD_2025.tif") as src: data = src.read(1) print(Counter(data.flatten()).most_common(20))用这个列表对照官方编码表,一眼看出0、255这类无效值占比。
5.3 获取渠道与引用方式
CLCD属于开放共享数据,常见获取渠道包括项目官网和国家级科学数据平台,按流程注册申请即可。下载后注意看版本号和发布说明,写论文时引用官方建议的文献和数据集版本。任何带保密信息或敏感位置的研究,注意数据发布合规性,不随意传播原始大数据文件。
5.4 问题速查表
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 加载tiff特别慢 | 全国图太大 | 改用分省图,或用rasterio按window读取 |
| 面积统计明显偏大/偏小 | 未投影直接算面积 | 投影到Albers后再统计 |
| 某一年份类别大面积突变 | 数据版本不一致 | 检查元数据和下载批次,重新标准化 |
| 采样点位出现大量0 | 点位落在背景或者图外 | 采样前检查坐标范围,采样后过滤无效值 |
| 边界处出现规则条带 | 分省裁剪导致的边界像元 | 用省界矢量精确裁剪 |
| 类别编码对不上说明 | 版本更新改编码 | 以数据自带legend文件为准 |
5.5 几个长期使用的独门经验
第一个经验:分析城市扩张不要单看某一年的不透水面,要在完整序列上计算不透水面的持续时长。比如“连续5年都为不透水面”的像元,才是真正稳定城市建设区域。这样能避开临时工棚、裸土误分等噪声。
第二个经验:CLCD的湿地和水体会在逐年间抖动。降雨多的年份,季节性水淹区容易在“水体”和“湿地”之间反复横跳。长时序研究建议用时间众数法做一次平滑,或者单独把这两类合并成“水域/湿地”大类,再分析趋势。
第三个经验:做分省或分县域统计时,边界处理必须贯穿始终。不要用栅格默认范围和行政边界做面积推算,一定要裁剪到边界内部,否则你算出来的面积里包含了邻省像元。这个坑我在一个县域耕地图斑统计项目里踩过,结果误差达到百分之十几。
第四个经验:保存处理中间文件时,统一GeoTIFF压缩格式和坐标系。团队合作时每个人都在自己的环境里转换一遍,最后合并结果对不上投影,浪费的时间比处理数据本身还多。建议项目一开始就定下一个标准:所有栅格统一用EPSG:6933或本项目专属Albers投影,NoData一律设0,文件命名一律“CLCD_年份_区域.tif”。
我个人现在的习惯是,每下载一批CLCD数据,先跑一遍一致性检查脚本,逐个年份打印投影、范围、像元统计值,把检查报告存成JSON。这个习惯帮我避开了至少两次数值灾难。后续做研究时,这些原始检查记录还能作为数据预处理的依据写进论文的方法部分,一举两得。