microproduct/vegetationHeight-L-SAR/VegetationHeightOrthoAlg.py

1157 lines
53 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# -*- 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采样率
gtdem_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:
TargetPositionnparray,nx3 地面坐标
Doppler_d:多普勒系数 -11
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:
TargetPositionnparray,nx3 地面坐标
Doppler_d:多普勒系数 -11
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)