侧边栏壁纸
博主头像
YouGIS博文 - YouGIS顽石工坊 博主等级

行动起来,活在当下

  • 累计撰写 60 篇文章
  • 累计创建 33 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

Python GDAL实战:ASTER GDEM V003全国DEM高程数据处理(1123幅分幅合并→34省裁切,30m精度)

Administrator
2026-07-16 / 0 评论 / 0 点赞 / 8 阅读 / 0 字

Python GDAL实战:ASTER GDEM V003全国DEM高程数据处理(1123幅分幅合并→34省裁切,30m精度)

主页:yougis.com.cn
博文:
blog.yougis.com.cn
工具:
yougis.com.cn/tool/home

GIS数据:yougis.com.cn/res/home

qr-wechat.jpg

扫码获取更多精彩内容

gh_1b60b293e57f_430.jpg

一键获取海量空间数据

摘要:本文详细记录了基于 Python(rasterio + GDAL)对 ASTER GDEM V003 原始数据进行全国34省级行政区DEM裁切的完整工程实践。涵盖数据下载、分幅合并(mosaic)、矢量裁切(mask)、质量检验全流程,附完整可复现代码。数据覆盖N18°~N53°、E73°~E134°,成果34个GeoTIFF文件,总计10.61GB,124.8亿有效像素。

关键词:DEM高程数据、ASTER GDEM、Python rasterio、GDAL、遥感数据处理、GeoTIFF、空间数据裁切、数字高程模型

标签GIS 遥感 空间数据库 数据处理 地理信息系统


一、数据背景与选型

1.1 ASTER GDEM V003 vs V002 vs SRTM

对比项

SRTM C-band

ASTER GDEM V002

ASTER GDEM V003

分辨率

30m

30m

30m

纬度覆盖

N60°~S56°

N83°~S83°

N83°~S83°

垂直精度(RMSE)

~16m

17m

8.5m

数据源年份

2000年2月

2000-2010

2000-2018

空洞密度

较多

大幅减少

中国高纬度覆盖

差(漠河N53°已覆盖,但更北缺失)

选型结论:全国DEM处理选 ASTER GDEM V003,兼顾覆盖范围(含高纬度)和精度。SRTM适合低纬度区域专项研究。

1.2 数据获取来源

来源

网址

特点

NASA EarthData

https://earthdata.nasa.gov

原始来源,需注册

地理空间数据云

https://www.gscloud.cn

国内镜像,下载速度快

ASTER GDEM官网

https://asterweb.jpl.nasa.gov/gdem.asp

产品说明文档


二、原始数据技术规格

2.1 核心参数

数据产品:ASTER GDEM V003
发布机构:NASA & METI
发布时间:2019年8月
分幅规则:1°×1° 经纬度网格
单幅像素:3601 × 3601
单幅大小:~41 MB
空间分辨率:0.000278°(赤道约30m)
数据类型:signed 16-bit integer (int16)
空间参考:WGS84 / EPSG:4326
NoData值:-9999
文件格式:GeoTIFF
命名规则:ASTGTMV003_N{纬度}E{经度}_dem.tif

2.2 全国覆盖统计

分幅总数:1,123幅
覆盖范围:N18°~N53°, E73°~E134°
总数据量:~49 GB
单幅示例:ASTGTMV003_N39E116_dem.tif → 北京
         ASTGTMV003_N30E114_dem.tif → 武汉

2.3 分幅筛选——根据省份bbox确定所需图幅

import numpy as np

def get_tile_range(min_lat, max_lat, min_lon, max_lon):
    """根据经纬度范围获取需要的ASTER GDEM分幅编号"""
    lats = range(int(np.floor(min_lat)), int(np.ceil(max_lat)) + 1)
    lons = range(int(np.floor(min_lon)), int(np.ceil(max_lon)) + 1)
    tiles = [f"N{lat}E{lon}" for lat in lats for lon in lons]
    return tiles

# 示例:河南省范围约 N31°~N36°, E110°~E117°
tiles = get_tile_range(31, 36, 110, 117)
print(f"河南需 {len(tiles)} 幅: {tiles}")
# 输出: 河南需 42 幅: ['N31E110', 'N31E111', ..., 'N36E117']

三、处理流程与核心代码

┌──────────┐    ┌──────────┐    ┌──────────┐    ┌──────────┐
│  数据下载  │ -> │  分幅合并  │ -> │  省界裁切  │ -> │  质量检验  │
│ 1123幅   │    │ 按省镶嵌  │    │ 矢量裁切  │    │  统计+核查 │
└──────────┘    └──────────┘    └──────────┘    └──────────┘
   ~49 GB          临时大文件       34个TIF       _summary.json

3.1 分幅合并(Mosaic)

import rasterio
from rasterio.merge import merge
from rasterio.transform import array_bounds

