
简介江苏省地形地貌最新30m精度数据是一套面向GIS、遥感和规划领域的基础地理数据集内容覆盖海拔等级、起伏程度、陆地地貌类型与中国地貌类型等多个维度适合用于地形分类、地貌制图、区域规划及教学科研。数据已按省域边界裁剪为标准tif栅格坐标系统提供WGS84和Albers_Conic_Equal_Area两种兼容主流GIS软件。资源包共含30个文件以tif栅格、tfw坐标信息、xml元数据、dbf属性表为主另有png预览图和使用说明整体体积仅4.12MB结构清晰便于快速调用。目前已有199人学习下载。数据在海拔上细分低海拔、中海拔、中高海拔、高海拔与极高海拔在起伏度上区分丘陵、小起伏、中起伏、大起伏和极大起伏并兼顾山脉、平原、沟壑等形态支撑多尺度地貌分析参考复杂地貌成因分类体系便于直接开展海拔—起伏—地貌类型叠加分析与制图有效节省前期数据整理与判读时间。1. 30m精度江苏省地形地貌TIF打开前先搞懂坐标和分类拿到这份《江苏省地形地貌最新30m精度.rar》的时候我第一反应不是解压而是先扫了一眼所有.tif的世界文件因为过去在网上下载的省域地貌数据很多顶着“30m”的名头实际却是WGS84经纬度栅格像元宽度在江苏这种中纬度地区被拉伸到35m以上做面积统计会系统性偏大。这份资源基本把雷避开了文件族完整WGS84和Albers双坐标版本都有海拔分类、起伏程度分类、陆地地貌类型和成因类型已经分层打包可以直接喂给ArcGIS、QGIS或者GDAL程序省去从DEM重分类到目视校正的几天功夫。如果你正在做环境影响评价、土地利用规划、电力选线、城市风廊或暴雨内涝模拟需要把江苏地貌按海拔、起伏程度、形态成因多层叠合这份数据是能直接落地的底图。适合GIS数据处理工程师、规划院分析岗和有Python基础的地理信息从业者使用不需要遥感反演经验但至少得知道栅格属性表和投影坐标的区别。2. 文件族与坐标系tfw、aux.xml、vat.dbf和双投影选型2.1 解压后不要动任何一个影子文件解压之后同名单里会出现大量同名不同后缀的文件。很多人从网盘下载数据习惯只考一个.tif走到现场打开发现图层没有坐标。以海拔分类_江苏省.tif为例同目录下的.tfw、.aux.xml、.vat.dbf、.vat.cpg都不是可有可无的垃圾文件。.tfw是标准世界文件记录栅格仿射变换的6个参数当.tif内部缺少GeoTIFF坐标标签时QGIS、ArcGIS和GDAL都会自动读取这个文本文件。这份数据里的tif其实已经内嵌坐标但在你用numpy做像元运算或者用OpenCV处理遥感影像时只有.tfw能告诉你像元对应的真实地面尺寸和左上角坐标。.aux.xml是GDAL辅助文件缓存了直方图、统计信息和投影描述丢了这个文件程序会花时间重新扫描统计。.vat.dbf是栅格值属性表记录分类值、像元个数和类名Value字段和栅格像元值一一对应。.vat.cpg只是属性表的字符编码声明缺失后中文类名可能变成问号。cat 海拔分类_江苏省.tfw正常会输出6行数字依次为X方向像元宽度、X旋转分量、Y旋转分量、Y方向像元高度、左上角X坐标、左上角Y坐标。注意Y方向高度如果是负数那是坐标原点在左上角的常规设定不要手动改成正数。文件后缀作用是否可省略.tif栅格像元和内嵌坐标否.tfwASCII世界文件提供仿射坐标参数建议保留.aux.xml缓存统计信息与坐标描述可省略.vat.dbf每个类的像元计数和类名需要保留.vat.cpgDBF编码声明可省略但推荐保留这里强调一点这组文件的命名前缀并不统一海拔分类_江苏省.tif和landform_江苏省.tif对应的是不同分类体系不能只凭文件名里的“江苏省”三个字就把它们当成同一套栅格的副本。后续建模型前一定要先看属性表确认分类代码的含义。2.2 WGS84和Albers30m精度的度量基准摘要里写“数据坐标WGS84及Albers_Conic_Equal_Area”实际上相同内容的tif会存在两种坐标版本分别是经纬度栅格和投影栅格。直接拿WGS84算面积会出现可感知的系统偏差江苏位于北纬31°到35°之间一个像元对应的经度跨度在纬度上被拉伸30m换算成度后接近0.00033°而不是赤道附近的0.000277°。如果用经纬度版本统计面积每个像元不再是900平方米整体可能偏差百分之几。在做坡度、面积、条带剖面这类参数时优先选Albers等积投影栅格。标准Albers参数通常是中央经线105°E双标准纬线25°N和47°N单位是米。这个投影在面积量算上是等积的但对角度和距离不是等形所以做邻域计算时要清楚你在表达什么。gdalinfo 海拔分类_江苏省.tif | grep -E ID\[|Projection|Pixel Size输出里Pixel Size如果显示0.000277左右说明是WGS84版本如果显示30.0或29.9说明是Albers投影。投影版本的高斯克吕格或UTM坐标有时会因重采样出现29.998这样的微小舍入只要偏差小于1%可以直接使用。提示同一份数据同时有经纬度和投影坐标两个版本面积统计一定用Albers投影版做风廊分析或剖面分析也建议用投影版结果更直观。2.3 海拔、起伏度、形态和成因多层分类数据包里最核心的是三张分类栅格海拔分类_江苏省.tif按低海拔、中海拔、中高海拔、高海拔、极高海拔切出五级起伏程度分类_江苏省.tif按地形起伏度切出丘陵、小起伏、中起伏、大起伏、极大起伏五级陆地地貌类型_江苏省.tif是形态学分类例如平原、丘陵、山脉、沟壑。另有一张landform_江苏省.tif属性表中很可能包含海积、湖积、冲积、洪积、风积、冰碛、剥蚀等成因描述。这些成因类型比普通高程分类更贴近地学分析比如风积地貌对应沙丘冰碛地貌对应高山区冰期堆积而江苏主要出现冲积平原、湖积平原、海积平原和少量剥蚀残丘。实际使用时最常见的是把海拔分类和起伏度分类合成一个复合类比如“低海拔-平原”“中海拔-中起伏”。这样既保留了海拔信息又把地形破碎度加进来比单独看一张分类栅格要可靠得多。分类的顺序不影响计算但在符号化之前必须检查VAT属性表中的Value和Count因为NoData值如果写入属性表制图时会多出一个黑色分类。3. Python读取海拔分类与起伏程度生成组合代码3.1 搭建环境并快速预览栅格元数据处理这个数据包只需要rasterio和numpy。如果还没装建议用conda创建独立环境避免和系统GDAL冲突。conda create -n geodata python3.10 -y conda activate geodata conda install rasterio numpy pandas -c conda-forge -y安装后先用一个循环扫描整个目录把每个tif的尺寸、投影、分辨率打印出来确认这些栅格是否在同一个像元网格上。from pathlib import Path import rasterio as rio tif_dir Path(jiangsu_tif) for tif_path in sorted(tif_dir.glob(*.tif)): with rio.open(tif_path) as ds: print( tif_path.name, CRS:, ds.crs, RES:, ds.res, WH:, ds.width, ds.height, DTYPE:, ds.dtypes[0] )这段代码读取每个tif的crs、分辨率、宽高和数据类型。Albers栅格的分辨率接近30WGS84栅格则带有小数值。如果发现不同tif的width和height不一致后续必须先通过rio.warp.reproject重采样到同一网格否则叠加会产生像元错位。3.2 统计各分类的面积分布读取栅格后用np.unique统计每个分类值的像元数再乘以像元面积得到真实地表面积。import rasterio as rio import numpy as np with rio.open(海拔分类_江苏省.tif) as ds: elev ds.read(1) nodata ds.nodata transform ds.transform valid elev[elev ! nodata] if nodata is not None else elev.astype(np.int16) unique, counts np.unique(valid, return_countsTrue) pixel_area abs(transform.a * transform.e) for class_id, cnt in zip(unique, counts): area_km2 cnt * pixel_area / 1_000_000 print(fclass{class_id}, pixels{cnt}, area_km2{area_km2:.1f})transform.a是X方向像元分辨率transform.e是Y方向像元分辨率通常为负数abs后相乘得到单个像元的地面面积。如果使用的是WGS84版本这里的pixel_area单位是度²还需要乘以纬度的余弦修正否则面积不会精确。另外注意读取时如果栅格是uint8且NoData为255直接和nodata比较没问题如果nodata为负比如-9999需要先把数组转为int16再比较。3.3 合成海拔与起伏度组合码核心操作是构造一个新的组合栅格规则用海拔代码乘10再加起伏代码。比如海拔代码1、起伏代码2得到12这样既保留原信息又能用整数做单值渲染。def combine_elev_relief(elev_tif, rel_tif, out_tif): with rio.open(elev_tif) as ds_e: elev ds_e.read(1) profile ds_e.profile.copy() nodata ds_e.nodata with rio.open(rel_tif) as ds_r: rel ds_r.read(1) if elev.shape ! rel.shape: raise ValueError(两张栅格尺寸不一致需要先重采样) combined elev.astype(np.int16) * 10 rel.astype(np.int16) if nodata is not None: mask (elev nodata) | (rel nodata) combined[mask] nodata profile.update(dtypeint16, nodatanodata) with rio.open(out_tif, w, **profile) as dst: dst.write(combined, 1) combine_elev_relief(海拔分类_江苏省.tif, 起伏程度分类_江苏省.tif, 组合_江苏省.tif)这里用int16而不是uint8因为组合码虽然小于255但保留NoData为-9999时必须用带符号整型。函数先检查两张栅格尺寸是否一致再合并最后写入。profile从海拔栅格继承但dtype被覆盖为int16投影和仿射变换不变这样组合栅格和原栅格可以直接在GIS里叠加。3.4 输出面积占比和类别名称映射组合码生成后需要把数字代码翻译回中文类名方便做面积占比表格或专题图。relief_names {1: 丘陵, 2: 小起伏, 3: 中起伏, 4: 大起伏, 5: 极大起伏} elev_names {1: 低海拔, 2: 中海拔, 3: 中高海拔, 4: 高海拔, 5: 极高海拔} def class_name(combo): if combo nodata: return NoData e combo // 10 r combo % 10 return f{elev_names.get(e, e)}-{relief_names.get(r, r)}这里用整除和取模拆出海拔代码与起伏代码再查字典。后续可以在pandas里用map函数把组合码替换成文本生成面积统计表。需要说明的是如果组合码出现25表示中海拔极大起伏这在江苏内部的茅山和宁镇山脉局部可能出现但要警惕极端值是否由NoData处理不当造成。4. QGIS叠加地貌数据产出组合分类专题图4.1 在QGIS中正确加载带vat.dbf的栅格把tif直接拖入QGIS如果图层管理器只显示“单通道灰度”说明没有加载属性表。右键图层进入属性切换到“属性表”面板。QGIS不一定能自动关联外部VAT这时需要手动连接在图层属性的“连接”面板中选择“栅格属性表”作为来源。如果连接失败最直接的办法是用Excel打开.vat.dbf将Value和Count另存为CSV再通过“连接矢量属性”关联到栅格属性表。为了避免每次加载都重复关联可以在QGIS中右键图层另存为新文件格式选TIFF并勾选“创建栅格属性表”保存后的tif会自带VAT表之后的符号化会自动读取类名。4.2 栅格计算器做组合分类的诀窍组合分类在QGIS里不需要写Python直接使用“栅格→栅格计算器”。在表达式框里输入int(海拔分类_江苏省1 * 10 起伏程度分类_江苏省1)1代表栅格的第一个波段。外面包一层int()是为了保证输出为整型如果不包计算器会生成浮点栅格符号化时可能把21.0和21.5当作不同类导致图例出现无效过渡分类。这是最容易踩的坑。执行完生成merged.tif后按组合码建立对照表。下面是一个通用模板组合码海拔代码起伏代码建议类名1111低海拔-丘陵1212低海拔-小起伏2323中海拔-中起伏3434中高海拔-大起伏4545高海拔-极大起伏江苏实际很少出现34和45这些类在VAT中Count接近0制图时应从符号化列表中排除避免图例出现空类。提示栅格计算器表达式里的双引号表示图层名1表示第一波段。如果图层名含中文建议先在图层管理器里重命名避免编码问题导致解析失败。4.3 区域面积统计与专题图输出统计每个组合码的面积可以直接在“处理→工具箱”里搜索“栅格图层唯一值统计”输入merged.tif输出每个栅格值的像元数量和总面积。如果要做乡镇级别的面积统计用“区域统计”工具选择高程分类栅格作为输入行政区划矢量作为多边形输出会给出每个乡镇内的各组合码面积占比。专题图成图时右键图层属性符号化选择“单值渲染”值选择组合码点击“分类”后手动调整颜色。NoData要设置为完全透明这样长江水域不会以黑色块出现在地图上。最后在“新建打印布局”中添加地图项设置固定比例尺例如1:50万导出分辨率300dpi格式PNG或PDF。叠加行政边界时把市级边界矢量放到栅格上层混合模式选“正片叠底”比直接调透明度更干净。5. 验证30m栅格数据精度和边界的三个技巧5.1 用tfw反向推算像元尺寸解压后第一时间看海拔分类_江苏省.tfw如果是WGS84版本第一行X方向像元宽度应接近30m对应的度数。江苏中纬度地区的理论值可以用脚本算from math import cos, radians lat 32.5 cell_width_deg 30 / (40075016.686 * cos(radians(lat)) / 360) print(cell_width_deg)我一般会分别算32.5°N和34°N两个值。如果tfw里的值和理论值误差超过5%说明这份“30m精度”可能是用更低分辨率重采样后的结果或者用0.000333度粗暴替换真实像元尺寸。5.2 验证边界像元一致性把多张tif叠进QGIS打开网格显示检查江苏边界附近的NoData区域是否重合。很多分享数据集用行政面裁剪但有的做了一次缓冲区有的没有导致沿海滩涂和长江岸线的像元不一致。最简单的程序化检查是比较shape和transformimport rasterio as rio with rio.open(海拔分类_江苏省.tif) as a: with rio.open(陆地地貌类型_江苏省.tif) as b: print(a.shape b.shape, a.transform b.transform)如果shape或transform不同必须用rio.warp.reproject统一到同一网格否则叠加分析会产生锯齿错位。5.3 用面积守恒检查VAT属性表将.vat.dbf里的所有Count求和乘以像元面积结果应接近江苏省陆地面积约10.72万平方公里。如果差异大于1%优先检查是否把NoData像元计入了面积——很多GIS软件在生成属性表时不会自动排除NoData。此时回到3.2节的Python统计用nodata掩膜过滤后重新计算面积。跑完这个检查后我会把像元尺寸、Shape和transform的记录写入数据清洗日志再进入后续建模。本文还有配套的精品资源点击获取