利用python将nc批量转为tif(可执行的通用代码,小白都能运行!)

之前写过一篇nc转tif的文章,发现一些问题,好多小伙伴也都提出来了,但是我没有一一解答,所以在这里我又写了一篇通用的文章,这里就不用管nc数据是单时间序列还是多时间序列,不用管是nc数据还是nc4数据,这里也解决了一些数据倒置的问题,如果哪里写的有什么问题的话,还请不断指正,一起进步!!也请问问题的小伙伴把自己详细出现的问题表达清楚。希望来参观我的github(里面是一些跟GIS,遥感,python等相关代码的一些仓库,点个关注是我最大的动力!!)

先放代码,稍后详解:

# -*- coding: utf-8 -*-
"""
Created on Fri Sep 23 18:05:48 2022

@author: HYF
"""

import numpy as np
import netCDF4 as nc
from osgeo import gdal,osr,ogr
import os
os.environ['PROJ_LIB'] = r'D:\Software\anaconda\Library\share\proj'
os.environ['GDAL_DATA'] = r'D:\Software\anaconda\Library\share'

'''必须没有中文'''
Input_data = r''

if Input_data == '':
    Input_data = input('请输入nc数据的路径——————————————:')

Out_dir = r''

if Out_dir == '':
    Out_dir = input('请输入存放nc或nc4数据转tif的结果文件夹——————————————:')
    