def mosaic_tiles(tile_paths, output_path):
    """合并多个DEM分幅为单个TIFF(LZW压缩)"""
    src_files = [rasterio.open(p) for p in tile_paths]
    mosaic, transform = merge(src_files)

    profile = src_files[0].profile.copy()
    profile.update({
        'height': mosaic.shape[1],
        'width': mosaic.shape[2],
        'transform': transform,
        'compress': 'lzw',
        'tiled': True,        # 启用分块写入,提升读取性能
        'blockxsize': 256,
        'blockysize': 256,
    })

    with rasterio.open(output_path, 'w', **profile) as dst:
        dst.write(mosaic)

    for src in src_files:
        src.close()

    print(f"[OK] 合并完成: {output_path} ({mosaic.shape[2]}×{mosaic.shape[1]})")

3.2 省界裁切(Mask)

import rasterio
from rasterio.mask import mask
import json

def clip_to_province(input_tif, geojson_path, output_tif, nodata=-9999):
    """用省级行政区划矢量(GeoJSON)裁切栅格"""
    with open(geojson_path) as f:
        geojson = json.load(f)

    # 处理 FeatureCollection / Feature / Geometry 等不同结构
    if geojson['type'] == 'FeatureCollection':
        shapes = [feat['geometry'] for feat in geojson['features']]
    elif geojson['type'] == 'Feature':
        shapes = [geojson['geometry']]
    else:
        shapes = [geojson]

    with rasterio.open(input_tif) as src:
        out_image, out_transform = mask(
            src, shapes, crop=True, nodata=nodata, all_touched=True
        )
        profile = src.profile.copy()
        profile.update({
            'height': out_image.shape[1],
            'width': out_image.shape[2],
            'transform': out_transform,
            'nodata': nodata,
            'compress': 'lzw',
            'tiled': True,
        })

        with rasterio.open(output_tif, 'w', **profile) as dst:
            dst.write(out_image)

    print(f"[OK] 裁切完成: {output_tif}")

3.3 质量检验

import rasterio
import numpy as np
from pathlib import Path
import json

def validate_dem(tif_path):
    """验证DEM数据质量,返回统计字典"""
    with rasterio.open(str(tif_path)) as src:
        arr = src.read(1)
        valid = arr[arr != src.nodata]

        return {
            'code': Path(tif_path).stem,
            'width': src.width,
            'height': src.height,
            'crs': str(src.crs),
            'dtype': str(src.dtypes[0]),
            'total_pixels': int(arr.size),
            'valid_pixels': int(valid.size),
            'valid_ratio': round(valid.size / arr.size * 100, 2),
            'elev_min': int(valid.min()),
            'elev_max': int(valid.max()),
            'elev_mean': round(float(valid.mean()), 1),
            'size_mb': Path(tif_path).stat().st_size // (1024 * 1024),
        }

# 批量检验
results = {}
for tif in sorted(Path('a_output').glob('*.tif')):
    stats = validate_dem(tif)
    results[stats['code']] = stats
    print(f"{stats['code']}: {stats['valid_pixels']:>12,} px | "
          f"{stats['elev_min']:>5}~{stats['elev_max']:<5}m | "
          f"{stats['size_mb']}MB")

# 导出汇总JSON
with open('_summary.json', 'w') as f:
    json.dump(results, f, ensure_ascii=False, indent=2)

四、成果数据总览

4.1 整体统计

指标

数值

成果文件数

34个

总数据量

10,868 MB (10.61 GB)

总有效像素

12,476,309,771(约124.8亿)

有效像素占比

43.42%

高程范围

-275m ~ 8802m

数据类型

int16

坐标系

WGS84 (EPSG:4326)

NoData值

-9999

压缩方式

LZW

4.2 34省完整清单

编码

省份

图幅数

像素尺寸

有效像素

高程范围

大小(MB)

110000

北京

6

4008×2865

9,258,626

3~2296m

19

120000

天津

4

3605×3491

8,632,021

-5~1097m

7

130000

河北

39

10845×9470

65,857,002

0~2818m

199

140000

山西

27

9010×7195

44,388,292

148~3055m

195

150000

内蒙古

464

28848×19948

280,552,490

91~2840m

1230

210000

辽宁

31

10846×9001

62,045,913

-275~1337m

162

220000

吉林

43

12642×8930

65,444,891

0~2630m

214

230000

黑龙江

84

18054×13394

145,335,435

0~1671m

519

310000

上海

5

3962×2889

6,837,004

-10~352m

4

320000

江苏

30

9014×6900

38,332,587

-32~685m

61

330000

浙江

25

7937×7226

34,425,836

0~1920m

118

340000

安徽

27

9010×7019

42,437,091

-2~1869m

122

350000

福建

23

8292×8292

40,449,760

0~2160m

150

360000

江西

29

9369×7958

47,502,717

-1~2145m

177

370000

山东

40

10849×7407

45,702,055

-11~1532m

134

410000

河南

42

10489×8529

50,054,549

12~2411m

156

420000

湖北

40

12646×9014

62,375,665

-6~3097m

201

430000

湖南

35

10489×9728

56,001,688

19~2097m

235

440000

广东

32

10493×9366

55,021,568

0~1901m

185

450000

广西

48

12646×10090

65,193,980

-16~2109m

271

460000

海南

