首頁 > 軟體

基於Python實現nc批次轉tif格式

2022-08-12 18:02:14

由於做專案需要運用到netCDF格式的氣象資料,而ArcGIS中需要用柵格影像進行處理,對於較多的檔案,ArcGIS一個個手動轉換過於繁瑣,因此我們採用Python進行轉換,當然也可以採用matlab進行轉換。

首先需要安裝下面幾個庫:

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

我們可以在下面網址中尋找對應python安裝版本的安裝包,下載後,在pycharm控制檯中直接安裝即可。例如pip install netCDF4-1.5.8-cp39-cp39-

win_amd64.whl

https://www.lfd.uci.edu/~gohlke/pythonlibs/

安裝之後即可進行轉換:

def nc2tif(data, Output_folder):
    tmp_data = nc.Dataset(data)  # 利用.Dataset()方法讀取nc資料
    print('tmp_data', tmp_data)
 
    Lat_data = tmp_data.variables['lat'][:]
    Lon_data = tmp_data.variables['lon'][:]
    # print(Lat_data)
    # print(Lon_data)
 
    tmp_arr = np.asarray(tmp_data.variables['temp'])
 
    # 影像的左上角&右下角座標
    Lonmin, Latmax, Lonmax, Latmin = [Lon_data.min(), Lat_data.max(), Lon_data.max(), Lat_data.min()]
    # print(Lonmin, Latmax, Lonmax, Latmin)
 
    # 解析度計算
    Num_lat = len(Lat_data)  # 5146
    Num_lon = len(Lon_data)  # 7849
    Lat_res = (Latmax - Latmin) / (float(Num_lat) - 1)
    Lon_res = (Lonmax - Lonmin) / (float(Num_lon) - 1)
    # print(Num_lat, Num_lon)
    # print(Lat_res, Lon_res)
 
    for i in range(len(tmp_arr[:])):
        # i=0,1,2,3,4,5,6,7,8,9,...
        # 建立tif檔案
        driver = gdal.GetDriverByName('GTiff')
        out_tif_name = Output_folder + '\' + data.split('\')[-1].split('.')[0] + '_' + str(i + 1) + '.tif'
        out_tif = driver.Create(out_tif_name, Num_lon, Num_lat, 1, gdal.GDT_Int16)
 
        # 設定影像的顯示範圍
        # Lat_re前需要新增負號
        geotransform = (Lonmin, Lon_res, 0.0, Latmax, 0.0, -Lat_res)
        out_tif.SetGeoTransform(geotransform)
 
        # 定義投影
        prj = osr.SpatialReference()
        prj.ImportFromEPSG(4326)  # WGS84
        out_tif.SetProjection(prj.ExportToWkt())
 
        # 資料匯出
        out_tif.GetRasterBand(1).WriteArray(tmp_arr[i])  # 將資料寫入記憶體,此時沒有寫入到硬碟
        out_tif.FlushCache()  # 將資料寫入到硬碟
        out_tif = None  # 關閉tif檔案
 
def main():
    Input_folder = r"E:competition航天宏圖2-meter air temperature_CMFDData_forcing_01yr_010deg\"
    # Input_folder = r"E:competition航天宏圖2-meter air temperature_CMFDData_forcing_01mo_010deg\"
    Output_folder = r"E:competition航天宏圖2-meter air temperature_CMFDtif\"
 
    # 讀取所有資料
    data_list = glob.glob(os.path.join(Input_folder + '*.nc'))
    print(data_list)
 
    for i in range(len(data_list)):
        data = data_list[i]
        nc2tif(data, Output_folder)
        print(data + '轉tif成功')

值得注意的是,tmp_arr = np.asarray(tmp_data.variables['temp'])中的temp可以根據需要轉換的波段進行選擇,我們可以在讀取資料之後print一下,找到對應的波段進行替換即可。如下圖中我們應該選擇的就是temp。

完成上述步驟即可得到所需的tif影象:

在上述程式碼中,經過處理的影像是倒置的,可能是處理過程中仿射矩陣讀寫錯誤導致的。因此我們可以在寫入影像的時候,進行影像的垂直映象操作即可:WriteArray(ndvi_arr_float[i][::-1]) 