def NC_to_tiffs(data,Out_dir):
    
    '''
    Input:
        data: Inputdata's path
        out_path: Outpath
        styear:   Start year name
    Output:
        None
        Example:  nc_to_tif(data = dat,out_path = Output_folder,styear)
    '''
    nc_data_obj = nc.Dataset(data)
    key = list(nc_data_obj.variables.keys())            #获取时间,经度,纬度,波段的名称信息,这些可能是不一样的
    print(f'{data} 的所有波段信息为————————:{key}')
    lon_loc = [i for i,x in enumerate(key) if (x.find('lon'.upper())!=-1 or x.find('lon'.lower())!=-1)][0]   #模糊查找属于经度的名称
    lat_loc = [i for i,x in enumerate(key) if (x.find('lat'.upper())!=-1 or x.find('lat'.lower())!=-1)][0]   #模糊查找属于纬度的名称

    band_start = eval(input(f"请在指定范围内 1~{len(key)} 输入您想要输出的多个波段的开始序号(int): "))   
    band_end = eval(input(f"请在指定范围内 1~{len(key)} 输入您想要输出的多个波段的结束序号(int)(如果你只有一个波段想要输出的话结束序号就与开始序号相同): ")) 
    if band_end > len(key):
        print('结束序号不在指定范围内')
        return 0
    for band_var in key[band_start-1:band_end]: 
        key_lon = key[lon_loc]              #获取经度的名称   
        key_lat = key[lat_loc]              #获取纬度的名称  
        Lon = nc_data_obj.variables[key_lon][:]   #获取每个像元的经度
        Lat = nc_data_obj.variables[key_lat][:]    #获取每个像元的纬度
        band = np.asarray(nc_data_obj.variables[band_var]).astype('float16')  #获取对应波段的像元的值,类型为数组
        print("请查看你的填充值:",nc_data_obj.variables[band_var])
        Filldata =  input("请输入您刚刚查看的填充值('FillValue'或者为'missing_value')如果没有的话就输入:'None':——————————")
        #影像的四个角的坐标
        LonMin,LatMax,LonMax,LatMin = [Lon.min(),Lat.max(),Lon.max(),Lat.min()] 
        #分辨率计算
        N_Lat = len(Lat) 
        if Lon.ndim==1 :
            N_Lon = len(Lon)   #如果Lon为一维的话,就取长度
        else:         
            N_Lon = len(Lon[0])   #如果Lon为二维的话,就取宽度
        Lon_Res = (LonMax - LonMin) /(float(N_Lon)-1)
        Lat_Res = (LatMax - LatMin) / (float(N_Lat)-1)

        ndim = band.ndim


        if ndim == 4 :
            print(f'正在处理的数据为:{data}')
            print(f'正在处理的波段为:{band_var}')
            print(f'{band_var}波段维度为:4')
            print(f'该四维数据中在第一维度上的长度为:{band.shape[0]}')
            print(f'该四维数据中在第二维度上的长度为:{band.shape[1]}')
            print(f'该四维数据中在第三维度上的长度为:{band.shape[2]}')
            print(f'该四维数据中在第四维度上的长度为:{band.shape[3]}')
            ndim_4_1_start = eval(input("请输入您在第一维度上开始时间,如果是xxxx年的话就输入xxxx比如2000:——————————"))
            step_4_1 = eval(input("请输入您在第一维度上时间的步长,如果是每隔x年的话就输入x比如5:——————————"))
            ndim_4_2_start = eval(input("请输入您在第二维度上开始时间,如果是x月的话就输入x比如1:——————————"))
            step_4_2 = eval(input("请输入您在第二维度上时间的步长,如果是每隔x月的话就输入x比如6:——————————"))
            for i in range(band.shape[0]):
                for j in range(band.shape[1]):
                    driver = gdal.GetDriverByName('GTiff')   # 创建驱动          
                    arr1 = band[i,j,:,:]               # 获取不同时间段的数据
                    out_tif_name = Out_dir + os.sep + data.split('\\')[-1][:-4] + '_' + band_var + '_' + str(ndim_4_1_start) + \
                                    '_' + str(ndim_4_2_start) + '.tif'
                    out_tif = driver.Create(out_tif_name,N_Lon,N_Lat,1,gdal.GDT_Float32) 
                    # 设置影像的显示范围
                    #-Lat_Res一定要是-的
                    geotransform = (LonMin, Lon_Res, 0, LatMax, 0, -Lat_Res)
                    out_tif.SetGeoTransform(geotransform)
                    srs = osr.SpatialReference()
                    srs.ImportFromEPSG(4326)
                    out_tif.SetProjection(srs.ExportToWkt())
                    

                    if Lat[0]<=Lat[-1]:   #如果维度上的第一个值小于等于最后的的一个值就认为是倒序,就得进行数组的倒序排列,否则就是正向,不用倒序排列
                        print(f'{data}行数据是倒的,现在进行矫正............')
                        arr1 = arr1[::-1]
                        print('矫正完成...........')
                    else:
                        pass
                    out_tif.GetRasterBand(1).WriteArray(arr1)   #写入数据
                    if Filldata =='None':
                        pass
                    else:
                        out_tif.GetRasterBand(1).SetNoDataValue(eval(Filldata))   #设置输出数据的无效值
                    out_tif.FlushCache() # 将数据写入硬盘
                    print(f'{out_tif_name} is ok!!!!')
                    del out_tif       # 注意必须关闭tif文件
                    ndim_4_2_start += step_4_2
                ndim_4_1_start += step_4_1
        if ndim == 3 :
            print(f'正在处理的数据为:{data}')
            print(f'正在处理的波段为:{band_var}')
            print(f'{band_var}波段维度为:3')
            print(f'该三维数据中在第一维度上的长度为:{band.shape[0]}')
            print(f'该三维数据中在第二维度上的长度为:{band.shape[1]}')
            print(f'该三维数据中在第三维度上的长度为:{band.shape[2]}')
            ndim_3_1_start = eval(input("请输入您在第一维度上开始时间,如果是xxxx年的话就输入xxxx比如2000,如果是x月的话就输入x比如1:——————————"))
            step_3_1 = eval(input("请输入您在第一维度上时间的步长,如果是每隔x年的话就输入x比如5:——————————"))
            for i in range(band.shape[0]):
                driver = gdal.GetDriverByName('GTiff')   # 创建驱动          
                arr1 = band[i,:,:]               # 获取不同时间段的数据
                out_tif_name = Out_dir + os.sep + data.split('\\')[-1][:-4] + '_' + band_var + '_' + str(ndim_3_1_start) +  '.tif'
                out_tif = driver.Create(out_tif_name,N_Lon,N_Lat,1,gdal.GDT_Float32) 
                # 设置影像的显示范围
                #-Lat_Res一定要是-的
                geotransform = (LonMin, Lon_Res, 0, LatMax, 0, -Lat_Res)
                out_tif.SetGeoTransform(geotransform)
                srs = osr.SpatialReference()
                srs.ImportFromEPSG(4326)
                out_tif.SetProjection(srs.ExportToWkt())
                if Lat[0]<=Lat[-1]:   #如果维度上的第一个值小于等于最后的的一个值就认为是倒序,就得进行数组的倒序排列,否则就是正向,不用倒序排列
                    print(f'{data}行数据是倒的,现在进行矫正............')
                    arr1 = arr1[::-1]
                    print('矫正完成...........')
                else:
                    pass
                out_tif.GetRasterBand(1).WriteArray(arr1)   #写入数据
                if Filldata == 'None':
                    pass
                else:
                    out_tif.GetRasterBand(1).SetNoDataValue(eval(Filldata))  # 设置输出数据的无效值
                out_tif.FlushCache() # 将数据写入硬盘
                print(f'{out_tif_name} is ok!!!!')
                del out_tif       # 注意必须关闭tif文件
                ndim_3_1_start += step_3_1
                
        if ndim == 2 :
            print(f'正在处理的数据为:{data}')
            print(f'正在处理的波段为:{band_var}')
            print(f'{band_var}波段维度为:2')
            print(f'该二维数据中在第一维度上的长度为:{band.shape[0]}')
            print(f'该二维数据中在第二维度上的长度为:{band.shape[1]}')
            driver = gdal.GetDriverByName('GTiff')   # 创建驱动          
            arr1 = band[:,:]               # 获取不同时间段的数据
            out_tif_name = Out_dir + os.sep + data.split('\\')[-1][:-4] + '_' + band_var + '.tif'
            out_tif = driver.Create(out_tif_name,N_Lon,N_Lat,1,gdal.GDT_Float32) 
            # 设置影像的显示范围
            #-Lat_Res一定要是-的
            geotransform = (LonMin, Lon_Res, 0, LatMax, 0, -Lat_Res)
            out_tif.SetGeoTransform(geotransform)
            srs = osr.SpatialReference()
            srs.ImportFromEPSG(4326)
            out_tif.SetProjection(srs.ExportToWkt())
            
            if Lat[0]<=Lat[-1]:   #如果维度上的第一个值小于等于最后的的一个值就认为是倒序,就得进行数组的倒序排列,否则就是正向,不用倒序排列
                print(f'{data}行数据是倒的,现在进行矫正............')
                arr1 = arr1[::-1]
                print('矫正完成...........')
            else:
                pass
            out_tif.GetRasterBand(1).WriteArray(arr1)   #写入数据
            if Filldata == 'None':
                pass
            else:
                out_tif.GetRasterBand(1).SetNoDataValue(eval(Filldata))  # 设置输出数据的无效值
            out_tif.FlushCache() # 将数据写入硬盘
            print(f'{out_tif_name} is ok!!!!')
            del out_tif       # 注意必须关闭tif文件
    print('ALL IS ok   !!!!!')