30

9370×6300

23,508,420

0~1839m

32

500000

重庆

21

7585×6845

36,514,212

26~2776m

106

510000

四川

70

16258×14022

125,472,821

169~7523m

658

520000

贵州

30

9369×8650

54,395,708

247~2896m

223

530000

云南

60

14479×11586

103,015,277

76~6710m

506

540000

西藏

151

28848×21612

260,749,872

122~8802m

1476

610000

陕西

40

11711×9013

65,016,912

166~3762m

266

620000

甘肃

187

20704×16057

172,464,233

615~5786m

507

630000

青海

97

19853×16625

205,670,309

1682~6751m

801

640000

宁夏

12

6127×5412

22,346,251

1090~3554m

56

650000

新疆

224

34260×23418

357,088,649

-154~8199m

1833

710000

台湾

30

6482×7938

19,908,780

0~3886m

44

810000

香港

2

1622×1801

1,582,840

0~958m

1

820000

澳门

1

1082×1441

762,668

-2~171m

0


五、工程注意事项

5.1 大文件内存管理

新疆成果文件 650000.tif 像素尺寸达 34260×23418(8亿+像素),直接全量读取会触发内存溢出。

# ❌ 错误:全量读取大文件
with rasterio.open('650000.tif') as src:
    arr = src.read(1)  # 1.6GB内存!

# ✅ 正确:分块读取(windowed read)
with rasterio.open('650000.tif') as src:
    for window in src.block_windows(1):
        block = src.read(1, window=window[1])
        # 逐块处理...

5.2 坐标系一致性检查

裁切前务必确认矢量与栅格坐标系一致,否则裁切结果为空或错位。

import rasterio
import geopandas as gpd

with rasterio.open('merged.tif') as src:
    raster_crs = src.crs.to_epsg()

gdf = gpd.read_file('province_boundary.geojson')
vector_crs = gdf.crs.to_epsg()

if raster_crs != vector_crs:
    print(f"[WARNING] 坐标系不一致! 栅格: EPSG:{raster_crs}, 矢量: EPSG:{vector_crs}")
    gdf = gdf.to_crs(raster_crs)  # 统一到栅格坐标系

5.3 噪声像素过滤

650000.tif(新疆)存在 104 个极端异常像素(-32287~32008m),使用前过滤:

import rasterio
import numpy as np

with rasterio.open('650000.tif') as src:
    profile = src.profile.copy()
    arr = src.read(1).astype(np.float32)
    # 过滤物理不可能的高程值
    arr[(arr < -1000) | (arr > 9000)] = -9999

    with rasterio.open('650000_filtered.tif', 'w', **profile) as dst:
        dst.write(arr.astype(np.int16), 1)

5.4 投影转换注意事项

数据为经纬度坐标(EPSG:4326),进行以下分析前需投影:

分析类型

推荐投影

原因

面积/体积计算

Albers等积投影

保持面积不变

距离/坡度分析

UTM投影

局部区域变形小

流域提取

UTM投影

水流方向计算需平面坐标

# 使用GDAL进行投影转换(命令行)
# gdalwarp -t_srs EPSG:32649 input.tif output_utm49n.tif

# Python方式
import subprocess
subprocess.run([
    'gdalwarp', '-t_srs', 'EPSG:32649',
    '-r', 'bilinear', '-of', 'GTiff',
    '-co', 'COMPRESS=LZW',
    'input.tif', 'output_utm49n.tif'
])

六、数据读取与可视化

import rasterio
import numpy as np
import matplotlib.pyplot as plt

with rasterio.open('410000.tif') as src:
    dem = src.read(1)
    dem = np.where(dem == -9999, np.nan, dem).astype(np.float32)

    fig, ax = plt.subplots(figsize=(10, 8))
    im = ax.imshow(dem, cmap='terrain')
    plt.colorbar(im, label='高程 (m)', shrink=0.8)
    ax.set_title('河南省 DEM (ASTER GDEM V003)', fontsize=14)
    ax.set_xlabel('列号')
    ax.set_ylabel('行号')
    plt.tight_layout()
    plt.savefig('henan_dem.png', dpi=150)
    plt.show()

七、总结

阶段

内容

规模

原始数据

ASTER GDEM V003

1123幅,~49GB

处理

下载→合并→裁切→检验

rasterio + GDAL

成果

int16, EPSG:4326, LZW压缩

34省TIF,10.61GB

处理流程全代码开源、可复现,所有34个成果文件技术规格统一。


参考文献

  1. NASA/METI. ASTER GDEM Version 3. (2019). https://asterweb.jpl.nasa.gov/gdem.asp

  2. NASA EarthData Search. https://earthdata.nasa.gov

  3. 地理空间数据云. https://www.gscloud.cn

  4. rasterio Documentation. https://rasterio.readthedocs.io

  5. GDAL Documentation. https://gdal.org


数据获取方式见下一篇: 全国DEM高程数据免费下载指南(34省+1123幅原始)

如果觉得有用,点赞收藏关注一键三连,有问题评论区交流 ✌️

0

评论区