简介:这份资源面向地理信息科学、城市规划、环境研究与灾害风险评估等领域的从业者与学习者,提供江西省赣州市30米分辨率的DEM数字高程数据,并附带本市级行政范围矢量文件,可用于地形分析、坡度坡向计算、水文与交通线路规划等场景。压缩包共12个文件,约139.7MB,主要包含tif高程栅格及其ovr、tfw、xml等配套元数据,以及shp、shx、dbf、prj、sbn、sbx等Shapefile几何、属性、投影与索引文件,覆盖栅格与矢量两类常用GIS数据格式。目前已有1110人学习下载。借助这套数据,读者可在ArcGIS或QGIS中直接加载地形与行政边界,提取高程信息、计算地形特征,并与人口、植被等图层叠加开展空间分析,为区域规划与决策提供科学依据。
1. 拿到一份市级 30m DEM 压缩包,先别急着往 GIS 里拖
做水文、选址、坡度分析或者三维地形渲染的人,迟早会碰到一个尴尬:全国范围的 DEM 数据要么分辨率太粗,要么切片下载拼接到手软,而项目偏偏只关心一个市。这时候一份「市级范围 + 30m 分辨率 + 带行政边界 shp」的打包数据,价值就出来了。这次拆的是赣州市的 30m 数字高程数据,压缩包里除了栅格高程文件,还附了本市级范围的 shp 边界,等于把「裁切范围」这件事提前替你办了一半。30m 这个格网间距,对应的是 1:5 万比例尺地形图的信息密度,做流域提取、坡度坡向、通视分析够用,又不至于像 12.5m、5m 那样让单机内存直接翻车。它适合谁?做区域地理信息分析的学生、跑水文模型的工程师、需要给三维场景垫地形底座的开发者。但先别双击解压就往 ArcGIS 或 QGIS 里拖,坐标系和 NoData 这两个坑,足够让新手卡一整个下午。
2. 拆包先看三样东西:坐标系、格网间距、边界范围
2.1 为什么 30m 分辨率是个「够用又不贵」的平衡点
DEM 的分辨率本质是采样密度。30m 意味着地面上每隔 30 米取一个高程值,一个像元代表 900 平方米。这个尺度下,丘陵和山地的大地形走势能完整保留,但小于 30 米的冲沟、陡坎会被平滑掉。赣州地处赣南,地形以丘陵山地为主,用 30m 数据做坡度分级、汇流分析是合理的;如果你要做城市内涝那种米级精度的模拟,这份数据就不够,得换更高分辨率的来源。
从数据量看,30m 全国 DEM 单省往往在几百 MB 到 1GB 量级,市级裁剪后通常压到几十 MB,普通笔记本 8GB 内存完全跑得动。这就是它「不贵」的地方——你不需要为了一次坡度分析去配 32GB 内存的工作站。常见做法是:先用这份 30m 数据把分析流程和参数跑通,确认方法没问题,再决定要不要上更高精度重跑。
2.2 坐标系不确认,后面全是白干
拿到任何 DEM,第一件事不是打开看颜色,而是确认它的坐标参考。国内常见的 30m DEM 有两种来源:一种是地理坐标系(经纬度,如 CGCS2000 或 WGS84),单位是度;另一种是投影坐标系(如 UTM 或高斯-克吕格),单位是米。这两者直接决定你后面算坡度、算距离时数字对不对。
判断方法很简单,用 GDAL 命令行看一眼元数据:
# 查看栅格的基本信息,重点看 Coordinate System 和 Pixel Size gdalinfo赣州市_dem_30m.tif输出里如果Pixel Size是(0.000277..., 0.000277...)这种小数,说明是经纬度坐标,约等于 30 米;如果是(30, 30),说明已经是投影坐标,单位就是米。这个区别很关键:经纬度坐标下,直接算欧氏距离会得到「度」,不是米,坡度分析也会因为纬度不同而产生形变。
提示:如果发现是经纬度坐标,做面积、距离、坡度这类量算前,先投影到适合赣州的高斯-克吕格带或 UTM 带,别在经纬度上硬算。
2.3 用 shp 边界做裁切,别拿整幅全国数据硬跑
压缩包里那个本市级范围 shp,最大的用处就是裁切。很多人图省事,直接拿全国或全省 DEM 跑分析,结果研究区外的像元也参与计算,边界处出现一堆无意义的边缘效应。正确做法是用 shp 把 DEM 裁到赣州市范围。
QGIS 里操作:栅格菜单 → 提取 → 按掩膜图层裁剪栅格,掩膜图层选那个 shp,勾选「保持裁剪范围」。命令行用 GDAL 更利索:
# 用 shp 边界裁切 DEM,-crop_to_cutline 让输出范围贴合边界 gdalwarp -cutline 赣州市边界.shp -crop_to_cutline \ -dstnodata -9999 赣州市_dem_30m.tif 赣州市_dem_clip.tif-cutline指定裁切边界,-crop_to_cutline让输出影像的外接矩形紧贴边界而不是保留原图幅,-dstnodata -9999把边界外的区域统一设成 -9999。这里 -9999 是约定俗成的 NoData 值,别用 0,因为 0 在赣州部分低洼地区可能是真实高程,混在一起后面填洼会出错。
裁完之后建议再确认一次范围:
# 对比裁切前后的范围,确认裁切生效 gdalinfo -stats 赣州市_dem_clip.tif | grep -E "Upper Left|Lower Right"如果裁切后范围还是整幅图那么大,多半是 shp 和 DEM 坐标系不一致,gdalwarp 没做重投影匹配。加-t_srs显式指定目标坐标系,或者先把 shp 转成和 DEM 一致再裁。
3. 从高程栅格到可用地形因子:坡度、坡向、填洼一条龙
3.1 填洼不是可选项,是水文分析的前置动作
原始 DEM 里普遍存在「洼地」——那些四周高、中间低的像元。它们有的是真实地形(比如火山口、喀斯特洼地),有的是数据采集误差造成的假洼地。做汇流分析时,假洼地会让水流「困」在里面出不来,最后汇流结果断断续续。所以填洼(Fill Sinks)是水文分析的标准前置步骤。
QGIS 里用「填洼(Wang & Liu)」算法,或者用 WhiteboxTools。命令行用 GDAL 的gdaldem配合fillnodata只能补空洞,真正填洼建议用 RichDEM 或 WhiteboxTools:
# 用 WhiteboxTools 填洼,输出填洼后的 DEM whitebox_tools -r=FillDepressions -v \ --dem=赣州市_dem_clip.tif \ --output=赣州市_dem_filled.tif-r=FillDepressions指定填洼算法,--dem是输入,--output是输出。填洼后可以用-r=D8FlowAccumulation直接算汇流累积量,验证水流是否连通。
注意:填洼会改变原始高程值,填洼后的 DEM 只用于水文分析,不要拿它去做高程统计或体积计算,否则结果偏大。
3.2 坡度坡向:一个参数设错,结果全歪
坡度(Slope)和坡向(Aspect)是最常用的两个地形因子。GDAL 一条命令就能出:
# 计算坡度,-p 表示输出为百分比坡度,不加则输出度 gdaldem slope 赣州市_dem_filled.tif 赣州市_slope.tif -p # 计算坡向,-zero_for_flat 把平地坡向设为 0 而不是 -9999 gdaldem aspect 赣州市_dem_filled.tif 赣州市_aspect.tif -zero_for_flat-p输出百分比坡度,工程上做边坡稳定性分析常用百分比;做地形分类常用度。坡向默认平地输出 -9999,加-zero_for_flat改成 0,方便后续分类。这里有个血泪经验:坡度计算前一定要确认 DEM 的垂直单位和高程单位一致。如果 DEM 是经纬度坐标、高程是米,GDAL 会自动做纬度校正,但如果你自己写脚本用相邻像元差算坡度,忘了把度转成米,坡度会大得离谱。
3.3 用 Python 批量跑地形因子,避免重复点鼠标
如果手头不止赣州一个市,或者要反复调参数,用 Python 脚本批量处理更省事。基于 rasterio 和 richdem 的写法:
import rasterio import richdem as rd import numpy as np # 读取裁切后的 DEM dem_path = "赣州市_dem_clip.tif" with rasterio.open(dem_path) as src: dem = src.read(1) profile = src.profile nodata = src.nodata # 把 NoData 转成 richdem 能识别的 nan dem = dem.astype(np.float32) dem[dem == nodata] = np.nan # 填洼 dem_filled = rd.FillDepressions(rd.rdarray(dem, no_data=np.nan), in_place=False) # 算坡度(度) slope = rd.TerrainAttribute(dem_filled, attrib='slope_degrees') # 写回 GeoTIFF,保持原投影和变换 profile.update(dtype=rasterio.float32, nodata=np.nan) with rasterio.open("赣州市_slope_py.tif", "w", **profile) as dst: dst.write(slope.astype(np.float32), 1)这段代码的逻辑:先用 rasterio 读栅格和元数据,把 NoData 统一成 nan 避免污染计算;richdem 的FillDepressions做填洼,TerrainAttribute算坡度;最后用原 profile 写回,保证坐标系和地理变换不丢。参数上,attrib可以换成'aspect'、'curvature'等,一次读入多次计算,比反复开软件快得多。
4. 避坑排查:这五条我几乎每次都要提醒一遍
4.1 现象:裁切后边界外全是 0,不是 -9999
原因:gdalwarp没指定-dstnodata,或者原 DEM 本身 NoData 就是 0,裁切后边界外继承了 0。解决:显式加-dstnodata -9999,并在后续分析前用gdal_translate -a_nodata -9999统一 NoData 标记。
4.2 现象:坡度图出现大片异常高值或条纹
原因:DEM 里混入了 NoData 像元,算法把 -9999 当成真实高程参与差分。解决:计算前先确认 NoData 值,用gdalinfo -stats看最小值是不是 -9999 或 -32768,必要时先做掩膜。
4.3 现象:shp 和 DEM 叠不上,边界偏到海里
原因:两者坐标系不一致,一个是 CGCS2000 经纬度,一个是投影坐标。解决:用ogr2ogr或 QGIS 把 shp 重投影到和 DEM 一致,再裁切。别指望软件自动对齐,它不会替你判断哪个对。
4.4 现象:填洼后汇流还是断
原因:填洼只处理了单像元洼地,平坦区域(如水库、宽河谷)需要额外做「平坦区处理」。解决:WhiteboxTools 里用FillDepressions后再跑BreachDepressions,或者直接用FillDepressions的-fix_flats选项。
4.5 现象:Python 读进来全是 nan
原因:rasterio 读出的数组里 NoData 值没被识别,或者 DEM 本身是整型而 nan 是浮点。解决:先src.nodata看标记值,再手动替换;确保数组转成 float32 再赋 nan。
5. 进阶:把 30m DEM 接进三维场景和流域划分
5.1 生成山体阴影,快速检查数据质量
在正式分析前,我习惯先生成一张山体阴影(Hillshade),用眼睛扫一遍有没有明显的拼接缝、条带或者空洞。GDAL 一行命令:
# 生成山体阴影,-az 315 是常用光照方位角,-alt 45 是高度角 gdaldem hillshade 赣州市_dem_filled.tif 赣州市_hillshade.tif \ -az 315 -alt 45 -z 2-z 2是垂直夸张系数,丘陵地区用 2 到 3 能让地形起伏更明显。如果阴影图里出现规则的方格或条纹,说明原始数据有拼接问题,得回去查数据来源。
5.2 用流域划分验证 DEM 是否「通」
流域划分是检验 DEM 水文连通性的终极手段。用 WhiteboxTools 一条龙:
# 填洼 → 汇流累积 → 提取河网 → 划分子流域 whitebox_tools -r=FillDepressions --dem=赣州市_dem_clip.tif --output=dem_f.tif whitebox_tools -r=D8FlowAccumulation --dem=dem_f.tif --output=flow_acc.tif whitebox_tools -r=ExtractStreams --flow_accum=flow_acc.tif \ --output=streams.tif --threshold=1000 whitebox_tools -r=Basins --dem=dem_f.tif --output=basins.tif--threshold=1000表示汇流累积超过 1000 个像元才认定为河道,这个值要按赣州的降水和地形调,太大河网稀疏,太小全是毛刺。划出来的子流域如果边界连续、没有断头河,说明 DEM 的水文一致性没问题。
5.3 接进三维引擎前,先转成引擎认的格式
如果要把地形垫进三维场景(比如 Cesium、Unity),通常需要把 GeoTIFF 转成地形切片或高度图。常见做法是用gdal_translate转成 PNG 高度图,或者用ctb工具切成 terrain 瓦片。转之前记得把 NoData 区域填成该区域最低高程,否则三维里会出现黑洞。
| 用途 | 推荐格式 | 关键参数 |
|---|---|---|
| GIS 分析 | GeoTIFF | 保留坐标系,NoData 设 -9999 |
| 三维高度图 | PNG 16bit | 拉伸到 0-65535,记录 min/max |
| 地形切片 | terrain 瓦片 | 按层级切,注意边界接缝 |
从那以后我每次拿到一份新 DEM,都强制走一遍「gdalinfo 看坐标系 → 山体阴影扫质量 → 填洼 → 汇流验证」这四步,哪怕数据来源再可靠也不跳过。这套流程帮我拦下过好几次坐标系错位和 NoData 污染的问题,省下的返工时间远比这四步多。希望帮到你。
本文还有配套的精品资源,点击获取