自從數據發佈以來局部中國區域文件官方只給出了圖像文件,並未給出對應的經緯度查找表,而對於只研究中國區域的同學來說,下載全圓盤圖像文件顯得費時費力,然後處理起來又佔據內存。爲了對中國區域圖像文件進行幾何校正,將標稱投影轉爲等經緯度投影,博主和同學老王進行了交流,終成此文。
下面將利用Python實現區域圖像文件的經緯度查找表建立!~
將中國區域行列號轉爲經緯度查找表,並且存爲tiff文件,band1爲經度,band2爲緯度。在ENVI中建立GLT,rotation選擇0,即圖像正上爲正北方向,其他不變,然後利用GLT進行幾何校正,投影選擇等經緯度。其他不變。這是Python實現區域經緯度查找表tiff文件的程序。選擇文件爲中國區域GEO 4km定位文件。下載好4km定位文件後,自行修改後綴爲HDF5!
程序路徑的話,自行修改路徑~
# -*- coding: utf-8 -*-
"""
Created on Tue Apr 23 11:39:02 2019
@author: Administrator
"""
import os
import numpy as np
import math
import h5py
import gdal
import operator
#讀取FY4A-_AGRI--_N_DISK_1047E_L1-_GEO-_MULT_NOM文件,空間分辨率4km
#此程序僅限於此類文件
#該文件中僅用於獲得FY4A-_AGRI--_N_REGC_1047E_L1_***_4000M_***.HDF文件
#中數據的行列號轉換成經緯度
def Get_Line_Col_in_Disk(File_Full_Path):
#print('#########################################')
#判讀輸入文件是否爲FY4A-_AGRI--_N_REGC_1047E_L1_***_4000M_***.HDF文件
#如果不是,則輸出文件是錯誤的,退出程序
fname = os.path.basename(File_Full_Path)
#print('fname =',fname)
str_GEO_value = fname.find('GEO')
#print(str_GEO_value)
str_REGC_value = fname.find('REGC')
#print(str_REGC_value)
str_4000M_value = fname.find('4000M')
#print(str_4000M_value)
if str_GEO_value == -1 or str_REGC_value == -1 or str_4000M_value == -1:
return None
#以只讀的方式打開hdf5文件
InFile_REGC_GEO_4KM = h5py.File(File_Full_Path,'r')
#ColumnNumber對應的數據,以numpy.ndarray方式存儲
#中國區域文件各個像點對應於全圓盤的列號
Data_Col_Num_in_Disk_GDAL = InFile_REGC_GEO_4KM['ColumnNumber'][:]
Data_Col_Num_in_Disk = Data_Col_Num_in_Disk_GDAL.astype('f4')
print(Data_Col_Num_in_Disk_GDAL.dtype)
print(Data_Col_Num_in_Disk.dtype)
#LineNumber對應的數據,以numpy.ndarray方式存儲
#中國區域文件各個像點對應於全圓盤的行號
Data_Line_Num_in_Disk_GDAL = InFile_REGC_GEO_4KM['LineNumber'][:]
Data_Line_Num_in_Disk = Data_Line_Num_in_Disk_GDAL.astype('f4')
InFile_REGC_GEO_4KM.close()
return Data_Line_Num_in_Disk,Data_Col_Num_in_Disk
def Convert_Line_Col_To_Lon_Lat(Data_Line_Num_in_Disk,Data_Col_Num_in_Disk):
#print('##########################################')
##根據中國區域在全圓盤中的行列號計算經緯度
#注意:各個文件中在全圓盤的行列號會有所不同
#中國區域內的有效行列號
Valid_Value_Index = np.where(Data_Line_Num_in_Disk != -1.0 )
Line = Data_Line_Num_in_Disk[Valid_Value_Index]
Column = Data_Col_Num_in_Disk[Valid_Value_Index]
#地球的長半軸,單位km
ea = 6378.137
#地球的短半軸,單位km
eb = 6356.7523
#地心到衛星質心的距離,單位km
h = 42164
#衛星星下點的經度
Lon_Sate = 104.7
#COFF全圓盤列偏移,4km對應的數值
COFF = 1373.5
#CFAC全圓盤列比例因子,4km對應的數值
CFAC = 10233137
#LOFF全圓盤行偏移,4km對應的數值
LOFF = 1373.5
#LFAC全圓盤列比例因子,4km對應的數值
LFAC = 10233137
tmp = np.pi/(180*math.pow(2,-16))
#print('tmp =',tmp)
x = tmp * (Column - COFF)/CFAC
#print('x =',x)
y = tmp * (Line - LOFF)/LFAC
#print('y =',y)
sinx = np.sin(x)
cosx = np.cos(x)
siny = np.sin(y)
cosy = np.cos(y)
cosxy = cosx * cosy
tmp2 = cosy*cosy + siny*siny * ea*ea /(eb*eb)
#print('tmp2=',tmp)
sd = np.power((h*cosxy)*(h*cosxy) - tmp2*(h*h-ea*ea),0.5)
sn = ( h*cosxy - sd ) / tmp2
s1 = h - sn * cosxy
s2 = sn * sinx * cosy
s3 = -sn * siny
sxy = np.power(s1*s1 + s2*s2,0.5)
tmp3 = 180 / np.pi
lon = tmp3 * np.arctan(s2/s1) + Lon_Sate
lat = tmp3 * np.arctan((ea*ea*s3)/(eb*eb*sxy))
#print('lon =',lon)
#print('lat =',lat)
Data_Lon = np.zeros(Data_Line_Num_in_Disk.shape, dtype = np.float64,order = 'C' )
Data_Lon[:,:] = 999
Data_Lon[Valid_Value_Index] = lon
Data_Lat = np.zeros(Data_Line_Num_in_Disk.shape, dtype = np.float64,order = 'C' )
Data_Lat[:,:] = 999
Data_Lat[Valid_Value_Index] = lat
return Data_Lon,Data_Lat
def writeTiff(im_data,im_width,im_height,im_bands,path):#im_geotrans,im_proj,path):
if 'int8' in im_data.dtype.name:
datatype = gdal.GDT_Byte
elif 'int16' in im_data.dtype.name:
datatype = gdal.GDT_UInt16
else:
datatype = gdal.GDT_Float64
if len(im_data.shape) == 3:
im_bands, im_height, im_width = im_data.shape
elif len(im_data.shape) == 2:
im_data = np.array([im_data])
else:
im_bands, (im_height, im_width) = 1,im_data.shape
#創建文件
driver = gdal.GetDriverByName("GTiff")
dataset = driver.Create(path, im_width, im_height, im_bands, datatype)
#if(dataset!= None):
#dataset.SetGeoTransform(im_geotrans) #寫入仿射變換參數
#dataset.SetProjection(im_proj) #寫入投影
for i in range(im_bands):
dataset.GetRasterBand(i+1).WriteArray(im_data[i])
del dataset
#主程序
if __name__ =='__main__':
GEO_File_Full_Path = 'E:\FY-4A大創\幾何校正\python_FY-4A\FY4A-_AGRI--_N_REGC_1047E_L1-_GEO-_MULT_NOM_20190310003000_20190310003416_4000M_V0001.HDF5'
GEO_file_name = os.path.basename(GEO_File_Full_Path)
first = GEO_file_name[44:57]
print(first)
second = GEO_file_name[73:79]
print(second)
out_name = first + second + '經緯度查找表'
Data_line_col = Get_Line_Col_in_Disk(GEO_File_Full_Path)
Lon_Lat = Convert_Line_Col_To_Lon_Lat(Data_line_col[0],Data_line_col[1])
#print(type(Lon_Lat))
if Lon_Lat is None :
print ('wrong file')
#elif (id(GEO_file_name[44:73]) is not id(Ocean_file_name[44:73])):
#print(type(GEO_file_name[44:73]))
#print('Geo file does not match Ocean file')
else:
Lon = Lon_Lat[0]
Lat = Lon_Lat[1]
im_data = np.array([Lon,Lat])
im_bands, im_height, im_width = im_data.shape
#保存tif文件函數
path = 'E:\FY-4A大創\幾何校正\python_FY-4A\\'+ out_name + '.tif'
writeTiff(im_data, im_width, im_height,im_bands,path)
tif命名爲:成像時間+空間分辨率+經緯度查找表,例如 2019031000300_4000M經緯度查找表.tif
生成的查找表如圖:
band1爲經度,band2爲緯度
建立GLT的過程參考鏈接[3],在建立GLT的過程中一定要注意,要先對生成的經緯度查找表做一個感興趣區域的裁剪,用ENVI Resize Data(special/spectral)工具進行,裁剪一個矩形的就好,既包括研究區又要大一些,不可以取到外圍999的無效值,ENVI在建立GLT的過程中,一旦有外圍999的無效值在,建立GLT時就會產生一個巨大無比的文件,並且一段時間後磁盤爆滿,電腦未響應死機。
利用GLT工具幾何校正結果如圖:
這樣的話整個過程不超過5分鐘!
博主用的是4km區域定位文件(GEO文件):
FY4A-_AGRI–_N_REGC_1047E_L1-_GEO-_MULT_NOM_20190310003000_20190310003416_4000M_V0001
博主用的3月10號的定位文件對3月8號的區域圖像進行的幾何校正,效果完全可以。不過據說,每次的區域文件嚴格地講,其大小會有一兩個像元的偏差。
寫入tiff部分的程序鳴謝train_for_skills參考:
[1]: https://blog.csdn.net/t46414704152abc/article/details/77482747
[2]:http://satellite.nsmc.org.cn/PortalSite/StaticContent/DocumentDownload.aspx?TypeID=3
[3]:http://blog.sina.com.cn/s/blog_764b1e9d0101da96.html