自从数据发布以来局部中国区域文件官方只给出了图像文件,并未给出对应的经纬度查找表,而对于只研究中国区域的同学来说,下载全圆盘图像文件显得费时费力,然后处理起来又占据内存。为了对中国区域图像文件进行几何校正,将标称投影转为等经纬度投影,博主和同学老王进行了交流,终成此文。
下面将利用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