Py学习  »  Python

Python批量实现NC转TIF:自动化处理全流程解析

生态遥感前沿 • 5 月前 • 276 次点击  

在地理数据处理中,批量将NetCDF(NC)文件转为GeoTIFF格式是高频需求。上期我们介绍了基础转换方法,本期结合完整Python代码,深入解析**自动化批量处理、多时间步拆分、填充值处理、错误监控**等进阶功能,助你打造高效数据处理流水线!

01

代码核心功能与优势

1. 全自动化维度识别*

自动匹配`lon`/`lat`/`time`维度,无需手动指定索引  

支持一维/二维经度数组(兼容不同NC文件结构)  

2. 多时间步批量拆分  

按时间维度生成独立TIF文件(如`2022-01.tif`、`2022-02.tif`)  

自动识别时间单位(如`days since 2000-01-01`)并格式化为`YYYY-MM`  

3. 专业级数据处理**

       填充值(`_FillValue`)自动替换为GIS通用无数据值`-32767`  

智能判断纬度方向(递增/递减),自动反转数组保证地理方向正确  

4. 健壮的错误处理*

关键步骤异常捕获(如维度缺失、文件已存在)  

详细错误日志输出,区分文件级错误与时间步错误  

02

代码逐行解析  

def NC_to_tiffs(data, out_path):

coord = 4326  # 预设WGS84坐标系

nc_data_obj = nc.Dataset(data)

key = list(nc_data_obj.variables.keys())  # 提取所有变量名

print('基础属性为  ', key)


# 自动定位核心维度(lon/lat/time)

try:

lon_size = [i for i, x in enumerate(key) if x.lower().find('lon') != -1][0]

lat_size = [i for i, x in enumerate(key) if x.lower().find('lat') != -1][0]

time_size = [i for i, x in enumerate(key) if x.lower().find('time') != -1][0]

except IndexError:

raise ValueError("找不到必要的维度变量(lon/lat/time)")


# 交互式获取目标波段名

global band_name

if not band_name:

band_name = input("请输入您想要输出的波段的名字:")  # 支持中文/英文变量名


# 解析数据与元信息

Lon = nc_data_obj.variables[key[lon_size]][:]

Lat = nc_data_obj.variables[key[lat_size]][:]

time = nc_data_obj.variables[key[time_size]]

times = nc.num2date(time[:], time.units)  # 时间戳转日期对象

band = np.asarray(nc_data_obj.variables[key[band_size]]).astype(float)


# 地理配准参数计算

LonMin, LatMax, LonMax, LatMin = [Lon.min(), Lat.max(), Lon.max(), Lat.min()]

N_Lat = len(Lat)

N_Lon = len(Lon[0]) if Lon.ndim == 2 else len(Lon)  # 兼容一维/二维经度

Lon_Res = (LonMax - LonMin) / (N_Lon - 1)  # 计算分辨率


# 逐时间步生成TIF

for i in range(band.shape[0]):

dt = times[i].strftime("%Y-%m")  # 格式化为年月

out_tif_name = os.path.join(out_path, f"{os.path.basename(data).replace('.nc', '')}_{dt}.tif")


if os.path.exists(out_tif_name):  # 避免重复生成

print(f"文件 {out_tif_name} 已存在,跳过")

continue


# 创建GeoTIFF

driver = gdal.GetDriverByName('GTiff')

out_tif = driver.Create(out_tif_name, N_Lon, N_Lat, 1, gdal.GDT_Float32)

out_tif.SetGeoTransform((LonMin, Lon_Res, 0, LatMax, 0, -Lat_Res))  # 六参数坐标系


# 处理填充值(关键!)

fill_value = getattr(nc_data_obj.variables[key[band_size]], '_FillValue', 1e20)

arr1 = band[i, :, :].copy()

arr1[arr1 == fill_value] = -32767  # 替换为GIS通用无数据值


# 反转纬度方向(解决南北颠倒问题)

if Lat[0] < Lat[-1]:  # 纬度递增(数据从南到北排列)

reversed_arr = arr1[::-1]  # 反转数组保证TIF中纬度从上到下递减

else:

reversed_arr = arr1


# 写入数据并设置元信息

out_tif.GetRasterBand(1).WriteArray(reversed_arr)

out_tif.GetRasterBand(1).SetNoDataValue(-32767)

out_tif.SetProjection(osr.SpatialReference().ImportFromEPSG(coord).ExportToWkt())

out_tif.FlushCache()

print(f"成功生成:{out_tif_name}")

03

批量处理全流程指南  

1.环境准备

安装依赖库(建议使用conda环境)

conda install netcdf4 gdal numpy -c conda-forge

2. 参数配置

输入文件夹:包含NC文件的目录(如`D:\NOAANDVI`)

文件后缀:支持自定义(如处理`.nc4`文件时改为`end_name='.nc4'`)

坐标系:默认`EPSG:4326`(WGS84),可修改`coord`参数为其他投影(如`32632`对应UTM Zone 32N)

3. 错误处理机制*

文件级错误:如维度缺失、波段不存在,会跳过当前文件并记录到`failed_files`列表

时间步错:单个时间点处理失败不影响其他时间步,错误信息包含堆栈跟踪

结果汇总:程序结束后自动打印成功/失败文件列表

04

实战场景与优化建议  

典型应用场景

1.气象数据处理:将ERA5等再分析数据按月份拆分为单波段TIF

2. 遥感影像批量转换:处理MODIS、VIIRS等传感器的NC格式产品

3. 科研数据归档:将多时间序列NC数据转为GIS兼容格式,便于ArcGIS/QGIS分析

05

性能优化技巧 

1. 多线程加速:

from concurrent.futures import ThreadPoolExecutor

def process_file(dat):

try:

NC_to_tiffs(dat, Output_folder)

except:

pass

with ThreadPoolExecutor(max_workers=4) as executor:  # 4线程并行处理

executor.map(process_file, data_list)

2. 内存管理:

- 对超大文件,使用`dask`库分块读取(替代`np.asarray`)

- 处理完成后及时删除临时变量(`del out_tif`)

3. 坐标系转换:

# 转换为UTM投影(示例:EPSG:32610)

coord = 32610

srs = osr.SpatialReference()

srs.ImportFromEPSG(coord)

out_tif.SetProjection(srs.ExportToWkt())

# 重采样为1000米分辨率

geotransform = (LonMin, 1000, 0, LatMax, 0, -1000)

06

常见问题与解决方案  

Q1:运行时提示`找不到GDAL库`?**

A:

1. Windows系统需手动添加GDAL路径:

os.environ['PATH'] += r';C:\Program Files\GDAL'  # 根据实际安装路径修改

2. 确认`gdal`包正确安装:`pip install gdal --global-option=build_ext --with-gdal=/path/to/gdal`


Q2:转换后TIF南北颠倒?

A:代码已内置纬度方向检测(`Lat[0] < Lat[-1]`),若仍异常,可强制反转:

reversed_arr = arr1[::-1]  # 忽略原始顺序,强制反转

Q3:如何处理无时间维度的NC文件?

A:删除代码中与`time`相关的循环,直接导出单波段TIF:

# 移除时间循环,直接写入数据

arr1 = band[:, :]  # 假设波段为二维数组


点击下方 关注我们






Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/182773