简介:这份资源面向从事GIS分析、地形测绘、城市规划与环境评估的技术人员及地理信息相关专业师生,提供安徽省黄山市12.5米分辨率的数字高程模型数据,并附带市级行政范围矢量边界,可支撑地形分析、洪水模拟、坡度坡向计算等精细化任务。压缩包共13个文件,约80.37MB,核心为tif格式的DEM栅格数据,辅以shp、shx、dbf组成的完整shapefile边界文件,另有prj投影定义、tfw坐标配准、ovr金字塔视图、sbn与sbx空间索引及xml元数据等配套文件,保证数据在ArcGIS等平台中可直接加载与正确配准。相比常见的30米DEM,该数据能更细致地还原黄山市地形起伏特征。目前已有161人学习下载,适合需要高精度高程底图与行政边界叠加分析的GIS项目使用。
1. 拿到一份 12.5 米 DEM 数据,先别急着往 GIS 里拖
做地形分析、水文建模或者三维可视化的朋友,大概率都经历过这样的场景:项目需要一块精度够用、范围明确的高程底图,找公开的 30 米数据觉得太糙,买商业的 5 米数据又超预算,最后卡在“有没有一个折中选项”上。这份安徽省黄山市的 12.5 米 DEM 数据,就是冲着这个缺口来的——它把黄山市行政范围内的数字高程栅格和市级边界 shp 文件打包在一起,解压即用,省掉了自己裁切、配准、找边界的麻烦。黄山市地处皖南山区,地形起伏剧烈,从海拔几十米的新安江河谷到近 1800 米的光明顶,落差极大,对 DEM 的垂直精度和水平分辨率都有不低的要求。12.5 米这个格网间距,恰好能在细节表现和文件体积之间取得一个可接受的平衡。适合谁用?做区域地形分析的研究生、搞 GIS 二次开发的工程师、需要快速搭建三维地形的技术美术,以及任何不想在数据预处理上耗掉一整天的从业者。
2. 12.5 米 DEM 的分辨率账本:为什么不是 10 米也不是 30 米
2.1 格网间距背后的精度与成本权衡
DEM 的分辨率,说白了就是每个高程采样点之间隔多远。12.5 米意味着栅格里每个像素代表地面上 12.5×12.5 米的一块正方形区域。这个数字不是随便定的,它通常来自原始测绘数据的重采样——比如 1:50000 地形图数字化后的格网,或者雷达干涉测量成果的降采样。和 30 米数据比,12.5 米的采样密度高了近 6 倍,对山脊线、沟谷这些地形特征的刻画明显更锐利;和 5 米、10 米比,它又不会让文件体积爆炸。以黄山市约 9800 平方公里的面积估算,12.5 米栅格的行列数大约在 8000×10000 量级,单波段浮点型 GeoTIFF 压缩后通常在几百 MB 级别,普通笔记本完全扛得住。如果你的分析尺度是流域级别或者市域级别,12.5 米是性价比很高的选择;但如果要做单条冲沟的精细水文模拟,这个精度可能就不够用了,得考虑更高分辨率的来源。
2.2 黄山市地形对 DEM 的特殊要求
黄山市的地形不是平原那种“一马平川”的友好场景。北部是黄山山脉,南部是白际山脉和天目山余脉,中间夹着新安江谷地,最高点和最低点落差超过 1700 米。这种剧烈起伏的地形,对 DEM 的垂直精度和洼地处理特别敏感。如果数据里存在大量伪洼地,做水文分析时水流方向会乱掉,汇流累积量算出来全是错的。12.5 米数据在山区通常能保留主要沟谷的连续性,但遇到陡崖或者采石场这类人工改造区域,可能会有台阶状异常。拿到数据后第一件事不是急着跑分析,而是先做一遍洼地填充和异常值检查,这个后面会细说。
2.3 数据包里的 shp 边界文件怎么用
压缩包里除了 DEM 栅格,还带了一份黄山市市级范围的 shp 文件。这份矢量边界的作用主要有三个:一是用来裁切 DEM,确保你拿到的栅格严格落在行政区划内,不会混入邻省的高程数据;二是做掩膜提取,比如你只想分析黄山市境内的流域,可以用这个边界去筛选河网;三是出图时叠加显示,让成果图一眼就能看出行政范围。常见做法是先在 GIS 里把 shp 和 DEM 的坐标系对齐,然后用“按掩膜提取”工具裁切。注意 shp 文件通常包含 .shp、.shx、.dbf、.prj 四个必备文件,解压后要放在同一个文件夹里,少一个都打不开。
3. 从解压到出图:QGIS 和 Python 两条落地路线
3.1 解压与目录结构检查
拿到 .7z 压缩包后,先用 7-Zip 或者 Bandizip 解压。解压后建议按下面的结构整理目录,避免后续路径混乱:
# 建议的目录结构 huangshan_dem/ ├── dem/ │ └── huangshan_12_5m.tif # 主 DEM 栅格文件 ├── boundary/ │ ├── huangshan_city.shp # 市级边界 │ ├── huangshan_city.shx │ ├── huangshan_city.dbf │ └── huangshan_city.prj └── output/ # 存放裁切、分析结果解压后先确认三件事:DEM 文件能不能正常打开、shp 的 .prj 文件里坐标系是什么、栅格的行列数和范围是否覆盖整个黄山市。如果 .prj 缺失,shp 就丢了坐标系信息,后续叠加会错位。常见做法是用ogrinfo命令快速查看 shp 的元数据:
ogrinfo -al -so huangshan_city.shp这条命令会输出图层名、几何类型、要素数量、坐标系和范围。重点看Extent是否大致落在东经 117°到 119°、北纬 29°到 30.5°之间,以及SRS是不是 CGCS2000 或 WGS84 地理坐标系。如果范围明显不对,可能是坐标系定义错了,需要手动指定。
3.2 用 QGIS 做裁切与地形渲染
QGIS 是免费开源的,对这份数据完全够用。操作流程如下:
第一步,把 DEM 和 shp 都拖进 QGIS。如果弹窗问坐标系,选 shp 的 .prj 里定义的那个。
第二步,确认两者坐标系一致。在图层属性里看 CRS,如果不一致,用“矢量 > 数据管理工具 > 重投影图层”把 shp 转到和 DEM 相同的 CRS。
第三步,裁切。菜单栏找“栅格 > 提取 > 按掩膜图层裁剪栅格”,输入图层选 DEM,掩膜图层选 shp,输出格式选 GeoTIFF,勾选“保持输入图层的分辨率”。
第四步,渲染地形。右键裁切后的图层,选“属性 > 符号化”,渲染类型改成“单波段伪彩色”,色带选地形常用的绿-黄-棕-白渐变。想要更直观的效果,可以用“栅格 > 分析 > 山体阴影”生成阴影图层,再把 DEM 设成半透明叠在上面。
# 如果要用 Python 批量处理,pyqgis 脚本示例 from qgis.core import QgsRasterLayer, QgsVectorLayer import processing dem_path = "/path/to/huangshan_12_5m.tif" shp_path = "/path/to/huangshan_city.shp" dem_layer = QgsRasterLayer(dem_path, "dem") shp_layer = QgsVectorLayer(shp_path, "boundary", "ogr") # 按掩膜裁剪 result = processing.run("gdal:cliprasterbymasklayer", { 'INPUT': dem_layer, 'MASK': shp_layer, 'NODATA': -9999, 'ALPHA_BAND': False, 'CROP_TO_CUTLINE': True, 'KEEP_RESOLUTION': True, 'OUTPUT': "/path/to/output/huangshan_dem_clipped.tif" })这段脚本的核心参数是NODATA和KEEP_RESOLUTION。NODATA设成 -9999 是为了让裁切边界外的区域不参与后续计算;KEEP_RESOLUTION必须为 True,否则 QGIS 可能会自动重采样,把 12.5 米变成别的间距。CROP_TO_CUTLINE控制输出范围是否严格贴合边界,一般选 True。
3.3 用 Rasterio 读取与统计地形参数
如果你更习惯在 Python 里做分析,Rasterio 是读 DEM 的首选库。下面这段代码演示了如何读取裁切后的 DEM,并计算高程统计值:
import rasterio import numpy as np with rasterio.open("/path/to/output/huangshan_dem_clipped.tif") as src: dem = src.read(1) # 读第一波段 nodata = src.nodata # 获取无效值标记 transform = src.transform # 仿射变换参数 crs = src.crs # 坐标系 # 把 NODATA 替换成 NaN,避免污染统计 if nodata is not None: dem = dem.astype(float) dem[dem == nodata] = np.nan print(f"高程最小值: {np.nanmin(dem):.1f} 米") print(f"高程最大值: {np.nanmax(dem):.1f} 米") print(f"平均高程: {np.nanmean(dem):.1f} 米") print(f"标准差: {np.nanstd(dem):.1f} 米") print(f"栅格尺寸: {dem.shape[1]} 列 × {dem.shape[0]} 行") print(f"像元大小: {transform[0]:.1f} 米 × {abs(transform[4]):.1f} 米")逻辑说明:src.read(1)读的是第一个波段,DEM 通常只有一个波段。nodata是栅格自带的无效值标记,常见的是 -9999 或 -32768,不处理的话最小值会变成这个数,统计就废了。transform[0]是 X 方向像元大小,transform[4]是 Y 方向像元大小(通常是负数,表示从上往下)。跑完这段,你应该看到黄山市的高程范围大约在 100 米到 1800 米之间,平均高程在 300 到 400 米左右。如果最小值出现负数或者异常大,说明 NODATA 没处理干净。
3.4 坡度坡向计算的参数设置
坡度坡向是 DEM 最常用的派生地形因子。用 GDAL 命令行算最快:
# 计算坡度,输出单位为度 gdaldem slope huangshan_dem_clipped.tif slope.tif -p -s 111120 # 计算坡向 gdaldem aspect huangshan_dem_clipped.tif aspect.tif-p表示输出坡度而非百分比,-s 111120是纬度换算系数,用于把地理坐标系下的度转换成米。如果你的 DEM 已经是投影坐标系(比如 UTM),就不需要-s参数。坡向输出是 0 到 360 度,0 代表正北,90 代表正东。注意坡度计算对 DEM 噪声很敏感,如果数据里有明显的台阶或孤立尖峰,坡度图会出现大量异常高值,这时候需要先做一次中值滤波。
4. 避坑与排查:DEM 处理里最容易翻车的五个地方
4.1 坐标系不匹配导致边界对不上
现象:把 shp 和 DEM 叠在一起,发现边界偏了几百米甚至几公里。原因:两者坐标系不一致,比如 DEM 是 WGS84 地理坐标系,shp 是 CGCS2000 投影坐标系,虽然基准面接近,但投影方式不同,直接叠加必然错位。解决:先用gdalsrsinfo查看 DEM 的坐标系,再用ogrinfo查看 shp 的坐标系,如果不一致,用gdalwarp或 QGIS 的重投影工具统一到同一个 CRS。常见做法是统一到 CGCS2000 高斯-克吕格投影,适合黄山市这种中纬度区域。
4.2 NODATA 值没处理导致统计失真
现象:算出来的最小高程是 -9999 或者 -32768。原因:DEM 边缘或者裁切后的外部区域被标记为 NODATA,但统计时没排除。解决:读取时先判断src.nodata是否为 None,如果不是,用dem[dem == nodata] = np.nan替换。如果 nodata 是 None 但数据里确实有异常值,可以用np.nanmin和np.nanmax先看范围,再手动设阈值过滤。
4.3 伪洼地导致水文分析结果全错
现象:做汇流累积量时,水流在某个平坦区域突然消失或者乱窜。原因:DEM 里存在伪洼地,即周围高、中间低的闭合区域,实际地形中不存在,但数据噪声造成了。解决:用gdalfillnodata或者 RichDEM 的filldepressions做洼地填充。填充前建议先做一次gdaldem slope看看坡度图,如果大片区域坡度为零,说明平坦区太多,可能需要更激进的填充策略。
4.4 裁切后像元大小变了
现象:裁切后的 DEM 像元大小从 12.5 米变成了 12.4999 或者 13 米。原因:裁切工具默认会重采样,尤其是当输出范围不能整除像元大小时。解决:在 QGIS 的裁切工具里勾选“保持输入图层的分辨率”,在 GDAL 命令里加-tr 12.5 12.5强制指定输出分辨率。如果裁切后还是不对,检查输出范围的坐标是否对齐到像元边界。
4.5 shp 文件缺失 .prj 导致坐标系丢失
现象:shp 能打开,但叠加时提示“未知坐标系”,或者位置明显偏移。原因:压缩包里只给了 .shp、.shx、.dbf,没给 .prj。解决:如果知道数据来源,手动创建一个 .prj 文件,内容用 WKT 格式写清楚坐标系。比如 CGCS2000 地理坐标系的 WKT 可以从其他同源数据里复制。实在找不到,就在 QGIS 里手动指定 CRS,然后导出一次,QGIS 会自动生成 .prj。
5. 进阶玩法:用 12.5 米 DEM 做流域提取与三维渲染
5.1 基于 WhiteboxTools 的流域自动提取
WhiteboxTools 是一套开源的地形分析工具,命令行调用很方便。下面这条命令链可以从 DEM 直接提取流域边界:
# 洼地填充 wbt_fill_depressions --dem=huangshan_dem_clipped.tif --output=filled.tif # 计算流向(D8 算法) wbt_d8_pointer --dem=filled.tif --output=flow_dir.tif # 计算汇流累积量 wbt_d8_flow_accumulation --input=flow_dir.tif --output=flow_acc.tif --out_type=cells # 提取河网,阈值设为 5000 个汇流像元 wbt_extract_streams --flow_accum=flow_acc.tif --output=streams.tif --threshold=5000 # 矢量化河网 wbt_raster_streams_to_vector --streams=streams.tif --d8_pntr=flow_dir.tif --output=streams.shp参数说明:--threshold=5000是河网提取的阈值,意思是汇流累积量超过 5000 个像元才认定为河流。这个值需要根据黄山市的实际降水和水系发育情况调整,太小会提取出大量伪沟谷,太大会漏掉小支流。常见做法是先跑一遍 5000,看看结果和实际水系图的吻合度,再微调。--out_type=cells表示汇流累积量以像元个数为单位,如果要转换成面积,乘以 12.5×12.5 平方米即可。
5.2 用 Blender 做三维地形可视化
如果你需要把黄山市的地形做成三维模型用于展示,Blender 配合 DEM 可以快速出效果。流程是:先把 DEM 导出为 PNG 高度图,再在 Blender 里用置换修改器贴到平面上。导出高度图时要注意归一化,把高程范围映射到 0 到 65535 的 16 位灰度值,否则细节会丢失。
# 用 Rasterio 导出 16 位高度图 import rasterio import numpy as np with rasterio.open("huangshan_dem_clipped.tif") as src: dem = src.read(1).astype(float) nodata = src.nodata if nodata is not None: dem[dem == nodata] = np.nan # 归一化到 0-65535 dem_min, dem_max = np.nanmin(dem), np.nanmax(dem) dem_norm = (dem - dem_min) / (dem_max - dem_min) * 65535 dem_norm = np.nan_to_num(dem_norm, nan=0).astype(np.uint16) # 写出为 16 位 PNG from PIL import Image Image.fromarray(dem_norm).save("huangshan_heightmap.png")这段代码的关键是np.nan_to_num把 NaN 填成 0,避免导出时出现黑斑。归一化后的高度图在 Blender 里置换强度要手动调,建议先用 0.1 左右试,再根据实际效果增减。黄山市的地形落差大,置换强度太低会显得平坦,太高又会把山脊拉成尖刺,需要反复试几次。
5.3 验证数据质量的三个硬指标
拿到任何 DEM 数据,我都会强制走一遍这三个检查:第一,用gdallocationinfo随机抽几个点,对比已知地标的高程,比如黄山光明顶实测约 1860 米,如果数据里对应位置差超过 30 米,说明垂直精度有问题;第二,算坡度图的直方图,正常山区坡度应该集中在 5 到 35 度之间,如果出现大量 0 度或者 90 度,说明数据有平坦区或尖峰噪声;第三,检查河网连续性,用提取的河网和实际水系图叠加,看主要河流是否连续,断头河太多说明洼地填充不彻底。从那以后我每次拿到新 DEM 都强制走一遍这三步,宁可多花半小时,也不想在分析跑完才发现数据有问题。希望帮到你。
本文还有配套的精品资源,点击获取