使用 ArcPy 批量处理栅格数据:重采样与矢量裁剪
背景介绍
在地理信息系统(GIS)工作中,我们常常需要处理大量栅格图像文件,比如卫星遥感数据。这些文件分辨率不一、覆盖范围过大,直接使用会让分析卡顿或超出研究区。这时,一个自动化脚本就能帮忙:它像一个"智能裁缝",批量将文件"裁剪"到合适大小和分辨率,让数据更精炼易用。
这个脚本针对编程新手设计,只需简单配置,就能处理成堆的TIF文件。特别适合初学者练习ArcPy,快速上手GIS自动化。
代码功能说明
这个脚本的核心用途是批量处理栅格TIF文件,解决手动重采样和裁剪耗时费力的痛点。它会自动扫描输入文件夹中的所有TIF文件,按年份分组,重采样到30米分辨率,然后用指定的矢量边界(SHP文件)裁剪,只保留感兴趣区域,最终保存为新TIF文件。
适用场景包括:地面沉降监测、土地利用变化分析、环境评估项目------任何需要统一分辨率和区域的遥感数据处理。运行后,你会在终端看到进度提示如"🔄 [1/10] 处理文件: xxx.tif(年份: 2020)"和"✅ 完成:xxx.tif",输出文件夹中出现按年份命名的裁剪后TIF文件,这些文件体积更小、边界精确,随时可导入ArcGIS查看或进一步分析。
运行环境准备
准备环境就像为厨师备齐锅碗瓢盆,确保脚本能顺利"下厨"。为什么要做这一步?因为ArcPy依赖ArcGIS软件,没有它脚本就"无米下锅"。
- ArcGIS 版本要求 :ArcGIS Desktop 10.5+ 或 ArcGIS Pro 2.5+(推荐 Pro,更稳定)。
- 检查方法:打开ArcGIS,查看"帮助 > 关于"中的版本信息。如果没有,下载安装从 esri.com。
- Python 环境:使用ArcGIS自带的Python(通常3.9+),无需额外安装。
- Spatial Analyst 扩展 :脚本需此扩展用于栅格处理。
- 授权检查:在ArcGIS中,工具箱 > Spatial Analyst Tools,确保可用。
- 文件准备:确保输入TIF文件和SHP边界文件存在,硬盘有足够空间(每个TIF处理可能需几百MB)。
这些准备好,脚本就能在ArcGIS Python环境中运行。
详细运行步骤
我们按顺序拆解运行,像搭乐高一样一步步来。每步解释"为什么",帮你理解逻辑:这样不是死记硬背,而是知道"为什么这样搭更稳"。
-
环境准备 :
为什么?确认工具就位,避免运行时突然报"缺货"。
- 启动ArcGIS Pro 或 Desktop,确保Spatial Analyst扩展已授权(在"项目 > 许可 > 扩展"中勾选)。
- 准备数据:将你的TIF文件放入一个主文件夹(如包含年份子文件夹的"data"),SHP文件单独保存。
-
依赖安装 :
为什么?脚本用到的库大多内置,但确认无误能防小问题。
- ArcPy 和 os/re/glob 是标准库,无需pip。
- 在ArcGIS Python Command Prompt(从开始菜单搜索)中输入
python -c "import arcpy; print('OK')"测试ArcPy是否可用。如果报错,重启ArcGIS。
-
代码修改 :
为什么?脚本路径是示例,换成你的才能"对号入座",否则找不到文件。
- 新建文本文件,命名为
batch_raster_process.py,复制下方代码块粘贴。 - 用记事本或VS Code打开,修改参数部分:
- 注意:运行前需修改
input_root_folder = r"【your_input_root】"为你的TIF主文件夹路径,例如r"C:\GISData\沉降数据"。 - 注意:运行前需修改
mask_shp = r"【your_mask_shp】"为SHP边界路径,例如r"C:\GISData\study_area.shp"。 - 注意:运行前需修改
output_folder = r"【your_output_folder】"为输出路径,例如r"C:\Output\processed"。 - 可选:调整
cell_size = 30为你的目标分辨率(米)。
- 注意:运行前需修改
- 保存为UTF-8编码。
pythonimport arcpy import os import re import glob # === 参数设定 === input_root_folder = r"【your_input_root】" # 包含多个年份子文件夹的主目录 mask_shp = r"【your_mask_shp】" # 用于裁剪的面矢量 output_folder = r"【your_output_folder】" # 最终输出文件夹 cell_size = 30 # 目标分辨率(米) variable_name = "kuangshan4" # 变量名作为输出前缀 # === 环境设定 === arcpy.env.overwriteOutput = True arcpy.CheckOutExtension("Spatial") # 估算地理坐标下的 30 米分辨率(大致) cellsize_degree = 0.0002695 # 创建输出文件夹 if not os.path.exists(output_folder): os.makedirs(output_folder) # === 搜索所有.tif文件 === tif_list = glob.glob(os.path.join(input_root_folder, "*", "*.tif")) total_files = len(tif_list) print(f"\n📦 共发现 {total_files} 个 .tif 文件,开始处理...\n") # === 遍历处理 === for idx, tif_path in enumerate(tif_list, 1): filename = os.path.basename(tif_path) parent_folder = os.path.basename(os.path.dirname(tif_path)) # 提取年份 year_match = re.search(r"\d{4}", parent_folder) year = year_match.group() if year_match else "unknown" print(f"🔄 [{idx}/{total_files}] 处理文件: {filename}(年份: {year})") try: # Step 1: 重采样 print(" ➤ 步骤 1:重采样至 30m...") resampled = arcpy.sa.Resample(tif_path, cellsize_degree, "BILINEAR") # Step 2: 裁剪 print(" ➤ 步骤 2:按矢量裁剪...") clipped = arcpy.sa.ExtractByMask(resampled, mask_shp) # Step 3: 保存结果 print(" 💾 步骤 3:保存输出...") out_name = f"{variable_name}_{year}_{os.path.splitext(filename)[0]}.tif" out_path = os.path.join(output_folder, out_name) arcpy.management.CopyRaster(clipped, out_path, pixel_type="32_BIT_FLOAT") print(f" ✅ 完成:{out_name}\n") except Exception as e: print(f" ❌ 处理失败:{e}\n") continue print("🎉 所有任务已完成!") - 新建文本文件,命名为
-
执行命令 :
为什么?这是"点火启动",让脚本开始扫描和处理文件。
- 打开ArcGIS Python Command Prompt,导航到脚本目录:输入
cd 【your_script_path】(例如cd C:\Scripts)。 - 运行命令:
python batch_raster_process.py。 - 耐心等待(大文件可能需几分钟),终端会显示进度条和完成提示。
- 打开ArcGIS Python Command Prompt,导航到脚本目录:输入
-
验证结果 :
为什么?像试穿衣服,确保"剪裁"后合身无误。
- 打开输出文件夹,检查是否生成以年份命名的TIF文件(如
kuangshan4_2020_xxx.tif)。 - 在ArcGIS中添加一个输出TIF,查看图层属性:分辨率应为30m,边界匹配SHP范围。
- 如果文件数与输入匹配,且无错误提示,即大功告成。
- 打开输出文件夹,检查是否生成以年份命名的TIF文件(如
核心代码解析
脚本像一个"流水线工厂":先"清点货物"(找TIF文件),然后对每个"零件"走三道工序(重采样、裁剪、打包),出错就"隔离"不影响整体。用大白话聊核心逻辑,就如组装玩具车------简单几步,成品就跑起来了。
-
搜索TIF文件 (
tif_list = glob.glob(...)):这行像"仓库管理员"拿着手电筒,在主文件夹及其子文件夹(按年份分)里搜罗所有".tif"货品,列个清单。为什么?批量处理前得知道"有多少活儿",避免漏掉文件。
-
提取年份 (
year_match = re.search(r"\d{4}", parent_folder)):想象成"标签阅读器":从文件夹名(如"2020_data")中抠出"2020"这个数字,当作文件名标签。为什么?这样输出文件带年份,便于后期按时间排序分析。
-
重采样 (
resampled = arcpy.sa.Resample(...)):像"放大镜调整器":把原TIF"拉伸"或"压缩"到30米像素大小,用"BILINEAR"方式平滑过渡(像邻居平均值,避免锯齿)。为什么?统一分辨率,让不同来源的数据"站齐队"。
-
裁剪 (
clipped = arcpy.sa.ExtractByMask(...)):这步如"剪刀手":用SHP边界当"模板",只切下研究区内的部分,扔掉外围"废料"。为什么?聚焦感兴趣区域,节省存储和计算时间。
-
保存结果 (
arcpy.management.CopyRaster(...)):像"打包机":给文件起名(变量+年份+原名),存为浮点TIF,确保数据精度不丢。为什么?浮点格式保持数值准确,适合沉降等连续数据。
整个流程循环遍历清单,try-except像"安全网",一个坏了不耽误别人。新手懂了,就能改成加投影或统计功能。
常见问题解决
跑脚本时,新手常遇小坎坷,但这些是"经验药方",提前知道就能少走弯路。为什么列出来?因为调试像找钥匙,知道常见藏处更快开门。
-
路径错误:
- 报错如"No such file or directory"。
- 解决:用
r"路径"(raw字符串),双检查输入/输出文件夹存在。用文件资源管理器复制完整路径粘贴。为什么?路径敏感,半点斜杠错就找不到家。
-
扩展未授权:
- 报错"CheckOutExtension failed"。
- 解决:在ArcGIS许可管理器中启用Spatial Analyst,重启软件。为什么?扩展像VIP门票,没它进不了栅格工坊。
-
分辨率估算不准:
- 输出图像变形或坐标错。
- 解决:如果你的TIF是投影坐标,改
cellsize_degree为实际米值(如直接用cell_size)。测试小文件先跑。为什么?度坐标下米需转换,投影坐标直接用米更准。
-
内存不足或处理慢:
- 大文件卡死或报"Out of memory"。
- 解决:关掉其他程序,处理前分批小文件夹;或加
arcpy.env.workspace = output_folder优化。为什么?栅格处理吃内存,像大锅煮饭,锅小就分次。
-
其他:TIF无年份文件夹时,输出名带"unknown"------手动调整文件夹结构。出错时,复制终端错误Google"ArcPy [错误] Resample"。
掌握这些,脚本就是你的得力助手。试跑后,欢迎分享你的GIS小项目!