1157 lines
53 KiB
Python
1157 lines
53 KiB
Python
# -*- coding: UTF-8 -*-
|
||
|
||
"""
|
||
@Project :microproduct
|
||
@File :OnePlantHeightAlg.PY
|
||
@Function :计算斜距、雷达波长;获取phi的tif文件、kz的tif文件
|
||
@Author :LMM
|
||
@Date :2021/10/19 14:39
|
||
@Version :1.0.0
|
||
"""
|
||
import os
|
||
import xmltodict
|
||
import numpy as np
|
||
import json
|
||
import datetime
|
||
import yaml
|
||
import math
|
||
from osgeo import gdal
|
||
from tool.algorithm.image.ImageHandle import ImageHandler
|
||
from osgeo import osr
|
||
import copy
|
||
import glob
|
||
import logging
|
||
import math
|
||
logger = logging.getLogger("mylog")
|
||
|
||
def FindInfomationFromJson(HeaderFile_dom_json, node_path_list):
|
||
"""
|
||
在Json文件中,按照指定路径解析出制定节点
|
||
"""
|
||
result_node = HeaderFile_dom_json
|
||
for nodename in node_path_list:
|
||
result_node = result_node[nodename]
|
||
return result_node
|
||
|
||
|
||
def GetVectorNorm(Vecter):
|
||
"""
|
||
得到向量的模
|
||
"""
|
||
Vecter = Vecter.reshape(-1,1)
|
||
Vecter_Norm_pow = np.matmul(Vecter.T,Vecter)
|
||
return np.sqrt(Vecter_Norm_pow)
|
||
|
||
|
||
def XYZOuterM2(A, B):
|
||
"""
|
||
外积(叉乘),日后版本换成可以任意维度的外积运算方程
|
||
args:
|
||
A:nx3
|
||
B:nx3
|
||
"""
|
||
cnt = A.shape[0]
|
||
C = np.zeros((cnt, 3))
|
||
C[:, 0] = A[:, 1] * B[:, 2] - A[:, 2] * B[:, 1]
|
||
C[:, 1] = A[:, 2] * B[:, 0] - A[:, 0] * B[:, 2]
|
||
C[:, 2] = A[:, 0] * B[:, 1] - A[:, 1] * B[:, 0]
|
||
return C
|
||
|
||
|
||
class SatelliteOrbit(object):
|
||
def __init__(self) -> None:
|
||
super().__init__()
|
||
self.__starttime = 1262275200.0
|
||
|
||
def get_starttime(self):
|
||
"""
|
||
返回卫星轨道时间起算点
|
||
"""
|
||
return self.__starttime
|
||
|
||
def ReconstructionSatelliteOrbit(self, GPSPoints_list):
|
||
"""
|
||
重建卫星轨道,使用多项式拟合法
|
||
args:
|
||
GPSPoints_list:GPS 卫星轨道点
|
||
return:
|
||
SatelliteOrbitModel 卫星轨道模型
|
||
"""
|
||
self.SatelliteOrbitModel = None
|
||
|
||
def SatelliteSpaceState(self, time_float):
|
||
"""
|
||
根据时间戳,返回对应时间的卫星的轨迹状态
|
||
args:
|
||
time_float:时间戳
|
||
return:
|
||
State_list:[time,Xp,Yp,Zp,Vx,Vy,Vz]
|
||
"""
|
||
return None
|
||
|
||
|
||
class SatelliteOrbitFitPoly(SatelliteOrbit):
|
||
"""
|
||
继承于SatelliteOribit类,为拟合多项式实现方法
|
||
"""
|
||
|
||
def __init__(self) -> None:
|
||
super().__init__()
|
||
|
||
def ReconstructionSatelliteOrbit(self, GPSPoints_list, starttime):
|
||
if len(GPSPoints_list) > 10:
|
||
# 多项式的节点数,理论上是超过5个可以起算,这里为了精度选择10个点起算。
|
||
# 多项式 XA=Y ==> A=(X'X)^X'Y,其中 A 为待求系数,X为变量,Y为因变量
|
||
# 这里使用三次项多项式,共有6组参数。
|
||
# 声明自变量,因变量,系数矩阵
|
||
self.__starttime = starttime
|
||
record_count = len(GPSPoints_list)
|
||
time_arr = np.zeros((record_count, 1), dtype=np.float64) # 使用np.float64只是为了精度高些;如果32位也能满足需求,请用32位
|
||
state_arr = np.zeros((record_count, 6), dtype=np.float64)
|
||
A_arr = np.zeros((5, 6), dtype=np.float64) # 四次项
|
||
X = np.ones((record_count,5),dtype=np.float64) # 记录时间坐标
|
||
# 将点记录转换为自变量矩阵、因变量矩阵
|
||
|
||
for i in range(record_count):
|
||
GPSPoint = GPSPoints_list[i]
|
||
time_ = GPSPoint[0] - self.__starttime # 为了保证精度,对时间进行缩放
|
||
X[i, :] = np.array([1,time_,time_**2, time_**3, time_**4])
|
||
state_arr[i, :] = np.array(GPSPoint[1:], dtype=np.float64).reshape(1, 6) # 空间坐标
|
||
self.model_f=[]
|
||
for i in range(6):
|
||
Y = state_arr[:, i].reshape(-1,1)
|
||
A_arr[:, i] = np.matmul(np.matmul(np.linalg.inv(np.matmul(X.T, X)), X.T), Y)[:, 0]
|
||
|
||
self.A_arr = copy.deepcopy(A_arr.copy())
|
||
''' 测试误差
|
||
from matplotlib import pyplot
|
||
label_list=['x','y','z','vx','vy','vz']
|
||
color_list=['r','g','b','gold','gray','pink']
|
||
pyplot.figure()
|
||
for i in range(6):
|
||
Y = state_arr[:, i]
|
||
Y_predict=self.model_f[i](X)
|
||
pyplot.subplot(int("23{}".format(i+1)))
|
||
d=Y-Y_predict
|
||
pyplot.plot(X,d,label=label_list[i],color=color_list[i])
|
||
pyplot.title("max:{}".format(np.max(d)))
|
||
#self.model_f.append(interpolate.interp1d(X,Y,kind='cubic',fill_value='extrapolate'))
|
||
pyplot.legend()
|
||
pyplot.show()
|
||
'''
|
||
return self.A_arr
|
||
else:
|
||
self.A_arr = None
|
||
return None
|
||
|
||
def SatelliteSpaceState(self, time_float):
|
||
"""
|
||
逐像素求解
|
||
根据时间戳,返回对应时间的卫星的轨迹状态,会自动计算与起算时间之差
|
||
args:
|
||
time_float:时间戳
|
||
return:
|
||
State_list:[time,Xp,Yp,Zp,Vx,Vy,Vz]
|
||
"""
|
||
if self.model_f is None:
|
||
return None
|
||
|
||
result_arr = np.zeros((1,7))
|
||
|
||
time_float = time_float - self.__starttime
|
||
result_arr[0, 0] = time_float
|
||
#time_arr[0, 4] = time_arr[0, 3] * time_float ** 4
|
||
time_float = np.array([1, time_float, time_float**2, time_float**3, time_float**4]).reshape(1, 5)
|
||
result_arr = np.matmul(time_float, self.A_arr)
|
||
return [time_float, result_arr]
|
||
|
||
def getSatelliteSpaceState(self, time_array):
|
||
"""
|
||
矩阵求解
|
||
根据时间戳矩阵,返回对应时刻的卫星空间状态(位置,速度),且会自动计算与起算时间之差
|
||
args:
|
||
time_array:nparray nx1 时间戳
|
||
return:
|
||
SatellitSpaceStateArray:nparray nx6 状态信息
|
||
"""
|
||
if self.model_f is None:
|
||
return None # 返回None,表示没有结果
|
||
n=time_array.shape[0]
|
||
result_arr_ = np.zeros((n, 6), dtype=np.float64)
|
||
time_float = time_array - self.__starttime
|
||
time_float = time_float.reshape(-1) # nx1
|
||
time_arr = np.ones((time_float.shape[0],5)) # nx5
|
||
time_arr[:, 1] = time_float
|
||
time_arr[:, 2] = time_float**2
|
||
time_arr[:, 3] = time_float**3
|
||
time_arr[:, 4] = time_float**4
|
||
result_arr_ = np.matmul(time_arr, self.A_arr) # nx5 5x6
|
||
#time_arr[0, 4] = time_arr[0, 3] * time_float ** 4
|
||
#result_arr=result_arr_
|
||
return result_arr_ # 位置矩阵
|
||
|
||
|
||
def ReconstructionSatelliteOrbit(GPSPoints_list, starttime):
|
||
"""
|
||
构建卫星轨道
|
||
args:
|
||
GPSPoints_list:卫星轨道点
|
||
starttime:起算时间
|
||
"""
|
||
if len(GPSPoints_list) > 16:
|
||
SatelliteOrbitModel = SatelliteOrbitFitPoly()
|
||
if SatelliteOrbitModel.ReconstructionSatelliteOrbit(GPSPoints_list, starttime=starttime) is None:
|
||
return None
|
||
return SatelliteOrbitModel
|
||
|
||
|
||
# 1 不同
|
||
class DEMProcess(object):
|
||
def __init__(self):
|
||
pass
|
||
|
||
@staticmethod
|
||
def get_extent(fn):
|
||
"""
|
||
原文链接:https://blog.csdn.net/XBR_2014/article/details/85255412
|
||
"""
|
||
ds = gdal.Open(fn)
|
||
rows = ds.RasterYSize
|
||
cols = ds.RasterXSize
|
||
# 获取图像角点坐标
|
||
gt = ds.GetGeoTransform()
|
||
minx = gt[0]
|
||
maxy = gt[3]
|
||
maxx = gt[0] + gt[1] * rows
|
||
miny = gt[3] + gt[5] * cols
|
||
return (minx, maxy, maxx, miny)
|
||
|
||
@staticmethod
|
||
def img_merge(in_dem_files,out_dem_path):
|
||
"""
|
||
根据子DEM的结果,保存结果。
|
||
args:
|
||
in_dem_files:tif 输入影像列表
|
||
out_dem_path:tif 输出影像地址
|
||
return:
|
||
0:删除
|
||
"""
|
||
# 读取影像的大小
|
||
in_dem_file_0=gdal.Open(in_dem_files[0])
|
||
out_dem_pro=in_dem_file_0.GetProjection()
|
||
del in_dem_file_0 # 删除目标影像
|
||
|
||
|
||
pass
|
||
|
||
|
||
@staticmethod
|
||
def img_mosaic(in_files, out_dem_path):
|
||
# 通过两两比较大小,将最终符合条件的四个角点坐标保存
|
||
# 即为拼接图像的四个角点坐标
|
||
minX, maxY, maxX, minY = DEMProcess.get_extent(in_files[0])
|
||
for fn in in_files[1:]:
|
||
minx, maxy, maxx, miny = DEMProcess.get_extent(fn)
|
||
minX = min(minX, minx)
|
||
maxY = max(maxY, maxy)
|
||
maxX = max(maxX, maxx)
|
||
minY = min(minY, miny)
|
||
|
||
# 获取输出图像的行列数
|
||
in_ds = gdal.Open(in_files[0])
|
||
bands_num = in_ds.RasterCount
|
||
gt = in_ds.GetGeoTransform()
|
||
rows = int((maxX - minX) / abs(gt[5]))
|
||
cols = int((maxY - minY) / gt[1])
|
||
|
||
# 判断栅格数据的数据类型
|
||
datatype = gdal.GDT_UInt16
|
||
|
||
# 创建输出图像
|
||
driver = gdal.GetDriverByName('GTiff')
|
||
out_dem = os.path.join(out_dem_path, 'mosaic0.tif')
|
||
out_ds = driver.Create(out_dem, cols, rows, bands_num, datatype)
|
||
out_ds.SetProjection(in_ds.GetProjection())
|
||
|
||
gt = list(in_ds.GetGeoTransform())
|
||
gt[0], gt[3] = minX, maxY
|
||
out_ds.SetGeoTransform(gt)
|
||
|
||
for fn in in_files:
|
||
in_ds = gdal.Open(fn)
|
||
x_size = in_ds.RasterXSize
|
||
y_size = in_ds.RasterYSize
|
||
trans = gdal.Transformer(in_ds, out_ds, [])
|
||
success, xyz = trans.TransformPoint(False, 0, 0)
|
||
x, y, z = map(int, xyz)
|
||
for i in range(1, bands_num + 1):
|
||
data = in_ds.GetRasterBand(i).ReadAsArray()
|
||
out_band = out_ds.GetRasterBand(i)
|
||
out_data = out_band.ReadAsArray(x, y, x_size, y_size)
|
||
data = np.maximum(data, out_data)
|
||
out_band.WriteArray(data, x, y)
|
||
|
||
del in_ds, out_band, out_ds
|
||
|
||
@staticmethod
|
||
def dem_clip(OutFilePath, DEMFilePath, SelectArea):
|
||
"""
|
||
根据选择范围裁剪DEM,并输出
|
||
agrs:
|
||
outFilePath:裁剪DEM输出地址
|
||
DEMFilePath:被裁减DEM地址
|
||
SelectArea:list [(xmin,ymax),(xmax,ymin)] 框选范围 左上角,右下角
|
||
"""
|
||
DEM_ptr = gdal.Open(DEMFilePath)
|
||
DEM_GeoTransform = DEM_ptr.GetGeoTransform() # 读取影像的投影变换
|
||
DEM_InvGeoTransform = gdal.InvGeoTransform(DEM_GeoTransform)
|
||
SelectAreaArrayPoints = [gdal.ApplyGeoTransform(DEM_InvGeoTransform, p[0], p[1]) for p in SelectArea]
|
||
SelectAreaArrayPoints = list(map(lambda p: (int(p[0]), int(p[1])), SelectAreaArrayPoints)) # 确定坐标
|
||
|
||
[(ulx, uly), (brx, bry)] = SelectAreaArrayPoints
|
||
rowCount, colCount = bry - uly, brx - ulx
|
||
|
||
# 输出DEM的桌面坐标转换
|
||
Out_Transfrom = list(DEM_GeoTransform)
|
||
Out_Transfrom[0] = SelectArea[0][0]
|
||
Out_Transfrom[3] = SelectArea[0][1]
|
||
|
||
# 构建输出DEM
|
||
Bands_num = DEM_ptr.RasterCount
|
||
gtiff_driver = gdal.GetDriverByName('GTiff')
|
||
datatype = gdal.GDT_UInt16
|
||
out_dem = gtiff_driver.Create(OutFilePath, colCount, rowCount, Bands_num, datatype)
|
||
out_dem.SetProjection(DEM_ptr.GetProjection())
|
||
out_dem.SetGeoTransform(Out_Transfrom)
|
||
|
||
for i in range(1, Bands_num + 1):
|
||
data_band = DEM_ptr.GetRasterBand(i)
|
||
out_band = out_dem.GetRasterBand(i)
|
||
data = data_band.ReadAsArray(ulx, uly, colCount, rowCount)
|
||
out_band.WriteArray(data)
|
||
del out_dem
|
||
|
||
@staticmethod
|
||
def dem_resample(in_dem_path, meta_file_path, out_dem_path):
|
||
"""
|
||
DEM重采样函数,默认坐标系为WGS84
|
||
agrs:
|
||
in_dem_path: 输入的DEM文件夹路径
|
||
meta_file_path: 输入的xml元文件路径
|
||
out_dem_path: 输出的DEM文件夹路径
|
||
"""
|
||
# 读取文件夹中所有的DEM
|
||
dem_file_paths=[os.path.join(in_dem_path,dem_name) for dem_name in os.listdir(in_dem_path) if dem_name.find(".tif")>=0 and dem_name.find(".tif.")==-1]
|
||
spatialreference=osr.SpatialReference()
|
||
spatialreference.SetWellKnownGeogCS("WGS84") # 设置地理坐标,单位为度 degree # 设置投影坐标,单位为度 degree
|
||
spatialproj=spatialreference.ExportToWkt() # 导出投影结果
|
||
# 将DEM拼接成一张大图
|
||
mergeFile =gdal.BuildVRT(os.path.join(out_dem_path,"mergeDEM.tif"),dem_file_paths)
|
||
out_DEM=os.path.join(out_dem_path,"mosaic0.tif")
|
||
gdal.Warp(out_DEM,
|
||
mergeFile,
|
||
format="GTiff",
|
||
dstSRS=spatialproj,
|
||
dstNodata=-9999,
|
||
outputType=gdal.GDT_Float32)
|
||
return out_DEM
|
||
|
||
|
||
class Orthorectification(object):
|
||
"""
|
||
正射校正模块类
|
||
"""
|
||
def __init__(self, configPath="config.yaml") -> None:
|
||
super().__init__()
|
||
# 常量声明
|
||
# 加载配置文件
|
||
d=os.listdir(".")
|
||
with open(configPath, 'r', encoding='utf-8') as f:
|
||
const = f.read()
|
||
self.config = yaml.load(const, Loader=yaml.FullLoader)
|
||
self.config['SatelliteOribit']['StartTime'] = datetime.datetime.strptime(
|
||
self.config['SatelliteOribit']['StartTime']['Value'],
|
||
self.config['SatelliteOribit']['StartTime']['format']).timestamp() # 转化成UTC时间格式
|
||
self.R_e = self.config['SatelliteOribit']['ReferenceSpheroid']['Re'] # m
|
||
self.R_p = self.config['SatelliteOribit']['ReferenceSpheroid']['Rp'] # m
|
||
self.w_e = self.config['SatelliteOribit']['ReferenceSpheroid']['we'] # rad/s
|
||
|
||
def ParseHearderFile(self, HeaderFilePath_str):
|
||
"""
|
||
解析头文件,返回计算所需要的必要信息。
|
||
args:
|
||
HeaderFilePath_str: 头文件地址
|
||
return:
|
||
HeaderFileInfomation_json: 头文件信息包
|
||
"""
|
||
|
||
with open(HeaderFilePath_str, 'r', encoding='utf-8') as fp:
|
||
HeaderFile_dom_str = fp.read()
|
||
HeaderFile_dom = xmltodict.parse(HeaderFile_dom_str) # 将XML转成json文本
|
||
HeaderFile_dom_json = json.loads(json.dumps(HeaderFile_dom)) # 将json字符串,转成json对象(对应于python中的dict)
|
||
# 获取头文件
|
||
HeaderInformation_json = {}
|
||
# 解析轨道节点,假定是GPS节点
|
||
HeaderInformation_json['GPS'] = []
|
||
# GPS 解析信息
|
||
GPSNode_Path = self.config['GPS']['GPSNode_Path']
|
||
GPSNodeNames_list = self.config['GPS']['NodeInfomation_Name']
|
||
GPSTime_Format = self.config['GPS']['Time_format']
|
||
GPSPoints = FindInfomationFromJson(HeaderFile_dom_json, GPSNode_Path)
|
||
|
||
for GPSPoint in GPSPoints:
|
||
GPSPoint = [
|
||
datetime.datetime.strptime(GPSPoint[GPSNodeNames_list[0]], GPSTime_Format).timestamp(), # TimeStamp
|
||
float(GPSPoint[GPSNodeNames_list[1]]), # Xp
|
||
float(GPSPoint[GPSNodeNames_list[2]]), # Yp
|
||
float(GPSPoint[GPSNodeNames_list[3]]), # Zp
|
||
float(GPSPoint[GPSNodeNames_list[4]]), # Vx
|
||
float(GPSPoint[GPSNodeNames_list[5]]), # Vy
|
||
float(GPSPoint[GPSNodeNames_list[6]])] # VZ
|
||
HeaderInformation_json['GPS'].append(GPSPoint)
|
||
|
||
# 提取成像相关信息
|
||
HeaderInformation_json['ImageInformation'] = {}
|
||
# 1、开始成像时间
|
||
HeaderInformation_json['ImageInformation']['StartTime'] = datetime.datetime.strptime(
|
||
FindInfomationFromJson(HeaderFile_dom_json, self.config['imageinfo']['StartImageTime']['NodePath']),
|
||
self.config['imageinfo']['StartImageTime']['Format']
|
||
).timestamp()
|
||
# 2、结束成像时间
|
||
HeaderInformation_json['ImageInformation']['EndTime'] = datetime.datetime.strptime(
|
||
FindInfomationFromJson(HeaderFile_dom_json, self.config['imageinfo']['EndImageTime']['NodePath']),
|
||
self.config['imageinfo']['StartImageTime']['Format']
|
||
).timestamp()
|
||
# 3、影像的宽高
|
||
HeaderInformation_json['ImageInformation']['height'] = int(
|
||
FindInfomationFromJson(HeaderFile_dom_json, self.config['imageinfo']['ImageHeight']['NodePath']))
|
||
HeaderInformation_json['ImageInformation']['width'] = int(
|
||
FindInfomationFromJson(HeaderFile_dom_json, self.config['imageinfo']['ImageWidth']['NodePath']))
|
||
# 4、影像的近斜距
|
||
HeaderInformation_json['ImageInformation']['NearRange'] = float(
|
||
FindInfomationFromJson(HeaderFile_dom_json, self.config['imageinfo']['NearRange']['NodePath']))
|
||
# 5、入射角
|
||
HeaderInformation_json['ImageInformation']['incidenceAngle'] = {
|
||
'NearRange': float(FindInfomationFromJson(HeaderFile_dom_json,
|
||
self.config['imageinfo']['incidenceAngle']['NearRange'][
|
||
'NodePath'])),
|
||
'FarRange': float(FindInfomationFromJson(HeaderFile_dom_json,
|
||
self.config['imageinfo']['incidenceAngle']['FarRange'][
|
||
'NodePath']))
|
||
}
|
||
# 6、成像时刻影像带宽
|
||
HeaderInformation_json['ImageInformation']['bandWidth'] = float(
|
||
FindInfomationFromJson(HeaderFile_dom_json, self.config['sensor']['bandWidth']['NodePath']))
|
||
# 7、多普勒质心常数
|
||
DopplerCentroidCoefficients_list = FindInfomationFromJson(HeaderFile_dom_json, self.config['imageinfo'][
|
||
'DopplerCentroidCoefficients']['NodePath'])
|
||
HeaderInformation_json['ImageInformation']['DopplerCentroidCoefficients'] = [
|
||
float(DopplerCentroidCoefficients_list[
|
||
self.config['imageinfo']['DopplerCentroidCoefficients']['DopplerCentroidCoefficients_Name'][0]]),
|
||
float(DopplerCentroidCoefficients_list[
|
||
self.config['imageinfo']['DopplerCentroidCoefficients']['DopplerCentroidCoefficients_Name'][1]]),
|
||
float(DopplerCentroidCoefficients_list[
|
||
self.config['imageinfo']['DopplerCentroidCoefficients']['DopplerCentroidCoefficients_Name'][2]]),
|
||
float(DopplerCentroidCoefficients_list[
|
||
self.config['imageinfo']['DopplerCentroidCoefficients']['DopplerCentroidCoefficients_Name'][3]]),
|
||
float(DopplerCentroidCoefficients_list[
|
||
self.config['imageinfo']['DopplerCentroidCoefficients']['DopplerCentroidCoefficients_Name'][4]]),
|
||
]
|
||
# 8、波长
|
||
HeaderInformation_json['ImageInformation']['lambda'] = float(
|
||
FindInfomationFromJson(HeaderFile_dom_json, self.config['sensor']['lambda']['NodePath']))
|
||
# 9、中心像元对应的中心经纬度
|
||
CenterPoint = FindInfomationFromJson(HeaderFile_dom_json,
|
||
self.config['imageinfo']['CenterImagePositon']['NodePath'])
|
||
HeaderInformation_json['ImageInformation']['centerPosition'] = [
|
||
float(CenterPoint[self.config['imageinfo']['CenterImagePositon']['Value'][0]]), # 纬度
|
||
float(CenterPoint[self.config['imageinfo']['CenterImagePositon']['Value'][1]]), # 经度
|
||
]
|
||
# 10、多普勒参数参考时间
|
||
HeaderInformation_json['ImageInformation']['DopplerParametersReferenceTime'] = float(
|
||
FindInfomationFromJson(HeaderFile_dom_json,
|
||
self.config['imageinfo']['DopplerParametersReferenceTime']['NodePath']))
|
||
# 11、参考斜距
|
||
HeaderInformation_json['ImageInformation']['refRange'] = float(
|
||
FindInfomationFromJson(HeaderFile_dom_json, self.config['imageinfo']['ReferenceRange']['NodePath']))
|
||
# 12、PRF
|
||
HeaderInformation_json['PRF'] = float(
|
||
FindInfomationFromJson(HeaderFile_dom_json, self.config['sensor']['PRF']['NodePath']))
|
||
# 13、中心时间
|
||
HeaderInformation_json['ImageInformation']['CenterTime'] = datetime.datetime.strptime(
|
||
FindInfomationFromJson(HeaderFile_dom_json, self.config['imageinfo']['CenterImageTime']['NodePath']),
|
||
self.config['imageinfo']['CenterImageTime']['Format']
|
||
).timestamp()
|
||
# 14 平台信息
|
||
HeaderInformation_json['plate']={}
|
||
PNode_Path = self.config['platform']['NodePath']
|
||
PNodeNames_list = self.config['platform']['NodeInfomation_Name']
|
||
PTime_Format = self.config['platform']['Time_format']
|
||
PGPSPoints = FindInfomationFromJson(HeaderFile_dom_json, PNode_Path)
|
||
PPoint = [
|
||
datetime.datetime.strptime(PGPSPoints[PNodeNames_list[0]], PTime_Format).timestamp(), # TimeStamp
|
||
float(PGPSPoints[PNodeNames_list[1]]), # Xp
|
||
float(PGPSPoints[PNodeNames_list[2]]), # Yp
|
||
float(PGPSPoints[PNodeNames_list[3]]), # Zp
|
||
float(PGPSPoints[PNodeNames_list[4]]), # Vx
|
||
float(PGPSPoints[PNodeNames_list[5]]), # Vy
|
||
float(PGPSPoints[PNodeNames_list[6]])] # VZ
|
||
HeaderInformation_json['plate']["position"]= PPoint
|
||
|
||
HeaderInformation_json['plate']["R"]= FindInfomationFromJson(HeaderFile_dom_json,self.config['platform']['RangeNodePath'])
|
||
# 15 影像的空间间隔分辨率
|
||
HeaderInformation_json['ImageInformation']['ImageWidthSpace']=float(FindInfomationFromJson(HeaderFile_dom_json, self.config['imageinfo']['ImageWidthSpace']['NodePath']))
|
||
|
||
HeaderInformation_json['ImageInformation']['ImageHeightSpace']=float(
|
||
FindInfomationFromJson(HeaderFile_dom_json, self.config['imageinfo']['ImageHeightSpace']['NodePath']))
|
||
# 16
|
||
HeaderInformation_json['plate']['height']=float(
|
||
FindInfomationFromJson(HeaderFile_dom_json,self.config['platform']['heightNodePath']))
|
||
return HeaderInformation_json
|
||
pass
|
||
|
||
def LLA_to_XYZ(self, latitude, longitude, altitude):
|
||
"""
|
||
经纬度转大地坐标系
|
||
args:
|
||
latitude:纬度
|
||
longitude:经纬
|
||
altitude:海拔高程
|
||
refrence: https://blog.csdn.net/dulingwen/article/details/96868530
|
||
"""
|
||
# 经纬度的余弦值
|
||
cosLat = math.cos(latitude * math.pi / 180)
|
||
sinLat = math.sin(latitude * math.pi / 180)
|
||
cosLon = math.cos(longitude * math.pi / 180)
|
||
sinLon = math.sin(longitude * math.pi / 180)
|
||
|
||
# WGS84坐标系的参数
|
||
rad = 6378137.0 # 地球赤道平均半径(椭球长半轴:a)
|
||
f = 1.0 / 298.257224 # WGS84椭球扁率 :f = (a-b)/a
|
||
C = 1.0 / math.sqrt(cosLat * cosLat + (1 - f) * (1 - f) * sinLat * sinLat)
|
||
S = (1 - f) * (1 - f) * C
|
||
h = altitude
|
||
|
||
# 计算XYZ坐标
|
||
X = (rad * C + h) * cosLat * cosLon
|
||
Y = (rad * C + h) * cosLat * sinLon
|
||
Z = (rad * S + h) * sinLat
|
||
|
||
return np.array([X, Y, Z]).reshape(1, 3)
|
||
|
||
def XYZ_to_LLA(self, X, Y, Z):
|
||
"""
|
||
大地坐标系转经纬度
|
||
适用于WGS84坐标系
|
||
args:
|
||
x,y,z
|
||
return:
|
||
lat,lon,altitude
|
||
"""
|
||
# WGS84坐标系的参数
|
||
a = 6378137.0 # 椭球长半轴
|
||
b = 6356752.314245 # 椭球短半轴
|
||
ea = np.sqrt((a ** 2 - b ** 2) / a ** 2)
|
||
eb = np.sqrt((a ** 2 - b ** 2) / b ** 2)
|
||
p = np.sqrt(X ** 2 + Y ** 2)
|
||
theta = np.arctan2(Z * a, p * b)
|
||
|
||
# 计算经纬度及海拔
|
||
longitude = np.arctan2(Y, X)
|
||
latitude = np.arctan2(Z + eb ** 2 * b * np.sin(theta) ** 3, p - ea ** 2 * a * np.cos(theta) ** 3)
|
||
N = a / np.sqrt(1 - ea ** 2 * np.sin(latitude) ** 2)
|
||
altitude = p / np.cos(latitude) - N
|
||
|
||
return np.array([np.degrees(latitude), np.degrees(longitude), altitude])
|
||
|
||
def getRByColumnCode(self, c):
|
||
"""
|
||
根据列号计算斜距
|
||
args:
|
||
c: 列号
|
||
"""
|
||
return self.R0 + c * self.delta_R
|
||
pass
|
||
|
||
def getTimeByLineCode(self, r):
|
||
"""
|
||
根据行号计算成像时间
|
||
args:
|
||
r: 行号
|
||
"""
|
||
return np.matmul(
|
||
np.concatenate([np.array([r ** i]).reshape(1, 1) for i in range(self.r2t_A_arr.shape[0])], axis=1),
|
||
self.r2t_A_arr)
|
||
|
||
def ReconstuctionTimesOflyDirectionPositionModel(self, timePoints_list):
|
||
"""
|
||
构建飞行向坐标与时间的转换模型,注意这里没有调整时间的起算点。
|
||
args:
|
||
timePoints_list:时间点坐标 [r,t]
|
||
"""
|
||
# 根据点数确定模型,最高为3次项模型
|
||
Y = np.zeros((len(timePoints_list), 1))
|
||
X = np.zeros((len(timePoints_list), 1))
|
||
|
||
for i in range(len(timePoints_list)):
|
||
Y[i, 0] = timePoints_list[i][1]
|
||
X[i, 0] = timePoints_list[i][0]
|
||
|
||
if len(timePoints_list) == 2: # 一次项
|
||
X = np.concatenate([np.ones((len(timePoints_list), 1)), X], axis=1)
|
||
A = np.matmul(np.matmul(np.linalg.inv(np.matmul(X.T, X)), X.T), Y)
|
||
|
||
elif len(timePoints_list) >= 3: # 二次项
|
||
X = np.concatenate([np.ones(len(timePoints_list), 1), X, np.power(X, 2)], axis=1)
|
||
A = np.matmul(np.matmul(np.linalg.inv(np.matmul(X.T, X)), X.T), Y)
|
||
|
||
elif len(timePoints_list) >= 8: # 三次项
|
||
X = np.concatenate([np.ones(len(timePoints_list), 1), X, np.power(X, 2), np.power(X, 3)], axis=1)
|
||
A = np.matmul(np.matmul(np.linalg.inv(np.matmul(X.T, X)), X.T), Y)
|
||
|
||
self.r2t_A_arr = A
|
||
|
||
def PrepareConvertSystem(self):
|
||
"""
|
||
计算常量
|
||
在数据计算之前,提前处理部分常量信息
|
||
构建r,c到坐标斜距的计算公式
|
||
"""
|
||
R0 = self.header_info['ImageInformation']['NearRange'] # 起始斜距/近斜距
|
||
delta_R = self.config['LightSpeed'] / (2 * self.header_info['ImageInformation']['bandWidth'] * 10 ** 6) # 计算距离向分辨率,参考《InSAR原理与应用》P36,距离向分辨率 带宽单位为MHZ
|
||
self.ReconstuctionTimesOflyDirectionPositionModel([
|
||
[0, self.header_info['ImageInformation']['StartTime']],
|
||
[self.header_info['ImageInformation']['height'] - 1, self.header_info['ImageInformation']['EndTime']]
|
||
]) # 构建坐标到时间的变换,这里仅用两个数据点构建
|
||
self.R0 = R0
|
||
self.delta_R = delta_R
|
||
|
||
def ConvertCoordinary(self):
|
||
"""
|
||
批量求解点坐标
|
||
"""
|
||
pass
|
||
|
||
def Orthorectification(self, FilePath_str):
|
||
"""
|
||
正射校正组件
|
||
正射校正整体可以分为两个步骤:
|
||
Step 1:计算出栅格坐标对应的真实的大地坐标系坐标
|
||
Step 2:根据大地坐标系将影像重采样到大地坐标系空间中
|
||
args:
|
||
FilePath_str:影像所在文件夹
|
||
"""
|
||
# 分离需要校正对象
|
||
file_name_list = os.listdir(FilePath_str)
|
||
header_name = [file_name for file_name in file_name_list if
|
||
file_name.rfind(".meta.xml") == len(file_name) - len('.meta.xml')][0] # xml头文件,存储在list中
|
||
tiff_name = [file_name for file_name in file_name_list if
|
||
file_name.rfind(".tiff") == len(file_name) - len('.tiff')] # tif影像文件,存储在list中
|
||
# 解析头文件
|
||
self.header_info = self.ParseHearderFile(os.path.join(FilePath_str, header_name))
|
||
# 构建轨道模型
|
||
self.SatelliteOrbitModel = ReconstructionSatelliteOrbit(self.header_info['GPS'],
|
||
starttime=self.config['SatelliteOribit']['StartTime'])
|
||
# 求解模型前计算常数变换模型
|
||
self.PrepareConvertSystem()
|
||
# 批量计算空间坐标
|
||
self.ConvertCoordinary()
|
||
|
||
|
||
# 2 不同
|
||
class IndirectOrthorectification(Orthorectification):
|
||
"""
|
||
间接定位法
|
||
"""
|
||
def parasInfomation(self,FilePath_str):
|
||
header_name = list(glob.glob(os.path.join(FilePath_str, '*.meta.xml')))[0]
|
||
self.header_info = self.ParseHearderFile(header_name)
|
||
return self.header_info
|
||
|
||
|
||
def IndirectOrthorectification(self, FilePath_str, dem_resampled_path):
|
||
"""
|
||
正射校正组件
|
||
正射校正整体可以分为两个步骤:
|
||
Step 1:计算出栅格坐标对应的真实的大地坐标系坐标
|
||
Step 2:根据大地坐标系将影像重采样到大地坐标系空间中
|
||
args:
|
||
FilePath_str:影像所在文件夹
|
||
dem_resampled_path:重采样后的DEM路径
|
||
lut_tif_path:输出的r,c,ti数据影像
|
||
work_temp_path: 输出的临时文件地址路径,方便存放计算临时文件
|
||
"""
|
||
# 分离需要校正对象
|
||
# file_name_list = os.listdir(FilePath_str)
|
||
# header_name = [file_name for file_name in file_name_list if
|
||
# file_name.rfind(".meta.xml") == len(file_name) - len('.meta.xml')][0] # 头文件
|
||
header_name = list(glob.glob(os.path.join(FilePath_str, '*.meta.xml')))[0]
|
||
# tiff_name = [file_name for file_name in file_name_list if
|
||
# file_name.rfind(".tiff") == len(file_name) - len('.tiff')] # 影像文件
|
||
# 解析头文件
|
||
# self.header_info = self.ParseHearderFile(os.path.join(FilePath_str, header_name))
|
||
self.header_info = self.ParseHearderFile(header_name)
|
||
# 构建轨道模型
|
||
self.SatelliteOrbitModel = ReconstructionSatelliteOrbit(self.header_info['GPS'],
|
||
starttime=self.header_info['ImageInformation']['CenterTime']) # 构建卫星轨道模型,取第0个节点的时间
|
||
lamda = self.header_info['ImageInformation']['lambda']
|
||
height=self.header_info['ImageInformation']['height']
|
||
width=self.header_info['ImageInformation']['width']
|
||
# 求解模型前计算常数变换模型
|
||
self.PrepareConvertSystem()
|
||
ti, p_0_x, p_0_y, p_0_z = self.Convert_Coordinary(dem_resampled_path)
|
||
ti_row = ti.shape[0]
|
||
ti_col = ti.shape[1]
|
||
rsp_1 = self.SatelliteOrbitModel.getSatelliteSpaceState(ti)[:, :3] # 卫星的地固坐标系
|
||
rsp_1_x = rsp_1[:, 0].reshape(ti_row, ti_col)
|
||
rsp_1_y = rsp_1[:, 1].reshape(ti_row, ti_col)
|
||
rsp_1_z = rsp_1[:, 2].reshape(ti_row, ti_col)
|
||
r1 = np.sqrt(np.power((rsp_1_x - p_0_x), 2) + np.power((rsp_1_y - p_0_y), 2) + np.power((rsp_1_z - p_0_z), 2)) # 主斜距
|
||
return r1, lamda, height, width
|
||
|
||
def Convert_Coordinary(self, dem_resampled_path):
|
||
"""
|
||
求解坐标,
|
||
为了节省内存和处理数据方便,基本所有方法都写在这一个类中,后续会进行拆分。保证内存的消耗
|
||
"""
|
||
# 间接定位法所需的参数
|
||
Doppler_d = np.array(self.header_info['ImageInformation']['DopplerCentroidCoefficients']).reshape(-1, 1)
|
||
LightSpeed = self.config['LightSpeed']
|
||
T0 = self.header_info['ImageInformation']['refRange'] * 2 / LightSpeed
|
||
lamda = self.header_info['ImageInformation']['lambda']
|
||
StartTime = self.header_info['ImageInformation']['StartTime']
|
||
PRF = self.header_info['PRF']
|
||
R0 = self.header_info['ImageInformation']['NearRange']
|
||
self.SatelliteOrbitModel = ReconstructionSatelliteOrbit(self.header_info['GPS'],
|
||
starttime=self.header_info['ImageInformation']['CenterTime']) # 构建卫星轨道模型,取第0个节点的时间
|
||
|
||
# 读取影像
|
||
dem_resampled_tiff = gdal.Open(dem_resampled_path)
|
||
row_count = dem_resampled_tiff.RasterYSize # 读取图像的行数
|
||
col_count = dem_resampled_tiff.RasterXSize # 读取图像的列数
|
||
im_proj = dem_resampled_tiff.GetProjection()
|
||
im_geotrans = list(dem_resampled_tiff.GetGeoTransform())
|
||
gt = im_geotrans # 坐标变换参数
|
||
# 计算采样率
|
||
sampling_f = self.CalSamplingRateOfDEM(dem_resampled_tiff)
|
||
if sampling_f % 10 != 0:
|
||
sampling_f = int(sampling_f/10)+1
|
||
sampling_f = int(sampling_f*10) # 保证抽样为10的倍数
|
||
# 根据目标内存(1G)计算实际的取块情况 ((100mb/4byte)/sampling_f)
|
||
block_height_width = math.sqrt(300*1000*1000/4)
|
||
block_height_width = int(math.ceil(block_height_width/sampling_f))
|
||
|
||
out_ti = np.zeros((row_count, col_count), dtype=float)
|
||
out_p_0_x = np.zeros((row_count, col_count), dtype=float)
|
||
out_p_0_y = np.zeros((row_count, col_count), dtype=float)
|
||
out_p_0_z = np.zeros((row_count, col_count), dtype=float)
|
||
# 分块读取,分块计算
|
||
for i in range(0, row_count, block_height_width): # 行
|
||
for j in range(0, col_count, block_height_width): # 列
|
||
# 判断最大行数
|
||
start_row = i # 设置起始行
|
||
start_col = j # 设置起始列
|
||
|
||
if start_row+block_height_width <= row_count:
|
||
start_row = start_row # 外推一行
|
||
block_row_count = block_height_width
|
||
else:
|
||
start_row = start_row
|
||
block_row_count = row_count - start_row # 行边界
|
||
|
||
if start_col+block_height_width < col_count:
|
||
start_col = start_col # 外推一列
|
||
block_col_count = block_height_width # 判断当前块的列边界 外推一列
|
||
else:
|
||
start_col = start_col
|
||
block_col_count = col_count-start_col # 列边界
|
||
|
||
# 粗估当前区域
|
||
# hasSARPixel=self.EstimateDEMCoordinate(dem_resampled_tiff,start_row,start_col,block_row_count,block_col_count,sampling_f,gt,Doppler_d, StartTime, lamda, T0, LightSpeed, PRF, R0)
|
||
# if not hasSARPixel: # 如果当前区域不在SAR影像范围内,就直接的跳过当前块
|
||
# continue
|
||
# 重采样DEM,构建重采样DEM块
|
||
block_resampled_ = self.ResamplingDEMBlock(dem_resampled_tiff, start_row, start_col, block_row_count, block_col_count, sampling_f, gt)
|
||
target_position = copy.deepcopy(block_resampled_)
|
||
del block_resampled_
|
||
|
||
resampled_row = target_position.shape[0]
|
||
resampled_col = target_position.shape[1]
|
||
resampled_band = target_position.shape[2]
|
||
target_position_ = target_position.reshape(-1, 3)
|
||
r, c, ti = self.PSTN_block(target_position_, Doppler_d, StartTime, lamda, T0, LightSpeed, PRF, R0)
|
||
ti = ti.reshape(resampled_row, resampled_col)
|
||
r = r.reshape(resampled_row, resampled_col)
|
||
c = c.reshape(resampled_row, resampled_col)
|
||
target_position_ = target_position_.reshape(resampled_row, resampled_col, resampled_band)
|
||
|
||
# 计算地面点的坐标
|
||
[lon, lat, altitude] = self.XYZ2LLAM(target_position_[:, :, 0], target_position_[:, :, 1], target_position_[:, :, 2])
|
||
altitude = altitude * 0
|
||
[p_0_x, p_0_y, p_0_z] = self.LLA2XYZM(lon, lat, altitude) # 求取 卫星在地面的投影点
|
||
p_0_x = p_0_x.reshape(resampled_row, resampled_col)
|
||
p_0_y = p_0_y.reshape(resampled_row, resampled_col)
|
||
p_0_z = p_0_z.reshape(resampled_row, resampled_col)
|
||
|
||
out_ti[start_row:(start_row+block_row_count), start_col:(start_col+block_col_count)] = ti
|
||
out_p_0_x[start_row:(start_row+block_row_count), start_col:(start_col+block_col_count)] = p_0_x
|
||
out_p_0_y[start_row:(start_row+block_row_count), start_col:(start_col+block_col_count)] = p_0_y
|
||
out_p_0_z[start_row:(start_row+block_row_count), start_col:(start_col+block_col_count)] = p_0_z
|
||
|
||
return out_ti, out_p_0_x, out_p_0_y, out_p_0_z
|
||
|
||
def ResamplingDEMBlock(self, dem_resampled_tiff, start_row, start_col, block_row_count, block_col_count, sampling_f,gt):
|
||
""" 根据DEM获取插值之后的规则格网块
|
||
agrs:
|
||
dem_resampled_tiff:原始DEM
|
||
start_row: 起始行号
|
||
start_col:终止行号
|
||
block_row_count:获取块的行数
|
||
block_col_count:获取块的列数
|
||
sampling_f:采样率
|
||
gt:dem_resampled_tiff 的仿射矩阵
|
||
return:
|
||
block_resampled:最终插值结果 经度(lon),纬度(lat),高程(ati)
|
||
"""
|
||
altii_block = dem_resampled_tiff.GetRasterBand(1).ReadAsArray(start_col, start_row, block_col_count, block_row_count) # 块 高程文件
|
||
h = altii_block.shape[0]
|
||
w = altii_block.shape[1]
|
||
point_block = np.ones((h, w, 3))
|
||
point_block[:, :, 0] = (np.ones((w, h))*range(h)).transpose(1, 0) # 行对应的x
|
||
point_block[:, :, 1] = np.ones((h, w))*range(w) # 列对应的 y
|
||
point_block[:, :, 2] = altii_block
|
||
|
||
# point_block_xy=np.ones((h+1,w+1,3)) # 扩充边界
|
||
# point_block_xy[:-1,:-1,:]=point_block
|
||
# # 行
|
||
# point_block_xy[-1,:,0]=point_block_xy[-2,:,0]+1
|
||
# point_block_xy[:,-1,0]=point_block_xy[:,-2,0]
|
||
# # 列
|
||
# point_block_xy[:,-1,1]=point_block_xy[:,-2,1]+1
|
||
# point_block_xy[-1,:,1]=point_block_xy[-2,:,1]
|
||
# # 高程
|
||
# point_block_xy[-1,:,2]=point_block_xy[-2,:,2]
|
||
# point_block_xy[:,-1,2]=point_block_xy[:,-2,2]
|
||
# point_block_xy[:,:,:2]=point_block_xy[:,:,:2]*sampling_f
|
||
#
|
||
# point_block_xy = point_block_xy.reshape((h+1)*(w+1),3)
|
||
|
||
# 采样目标行列对象
|
||
# row_count_resampled=int(block_row_count*sampling_f)+1
|
||
# col_count_resampled=int(block_col_count*sampling_f)+1
|
||
# # 创建重采样block
|
||
# block_resampled=np.ones((row_count_resampled,col_count_resampled,3)) # 行,列,DEM
|
||
# block_resampled[:,:,0]=(np.ones((col_count_resampled,row_count_resampled))*range(row_count_resampled)).transpose(1,0) # 行对应的x
|
||
# block_resampled[:,:,1]=np.ones((row_count_resampled,col_count_resampled))*range(col_count_resampled)
|
||
|
||
# scipy 规则格网插值
|
||
# block_resampled_Z=interpolate.griddata(point_block_xy[:,:2],point_block_xy[:,2],
|
||
# ((block_resampled[:,:,0]).reshape(col_count_resampled*row_count_resampled,),
|
||
# (block_resampled[:,:,1]).reshape(col_count_resampled*row_count_resampled,)),
|
||
# method='cubic') # 三次项插值
|
||
# block_resampled[:,:,2]=block_resampled_Z.reshape(row_count_resampled,col_count_resampled)
|
||
# block_resampled=block_resampled[:-1,:-1,:] # 剔除边
|
||
block_resampled = point_block
|
||
# 直接根据仿射矩阵计算对应的X,Y
|
||
gt_resample = [gt[0]+gt[1]*start_col+gt[2]*start_row, gt[1]/sampling_f, gt[2]/sampling_f,
|
||
gt[3]+gt[4]*start_col+gt[5]*start_row, gt[4]/sampling_f, gt[5]/sampling_f]
|
||
X = gt_resample[0]+gt_resample[1]*block_resampled[:, :, 1]+gt_resample[2]*block_resampled[:, :, 0] # 经度 lon
|
||
Y = gt_resample[3]+gt_resample[4]*block_resampled[:, :, 1]+gt_resample[5]*block_resampled[:, :, 0] # 纬度 lat
|
||
block_resampled[:, :, 0] = X
|
||
block_resampled[:, :, 1] = Y
|
||
|
||
# 根据的情况计算最终的投影坐标系值
|
||
Land_point = self.LLA2XYZM(block_resampled[:, :, 0].reshape(-1, 1), block_resampled[:, :, 1].reshape(-1, 1),block_resampled[:,:,2].reshape(-1,1))
|
||
block_resampled = np.ones((block_resampled.shape[0], block_resampled.shape[1], 3))
|
||
block_resampled[:, :, 0] = Land_point[0].reshape(block_resampled.shape[0], block_resampled.shape[1]).copy()
|
||
block_resampled[:, :, 1] = Land_point[1].reshape(block_resampled.shape[0], block_resampled.shape[1]).copy()
|
||
block_resampled[:, :, 2] = Land_point[2].reshape(block_resampled.shape[0], block_resampled.shape[1]).copy()
|
||
result=copy.deepcopy(block_resampled)
|
||
del block_resampled
|
||
return result
|
||
|
||
def EstimateDEMCoordinate(self,dem_resampled_tiff,start_row,start_col,block_row_count,block_col_count,sampling_f,gt,Doppler_d, StartTime, lamda, T0, LightSpeed, PRF, R0):
|
||
""" 粗估当前区域有无重采样的必要"""
|
||
altii=dem_resampled_tiff.GetRasterBand(1).ReadAsArray(start_col,start_row , block_col_count, block_row_count) # 块 高程文件
|
||
h=int(altii.shape[0])
|
||
w=int(altii.shape[1])
|
||
y_pixel=(np.ones((w,h))*range(h)+start_row).transpose(1,0)
|
||
x_pixel=np.ones((h,w))*range(w)+start_col
|
||
lat=gt[0]+gt[1]*x_pixel+gt[2]*y_pixel # 经度
|
||
lon=gt[3]+gt[4]*x_pixel+gt[5]*y_pixel # 纬度
|
||
#del x_pixel,y_pixel
|
||
#gc.collect()
|
||
[X, Y, Z] = self.LLA2XYZM(lat.reshape(-1,1), lon.reshape(-1,1), altii.reshape(-1,1)) # 计算错误
|
||
TargetPosition = np.ones((int(h*w), 3), dtype=np.float32)
|
||
TargetPosition[:, 0] = X.reshape(-1)
|
||
TargetPosition[:, 1] = Y.reshape(-1)
|
||
TargetPosition[:, 2] = Z.reshape(-1)
|
||
r, c, ti = self.PSTN_block(TargetPosition, Doppler_d, StartTime, lamda, T0, LightSpeed, PRF, R0) # 间接定位法,核心求解代码
|
||
if np.max(r) < -1*sampling_f*2 or np.min(r) > self.header_info['ImageInformation']['height']+sampling_f*2:
|
||
return False
|
||
if np.max(c)<-1*sampling_f*2 or np.min(c) > self.header_info['ImageInformation']['width']+sampling_f*2:
|
||
return False
|
||
return True
|
||
|
||
def CalSamplingRateOfDEM(self,DEM_tiff):
|
||
"""
|
||
计算DEM的重采样率f,必须在解析头文件之后,参考陈尔学 博士学位论文 《 星载合成孔径雷达影像正射校正方法研究 》
|
||
args:
|
||
DEM_tiff:tif DEM的影像
|
||
return:
|
||
f:采样率,向上取整
|
||
"""
|
||
# 获取DEM_tiff的高宽、投影、仿射矩阵
|
||
Trans_array=list(DEM_tiff.GetGeoTransform()) # 仿射变换矩阵
|
||
# width=DEM_tiff.RasterXSize
|
||
# height=DEM_tiff.RasterYSize
|
||
# x=trans[0]+trans[1]*c+trans[2]*r
|
||
# y=trans[3]+trans[4]*c+trans[5]*r
|
||
# 获得其高宽分辨率
|
||
delta_x=Trans_array[1]+Trans_array[2] # x轴上的分辨率 经度
|
||
delta_y=Trans_array[4]+Trans_array[5] # y轴上的分辨率 纬度
|
||
# 因为单位为度,所以需要转换为 米
|
||
y_resultion=abs(111194.926644558737*delta_y)
|
||
x_resultion=abs(111194.926644*math.cos(Trans_array[3])*delta_x)
|
||
resultion=x_resultion if x_resultion>y_resultion else y_resultion
|
||
delta_R=self.delta_R # 斜距分辨率
|
||
incidenceAngle=self.header_info['ImageInformation']['incidenceAngle']["NearRange"] # 入射角
|
||
f=math.sin(incidenceAngle*math.pi/180)*1.4142135623730951*resultion/delta_R
|
||
f=math.ceil(f)
|
||
return f
|
||
|
||
def PSTN_M(self, TargetPostion, Doppler_d, StartTime, lamda, T0, LightSpeed, PRF, R0):
|
||
"""
|
||
间接求解方法,使用矩阵方法,分段计算,方便加速
|
||
args:
|
||
TargetPosition:nparray,nx3 地面坐标
|
||
Doppler_d:多普勒系数 -1,1
|
||
lamda:波长
|
||
T0:多普勒参考时间
|
||
LightSpeed:光速
|
||
return:
|
||
rc:nparray shape nx2 行列号
|
||
"""
|
||
#
|
||
n = int(TargetPostion.shape[0]) # 坐标点数据 nx3
|
||
r=np.zeros((n,1))
|
||
c=np.zeros((n,1))
|
||
ti=np.zeros((n,1),dtype=np.float64)
|
||
for i in range(0,n,8000):
|
||
start_i=i
|
||
len_block=8000
|
||
if start_i+len_block>n:
|
||
len_block=n-start_i
|
||
end_i=start_i+len_block
|
||
temp_TargetPosition=TargetPostion[start_i:end_i,:]
|
||
r_temp, c_temp, ti_temp=self.PSTN_block(temp_TargetPosition, Doppler_d, StartTime, lamda, T0, LightSpeed, PRF, R0)
|
||
r[start_i:end_i,:]=r_temp.copy()
|
||
c[start_i:end_i,:]=c_temp.copy()
|
||
ti[start_i:end_i,:]=ti_temp.copy()
|
||
return r,c,ti
|
||
|
||
def PSTN_block(self, TargetPostion, Doppler_d, StartTime, lamda, T0, LightSpeed, PRF, R0):
|
||
"""
|
||
间接求解方法,使用矩阵方法
|
||
args:
|
||
TargetPosition:nparray,nx3 地面坐标
|
||
Doppler_d:多普勒系数 -1,1
|
||
lamda:波长
|
||
T0:多普勒参考时间
|
||
LightSpeed:光速
|
||
return:
|
||
rc:nparray shape nx2 行列号
|
||
"""
|
||
n = TargetPostion.shape[0] # 坐标点数据 nx3
|
||
ti = np.ones((n, 1),dtype=np.float64) * StartTime # 初始值
|
||
delta_R = self.delta_R
|
||
delta_t = 1 / PRF
|
||
R=np.zeros((n,1))
|
||
Rs = np.zeros((n, 3))
|
||
R_sc = np.zeros((n, 3)) # 地面-卫星空间位置矢量
|
||
V_sc = np.zeros((n, 3)) # 地面-卫星空间速率矢量
|
||
FdNumerical = np.ones((n, 1)) # 多普勒公式的数值解法
|
||
FdTheory = np.ones((n, 1)) # 多普勒公式的理论解法
|
||
FdTheory_grad = np.ones((n, 1)) # 多普勒公式的导数
|
||
# 多普勒参数系数
|
||
Doppler_d = Doppler_d.reshape(-1, 1) # 5x1
|
||
TSR=np.ones((n, 1)) # nx1
|
||
TSRx = np.ones((n, Doppler_d.shape[0])) # nx5
|
||
inc_t = np.ones((n, 1)) # 计算增加的导数
|
||
dt = 0.0001 # 数值法求解多普勒距离公式的导数
|
||
dt_rec=1/dt
|
||
# 默认最高迭代100次,如果还未求解出结果,就将所有的未收敛的时间值记录为0 ,注意时间不能为0
|
||
for i in range(100):
|
||
tempT = ti + dt # 计算增加时间
|
||
# ------- 求解导数 ----------------
|
||
#del Rs,R_sc,V_sc,TSR,TSRx,satelliteSpaceState,R
|
||
satelliteSpaceState = self.SatelliteOrbitModel.getSatelliteSpaceState(tempT) # 卫星坐标与速度 nx6
|
||
Rs = satelliteSpaceState[:, :3]
|
||
R_sc = satelliteSpaceState[:, :3] - TargetPostion # 地面-卫星空间位置矢量
|
||
V_sc = satelliteSpaceState[:, 3:] # 地面-卫星空间位置矢量
|
||
R =np.sqrt(np.sum(R_sc ** 2, axis=1)).reshape(-1, 1) # nx1
|
||
#FdTheory_grad = (-2 / lamda) * (1 / R) * np.sum(R_sc * V_sc, axis=1).reshape(-1, 1) # nx1
|
||
FdTheory_grad = -2*np.reciprocal(R*lamda) * np.sum(R_sc * V_sc, axis=1).reshape(-1, 1) # nx1
|
||
|
||
# 获取卫星轨道状态信息
|
||
satelliteSpaceState = self.SatelliteOrbitModel.getSatelliteSpaceState(ti) # 卫星坐标与速度 nx6
|
||
# 卫星轨道坐标
|
||
Rs =satelliteSpaceState[:, :3]
|
||
# 卫星相对地面的位置向量、卫星速度向量
|
||
R_sc=Rs - TargetPostion # 地面-卫星空间位置矢量
|
||
V_sc =satelliteSpaceState[:, 3:] # 地面-卫星空间位置矢量
|
||
# 斜距
|
||
R = np.sqrt(np.sum(R_sc ** 2, axis=1)).reshape(-1, 1) # nx1
|
||
# 根据多普勒数值求解公式求解多普勒频移值
|
||
TSR= R * (2 / LightSpeed) - T0 # nx1
|
||
TSRx[:,0]=TSR[:,0]**0 # nx5
|
||
TSRx[:,1]=TSR[:,0]**1
|
||
TSRx[:,2]=TSR[:,0]**2
|
||
TSRx[:,3]=TSR[:,0]**3
|
||
TSRx[:,4]=TSR[:,0]**4
|
||
# 根据多普勒物理公式求解求解多普勒频移值
|
||
FdTheory=-2*np.reciprocal(lamda*R)*np.sum(R_sc * V_sc, axis=1).reshape(-1, 1) # nx1
|
||
FdNumerical= np.matmul(TSRx, Doppler_d) # nx1
|
||
|
||
FdTheory_grad = np.reciprocal((FdTheory_grad - FdTheory) * dt_rec) # nx1
|
||
inc_t = (FdTheory - FdNumerical) * FdTheory_grad #(FdTheory - FdNumerical) * (1 / FdTheory_grad) # nx1
|
||
# inc_t = inc_t - inc_t * ti_mask # 允许继续迭代 nx1
|
||
if np.max(np.abs(inc_t)) < delta_t * 0.001:
|
||
break
|
||
ti = ti - inc_t # 更新坐标
|
||
|
||
# 计算行号
|
||
ti_=copy.deepcopy(ti.copy())
|
||
r_ = (ti_ - StartTime) * (1 / delta_t)
|
||
r=copy.deepcopy(r_.copy())
|
||
del r_
|
||
c_ = (R - R0) * (1 / delta_R)
|
||
c=copy.deepcopy(c_.copy())
|
||
del c_
|
||
ti = copy.deepcopy(ti_.copy())
|
||
del ti_
|
||
return r, c, ti
|
||
pass
|
||
|
||
@staticmethod
|
||
def LLA2XYZM(longitude, latitude, altitude):
|
||
# 经纬度余弦值
|
||
cosLat = np.cos(latitude * math.pi / 180).reshape(-1,1)
|
||
sinLat = np.sin(latitude * math.pi / 180).reshape(-1,1)
|
||
cosLon = np.cos(longitude * math.pi / 180).reshape(-1,1)
|
||
sinLon = np.sin(longitude * math.pi / 180).reshape(-1,1)
|
||
# WGS84坐标系参数
|
||
rad = 6378137.0 #地球赤道平均半径
|
||
f = 1.0/298.257224 #WGS84椭球扁率
|
||
C = 1.0/(np.sqrt(cosLat*cosLat + (1-f)*(1-f)*sinLat*sinLat)).reshape(-1,1)
|
||
S = (1-f)*(1-f)*C
|
||
h = altitude.reshape(-1,1)
|
||
# 计算XYZ坐标
|
||
X = (rad * C + h) * cosLat * cosLon
|
||
Y = (rad * C + h) * cosLat * sinLon
|
||
Z = (rad * S + h) * sinLat
|
||
return [X, Y, Z]
|
||
|
||
@staticmethod
|
||
def XYZ2LLAM(X, Y, Z):
|
||
""" 大地坐标系转经纬度
|
||
适用于WGS84坐标系
|
||
args:
|
||
x,y,z
|
||
return:
|
||
lat,long,altitude
|
||
"""
|
||
# WGS84坐标系的参数
|
||
a = 6378137.0 # 椭球长半轴
|
||
b = 6356752.314245 # 椭球短半轴
|
||
ea = np.sqrt((a ** 2 - b ** 2) / a ** 2)
|
||
eb = np.sqrt((a ** 2 - b ** 2) / b ** 2)
|
||
p = np.sqrt(X ** 2 + Y ** 2)
|
||
theta = np.arctan2(Z * a, p * b)
|
||
|
||
# 计算经纬度及海拔
|
||
longitude = np.arctan2(Y, X)
|
||
latitude = np.arctan2(Z + eb ** 2 * b * np.sin(theta) ** 3, p - ea ** 2 * a * np.cos(theta) ** 3)
|
||
N = a / np.sqrt(1 - ea ** 2 * np.sin(latitude) ** 2)
|
||
altitude = p / np.cos(latitude) - N
|
||
|
||
# return np.array([np.degrees(latitude), np.degrees(longitude), altitude])
|
||
return [np.degrees(longitude), np.degrees(latitude), altitude]
|
||
|
||
def calc_kz_array(self, master_incident_file, auxiliary_incident_file, r1_file, r2_file, lamda_01):
|
||
"""
|
||
计算垂直基线
|
||
:return:数组
|
||
"""
|
||
v1 = ImageHandler().get_data(master_incident_file) # v1是cos值
|
||
v2 = ImageHandler().get_data(auxiliary_incident_file) # v2是cos值
|
||
# v11=v1/180*math.pi # 转成弧度
|
||
# v22=v2/180*math.pi
|
||
mean= (v1+v2)/2
|
||
chazhi=v1-v2
|
||
print(chazhi)
|
||
r1 = ImageHandler().get_data(r1_file)
|
||
r2 = ImageHandler().get_data(r2_file)
|
||
if r1.shape[0] != r2.shape[0] or v1.shape[0] != v2.shape[0] or r1.shape[0] != v1.shape[0]:
|
||
if r1.shape[1] != r2.shape[1] or v1.shape[1] != v2.shape[1] or r1.shape[1] != v1.shape[1]:
|
||
raise Exception("r1 or r2 or v1 or v2 shape different")
|
||
mean_mask1= np.where(mean == np.isnan)
|
||
mean[mean_mask1]=math.pi/4 # 排除零值点
|
||
|
||
# v_b = r2 * angle # 计算垂直基线
|
||
# lamda_01 雷达波长;r1 主天线与目标地物的斜距;v1 主天线入射角
|
||
# kz_array = 4*math.pi*v_b/(lamda_01*r1*np.sin(v1)) # 计算垂直波数,已经是弧度制不需要v1*(math.pi/180)
|
||
|
||
# kz_array01 = 4*math.pi*v_b/(lamda_01*r1*np.sin(v1)) # 计算垂直波数,已经是弧度制不需要v1*(math.pi/180)
|
||
kz_array=4*math.pi*(abs(v2 - v1))/(np.sin(mean)*lamda_01)
|
||
mask_v1 = np.where(v1 == 1.111, 0, 1) # 掩膜
|
||
kz_array = kz_array * mask_v1
|
||
return kz_array
|
||
|
||
|
||
|
||
|
||
|
||
|
||
# 数据测试模块
|
||
# if __name__ == "__main__":
|
||
# path = r"D:\MicroWorkspace\DirectOrtho\Input"
|
||
# in_dem_path = path + "\\DEM"
|
||
# SLC_path_01 = "D:\MicroWorkspace\PlantHeight\Input"
|
||
# SLC_path_02 = path + "\\auxi"
|
||
# out_dem_path = path + "\\TestLut"
|
||
# Sim_path = path + "\\TestLut"
|
||
# HeadConfig =path + "\\config.ymal"
|
||
# meta_file_path_01 = list(glob.glob(os.path.join(SLC_path_01, '*.meta.xml')))
|
||
# meta_file_path_02 = list(glob.glob(os.path.join(SLC_path_02, '*.meta.xml')))
|
||
#
|
||
# # dem 拼接
|
||
# dem_resampled_path = DEMProcess.dem_resample(in_dem_path, meta_file_path_01[0], out_dem_path)
|
||
# dem_resampled_path = r"D:\MicroWorkspace\DirectOrtho\Input\TestLut\mosaic0.tif"
|
||
#
|
||
# # 计算斜距、雷达波长、phi
|
||
# Orthorectification = IndirectOrthorectification(HeadConfig)
|
||
# r1, lamda_01 = Orthorectification.IndirectOrthorectification(SLC_path_01, dem_resampled_path)
|
||
# r2, lamda_02 = Orthorectification.IndirectOrthorectification(SLC_path_02, dem_resampled_path)
|
||
# print("输出r1、lamda_01:", r1, lamda_01)
|
||
# print("输出r2、lamda_02:", r2, lamda_01)
|
||
# im_proj = ImageHandler().get_projection(dem_resampled_path)
|
||
# im_geotrans = ImageHandler().get_geotransform(dem_resampled_path)
|
||
# out_r1 = r"D:\MicroWorkspace\DirectOrtho\out\\r1.tif"
|
||
# out_r2 = r"D:\MicroWorkspace\DirectOrtho\out\\r2.tif"
|
||
# ImageHandler().write_img(out_r1, im_proj, im_geotrans, r1)
|
||
# ImageHandler().write_img(out_r2, im_proj, im_geotrans, r2)
|
||
#
|
||
# # 计算phi, 转成tiff文件
|
||
# phi_land = 4*math.pi*(r1-r2)*lamda_01
|
||
# gc.collect() # 回收内存
|
||
# out_r3 = r"D:\MicroWorkspace\DirectOrtho\out\\phi.tif"
|
||
# ImageHandler().write_img(out_r3, im_proj, im_geotrans, phi_land)
|
||
#
|
||
# # 计算kz, 转成tiff文件
|
||
# master_incident_file = r"D:\MicroWorkspace\DirectOrtho\Input\MasterAngle.tif"
|
||
# auxiliary_incident_file = r"D:\MicroWorkspace\DirectOrtho\Input\AuxilAngle.tif"
|
||
# kz_array= Orthorectification.calc_kz_array(master_incident_file, auxiliary_incident_file, out_r1, out_r2, lamda_01)
|
||
# out_kz = r"D:\MicroWorkspace\DirectOrtho\out\\kz.tif"
|
||
# ImageHandler().write_img(out_kz, im_proj, im_geotrans, kz_array)
|