NC_to_tiffs(Input_data,Out_dir)   

1.首先导入必要的库(如果不会安装的话可以私聊我):

import numpy as np
import netCDF4 as nc
from osgeo import gdal,osr,ogr
import os

2.一些输入路径和输出路径:

'''必须没有中文'''
Input_data = r''

if Input_data == '':
    Input_data = input('请输入nc或者nc4数据的路径——————————————:')

Out_dir = r''

if Out_dir == '':
    Out_dir = input('请输入最后存放tif的结果文件夹——————————————:')

将自己的nc或者nc4数据的绝对路径填入:Input_data = r'' 的 r'' 中,将最后输出tif数据的的文件夹路径填入:Out_dir  = r'' 的 r''中。(也可以不填,直接运行的话,等会控制台也会叫你输入的)

(注意!!!输入路径不要有中文,不然会报错,如果有哪位大佬知道怎么解决的话可以评论一下)

3.可以直接运行了,不过最好你自己首先要知道你的数据的时间格式,虽然运行中会有一些提示会让你知道你的数据的时间范围,但是为了最后好将输出出来的tif数据命名的话最好要自己知道自己的数据的开始时间,结束时间,时间间隔等。

4.运行中会叫你输入一些必要的参数,不过提示里面有叫你怎么输入,相信你们都能看懂的,不会的评论区或者私信告诉我,我只要不忙的话就会看的!

  • 24
    点赞
  • 94
    收藏
    觉得还不错? 一键收藏
  • 35
    评论
要实现Python批量nc文件换为tif格式的话,可以使用xarray和rasterio这两个库来处理。下面是一个示例代码: ```python import os import xarray as xr import rasterio from rasterio.transform import from_origin # 定义输入文件夹和输出文件夹路径 input_folder = '/path/to/input/folder' output_folder = '/path/to/output/folder' # 获取输入文件夹中所有nc文件的路径 nc_files = [os.path.join(input_folder, file) for file in os.listdir(input_folder) if file.endswith('.nc')] # 遍历处理每个nc文件 for nc_file in nc_files: # 读取nc文件 dataset = xr.open_dataset(nc_file) # 提取需要的数据变量和坐标系信息 data_variable = dataset['data_variable'] crs = dataset.rio.crs # 获取数据变量的尺寸 height, width = data_variable.shape # 定义输出tif文件路径 output_file = os.path.join(output_folder, os.path.splitext(os.path.basename(nc_file))[0] + '.tif') # 创建输出tif文件 with rasterio.open(output_file, 'w', driver='GTiff', height=height, width=width, count=1, dtype='float64', crs=crs) as dst: # 设置地理换信息 dst.transform = from_origin(dataset.attrs['longitude'].values[0], dataset.attrs['latitude'].values[0], dataset.attrs['longitude'].values[1]-dataset.attrs['longitude'].values[0], dataset.attrs['latitude'].values[1]-dataset.attrs['latitude'].values[0]) # 将数据变量写入tif文件 dst.write(data_variable.values, 1) print(f'换完成: {nc_file} -> {output_file}') ``` 在以上代码中,我们首先指定输入文件夹和输出文件夹的路径。然后使用`os.listdir`函数获取输入文件夹中的所有nc文件路径,并以列表的形式存储在`nc_files`中。 接下来,我们遍历每个nc文件,并使用`xr.open_dataset`函数读取文件。然后提取需要的数据变量和坐标系信息,并获取数据变量的尺寸。 接着,我们定义输出tif文件的路径,并使用`rasterio.open`函数创建输出tif文件。在创建时,我们指定了输出tif文件的大小、数据类型和坐标系等信息,并设置了地理换信息。 最后,我们将数据变量的值写入到输出tif文件中,并打印换完成的信息。 运行以上代码后,Python将会批量将输入文件夹中的所有nc文件换为对应的tif文件,并保存到输出文件夹中。每个tif文件的名称与其对应的nc文件名称保持一致,只是后缀名不同。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 35
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值