from tool.algorithm.image.ImageHandle import ImageHandler from tool.algorithm.algtools.ROIAlg import ROIAlg #from Orthorectification.Indirect_pstn import PSTN import os from types import resolve_bases from typing import OrderedDict # import gdal from numpy.ma.core import power, reshape import xmltodict from xml.dom.minidom import parse import pandas import numpy as np import json from matplotlib import pyplot as plt import datetime import yaml import math from decimal import Decimal # 为了更好的精度 # from multiprocessing import Pool # 进程池 import multiprocessing # 多进程类 # import numba # from numba import jit from SatelliteOrbit import ReconstructionSatelliteOrbit from util import GetVectorNorm,FindInfomationFromJson,appendInfomationForCsv from util import XYZ_to_LLA,LLA_to_XYZ #import indirect_pstn import scipy as sp import pylab as pl from scipy.optimize import leastsq def Interpolation_sinc(): ''' 基于sinc的插值算法,专门用于影像校正 ''' pass class Orthorectification(object): ''' 正射校正模块类。 ''' def __init__(self,configPath="./config.ymal") -> None: super().__init__() # 常量声明 # 加载配置文件 with open(configPath,'r',encoding='utf-8') as f: cont = f.read() self.config = yaml.load(cont,Loader=yaml.FullLoader) self.config['SatelliteOribit']['StartTime']=datetime.datetime.strptime(self.config['SatelliteOribit']['StartTime']['Value'],self.config['SatelliteOribit']['StartTime']['format']).timestamp() 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,GPSNodeNames_list=['TimeStamp', 'xPosition', 'yPosition', 'zPosition', 'xVelocity', 'yVelocity', 'zVelocity']): ''' 解析头文件,返回计算所需要的必要信息: 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) HeaderFile_dom_json=json.loads(json.dumps(HeaderFile_dom)) # 获取头文件 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'])) HeaderInformation_json['PRF']=float(FindInfomationFromJson(HeaderFile_dom_json,self.config['sensor']['PRF']['NodePath'])) return HeaderInformation_json pass def getRByColumncode(self,c): ''' 根据列号计算斜距 args: c:列号 ''' return self.R0+c*self.delta_R 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)) # 确定Y 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) pass 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) pass self.r2t_A_arr=A def PrepareConverteSystem(self): ''' 计算常量 在数据计算之前,提前处理部分常量信息 1、构建r,c 到坐标斜距的计算公式 2、计算行号对应的时间频率 ''' 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 # 计算行号分辨率 self.delta_t=1/self.header_info['PRF'] def Orthorectification(self,FilePath_str,ori_sim): ''' 正射校正组件。 正射校正整体可以分为两个步骤: 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] # 头文件 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.SatelliteOrbitModel=ReconstructionSatelliteOrbit(self.header_info['GPS'],starttime=self.header_info['ImageInformation']['StartTime']) # 构建卫星轨道模型,取第0个节点的时间 # 求解模型前计算常数变换模型 self.PrepareConverteSystem() # # 测试第0,0个点的空间坐标 # self.ConverteCoordinaryPoint_single(0,0) # 批量计算空间坐标 lamda = self.header_info['ImageInformation']['lambda'] height_array,width_array,width,height,geo,pro=self.analy_image(ori_sim) p0_array=np.zeros((3,height, width),dtype=float) # 创建3波段空数组存放p0坐标 sat_array=np.zeros((3,height, width),dtype=float) # 创建3波段空数组存放卫星位置 im_data, im_data2=self.ConverteCoordinary(height_array, width_array,width,height, geo, pro, p0_array, sat_array) return im_data, im_data2, lamda def analy_image(self, ori_sim): """ 计算影像的行列号的范围、投影系、坐标系 """ height_array = ImageHandler.get_band_array(ori_sim, 1) width_array = ImageHandler.get_band_array(ori_sim, 2) geo = ImageHandler.get_geotransform(ori_sim) pro = ImageHandler.get_projection(ori_sim) width=ImageHandler.get_img_width(ori_sim) height=ImageHandler.get_img_height(ori_sim) return height_array,width_array,width,height,geo,pro def ConverteCoordinary(self, height_array, width_array,width,height, geo, pro, p0_array, sat_array): ''' 批量求解点坐标 ''' return p0_array, sat_array pass def ConverteCoordinaryPoint_single(self,r,c,h=0,breakCondition=1): ''' 求解单个点坐标 args: r: 行号 height c: 列号 width h:平均大地高 breakCondition: 迭代终止条件,默认值为1 ''' pass class Orthorectification_RD(Orthorectification): ''' 正射校正模块类。 ''' def __init__(Orthorectification_RD,configPath="./config.ymal") -> None: super().__init__(configPath) def ConverteCoordinary(self, height_array, width_array,width,height, geo, pro, p0_array, sat_array): ''' param: height_min: 批量求解点坐标 ''' # 构建映射表 ----------------------------------需要重写代码 result={} print("开始时间:",datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")) alpha0=0 beta0=0 # for r in range(self.header_info['ImageInformation']['height']): # if r%10==0: # print("r={} 时间:".format(str(r)),datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")) # for c in range(self.header_info['ImageInformation']['width']): # result[(r,c)]=self.ConverteCoordinaryPoint_single(r,c,alpha0=alpha0,beta0=beta0) # alpha0=result[(r,c)][1] # beta0=result[(r,c)][2] # print("终止时间:", datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")) # 计算ori_smi对应的卫星空间位置及地面p0坐标,并存入三维数组中。 for r in range(0, height): if r%10==0: print("r={} 时间:".format(str(r)),datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")) for c in range(0, width): num_r=height_array[r,c] num_c=width_array[r,c] result=self.ConverteCoordinaryPoint_single(num_r,num_c,alpha0=alpha0,beta0=beta0) xyz=result[0] alpha0=result[1] beta0=result[2] Sate_x, Sate_y, Sate_z=result[3],result[4],result[5] p0_array[0,r, c] = xyz[0, 0] # 存放p0坐标(地固参心坐标) p0_array[1,r, c] = xyz[0, 1] p0_array[2,r, c] = xyz[0, 2] sat_array[0,r, c] = Sate_x # 存放卫星位置(地固参心坐标) sat_array[1,r, c] = Sate_y sat_array[2,r, c] = Sate_z print("终止时间:", datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")) return p0_array, sat_array pass # def ConverteCoordinary(self,OutputPath=None,DEM=None,BlocksPath="./OrthorecticationGrid",BlockSize=1): # '''批量转换坐标 # 采用矩阵结构,批量转换点,并将坐标点保存到指定文件分块文件中,并最终汇总成一个大型文件。 # 分块文件夹内容格式: # # Args: # OutputPath: 最终文件地址,如果为None,则不把分块文件进行汇总成一个整体文件。 # DEM:与坐标对应的高程,default:None # BlocksPath:分块存储地址与最终集合地址 # BlockSize:块大小,default:1 GB # return: # Result_path: 最终文件地址 # ''' # # 数据参数预读取 # # 多普勒参数 # Dopper_d=np.array(self.header_info['ImageInformation']['DopplerCentroidCoefficients']).reshape(-1,1) # LightSpeed=self.config['LightSpeed'] # # T0 # DopplerParametersReferenceTime=self.header_info['ImageInformation']['refRange']*2/LightSpeed # # 波长 # lamda=self.header_info['ImageInformation']['lambda'] # # Re,Rp,we # Re=self.config['SatelliteOribit']['ReferenceSpheroid']['Re'] # Rp=self.config['SatelliteOribit']['ReferenceSpheroid']['Rp'] # we=self.config['SatelliteOribit']['ReferenceSpheroid']['we'] # we 地球自转速度矢量 --- 废弃 # # 影像宽高 # height=self.header_info['ImageInformation']['height'] # width=self.header_info['ImageInformation']['width'] # # 粗估分块文件的大小 # size_max=BlockSize*1024*1024*1024 # 粗估最大字节数 # col_num_block=int(size_max/(height*3*8))-1 # 预留一行作为其他信息的存储空间 # alpha0=0 # beta0=0 # for r in range(self.header_info['ImageInformation']['height']): # if r%10==0: # print("r={} 时间:".format(str(r)),datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")) # for c in range(self.header_info['ImageInformation']['width']): # result=self.ConverteCoordinaryPoint_single(r,c,alpha0=alpha0,beta0=beta0) # alpha0=result[1] # beta0=result[2] # print("终止时间:",datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")) # # 构建分块矩阵计算代码 # pass def ConverteCoordinaryPoint_single(self,r,c,h=0,breakCondition=1,alpha0=0,beta0=0): ''' 求解单个点坐标 args: r: 行号 height c: 列号 width h:平均大地高 breakCondition: 迭代终止条件,默认值为1 return: TargetPosition_:点坐标 版本改动: 2021.8.19 尝试将椭球方程进行变形 2021.8.22 方法重写 ''' # 计算对应成像时间和成像斜距 R=self.getRByColumncode(c) # 斜距 t=self.getTimeByLineCode(r) # 成像时间 # 解析成像时刻,卫星空间位置 SatelliteState=self.SatelliteOrbitModel.SatelliteSpaceState(t) [Sate_time,Sate_x,Sate_y,Sate_z,Sate_vx,Sate_vy,Sate_vz]=SatelliteState.reshape(1,7).tolist()[0] # 多普勒 Dopper_d=np.array(self.header_info['ImageInformation']['DopplerCentroidCoefficients']).reshape(-1,1) LightSpeed=self.config['LightSpeed'] # DopplerParametersReferenceTime=self.header_info['ImageInformation']['DopplerParametersReferenceTime'] DopplerParametersReferenceTime=self.header_info['ImageInformation']['refRange']*2/LightSpeed # 波长 lamda=self.header_info['ImageInformation']['lambda'] # Re,Rp,we Re=self.config['SatelliteOribit']['ReferenceSpheroid']['Re'] Rp=self.config['SatelliteOribit']['ReferenceSpheroid']['Rp'] we=self.config['SatelliteOribit']['ReferenceSpheroid']['we'] # we 地球自转速度矢量 # 使用牛顿迭代法,求解Xp,Yp,Zp # 椭球体方程常数 a+h ==>a b==>b a=(Re+h)**2 b=Rp**2 # 初始迭代点为中心像元经纬度对应的大地坐标系 #XYZ_=self.LLA_to_XYZ(self.header_info['ImageInformation']['centerPosition'][0], #self.header_info['ImageInformation']['centerPosition'][1], #h) XYZ=np.array([Sate_x,Sate_y,Sate_z]).reshape(1,3) # 确定初始值,作为求解起始值 TargetPosition=math.sqrt( 1/((Sate_x**2+Sate_y**2)/a+(Sate_z**2)/b)) TargetPosition=TargetPosition*np.array([Sate_x,Sate_y,Sate_z]).reshape(1,3) TargetPosition=TargetPosition.reshape(1,3) R_threshold= np.sqrt( np.sum( np.power(TargetPosition-XYZ,2) )) SatellitePosition=np.array([Sate_x,Sate_y,Sate_z]).reshape(3,1) SatelliteVelocity=np.array([Sate_vx,Sate_vy,Sate_vz]).reshape(3,1) TargetPosition_,alpha,beta=self.ASF(R,SatellitePosition,SatelliteVelocity,TargetPosition,Dopper_d,LightSpeed,DopplerParametersReferenceTime,lamda,R_threshold,H=h,alpha0=alpha0,beta0=beta0) # 中间检查有无错误 # TargetPositionLLA=XYZ_to_LLA(TargetPosition[0,0],TargetPosition[0,1],TargetPosition[0,2]).reshape(1,-1) # TargetPosition_LLA=XYZ_to_LLA(TargetPosition_[0,0],TargetPosition_[0,1],TargetPosition_[0,2]).reshape(1,-1) np.set_printoptions(suppress=True) # print(TargetPosition.reshape(1,-1)) # print(TargetPosition_.reshape(1,-1)) # print(TargetPositionLLA.reshape(1,-1)) # print(TargetPosition_LLA.reshape(1,-1)) # print(TargetPosition_-TargetPosition) # print(TargetPosition_LLA-TargetPositionLLA) np.set_printoptions(suppress=False) return TargetPosition_.reshape(1,-1),alpha,beta, Sate_x,Sate_y,Sate_z ''' RD模型解算模块,这里主要使用ASF方法 reference: 陈尔学. 星载合成孔径雷达影像正射校正方法研究[D].中国林业科学研究院,2004. 第三章内容 且假定地表运动速度为0 ''' def ASF(self,R,SatellitePosition,SatelliteVelocity,TargetPosition,Dopper_d,LightSpeed,DopplerParametersReferenceTime,lamda,R_threshold,H=0,alpha0=0,beta0=0): # 部分参数初始化 alpha=alpha0 beta=beta0 delta_alpha=0 Dopper_d=Dopper_d.reshape(-1,1) # 这里需要重构 TSR=2*R/LightSpeed T0=DopplerParametersReferenceTime TSR=TSR-T0 # 这个公式是根据《RADARSAT-2 PRODUCT FORMAT DEFINITION》(RadarSat2的数据格式手册) # “table 5-17 Doppler Rate Values” 中 dopplerRateValuesCoefficients 一行 # ist of up to 5 Doppler rate values coefficients as a function of slant range time: r0, r1, r2, r3, and r4 where: # Doppler rate values = r0 + r1(tSR - t0) + r2(tSR-t0)^2 + r3(tSR-t0)^3 + r4(tSR-t0)^4 fd=np.matmul(np.array([TSR**0,TSR**1,TSR**2,TSR**3,TSR**4]).reshape(1,5),Dopper_d) we=self.w_e M=self.SatelliteCoordination2ECR(SatellitePosition,SatelliteVelocity) i=0 # 统计迭代次数 while True: TargetVelocity=np.array([0,0,0]).reshape(3,1)# np.array([-1*we*TargetPosition[1,0],we*TargetPosition[0,0],0]) # 计算地面速度,粗糙计算时,默认为0 beta=self.GetLookFromRangeYaw(R,alpha,beta,SatellitePosition,SatelliteVelocity,R_threshold,H=H) FD_=self.FD(alpha,beta,SatelliteVelocity,TargetVelocity,R,lamda,M) delta_fd=FD_-fd delta_alpha=-1*delta_fd*lamda/(2* np.sum(np.sqrt(np.power(SatelliteVelocity-TargetVelocity,2)))) if np.abs(delta_alpha*R)<0.1: XYZ=self.GetXYZByBetaAlpha(alpha,beta,SatellitePosition,R,M) break alpha=alpha+delta_alpha i=i+1 return XYZ.reshape(1,-1),alpha,beta def GetLookFromRangeYaw(self,R,alpha,beta,SatellitePosition,SatelliteVelocity,R_threshold,H=0): ''' 根据R和alpha 计算出beta来。 根据参考论文,式3-13,完成此方法。(注意这是近似法 args: R:斜距 alpha:雷达侧视角 beta0:beta初始值 SatellitePosition:3x1 卫星空间位置 TargetPosition:3x1 目标对象 ''' M=self.SatelliteCoordination2ECR(SatellitePosition,SatelliteVelocity) # 地球半径 Rp=self.R_p+H Rs_norm=math.sqrt(np.matmul(SatellitePosition.T,SatellitePosition).reshape(1,1)[0,0]) # 初始化beta if beta==0: beta_cos=(Rs_norm**2+R**2-Rp**2)/(2*Rs_norm*R) beta=math.acos(beta_cos) # 迭代 i=0 while True: # 计算斜率的增加 delta_R=R-self.FR(alpha,beta,SatellitePosition,M,R_threshold,R,H=H) # 计算入射角 sin_eta=Rs_norm*math.sin(beta)/Rp tan_eta=sin_eta/math.sqrt(1-sin_eta**2) # 计算增量 delta_beta=delta_R/(R*tan_eta) # 更新 beta=beta+delta_beta # 判断循环终止条件 if np.abs(delta_R)<0.1: break i=i+1 if i>=10000: # 达到终止条件 return None return beta def XYZOuter(self,A,B): ''' 外积(叉乘),日后版本换成可以任意维度的外积运算方程 args: A:3x1 B:3x1 ''' C=np.cross(A.reshape(1,3),B.reshape(1,3)).reshape(-1,1) return C def SatelliteCoordination2ECR(self,SatellitePosition,SatelliteVelocity): ''' 将卫星为中心的直角坐标系Sxyz转换为ECR坐标系。 M=[x,y,z] args: SatellitePosition:np.array 3x1 ECR坐标系下,卫星空间位置 SatelliteVelocity:np.array 3x1 ECR坐标系下,卫星运动速度 return: 坐标系变换矩阵 M ECR=M*Sxyz P‘=MP ''' z=SatellitePosition/GetVectorNorm(SatellitePosition) y=self.XYZOuter(SatellitePosition,SatelliteVelocity)/(np.sqrt(np.matmul(SatellitePosition.T,SatellitePosition))*np.sqrt(np.matmul(SatelliteVelocity.T,SatelliteVelocity))) # 外积 x=self.XYZOuter(y,z) M=np.concatenate([x.reshape(3,1),y.reshape(3,1),z.reshape(3,1)],axis=1) # 以列组合 return M def UnitVectorOfSatelliteAndTarget(self,alpha,beta,M): ''' 获取从卫星指向地面目标的单位矢量 ''' # 目标T的单位向量 ST=R*M*P P=np.array([math.sin(alpha),-math.cos(alpha)*math.sin(beta),-math.cos(alpha)*math.cos(beta),]).reshape(3,1) P_=np.matmul(M,P).reshape(-1,1) return P_ def FD(self,alpha,beta,SatelliteVelocity,TargetVelocity,R,lamda,M): ''' 根据beta,alpha,卫星空间位置,斜距,转换矩阵 ''' we=self.w_e # TargetVelocity=0 # 假设地面运动为0 UnitVector=self.UnitVectorOfSatelliteAndTarget(alpha,beta,M) Rst=-1*R*UnitVector Rst_Vst=np.matmul(Rst.T,SatelliteVelocity-TargetVelocity) fd=-1*(2/lamda)*Rst_Vst/R return fd def GetXYZByBetaAlpha(self,alpha,beta,SatellitePosition,R,M): ''' 从beta,alpha获取获取目标的空间位置 ''' P=np.array([math.sin(alpha),-math.cos(alpha)*math.sin(beta),-math.cos(alpha)*math.cos(beta),]).reshape(3,1) Rt=SatellitePosition+R*np.matmul(M,P) return Rt def FR(self,alpha,beta,SatellitePosition,M,R_threshold,R_ref,H=0): ''' 根据 雷达侧视角,雷达视角,卫星位置,坐标系变换矩阵,大地高等参数,根据参考论文中公式3-1 ==》3-10的计算过程,设计此方程 args: alpha:雷达侧视角 卫星与地物间速度运动差导致的(即多普勒频移的结果) beta: 雷达视角 Satellite_position:卫星空间位置 M:坐标系转换矩阵 H:大地高 return: R:斜距 ''' UnitVector=self.UnitVectorOfSatelliteAndTarget(alpha,beta,M) # 解方程 3-10 纠正错误,A公式有问题 a=(self.R_e+H)**2 b=self.R_p**2 [Xs,Ys,Zs]=SatellitePosition.reshape(-1,1) [Xp,Yp,Zp]=UnitVector.reshape(-1,1) A=(Xp**2+Yp**2)/a+(Zp**2)/b B=2*(Xs*Xp+Ys*Yp)/a+2*Zs*Zp/b C=(Xs**2+Ys**2)/a+Zs**2/b C=C-1 t=B**2-4*A*C # R1=(-B-math.sqrt(t))/(2*A) if R1>R_threshold: return R1 else: return None #return (-B+math.sqrt(t))/(2*A) # 这里通过几何分析排除这个解 return None class Orthorectification_PSTN(Orthorectification): '''间接定位法,生产GTC ''' def Orthorectification(self,FilePath_str, ori_sim): ''' 正射校正组件。 正射校正整体可以分为两个步骤: 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] # 头文件 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.SatelliteOrbitModel=ReconstructionSatelliteOrbit(self.header_info['GPS'],starttime=self.config['SatelliteOribit']['StartTime']) # 构建卫星轨道模型,取第0个节点的时间 # 求解模型前计算常数变换模型 self.PrepareConverteSystem() # 测试第0,0个点的空间坐标 Doppler_d=np.array(self.header_info['ImageInformation']['DopplerCentroidCoefficients']).reshape(-1,1) LightSpeed=self.config['LightSpeed'] T0=self.header_info['ImageInformation']['refRange']*2/LightSpeed # -2312340.457 5393726.182 2489909.349 TargetPosition=np.array([-2312340.457, 5393726.182 ,2489909.349]).reshape(1,-1) #TargetPosition=np.array([-2366713.39445398 , 5350367.51812531 , 2531732.36706542]).reshape(1,-1) lamda=self.header_info['ImageInformation']['lambda'] StartTime=self.header_info['ImageInformation']['StartTime'] PRF=self.header_info['PRF'] #self.PSTN(TargetPosition,Doppler_d,StartTime,lamda,T0,LightSpeed,PRF) def ConverteCoordinary(self,DEMClip): ''' 批量求解点坐标 args: DEMClip:裁剪后的DEM return: rcArray:像元的对应的行列号 ''' pass def ConverteCoordinaryPoint_single(self,r,c,h=0,breakCondition=1): ''' 求解单个点坐标 args: r: 行号 height c: 列号 width h:平均大地高 breakCondition: 迭代终止条件,默认值为1 ''' pass def PSTN(self,TargetPostion,Doppler_d,StartTime,lamda,T0,LightSpeed,PRF): '''间接定位法 Args: TargetPostion:地面坐标 Doppler_d:多普勒系数 StartTime:成像开始时间 lamda: 波长 T0: 多普勒参考时间 LightSpeed: 光速 return: r,c:影像的行列号 ''' ti=StartTime Doppler_d=Doppler_d.reshape(-1,1) dt=0.001 delta_t=1/PRF delta_R=self.delta_R i=0 while True: # 卫星轨道 statellitePosition=self.SatelliteOrbitModel.SatelliteSpaceState(ti) # 卫星轨道 statellite_XYZ=statellitePosition[0,1:4] statellite_velocity=statellitePosition[0,4:] # 位置向量 R_sp=statellite_XYZ-TargetPostion.reshape(1,-1) V_sp=statellite_velocity inc_r=GetVectorNorm(V_sp) # 斜距 R=GetVectorNorm(R_sp) # 计算多普勒频率 fde=-(2/lamda)*np.matmul(R_sp.reshape(1,3),V_sp.reshape(3,1))/R # 理论 TSR=R*2/LightSpeed-T0 fd=np.matmul(np.array([TSR**0,TSR**1,TSR**2,TSR**3,TSR**4]).reshape(1,5),Doppler_d) #t=ti # 计算多普勒频率的导数 t=ti+dt satellitionPostion_t=self.SatelliteOrbitModel.SatelliteSpaceState(t) sate_position=satellitionPostion_t[0,1:4] sate_velocity=satellitionPostion_t[0,4:] R_sp_t=sate_position-TargetPostion V_sp_t=sate_velocity R_t=GetVectorNorm(R_sp_t) fd_dt=-(2/(lamda*R_t))*np.matmul(R_sp_t.reshape(1,3),V_sp_t.reshape(3,1)) fd_grad=(fd_dt-fde)/dt inc_t=(fde-fd)/fd_grad # 求得变量 if np.abs(inc_t)(rs,cs) :param master_sim_file:主影像的ori_sim.tif路径(正射输出的成果) :param auxil_sim_file:辅影像的ori_sim.tif路径(正射输出的成果) return 数组rm、cm、rs、cs """ width= ImageHandler.get_img_width(master_sim_file) #8182 height=ImageHandler.get_img_height(master_sim_file) img_geotrans = ImageHandler.get_geotransform(master_sim_file) pro = ImageHandler.get_projection(master_sim_file) master_height_array = ImageHandler.get_band_array(master_sim_file, 1) master_width_array = ImageHandler.get_band_array(master_sim_file, 2) auxil_height_array = ImageHandler.get_band_array(auxil_sim_file, 1) auxil_width_array = ImageHandler.get_band_array(auxil_sim_file, 2) # 判断影像的大小,1.若影像的行列小于6 无法选择同名点;2.影像行列在6-2000,则每隔两个点取一个同名点;3.影像行列在2000以上,每隔20个点取一个同名点 if (width < 6) and (height < 6): raise Exception('overlap so small,less of 9 pixel!') elif (width > 6 and height > 6) and (width < 2000 and height < 2000) : # 取一半的同名点 point_dict1={} wid_param1=int(width/2) hig_param1 = int(height/2) for i in range(1,hig_param1+1): for j in range(1,wid_param1+1): hig_value = (height - 2) * (i / hig_param1) wid_value = (width - 2) * (j / wid_param1) value=np.array([hig_value,wid_value]) # print(value) name="a"+str(i)+str(j) point_dict1.update({name:value}) elif (width > 2000) and (height > 2000): # 取一半的同名点 point_dict1 = {} wid_param1 = int(width / 20) hig_param1 = int(height / 20) for i in range(1, hig_param1 + 1): for j in range(1, wid_param1 + 1): hig_value = (height - 2) * (i / hig_param1) wid_value = (width - 2) * (j / wid_param1) value = np.array([hig_value, wid_value]) name = "a" + str(i) +"_"+ str(j) point_dict1.update({name: value}) # 将同名点的行、列分别存到不同的数组中 master_rm=[] auxil_rs=[] master_cm=[] auxil_cs=[] for key,value in point_dict1.items(): x,y=int(value[0]),int(value[1]) # print((x,y)) master_rm_array = master_height_array[x, y] # 主影像行列6006,8182 master_cm_array = master_width_array[x, y] auxil_rs_array = auxil_height_array[x, y] # 辅影像行列 auxil_cs_array = auxil_width_array[x, y] if master_rm_array>1 and master_cm_array>1 and auxil_rs_array>1 and auxil_cs_array>1: # 剔除边界值 master_rm.append(master_rm_array) master_cm.append(master_cm_array) auxil_rs.append(auxil_rs_array) auxil_cs.append(auxil_cs_array) return np.array(master_rm), np.array(master_cm), np.array(auxil_rs), np.array(auxil_cs) def fun(self,p1,rm,cm): """ 最小二乘法的多项式公式 :param p1:系数的数组 :param rm:同名点的列 :param cm:同名点的行 """ a0, a1, a2, a3, a4, a5=p1 return a0+a1*rm+a2*cm+a3*rm*rm+a4*cm*cm+a5*rm*cm def error(self,p1,rm,cm,y): """ 误差公式 :param p1:系数的数组 :param rm:同名点的列 :param cm:同名点的行 :param y:误差值 """ error_value=self.fun(p1,rm,cm)-y return error_value def fun2(self,p2,rm,cm): b0, b1, b2, b3, b4, b5=p2 return b0+b1*rm+b2*cm+b3*rm*rm+b4*cm*cm+b5*rm*cm def error2(self,p2,rm,cm,y): error_value2=self.fun2(p2,rm,cm)-y return error_value2 def least_sqrt(self, master_sim_file, auxil_sim_file): """ 最小二乘法拟合多项式 """ x1,x2,y1,y2=self.choose_same_point(master_sim_file, auxil_sim_file) # 获取同名点的矩阵 p0=np.array([0,0,0,0,0,0]) # 指定多项式系数的初始值 r_plsq=leastsq(self.error,p0,args=(x1,x2,y1)) # 最小二乘法拟合含有多变量的多项式 # print(r_plsq[0]) c_plsq2=leastsq(self.error2,p0,args=(x1,x2,y2)) # print(c_plsq2[0]) return r_plsq[0], c_plsq2[0] def get_new_master_sim(self, r_plsq, c_plsq2, master_ori_sim, out_new_master_ori_sim): """ 主影像的ori_sim数据,通过变换模型生成新的ori_sim数据 :param r_plsq:列变换模型系数矩阵 :param c_plsq2:行变换模型系数矩阵 :param master_ori_sim:主影像的ori_sim数据(正射输出的结果) :param out_new_master_ori_sim:输出由主影像生成的ori_sim数据 """ height=ImageHandler.get_img_height(master_ori_sim) width= ImageHandler.get_img_width(master_ori_sim) img_geotrans = ImageHandler.get_geotransform(master_ori_sim) img_pro = ImageHandler.get_projection(master_ori_sim) new_array=np.zeros((2,height,width),dtype=float) master_height_rm = ImageHandler.get_band_array(master_ori_sim, 1) master_width_cm = ImageHandler.get_band_array(master_ori_sim, 2) rm=master_height_rm cm=master_width_cm a0, a1, a2, a3, a4, a5=r_plsq[0],r_plsq[1],r_plsq[2],r_plsq[3],r_plsq[4],r_plsq[5] b0, b1, b2, b3, b4, b5=c_plsq2[0],c_plsq2[1],c_plsq2[2],c_plsq2[3],c_plsq2[4],c_plsq2[5], rs_array=a0+a1*rm+a2*cm+a3*rm*rm+a4*cm*cm+a5*rm*cm cs_array=b0+b1*rm+b2*cm+b3*rm*rm+b4*cm*cm+b5*rm*cm new_array[0,:,:]=rs_array new_array[1,:,:]=cs_array ImageHandler.write_img(out_new_master_ori_sim, img_pro, img_geotrans, new_array, no_data='null') def calu_vector_angle(self, S1, S2, P): """ 计算垂直基线 S1:s1坐标 S2:s2坐标 R1:P坐标 输出基线B """ # 计算垂直基线绝对值 S1_P_x=P[0,:,:]-S1[0,:,:] # 矢量S1-P在x方向 S1_P_y=P[1,:,:]-S1[1,:,:] # 矢量S1-P在y方向 S1_P_z=P[2,:,:]-S1[2,:,:] # 矢量S1-P在z方向 S1_S2_x=S2[0,:,:]-S1[0,:,:] # 矢量S1-S2在x方向 S1_S2_y=S2[1,:,:]-S1[1,:,:] # 矢量S1-S2在y方向 S1_S2_z=S2[2,:,:]-S1[2,:,:] # 矢量S1-S2在z方向 S2_P_x=P[0,:,:]-S2[0,:,:] S2_P_y=P[1,:,:]-S2[1,:,:] S2_P_z=P[2,:,:]-S2[2,:,:] P_0_x=-P[0,:,:] # 矢量地心点-P在x方向 P_0_y=-P[1,:,:] # 矢量地心点-P在y方向 P_0_z=-P[2,:,:] # 矢量地心点-P在z方向 S1P_S1S2=S1_P_x*S1_S2_x+S1_P_y*S1_S2_y+S1_P_z*S1_S2_z # 矢量的乘积S1P*S2P len_S1_P=np.sqrt(S1_P_x*S1_P_x+S1_P_y*S1_P_y+S1_P_z*S1_P_z) # 矢量的模S1_P0 len_S1_S2=np.sqrt(S1_S2_x*S1_S2_x+S1_S2_y*S1_S2_y+S1_S2_z*S1_S2_z) # 矢量的模S1_S2 cos_angle_s2s1p=S1P_S1S2/(len_S1_P*len_S1_S2) # 夹角S1 余弦值 sin_angle_s2s1p = np.sqrt(1 - cos_angle_s2s1p * cos_angle_s2s1p) # 夹角S1 正弦值 B_vertical=len_S1_S2*sin_angle_s2s1p # 垂直基线的绝对值 # 判断垂直基线的符号(地球观测与导航技术丛书InSAR原理与应用.pdf)68页 len_P_0=np.sqrt(P_0_x*P_0_x+ P_0_y* P_0_y+P_0_z*P_0_z) # 矢量的模P0_P0 S1P_P0=S1_P_x*P_0_x+S1_P_y*P_0_y+S1_P_z*P_0_z cos_angle1 = S1P_P0 / (len_S1_P * len_P_0) S2P_P0=S2_P_x*P_0_x+S2_P_y*P_0_y+S2_P_z*P_0_z len_S2_P=np.sqrt(S2_P_x*S2_P_x+S2_P_y*S2_P_y+S2_P_z*S2_P_z) # 矢量的模S1_P0 cos_angle2 =S2P_P0/(len_S2_P*len_P_0) # 垂直基线绝对值x垂直基线的符号 cos_angle=cos_angle1-cos_angle2 # 若cos_angle10 and y>0: if x