DEM数据包处理全流程:从解压体检到等高线生成
发布时间:2026/9/11 21:03:59 作者:尧图编辑部 阅读量:1,286

简介重庆市DEM数字高程TIF数据包是一套面向GIS学习者、测绘与规划人员的精细地形数据覆盖重庆市域并适当延伸至周边区域分辨率30米意味着每个像元对应地面30米×30米的范围可满足地形分析、坡度坡向计算、专题制图与城市规划等常见需求。压缩包共12个文件以高精度DEM主文件TIF为核心配套tfw坐标信息、ovr快速显示金字塔同时包含完整的重庆市范围Shapefile及其dbf属性表、prj投影文件、sbn/sbx索引等边界辅助文件整体约367MB目录结构清晰便于按需取用。已有2510人学习/下载适合通过QGIS或ArcGIS直接打开使用。借助完整的高程与边界数据可快速完成高程渲染、等高线生成、剖面分析或按行政区划裁剪统计也能作为高校GIS课程实习和科研练习的数据源为后续地理分析提供可靠支持。1. DEM数据压缩包不是拿来即用的拿到“重庆市dem数字高程tif数据含市范围shp文件.zip”这个压缩包很多人会直接解压拖进 ArcGIS 或 QGIS然后立刻遇到黑屏、错位、程序卡死。这个标题看似简单实际坑很多zip 包里的 tif 和 shp 可能坐标系不一致tif 的 NoData 没定义shp 缺少 .prj 文件甚至 zip 本身因为网络中断后半段缺失报 “could not find eocd”。接下来的内容要讲的是拿到这种带市范围 shp 的 DEM 包后从解压、体检、坐标统一、矢量裁剪到生成坡度、等高线最后验证成果的完整路径。适用人群是 GIS 工程师、遥感数据处理人员、测绘专业的同学以及所有被 “dem文件”“tif影像图怎么在cad中自动定位” 这类问题困扰的从业者。2. 拿到 DEM tif 和 SHP 后的第一步解包体检2.1 DEM、TIF、SHP 在空间分析里的角色差异DEM 是数字高程模型的英文缩写它不像卫星影像那样是“照片”而是一个单波段栅格每个像元的值就是高程。tif 在这里是 GeoTIFF内部除了像元像素值还包含地理坐标参考、像元尺寸、旋转矩阵等元数据。SHP 则是一个矢量文件集合重庆市政区范围、区县边界、河流中心线都属于矢量。只有当栅格和矢量的坐标参考系一致时它们才能在同一窗口中精确叠加。举个例子重庆市的 DEM 如果是 ALOS 12.5 米数据原始包内的 tif 可能是 WGS84 经纬度而配套的 shp 如果是 CGCS2000 高斯克吕格投影EPSG:4547直接叠加就会偏移几十米到几百米。下表是我在拿到不同 DEM 数据包时的常用判断依据也可以用来快速识别你手里的 tif 属于哪一类数据源常见投影像元大小适用场景ALOS PALSARWGS84 / UTM12.5 m局地精细地形SRTM 30mWGS8430 m中小尺度ASTER GDEMWGS8430 m区域分析国内生产的DEMCGCS2000 / 高斯5m/10m/12.5m工程测量DSM数字表面模型与 DEM 不一样DSM 记录了建筑和树冠顶面DEM 是裸地面。很多人想“DSM生成DEM”一般要用点云滤波不是一两条命令能搞定的也不是这个数据包要解决的。理解这个区别能帮你判断 tif 文件里的高程是不是真的地表高程尤其是在重庆这种山区、林区密集的地方。2.2 用 zip 命令检查压缩包不要双击拿到 .zip 文件我的习惯是先在终端用 unzip -l 看内容清单。如果压缩包来自网盘或邮件经常出现下载不完整Windows 资源管理器会笼统提示“文件已损坏”而 unzip 能告诉你缺了哪个段。unzip -l 重庆市dem数字高程tif数据含市范围shp文件.zip输出会列出包内所有文件重点检查三项是否存在 .tif 或 .tiff是否存在同名 .shp/.shx/.dbf/.prj是否有 readme.txt。如果只有 .shp 没有 .shx 和 .dbf矢量基本废了如果 .shp 缺少 .prj坐标信息缺失后期需要人工指定。假如 unzip 报 “invalid zip archive: could not find eocd”说明 zip 中央目录不在文件末尾通常是下载不完整或复制中断。可以先用 zip -FF 修复zip -FF 重庆市dem数字高程tif数据含市范围shp文件.zip --out 重庆dem_修复.zip修复后再解压。如果还提示“Failed to copy spatial iop zip”就需要重新获取源文件。至于网上的“zip压缩包密码破解工具”和“zip密码移除”不建议浪费时间发布方如果加了密码正路是找来源要密码。暴力破解工具极易携带恶意代码而且对动辄数 GB 的 DEM 包来说破解成本高到不现实。2.3 用 gdalinfo 给 tif 做体检解压后第一件事是确认 tif 的坐标系、范围、位深和 NoData。我一般用 GDAL 的 gdalinfoWindows 下装完 GDAL 后直接执行gdalinfo 重庆dem_12.5m.tif输出中重点看这几行Coordinate System isOrigin (x, y)Pixel SizeSize isData TypeNoData Value。Coordinate System 是坐标系描述比如 GCS_WGS_1984 或 PROJCS[...]。Origin 和 Pixel Size 共同决定了像元的真实坐标范围Size 是宽高像素数。Data Type 通常是 Float32 或 Int16少数是 Byte如果是 Int16读取时要用带符号的短整型。NoData 如果没显示之后计算坡度、提取高程时会把空洞当 0导致错误。如果你发现 tif 里没有投影信息可以查看数据来源说明。重庆地区常见的 EPSG 编号有 4326WGS84 经纬度、4490CGCS2000 经纬度、4547CGCS2000 3 度带高斯中央经线为 105/108。多数 12.5 米 ALOS 数据是 4326 的但包装者如果重投影过也可能是 UTM 47N。当你确定真实投影后可以用以下命令补写gdal_edit.py -a_srs EPSG:4547 重庆dem_12.5m.tif注意随意给 tif 指定坐标系会把数据毁掉只有明确来源时才能这么做。我见过有人把中国的 DEM 标成 EPSG:3857结果在 QGIS 里整个图层被拉成一条斜线。2.4 用 ogrinfo 检查 SHP 的范围和坐标系矢量端用 ogrinfo 检查命令比 QGIS 属性面板更直接ogrinfo -so -al 重庆市区县界.shp这条命令会显示 Feature Count、Extent、Geometry Column 和 CRS。Extent 若是经度 105-108、纬度 28-31大概率是经纬度若 Extent 里 x 是 300000-500000 米y 是 3200000-3400000 米这种大数值就是投影坐标。这里有个小技巧当 Extent 里的坐标带小数点且范围在 -180 到 180 之间一定是经纬度如果数值大到百万级且带单位 meter则是投影坐标。当 shp 是 CGCS2000tif 是 WGS84两者在同一区域内叠加会有偏移。用老版本 Proj 软件的七参数转换误差可以到米级但很多离线包根本没内置转换网格所以实际偏移可能更大。我一般建议先把 tif 或 shp 统一到 EPSG:4490避免涉及基准面转换。3. 统一坐标系并按 shp 范围精确裁剪 DEM tif3.1 先重投影再裁剪避免空白边距常见错误是拿不同坐标系的 shp 直接去裁剪 tif得到一片黑。GDAL 的 gdalwarp 允许用 -cutline但 cutline 会临时投影坐标写法不一致时容易产生锯齿和偏移。我一般用 ogr2ogr 把 shp 转到与 tif 相同的 CRS再执行 gdalwarp。以 EPSG:4490 为例ogr2ogr -t_srs EPSG:4490 重庆市区县界_4490.shp 重庆市区县界.shp gdalwarp -t_srs EPSG:4490 -cutline 重庆市区县界_4490.shp -crop_to_cutline -dstnodata -9999 -of GTiff 重庆dem_12.5m.tif 重庆dem_4490.tif第一行把矢量转成 CGCS2000 经纬度第二行把 DEM 重投影并按边界裁剪。参数 -t_srs 指定输出坐标系-cutline 指定裁剪范围矢量-crop_to_cutline 让输出栅格范围严格匹配 shp 要素集合的外边界-dstnodata -9999 把裁剪后四周的空洞设为 -9999-of 指定输出格式。执行后建议再用 gdalinfo 看新 tif 的 Extent 和 Size。如果 Extent 与 shp 的 Extent 一致说明裁剪到位如果 Extent 是源 tif 的范围说明 cutline 没生效多半是因为 shp 没有投影信息或投影不匹配。注意如果 shp 是多个区县面要素-cutline 会按所有要素的合集裁剪而不是分别输出多个文件。想分别输出需要走 3.2 的 Python 方案。如果 tif 文件特别大比如超过 20GBgdalwarp 内存占用会很高。可以加 -wm 1024 把内存缓存设到 1GB并用 -wo NUM_THREADSALL_CPUS 开启多线程。但多线程在读取压缩 tif 时可能触碰到 IO 瓶颈速度不升反降。我一般先不加线程等观测到 CPU 占用不足再调整。3.2 用 Python rasterio 处理批量裁剪当 zip 包里有多个区县 shp或者你想按行政区拆分成多个 DEM我常用 Python 写循环。先安装依赖pip install rasterio geopandas处理脚本如下代码里有注释import geopandas as gpd import rasterio from rasterio.mask import mask dem_path 重庆dem_12.5m_4490.tif shp_path 重庆市区县界_4490.shp # 读取区县面要素 gdf gpd.read_file(shp_path) with rasterio.open(dem_path) as src: for idx, row in gdf.iterrows(): # 每个区县几何转成列表用于裁剪 geom [row.geometry] arr, out_transform mask(src, geom, cropTrue, nodata-9999) out_meta src.meta.copy() out_meta.update({ driver: GTiff, height: arr.shape[1], width: arr.shape[2], transform: out_transform, nodata: -9999 }) out_path fcut/{row[区县名]}_dem.tif with rasterio.open(out_path, w, **out_meta) as dst: dst.write(arr) print(finished:, out_path)mask 是核心它读入一个几何列表并裁剪栅格cropTrue 会把输出范围缩小到几何的外接矩形和矢量边界形状nodata-9999 统一无数据值。注意gdf 必须与 DEM 坐标系一致如果不确定在读取后加一行 gdf gdf.to_crs(src.crs)。这个脚本会把每个区县保存成独立 tif区县边界外的地方全部变成 NoData而不是简单的矩形切除。如果区县数量超过三十个建议先把源 tif 分块读入 numpy再做逐像元掩膜这样能省下反复打开文件的损耗。裁剪后建议检查有效像元占比。如果一个区县在 shp 里非常碎小而裁剪出的 tif 里有超过 90% 是 NoData说明这个范围可能跟 DEM 没有重叠或者在投影转换时出了问题。有效像元占比的计算可以用 numpyimport numpy as np valid_ratio (arr ! -9999).sum() / arr.size print(valid_ratio)拿到比例后低于 5% 的文件直接删掉避免后续给客户交付一堆“空瓦片”。3.3 经纬度 DEM 的坡度和山体阴影要指定水平比例重庆海拔起伏大拿到 DEM 后很多人马上生成坡度和山体阴影。这里有个隐藏坑gdaldem 默认把水平单位当成米如果输入是 EPSG:4326 经纬度的 tif算出来的坡度会整体偏小山体阴影也发灰。必须用 -s 指定水平比例。纬度 29° 附近1 度经度约 97 公里1 度纬度约 111 公里综合可用一个近似值gdaldem slope 重庆dem_4490.tif 重庆slope.tif -p -s 111320 gdaldem hillshade 重庆dem_4490.tif 重庆hillshade.tif -z 2.2 -s 111320-p 表示输出百分比的坡度去掉 -p 则输出度数-s 是水平单位与垂直单位的比例输入经纬度、垂直单位是米的情况下用 111320 这个近似值-z 是垂直夸张倍数重庆这种中低山地形建议 1.8-2.5。如果输入是投影坐标例如 4547水平单位就是米这时不需要 -s。如果在投影坐标下误加了 -s 111320坡度会被放得非常大几乎全部接近 90 度。如果只是为了出图而不是定量分析也可以在 QGIS 的“处理工具箱”里运行“坡度”和“山体阴影”算法参数面板会自动处理经纬度场景。命令行仍然更适合批量处理毕竟几十个区县寨子要一次跑完。3.4 矩形裁剪与矢量裁剪的选择有些场景只需要一个矩形实验区用 gdal_translate -projwin 比 gdalwarp 快很多gdal_translate -projwin 105.8 30.4 107.3 28.6 -of GTiff 重庆dem_4490.tif 重庆矩形dem.tif-projwin 的四个数字是左上角经度、左上角纬度、右下角经度、右下角纬度。很多人写成左下角和右上角得到空白。另外-projwin 后面的坐标必须与源 tif 坐标系一致如果源是 4547 而这里写经纬度输出会是黑色。矩形裁剪的缺点是把边界外区域也切进来。我的习惯是先矩形粗裁再用 shp 精裁因为 gdalwarp 在超大 tif 上做 cutline 会占用大量内存裁剪前缩小范围能明显提速。如果原始 tif 超过 4GB建议先用 gdal_translate 加 -co BIGTIFFYES -co COMPRESSDEFLATE 转成压缩格式。压缩后的 tif 体积可能只有原来的三分之一gdalwarp 读取时更流畅而且不会因为单个文件无法写入超过 4GB 而失败。这样也能让最终交付的 zip 体积更小方便拷贝。4. 裁剪后的 DEM 和 SHP 怎么落到实际业务里4.1 用 zonal_stats 统计各区县的高程拿到重庆市范围 shp 和裁剪后的 DEM tif最常见的需求是“统计每个区县的平均海拔、最高最低海拔”。用 rasterstats 一行能出结果pip install rasterstatsfrom rasterstats import zonal_stats import json stats zonal_stats(重庆市区县界_4490.shp, 重庆dem_4490.tif, stats[min, max, mean, median, std], nodata-9999) print(json.dumps(stats, ensure_asciiFalse, indent2))zonal_stats 会根据矢量边界把栅格切成不同区域然后按 stats 参数指定的统计量计算。nodata 参数必须和裁剪时一致否则把空洞当成 0 参与平均整个平均海拔会被严重拉低。重庆主城区平均海拔约 200-300 米城口、巫溪的高海拔乡镇可以到 2000 米左右看到统计结果时可以快速判断是否合理。如果想进一步统计“海拔超过 1000 米占多少面积”可以用 add_stats 自定义函数或者把 DEM 重分类后再做 zonal statistics。对于大范围数据zonal_stats 会比较慢因为每个区县都要做一次栅格掩膜。可以先按区县拆分 shp再用 Python 的多进程 parallel 并行处理。每个线程处理一个区县时内存占用也会被限制在单县范围内不像整片重庆 DEM 那样吃紧。4.2 确认 tif 到底是 DEM 还是 DSM这个问题很容易被忽略。很多所谓“DEM”包实际是 DSM包含建筑和树冠高度。判断方法很直接在 QGIS 里加载 tif找个江面或者平坦的机场跑道用“信息”工具读取高程。重庆长江江面海拔约 150-200 米如果读出的值是连续且接近这个高度的说明是真实的 DEM如果出现 500 米甚至更高的异常点就要怀疑是 DSM 或者未滤波的点云插值。DSM 想转 DEM 不是换个格式就行要用点云分类算法把地面点和非地面点分开再重插值。这已经超出 zip 包本身的范围但理解这一点能避免拿错误的 tif 做淹没分析或土方量计算。另外还要看 tif 直方图。如果直方图里有大量像元集中在 0 或者 -32768说明背景和 NoData 混在一起。用 QGIS 的光谱工具查看直方图可以快速判断。对重庆来说真实的江面高程不会为 0出现大片 0 值就说明背景值没处理好需要回到第 3.1 节重新裁剪并设置 NoData。4.3 从 DEM 生成等高线 shp并叠加验证有了裁剪后的 DEM可以快速提取等高线 shp用于成图和质检gdal_contour -a elev -interval 50 重庆dem_4490.tif 重庆等高线50m.shp-a elev 给输出 shp 添加一个 elev 字段interval 是等高距。重庆地区高差大总览用 50 米局部工程用 10 米或 5 米再小就会产生大量短线并且渲染很慢。等高线生成后加载到 QGIS和范围 shp 叠加检查有没有等高线突出到边界外。如果有说明 NoData 区域没有裁剪干净回到第三章的 crop 流程。如果等高线在河谷处形成密集锯齿通常是原始 DEM 噪声或填洼前的水文地形可以先用 gdaldem 做平滑。提到“tif影像图怎么在cad中自动定位”本质上就是给 tif 附带世界文件。GDAL 可以用一条命令生成 CAD 可识别的 tfwgdal_translate -of GTiff -co TFWYES 重庆dem_4490.tif 重庆dem_cad.tif同目录下会出现重庆dem_cad.tfwCAD 通过它读取栅格的插入点、像元尺寸和旋转参数。这样在 CAD 里插入图像时图像就能自动落到重庆的坐标位置不需要手动缩放旋转。生成 tfw 之后不要随意改文件名CAD 的“图像管理器”会把同名的 .tif 和 .tfw 自动配对一旦重命名就必须手动指定外部参照路径很容易出现位置丢失。4.4 将 SHP 转成 TXT/CSV 并采样高程很多外部工具只认识点坐标文本比如飞控地面站、土木计算软件。需要把 shp 转成 txt 或 csvogr2ogr -f CSV 重庆市区县界.csv 重庆市区县界_4490.shp -lco GEOMETRYAS_XY-lco GEOMETRYAS_XY 会让输出 csv 包含 X、Y 两列。如果是面要素ogr2ogr 会把每个面边界的连续坐标点都输出行数会很多适合做边界导入。接下来要对这些坐标点补上高程用 rasterio.sample 取最近邻的像元值import rasterio coords [(106.5, 29.5), (107.0, 30.0)] # 示例坐标 with rasterio.open(重庆dem_4490.tif) as src: for lon, lat in coords: elev list(src.sample([(lon, lat)]))[0][0] print(lon, lat, elev)src.sample 返回一个生成器list 后取第一个元素再下标取出像元值。这里如果用“shp转txt”这条路要注意 CSV 的坐标系说明最好在 txt 头写一行 EPSG:4490避免外部程序按默认坐标系读取。rasterio.sample 默认是最近邻插值对 DEM 这种连续表面来说可能会出现台阶感。如果需要平滑可以先对 tif 做双线性重采样gdal_translate -r bilinear -tr 0.0002 0.0002 重庆dem_4490.tif 重庆dem_bilinear.tif-r bilinear 指定重采样方法-tr 给出输出像元大小。这样后续采样得到的高程就不会有跳变。5. 交付前的质量验证和边界处理5.1 用 gdalinfo QGIS 双重检查偏移处理完的 DEM 必须做位置验证。命令行用 grep 提取关键信息gdalinfo 重庆dem_4490.tif | grep -E Origin|Pixel Size|Size is|Extent重庆的真实经度范围约 105.2-110.2纬度范围 28.2-32.2。如果 Extent 落在这两个范围之外说明投影设错了。再把 tif 和 shp 一起拖进 QGIS边界应该完全贴合。注意 QGIS 加载时默认使用 tif 自带投影如果你的 4490 tif 被手工改成 4326QGIS 仍会显示正确因为两种坐标系的平面距离在重庆地区可能只差几十米但打印 Extent 时会差 0.0-0.1 度。严格来说 CGCS2000 和 WGS84 有理论椭球差异在重庆地区偏移约 60-100 米所以如果不做七参数转换直接标注 4326 会在工程复核时被质疑。还可以用 gdal_polygonize 把 DEM 的外边界转成面矢量再和 shp 做空间对比。如果矢量边界比 DEM 的有效范围大说明裁剪时留了一圈 NoData可能是 gdalwarp 的采样容差没设好。使用gdal_polygonize.py 重庆dem_4490.tif -b 1 -mask 重庆dem_4490.tif 重庆有效边界.shp这里 -mask 参数把所有非 NoData 的像元输出为面。生成的矢量会非常碎片化但可以用 ogr2ogr 的 ST_Union 合并再用 ST_Snap 检查缝隙。5.2 NoData 坑位产生的“黑洞”处理很多 DEM tif 的 NoData 是 -32768 或 0如果不统一生成的坡度、山体阴影会出现大量黑色区域。先查gdalinfo 重庆dem_4490.tif | grep -i nodata没有 NoData 行就手动设置gdal_edit -a_nodata -9999 重庆dem_4490.tif如果源 tif 的 NoData 是 0而背景又没有任何小于 0 的有效值也可以直接用 0。但要小心重庆的河滩、洼地位置也可能有真实高程为 0 或接近 0 的像元直接设 0 会造成误杀。更稳妥的方法是读取 tif 后统计直方图把背景和高山分开。一般负值基本可以认定是 NoData除非是死海或吐鲁番盆地的负高程。重庆不存在这种地形所以负值设为 NoData 是安全的。5.3 用 ST_Union 和 ST_Boundary 得到外边界线范围 shp 如果包含几十个区县面但你只需要重庆市整体外边界两条 ogr2ogr 就够ogr2ogr 重庆合并.shp 重庆市区县界_4490.shp -dialect sqlite -sql SELECT ST_Union(geometry) AS geometry FROM 重庆市区县界_4490 ogr2ogr 重庆外边界.shp 重庆合并.shp -dialect sqlite -sql SELECT ST_Boundary(geometry) AS geometry FROM 重庆合并第一句用 ST_Union 合并所有多边形第二句用 ST_Boundary 提取合并后多边形的边界线。这个外边界 shp 比直接用原始 range.shp 更干净因为原始范围包可能包含岛屿或飞地合并后去掉了内部的区县边界。最后把外边界和 DEM 一起打包你就得到一份标准的“重庆dem数字高程tif数据 市范围shp文件”交付包。本文还有配套的精品资源点击获取