def NC_to_tiffs(data, Output_folder):
    nc_data_obj = nc.Dataset(data)
    Lon = nc_data_obj.variables['lon'][:]
    Lat = nc_data_obj.variables['lat'][:]
    ndvi_arr = np.asarray(nc_data_obj.variables['temp'])  
    ndvi_arr_float = ndvi_arr.astype(float) / 10000  之間
    # 影像的左上角和右下角座標
    LonMin, LatMax, LonMax, LatMin = [Lon.min(), Lat.max(), Lon.max(), Lat.min()]
    # 解析度計算
    N_Lat = len(Lat)
    N_Lon = len(Lon)
    Lon_Res = (LonMax - LonMin) / (float(N_Lon) - 1)
    Lat_Res = (LatMax - LatMin) / (float(N_Lat) - 1)
    for i in range(len(ndvi_arr[:])):
        driver = gdal.GetDriverByName('GTiff')
        out_tif_name = Output_folder + '\' + data.split('\')[-1].split('.')[0] + '_' + str(i + 1) + '.tif'
        out_tif = driver.Create(out_tif_name, N_Lon, N_Lat, 1, gdal.GDT_Float32)
       
        geotransform = (LonMin, Lon_Res, 0, LatMax, 0, -Lat_Res)
        out_tif.SetGeoTransform(geotransform)
      
        srs = osr.SpatialReference()
        srs.ImportFromEPSG(4326) 
        out_tif.SetProjection(srs.ExportToWkt()) 
        # 資料寫出
        out_tif.GetRasterBand(1).WriteArray(ndvi_arr_float[i][::-1])  # 將資料寫入記憶體,此時沒有寫入硬碟 此處[::-1]用於影象的垂直映象對稱,避免影象顛倒
        out_tif.FlushCache()  # 將資料寫入硬碟
        out_tif = None  # 注意必須關閉tif檔案

這樣便可以得到正確輸出的影像:

當然,我們除了在寫入時做垂直映象操作之外,還可以利用python對影象進行幾何變換來實現翻轉。具體程式碼如下:

影象水平翻轉:

#  影象水平翻轉
    im_data_hor = np.flip(im_data, axis=2)
    hor_path = train_image_path + "\" + str(tran_num) + imageList[i][-4:]
    writeTiff(im_data_hor, im_geotrans, im_proj, hor_path)

標籤水平翻轉: 

 #  標籤水平翻轉
    Hor = cv2.flip(label, 1)
    hor_path = train_label_path + "\" + str(tran_num) + labelList[i][-4:]
    cv2.imwrite(hor_path, Hor)
    tran_num += 1

影象垂直翻轉:

 #  影象垂直翻轉
    im_data_vec = np.flip(im_data, axis=1)
    vec_path = train_image_path + "\" + str(tran_num) + imageList[i][-4:]
    writeTiff(im_data_vec, im_geotrans, im_proj, vec_path)

標籤垂直翻轉:

 #  標籤垂直翻轉
    Vec = cv2.flip(label, 0)
    vec_path = train_label_path + "\" + str(tran_num) + labelList[i][-4:]
    cv2.imwrite(vec_path, Vec)
    tran_num += 1

影象映象翻轉:

 #  影象對角映象
    im_data_dia = np.flip(im_data_vec, axis=2)
    dia_path = train_image_path + "\" + str(tran_num) + imageList[i][-4:]
    writeTiff(im_data_dia, im_geotrans, im_proj, dia_path)

標籤映象翻轉:

 #  標籤對角映象
    Dia = cv2.flip(label, -1)
    dia_path = train_label_path + "\" + str(tran_num) + labelList[i][-4:]
    cv2.imwrite(dia_path, Dia)
    tran_num += 1

若是輸出路徑的資料夾沒有建立好,則會報如下錯誤。當然,為了減少工作量,也可以定義一個函數,如果路徑不存在則自動建立,就可以解決這個問題。

到此這篇關於基於Python實現nc批次轉tif格式的文章就介紹到這了,更多相關Python nc轉tif內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com