简介:这份资源面向地理信息、城乡规划、测绘及环境研究等领域的从业者与学习者,提供湖南省湘西土家族苗族自治州30米分辨率的DEM数字高程数据,并附带本市级行政范围矢量边界,可用于地形分析、坡度计算、洪水模拟与制图等GIS任务。压缩包共12个文件,约50.18MB,主要包含tif格式的高程栅格数据、shp格式的行政边界矢量文件,以及prj坐标系统、tfw坐标配准、dbf属性表、shx与sbn/sbx索引、ovr金字塔缩略图和xml元数据等配套文件,构成一套可直接在ArcGIS、QGIS中加载的完整空间数据集。目前已有301人学习下载。数据覆盖范围完整、分辨率适中,既能满足区域尺度地形建模需求,也便于与行政边界叠加开展空间统计,适合作为课程实验、项目底图或规划分析的基础数据使用。
1. 湘西州 30m DEM 数据到手后:先搞清楚它能干什么、不能干什么
如果你正在做湘西土家族苗族自治州范围内的地形分析、水文建模、选址评估或者三维可视化,大概率绕不开一份 30m 分辨率的 DEM 数字高程数据。这次拆的这份资源,是覆盖湘西州本市级范围的 30m DEM 栅格,外加配套的 shp 边界文件。很多人拿到这类压缩包的第一反应是直接拖进 ArcMap 或者 QGIS 里看效果,但真正决定后面顺不顺的,是你在打开之前有没有想清楚三件事:这份数据的精度够不够支撑你的分析尺度、shp 边界和栅格范围对不对得上、以及你打算用它做提取还是做裁剪。
30m 分辨率意味着每个像元代表地面约 900 平方米的范围,这个尺度适合流域级、县域级的坡度坡向分析、汇流计算和地形起伏度统计,但拿它去做地块级的土方量计算或者精细的场地平整设计,精度就不够了。湘西州地处武陵山区,地形起伏大、沟谷密集,30m 数据在描述山脊线和沟谷走向时会有一定的平滑效应,这一点在做水文分析时要特别留意。配套的 shp 文件通常是行政边界或者本市级范围面图层,它的作用不是装饰,而是帮你把分析范围卡死在目标区域内,避免跑出边界算出无意义的结果。适合谁用?做区域规划、自然资源调查、遥感预处理、教学演示的从业者,以及需要快速拿到一份可用地形底图的新手。不适合谁?做厘米级工程测量或者城市级精细建模的团队,这个精度撑不住。
2. 把 DEM 和 shp 正确装进工作流:从坐标系检查到范围对齐
2.1 先验坐标系,别等裁剪完才发现偏了几百米
拿到栅格和矢量数据,第一步永远不是裁剪,而是确认两者的坐标系是否一致。DEM 常见的是地理坐标系 WGS84 或者 CGCS2000,单位是度;shp 边界可能是投影坐标系,单位是米。如果直接拿投影坐标的 shp 去裁地理坐标的栅格,ArcMap 会弹警告,QGIS 可能直接给你裁出一片空白或者错位的结果。我一般会先在 ArcMap 里右键图层看属性,或者用 QGIS 的图层属性面板确认 CRS。如果两者不一致,优先把 shp 投影到和 DEM 相同的坐标系,而不是反过来动栅格,因为重采样栅格会引入额外的高程误差。
# 用 rasterio 和 geopandas 快速检查 DEM 与 shp 的坐标系 import rasterio import geopandas as gpd dem_path = "xiangxi_dem_30m.tif" shp_path = "xiangxi_boundary.shp" with rasterio.open(dem_path) as src: print("DEM CRS:", src.crs) print("DEM 范围:", src.bounds) print("DEM 分辨率:", src.res) gdf = gpd.read_file(shp_path) print("SHP CRS:", gdf.crs) print("SHP 范围:", gdf.total_bounds)这段代码的逻辑很直接:rasterio 读栅格的 CRS、边界和分辨率,geopandas 读矢量的 CRS 和总范围。参数上重点看src.res,30m 数据在地理坐标系下大约是 0.000277 度左右,如果显示的是 30 或者 0.000277 都算正常,但单位不同后续处理方式完全不同。total_bounds返回的是 shp 的四至范围,拿它和 DEM 的 bounds 对比,如果 shp 范围明显大于 DEM,说明边界文件可能包含了州外区域,裁剪时要以 DEM 实际覆盖为准。
2.2 用面图层裁剪 DEM:Extract by Mask 和 Clip 的区别要分清
这是搜索热词里反复出现的问题:ArcMap 中依靠面图层裁剪 DEM 栅格,和依靠面图层掩码提取,到底有什么区别。简单说,Clip工具是几何裁剪,输出栅格的像元值不变,只是把边界外的像元去掉,边界上的像元按面积比例处理;Extract by Mask是掩码提取,边界外的像元被设为 NoData,边界内的像元值原样保留。两者在边界规整、范围完全包含的情况下结果几乎一样,但当 shp 边界和栅格像元边界不重合时,Clip 可能会在边缘产生半个像元的问题,而 Extract by Mask 更干净。
# 用 rasterio 的 mask 功能实现按面裁剪 DEM import rasterio from rasterio.mask import mask import geopandas as gpd with rasterio.open("xiangxi_dem_30m.tif") as src: gdf = gpd.read_file("xiangxi_boundary.shp") # 确保 shp 和 DEM 坐标系一致 if gdf.crs != src.crs: gdf = gdf.to_crs(src.crs) geoms = [geom for geom in gdf.geometry] out_image, out_transform = mask(src, geoms, crop=True) out_meta = src.meta.copy() out_meta.update({ "height": out_image.shape[1], "width": out_image.shape[2], "transform": out_transform }) with rasterio.open("xiangxi_dem_clipped.tif", "w", **out_meta) as dest: dest.write(out_image)这段代码的关键参数是crop=True,它会把输出栅格的范围收缩到 shp 的实际边界,而不是保留原始 DEM 的完整范围。out_meta继承原栅格的元数据后更新了行列数和仿射变换,保证输出文件的地理定位正确。如果你在 ArcMap 里操作,对应的是 Spatial Analyst 工具条下的 Extract by Mask,输入栅格选 DEM,掩码选 shp,输出就是裁剪后的结果。注意一点:如果 shp 有多个面要素,mask 函数会取所有面的并集作为掩码范围,这和 ArcMap 里逐个要素裁剪的逻辑不同,需要分开处理时得先拆分 shp。
2.3 裁剪后必做的三项检查:范围、NoData 和统计值
裁剪完不是就结束了,我见过太多人裁完直接拿去算坡度,结果发现边缘一圈全是异常值。第一项检查是范围,把裁剪后的栅格和 shp 叠在一起看,边界应该严丝合缝,不能出现栅格超出 shp 或者 shp 内有大片空白的情况。第二项检查是 NoData 值,Extract by Mask 会把边界外设为 NoData,但有些 DEM 原始数据本身在河流或者建筑区域就有 NoData,裁剪后这些值会混在一起,需要在属性里确认 NoData 的数值。第三项是统计值,用栅格统计工具看最小、最大和均值,湘西州的高程范围大致在 200 到 1700 米之间,如果最小值出现负数或者最大值超过 2000,大概率是数据本身有问题或者裁剪时混入了异常像元。
# 裁剪后快速统计高程分布 import rasterio import numpy as np with rasterio.open("xiangxi_dem_clipped.tif") as src: data = src.read(1) nodata = src.nodata if nodata is not None: valid = data[data != nodata] else: valid = data.flatten() print("最小值:", np.min(valid)) print("最大值:", np.max(valid)) print("均值:", np.mean(valid)) print("有效像元数:", valid.size)这段代码先读取第一个波段,然后根据 nodata 值过滤掉无效像元,再算统计量。参数上注意src.nodata可能是 None,这时候需要手动指定一个明显不合理的值来过滤,比如 -9999。湘西州的地形统计如果均值在 600 到 800 米之间、标准差在 200 米左右,说明数据分布合理;如果均值异常低或者标准差极小,可能是裁剪时把大片 NoData 当成了有效值。
3. 从 DEM 到 shp:等高线、坡度分级和流域边界的提取方法
3.1 等高线提取:参数设错就是一堆碎线
从 DEM 提取等高线是常见需求,ArcMap 里用 Contour 工具,QGIS 里用等值线提取。核心参数是等高距,30m 数据建议等高距设在 10 到 20 米之间,设太小会生成大量碎线,设太大又丢失地形细节。湘西州山地起伏大,我一般用 10 米等高距做整体展示,局部区域用 5 米。提取出来的等高线 shp 要检查是否闭合、是否有自相交,这些在后续做地形分析时都会导致拓扑错误。
# 用 GDAL 从 DEM 提取等高线 from osgeo import gdal, ogr dem = gdal.Open("xiangxi_dem_clipped.tif") band = dem.GetRasterBand(1) driver = ogr.GetDriverByName("ESRI Shapefile") out_ds = driver.CreateDataSource("contour_10m.shp") out_layer = out_ds.CreateLayer("contour", geom_type=ogr.wkbLineString) out_layer.CreateField(ogr.FieldDefn("elev", ogr.OFTReal)) gdal.ContourGenerate(band, 10, 0, [], 0, 0, out_layer, 0, 0) out_ds = NoneContourGenerate的参数依次是波段、等高距、基准高程、忽略值列表、是否用 NoData、是否用固定间隔、输出图层、字段索引等。这里等高距设为 10,基准高程设为 0,表示从 0 开始每 10 米生成一条线。生成的 shp 里 elev 字段记录了每条等高线的高程值,方便后续按高程筛选或者做标注。
3.2 坡度分级和坡向分析:别直接拿原始坡度做规划图
DEM 算坡度是基础操作,但直接输出的坡度栅格是连续值,做规划图或者统计报告时需要分级。湘西州的山地坡度分级一般按 0-5 度、5-15 度、15-25 度、25-35 度、35 度以上来分,对应平缓、较缓、中等、陡峭和极陡。ArcMap 里用 Reclassify 工具,QGIS 里用栅格重分类。坡向分析同理,输出的是 0 到 360 度的方向值,需要按北、东北、东等八个方向重分类。注意坡度计算前要确认 DEM 的 Z 单位,地理坐标系下 Z 单位是米而 XY 单位是度,直接算坡度会得到错误结果,需要先用投影坐标系或者设置 Z 因子。
# 用 GDAL 计算坡度并重分类 from osgeo import gdal import numpy as np dem = gdal.Open("xiangxi_dem_clipped.tif") gt = dem.GetGeoTransform() # 地理坐标系下需要设置 Z 因子,约等于 1/111320 z_factor = 1.0 / 111320.0 slope_ds = gdal.DEMProcessing("slope.tif", dem, "slope", zFactor=z_factor) slope_data = slope_ds.GetRasterBand(1).ReadAsArray() # 按 5 度间隔分级 bins = [0, 5, 15, 25, 35, 90] classified = np.digitize(slope_data, bins) print("各级别像元数:", [np.sum(classified == i) for i in range(1, len(bins))])DEMProcessing的zFactor参数是关键,地理坐标系下不设置这个值,坡度会被严重放大。分级用np.digitize按边界值把连续坡度映射到离散类别,输出的是 1 到 5 的整数栅格。实际项目中我会把这个分级结果再转成 shp 或者做掩码统计,方便出报告。
3.3 流域边界和河网提取:填洼是绕不过去的一步
用 DEM 做水文分析,填洼是第一步,也是最多人翻车的地方。原始 DEM 里存在洼地,不填洼直接算流向会出现断流或者内流区。ArcMap 里用 Fill 工具,QGIS 里用 Wang and Liu 填洼算法。填洼之后算流向、流量累积,设定阈值提取河网,再转成 shp。湘西州的喀斯特地貌区域洼地特别多,填洼的阈值要适当调大,否则会把大量真实洼地填平,改变水文响应特征。
# 用 RichDEM 做填洼和流量累积 import richdem as rd dem = rd.LoadGDAL("xiangxi_dem_clipped.tif") dem_filled = rd.FillDepressions(dem, epsilon=True, in_place=False) flow_accum = rd.FlowAccumulation(dem_filled, method="D8") rd.SaveGDAL("flow_accum.tif", flow_accum)FillDepressions的epsilon=True表示在填洼时加入微小坡度,避免平坦区域流向不确定。FlowAccumulation用 D8 算法,每个像元的流向指向最陡的下坡方向,流量累积值表示上游汇水像元数。阈值一般设在 1000 到 5000 之间,具体看流域面积和河网密度,湘西州建议从 2000 开始试。
4. 避坑与排查:30m DEM 处理中最容易翻车的五个地方
4.1 裁剪后栅格范围对不上 shp 边界
现象:裁剪后的 DEM 边缘和 shp 边界有明显偏移,或者 shp 内出现大片 NoData。原因通常是坐标系不一致,或者 shp 本身有拓扑错误比如自相交、重叠面。解决方法是先统一坐标系,再用拓扑检查工具修复 shp,最后重新裁剪。如果 shp 是多个面要素,确认是否需要合并成一个面再裁剪。
4.2 坡度计算结果明显偏大
现象:算出来的坡度动辄七八十度,明显不符合实际地形。原因是在地理坐标系下直接计算坡度,没有设置 Z 因子。解决方法是先把 DEM 投影到投影坐标系,或者在坡度工具里手动设置 Z 因子为 1/111320 左右。ArcMap 的 Slope 工具里有 Z factor 参数,QGIS 的坡度工具也有类似设置。
4.3 填洼后河网位置偏移
现象:填洼后提取的河网和实际河流走向对不上,或者河网密度异常。原因是填洼阈值设置不当,把真实洼地填平了,或者流量累积阈值太小导致碎河网过多。解决方法是先用小阈值填洼,对比填洼前后的高程差异,确认没有大面积改变地形;流量累积阈值从大到小试,找到河网密度合理的值。
4.4 等高线提取出现大量碎线
现象:生成的等高线 shp 里有很多短小、不闭合的线段。原因是 DEM 本身有噪声,或者等高距设得太小。解决方法是对 DEM 先做一次平滑滤波,或者把等高距调大。如果只是展示用,可以在提取后按长度过滤掉短于某个阈值的线段。
4.5 裁剪后统计值异常
现象:裁剪后的 DEM 最小值出现负数,或者最大值远超实际高程。原因是 NoData 值没有被正确识别,或者裁剪时混入了原始 DEM 的异常像元。解决方法是在裁剪前先检查原始 DEM 的 NoData 定义,裁剪后用栅格统计工具确认有效像元范围,必要时手动设置 NoData 值再重新统计。
5. 进阶用法:用这份 DEM 做地形起伏度和剖面分析
地形起伏度是描述区域地形特征的常用指标,计算方式是在一个滑动窗口内取高程最大值和最小值的差。30m 数据做起伏度分析,窗口大小一般选 3×3 到 9×9,对应 90 米到 270 米的邻域范围。湘西州的地形起伏度整体偏高,武陵山区核心地带的起伏度可以达到 300 米以上,这个值在做选址和规划时很有参考意义。
# 用 scipy 计算地形起伏度 import rasterio import numpy as np from scipy.ndimage import maximum_filter, minimum_filter with rasterio.open("xiangxi_dem_clipped.tif") as src: dem = src.read(1) nodata = src.nodata dem_valid = np.where(dem == nodata, np.nan, dem) # 3x3 窗口的起伏度 window_size = 3 max_dem = maximum_filter(dem_valid, size=window_size) min_dem = minimum_filter(dem_valid, size=window_size) relief = max_dem - min_dem # 保存结果 with rasterio.open("relief_3x3.tif", "w", **src.meta) as dst: dst.write(relief.astype(np.float32), 1)maximum_filter和minimum_filter分别取窗口内的最大值和最小值,相减得到起伏度。窗口大小根据分析尺度调整,做县域级分析用 3×3 就够了,做流域级可以用 9×9。注意 NoData 区域在滤波后会产生边缘效应,需要在结果里重新标记 NoData。
剖面分析是另一个实用技巧,沿着某条线路提取高程剖面,可以直观看到地形起伏。在 QGIS 里用 Profile Tool 插件,ArcMap 里用 3D Analyst 的 Profile Graph。我一般会沿着规划线路或者地质剖面线提取,输出高程和距离的对应关系,用来判断线路的爬升和下降情况。湘西州的山地线路剖面往往呈现剧烈的锯齿状,这时候要结合起伏度数据一起看,判断哪些路段需要重点处理。
从那以后我每次拿到新的 DEM 数据,都会先跑一遍坐标系检查、范围对齐和统计值验证这三步,确认没问题再进入分析流程。这套习惯帮我省掉了大量返工时间,也希望帮到你。
本文还有配套的精品资源,点击获取