
简介湖北省宜昌市30米分辨率DEM数字高程数据面向GIS学习者、地理信息从业者与规划研究人员可用于地形制图、坡度坡向分析、洪水淹没模拟、可视域分析及区域环境评估等场景。压缩包共12个文件包含TIFF格式高程栅格、Shapefile格式市域边界矢量、投影坐标系定义文件、金字塔预览文件、空间索引与XML元数据等总大小约63.67MB文件组织规范便于在ArcGIS、QGIS等平台直接加载使用。包内单独提供宜昌市范围shp边界配合tfw地理参考文件可快速将DEM影像与真实坐标对齐裁剪出完整市域地形图层且覆盖范围含周边部分区域。已有825人学习下载适用于教学演示、课程设计与中小尺度地理建模实践能为后续坡度计算、流域划分等分析提供标准化基础数据。1. 这个 30m DEM 包不是拿来就能出图先把它修成能分析的地形底图很多朋友用 ArcGIS 双击打开宜昌市 DEM 数字高程数据包里的 tif看到的不是彩色地形而是一片灰黑或者整块绿得发假。这不是数据坏了而是拉伸方式和无效高程没处理好。30m 分辨率意味着一个栅格像元约对应 900 平方米的地面范围做市县尺度、小流域分析、规划选址够用做单体场地设计就偏粗。藏在 zip 里的市级范围 shp 文件不是装饰它既是裁剪边界也是后续填洼、坡度、坡向统计的掩膜范围。这篇按预检、裁剪、派生、排错、交付的顺序把这套 30m DEM 数据用透。2. DEM 预检比实际操作更耗时30 分钟搞定文件结构、坐标系与无效高程拿到 zip 包后最常见的冲动是直接解压、往地图里一拖、随手做个坡度出图。但 30m 栅格和市级范围 shp 的组合里真正耽误时间的从来不是裁剪那一下而是坐标系对不上、NoData 值被当成 0 米、shp 缺投影文件这类前置问题。预检做扎实后面裁剪和填洼一次过预检跳过后面每一步都在给前面的偷懒还债。2.1 解压后的文件清单shp 为什么是五个文件而不是一个先不要双击 zip 再拖拽解压到一个干净目录然后按文件清单核对。zip 解压后至少有两类东西一类是栅格 DEM通常以 .tif 或 .img 结尾另一类是宜昌市市级范围的 shp 矢量边界。很多人以为 shp 就是单个文件实际它是一组文件.shp 存几何、.dbf 存属性、.shx 存索引、.prj 存投影信息。有的包还带 .cpg 字符集和 .sbn/.sbx 空间索引。缺 .dbf 会打不开属性表缺 .prj 则会让 ArcMap 和 QGIS 猜坐标系后面裁剪整体错位。unzip -q 湖北省宜昌市DEM数字高程数据30m含本市级范围shp文件.zip -d ./yichang_dem ls -lh ./yichang_dem # 期望看到 1 个 tif 栅格以及同名 shp 派生出的 5 个以上文件解压参数里-q是安静模式-d指到指定目录。Windows 上建议解压到D:\work\yichang这种全英文路径。这一步是后续 arcpy 和 GDAL 能稳定运行的前提路径带中文时各工具编码行为不一致经常出现“数据明明在却打不开”的奇怪报错。解压完再看有没有 .tfw 世界文件和 .aux.xml 辅助文件前者记录地理配准参数后者存栅格统计信息。老版本 ArcMap 缺了 .aux.xml 可能不显示有效范围整张图看起来像被压成一个点。2.2 坐标系一致性核对先统一再裁剪还是先裁剪再统一这个问题的答案是先统一坐标系再裁剪。先裁剪后投影会把栅格重采样两次第一次按 shp 范围切第二次按目标坐标系抽点边缘像元会多一层锯齿和错位。gdalinfo ./yichang_dem/dem.tif | head -20 ogrinfo ./yichang_dem/宜昌市界.shp -so -al | grep -E EXTENSION|PROJCS|GEOGCS | head -5gdalinfo会输出栅格的 EPSG 代码、像元大小和四个角坐标ogrinfo输出 shp 的几何类型和空间参考。宜昌市常见的数据组合是 WGS84 或 CGCS2000 地理坐标经纬度显示单位通常是度和分也可能是高斯-克吕格投影的米制坐标。判断标准很简单看坐标值——数值在 110 到 112 之间且带小数点是经纬度数值在几十万到几百万量级是投影坐标。两者不一致时用 ArcMap 的 Project Raster 和 Project 工具统一到同一个坐标系TIN 地形和坡度计算之前尽量选米制投影坐标否则坡度结果会按经纬度度数去解释数值完全不可用。如果 .prj 文件缺失旧版 ArcMap 会弹出“未知空间参考”提示。不要点确定硬算正确做法是先用 Define Projection 工具手动指定数据来源坐标系再用 Project 工具转换。指定错了虽然也能出图但所有距离、面积、坡度结果都会错且很难回头排查。2.3 无效高程筛查负值不一定是错误0 值不一定能用DEM 栅格里的 NoData 与 0 是完全不同的概念。NoData 表示该像元没有有效观测值0 表示真实海拔为 0 米左右。但很多数据生产环节会把无效值写成 -9999、-32768甚至直接写成 0。如果直接把 0 当真实高程参与填洼宜昌长江沿岸的河谷地带会被挖出一个假的“海平面凹陷”后面所有汇水路径都跟着歪。import rasterio import numpy as np with rasterio.open(./yichang_dem/dem.tif) as src: arr src.read(1).astype(np.float32) nodata src.nodata valid arr[arr ! nodata] if nodata is not None else arr print(nodata:, nodata) print(min:, valid.min(), max:, valid.max()) print(zero_count:, int((arr 0).sum())) print(negative_count:, int((arr 0).sum()))这段脚本用 rasterio 读栅格先取元数据里的 nodata 标记再统计有效值的最小、最大值以及 0 值、负值数量。如果零值数量占全图比例很低通常是无数据填充如果负值集中出现在某一区域需要对照地形判断是不是内陆湖底或河谷负海拔。ArcMap 里可以在栅格图层属性 - 符号系统里把 NoData 显示为单独颜色QGIS 则可以在图层属性 - 透明度里单独设置。预检这一步把无效值范围定下来第三章裁剪时才不会把地狱值带进派生分析。3. 用市级范围 shp 裁剪 DEMArcmap 掩膜提取、QGIS 与 GDAL 的最小操作集预检通过后进入核心操作用面图层把大范围 DEM 裁到宜昌市市级边界内。这步工具选型决定了后续成果的边界形状和 NoData 表现。搜索这个标题的人多半会搜到“arcmap 中依靠面图层裁剪 dem 栅格 tif 文件和依靠面图层掩码提取有啥区别”下面先把这两个常用工具的关系讲透再给出 QGIS 和 Python 的落地操作。3.1 ArcMap 中 Clip 与掩膜提取两个工具结果有什么不一样ArcMap 里有两个工具看起来都能裁剪数据管理工具箱里的 Clip栅格裁剪和 Spatial Analyst 工具箱里的 Extract by Mask按掩膜提取。两者的差别不在最终影像差多少而在处理逻辑。Clip 是按照面要素的外包矩形或面本身去切栅格直接改写输出范围的像元边缘是否完全贴合边界取决于像元对齐Extract by Mask 则是用掩膜面去“筛选”栅格像元处于面内的像元被保留面外的像元统一写成 NoData同时受 ArcToolbox 环境设置里的掩膜和范围影响。import arcpy from arcpy.sa import * arcpy.env.workspace rD:\work\yichang arcpy.env.snapRaster dem.tif arcpy.env.extent 宜昌市界.shp # 方式一数据管理工具箱裁剪 arcpy.Clip_management( in_rasterdem.tif, rectangle#, out_rasterdem_clip.tif, in_template_dataset宜昌市界.shp, nodata_value-9999, clipping_geometryClippingGeometry, ) # 方式二Spatial Analyst 掩膜提取 outExtractByMask ExtractByMask(dem.tif, 宜昌市界.shp) outExtractByMask.save(dem_mask.tif)代码里Clip_management的clipping_geometry参数传ClippingGeometry是按 shp 面边界裁剪而非外接矩形这一步很多人漏掉默认参数会裁出整个矩形外框。nodata_value要配合预检结果写避免输出栅格把原 NoData 改成 0。ExtractByMask更简洁但它要求 Spatial Analyst 授权且输出会在面边界处保留一圈 NoData 像元。这两种方式的结果在 ArcMap 里肉眼几乎一样差别在后续计算掩膜提取的 NoData 会参与栅格计算器的条件判断而 Clip 输出通常直接带背景值。做水文分析推荐 ExtractByMask做地形切片导出推荐 Clip。3.2 QGIS 里用面图层裁剪gdalwarp 一条命令解决QGIS 用户不需要打开两个工具箱核心就是 GDAL 的gdalwarp。栅格菜单里的“裁剪栅格按掩膜图层”对话框最终也是在调它只是界面把参数藏起来了。直接在终端跑的好处是参数透明、可以批量。gdalwarp \ -cutline ./yichang_dem/宜昌市界.shp \ -crop_to_cutline \ -dstnodata -9999 \ -co COMPRESSDEFLATE \ ./yichang_dem/dem.tif ./yichang_dem/dem_clip.tif-cutline指定裁剪边界 shp-crop_to_cutline是核心参数让输出范围贴合面边界而不是外包矩形少了它你会得到一张矩形底图加一个空洞。-dstnodata -9999把外部区域统一写成 -9999与上一步无效值口径保持一致。-co COMPRESSDEFLATE是压缩选项30m DEM 裁到市域范围后文件不大但 DEFLATE 能让后续读取更快。执行完用gdalinfo dem_clip.tif看一眼角坐标和 NoData 标记确认没有丢失投影。QGIS 图形界面里如果发现裁剪结果边缘有白边多半是没勾选“裁剪到裁切线”选项中文界面里它叫“按裁切线裁剪”不是“裁剪到图层范围”。3.3 Python 批量裁剪rasterio 的 mask 函数与多块边界合并当你有多个区县 shp 想分别裁出 DEM或者想把宜昌市级 shp 拆成乡镇后批量处理ArcMap 一个个点工具太慢。用 rasterio 写个循环最省事。import rasterio from rasterio.mask import mask from shapely.geometry import mapping import geopandas as gpd boundary gpd.read_file(./yichang_dem/宜昌市界.shp) features [mapping(boundary.geometry.unary_union)] with rasterio.open(./yichang_dem/dem.tif) as src: out_img, out_transform mask( src, features, cropTrue, nodata-9999, ) out_meta src.meta.copy() out_meta.update({ driver: GTiff, height: out_img.shape[1], width: out_img.shape[2], transform: out_transform, nodata: -9999, }) with rasterio.open(./yichang_dem/dem_clip.tif, w, **out_meta) as dst: dst.write(out_img)代码里boundary.geometry.unary_union先做几何合并避免 shp 里存在多个面要素时掩膜只套用第一个面。cropTrue表示按边界收缩输出范围。nodata-9999让裁出来的背景区域统一成无效值这样后面填洼时不会把边界外的平地误当成真实地形。注意输出投影来自源栅格如果 shp 与 dem 投影不一致mask 会抛异常或裁出错误区域。这种批量方式配合 glob 遍历多个 tif 和多个 shp一晚上能把一整个地市的数据洗一遍。4. 裁剪后的 DEM 才真正可用填洼、坡度坡向与等高线三个派生方向裁剪完成不代表分析能直接开始。原始 DEM 里包含真实地形中的洼地、平地噪声和采集误差直接做汇水分析会出现断头河和伪洼地。所以裁剪后的下一步是把 DEM 变成“可被水文和地形工具信任”的底图常见做法是依次做填洼、坡度坡向、等高线提取。这三个方向也是搜索热词里“dem文件”“从dem提取shp”最常见的落点。4.1 填洼Fill为什么流域分析前必须填Z limit 怎么设填洼就是把 DEM 中低于周围像元的闭合凹陷填平到出水口高度。天然地形确实存在封闭洼地比如喀斯特地貌里的漏斗但在小流域分析里这些洼地会阻断水流路径导致流向计算戛然而止。填洼工具不区分真实洼地和数据噪声肉眼判断不了只能靠参数控制。import arcpy from arcpy.sa import * arcpy.env.workspace rD:\work\yichang arcpy.env.snapRaster dem_clip.tif fill_out Fill(dem_clip.tif, z_limit5) fill_out.save(dem_fill.tif)z_limit是填洼深度的上限单位与 DEM 高程单位一致。设 5 表示只填埋深度在 5 米以内的洼地超过 5 米的真实漏斗和采石坑会被保留。如果不填这个参数工具会把所有洼地全部填平宜昌西部山区的溶蚀洼地会被彻底抹掉后续提取的等高线会多出一圈假闭合圈。QGIS 里对应工具是 SAGA 的 Fill Sinkswang liu参数 Threshold 同理。填洼完成后用栅格计算器做一次dem_fill - dem_clip差值图里亮点集中的区域就是被填掉的主要洼地顺手检查有没有填出异常大的水面。4.2 坡度坡向输出单位选度数还是百分比影响很大坡度工具输出单位有两种度数degree和百分比percent。度数适合做坡度分级图百分比适合做土壤侵蚀和工程设计。两者换算关系是百分比等于度数正切值乘以10045 度对应 100%。做规划选址时百分比的“临界值”更容易被人接受比如 25% 以下算缓坡超过 60% 算陡坡。import arcpy from arcpy.sa import * slope_out Slope(dem_fill.tif, output_measurementDEGREE) slope_out.save(yichang_slope.tif) aspect_out Aspect(dem_fill.tif) aspect_out.save(yichang_aspect.tif) hillshade_out Hillshade(dem_fill.tif, azimuth315, altitude45) hillshade_out.save(yichang_hillshade.tif)output_measurement传DEGREE或PERCENT_RISE。坡度计算前必须确保 DEM 是投影坐标系如果是经纬度坐标ArcGIS 会按伪米制计算结果偏小且不可信。Aspect输出是 0 到 360 度的坡向方位角平地为 -1用来做阴坡阳坡分析时要重分类把 315-360 和 0-45 合并成北坡。Hillshade是山体阴影虽然是渲染工具不是分析工具但它能快速暴露 DEM 里残留的条带噪声我经常用凌晨阳光角度先跑一张看数据质量。4.3 从 DEM 提取 shp等高线间距的选择与线平滑标题热词里有不少人在找“arcgis 从 dem 提取 shp”这里特指等高线。等高线是从 DEM 栅格里提取出的矢量线要素输出为 shp可以作为宜昌市级边界内的地形辅助线叠加到规划图上。import arcpy arcpy.env.workspace rD:\work\yichang arcpy.env.snapRaster dem_fill.tif contour_out arcpy.gp.Contour_sa( in_rasterdem_fill.tif, out_polyline_featuresyichang_contour.shp, contour_interval10, base_contour0, )contour_interval设 10 表示每 10 米生成一条等高线。宜昌市城区平缓地段高差几十米10 米间距能看清地形骨架西部山区陡峭建议 20 米或 50 米否则线太密压盖道路和房屋。base_contour设起始高程常用 0 米起算。提取出的等高线带有锯齿直接出图不好看但不要急着平滑——平滑工具会把高程属性字段搞乱而且矢量线一旦平滑会绕过真实地形特征。更合理的做法是把等高线 shp 转成 3D 线要素显示在 ArcScene 里或者叠加到山体阴影上做半透明出图。如果源数据其实是 DSM表面模型即包含了树木和建筑高度的表面高程直接提取等高线会出现大量虚假闭合圈必须先做地面滤波或者换数据源。这里的密码在于明白 DEM 与 DSM 的区别DEM 是裸地表DSM 是地物顶面。5. 宜昌 DEM 分析常见问题排查五个最容易翻车的现场与处理办法30m DEM 数据本身的坑不算多真正让人反复重做的是坐标系、无效值和工具参数这三个黑匣子。以下五个现象按“现象 → 原因 → 解决”写照着排查能省掉一整天返工。5.1 裁剪结果全黑或全 0现象ArcMap 里裁剪后的 tif 一片黑拉伸显示只有 0 和 255 两个值。原因shp 面要素和 DEM 栅格的投影坐标系不一致导致掩膜范围根本没落在栅格上所有像元都被判为 NoData或者nodata_value参数写作 0把有效高程也标记成空。解决打开两个图层属性分别记录投影信息用 Project 工具统一后再裁剪。若确认只有 NoData 问题在 Clip_management 里把nodata_value设为 -9999并在符号系统里单独给 NoData 设透明色。验证方法是用识别工具点几个像元读出真实高程而不是 0。5.2 裁剪范围整体偏移几百米边界线切在山顶上现象裁剪结果边界大体正确但锯齿边缘明显边界线与 shp 边界差出两三个像元部分山坡被切掉。原因栅格像元与 shp 矢量的空间位置没有严格对齐GDAL 的 mask 默认按像元边界取整ArcGIS 环境设置里没有指定 snapRaster。解决在 ArcToolbox 环境里把snapRaster指向源 DEM让裁剪输出像元格网与源栅格完全重合用 gdalwarp 时增加-tr参数明确输出分辨率比如-tr 30 30并让它与源栅格对齐。裁剪后把 shp 叠加到底图上边界处像元脱落超过一个像元宽度就需要重算。5.3 NoData 区域被当成 0 米参与填洼现象填洼后的水文分析在边界外出现巨大洼地或者河网顺着矩形边缘走。原因裁剪输出没有正确设置 NoData背景区域被写成 0 或 -9999而 Fill 工具把它当作有效高程参与计算边缘处形成一道虚假挡墙。解决填洼前用栅格计算器写Con(IsNull(dem_clip), dem_clip, dem_clip)确认 NoData 存在然后用SetNull把所有非有效值统一。再做一次Fill并用IsNull检查输出节点。更稳妥的办法是在裁剪工具里指定-dstnodata -9999让背景值保持为空。5.4 高程统计里出现负 100 米或一万米的异常值现象用识别工具点长江水面高程显示为 -32768点山顶显示为 10000 以上。原因数据生产阶段把无效高程填充成了极端哨兵值常见 -32768、-9999、0ArcMap 默认把这些值当有效数据参与拉伸显示才会整片怪异颜色。解决用第二章的 python 统计脚本找出哨兵值然后做条件重映射把哨兵值改写成 NoData。栅格计算器写法是Con(dem -32768, NoData(), dem)。处理完再检查一遍极值确保有效高程范围落在该区域合理的几十米到两千多米区间。5.5 shp 缺少 .prj 文件导致裁剪和填洼全程错位现象shp 能打开能显示但和 DEM 叠不上gdalwarp 报“transform failed”或坐标系 mismatch。原因zip 包里数据来源裁剪时不严谨shp 文件没带投影定义。ArcMap 在有投影缺失时可能自动猜测成 WGS84 地理坐标猜错就全盘错位。解决先看 shp 所在目录有没有 .prj没有就按已知来源补坐标系。通常这种行政边界一版来自国土空间规划或基础测绘数据坐标系不是 CGCS2000 就是 WGS84。用 Define Projection 工具手动指派再 Project 到目标坐标系。注意补投影和重新投影是两步必须先补齐再转换顺序反了等于又把错误放大一次。6. 把成果变成可交付的数据包分块导出、文本互转与三维切片收尾技巧裁剪和派生做完通常会进入交付环节。给甲方或同事的成果至少要考虑三件事大范围 DEM 要不要分块、shp 怎么转成其它交换格式、三维展示用哪种方案。这三个收尾技巧都是实际工作中高频出现的需求。渔网分块处理大面积 DEM 时常见做法是先用 Create Fishnet 生成覆盖全市的格网 shp再按格网循环裁剪。30m DEM 在宜昌市范围不算大但如果后续接 5 米或 10 米数据分块会让读取和处理快很多。格网间距按 2000 乘 2000 像元切每块约 60 万像元ArcMap 加载和 python 处理都舒服。shp 转 txt 的诉求多来自需要用文本交换数据的场景。ArcGIS 里可以用 Raster to ASCII 把 DEM 导出成 txt 栅格但 shp 转 txt 通常指的是把矢量属性写成逗号或制表符分隔文本用 geopandas 一行代码实现。import geopandas as gpd gdf gpd.read_file(./yichang_dem/宜昌市界.shp) gdf[wkt] gdf.geometry.to_wkt() gdf[[name, wkt]].to_csv(./yichang_dem/宜昌市界.txt, sep\t, indexFalse)to_wkt()把几何写出文本格式再连带属性字段导出成 tab 分隔的 txt。反过来别人发来带 WKT 字段的文本用shapely.wkt.loads转成几何再写成 shp 文件就能恢复矢量。这套互转流程比直接用 FME 脚本简单得多也绕开了 dbf 中文字段编码的老问题。三维展示方面除了 ArcScene 拉伸近两年流行把 DEM 和边界 shp 一起转成三维瓦片网页端直接加载。转换思路并不复杂先把 DEM 转成带高程属性的 terrain 或 3D 模型再切片成 3D Tiles。但 30m 数据做城市级三维会显得很粗糙更合适的是做山体阴影叠加后的半透明起伏图配合市级边界 shp 做范围线。最后说个习惯我每次把包含 shp 的 zip 交付出去之前强制自己先删掉临时文件再压缩解压后第一件事是看 .prj 和 .tfw 是否齐全。早年为图省事跳过预检被甲方一句“你的裁切结果为什么整体往东飘了十几米”问得哑口无言。从那以后凡是 DEM 加 shp 的活先把坐标系和无效值这两关过了再谈出图。希望帮到你。本文还有配套的精品资源点击获取