microproduct/surfaceRoughness/SurfaceRoughnessMain.py

519 lines
24 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 SurfaceSalinityMain.py
@Author SHJ
@Contact土壤粗糙度算法主函数
@Date 2022/11/7 9:04
@Version 2.0.0
"""
import logging
from tool.algorithm.algtools.PreProcess import PreProcess as pp
from tool.algorithm.image.ImageHandle import ImageHandler
from tool.algorithm.xml.AlgXmlHandle import ManageAlgXML, CheckSource, InitPara
from tool.algorithm.algtools.logHandler import LogHandler
from tool.algorithm.block.blockprocess import BlockProcess
from tool.algorithm.algtools.MetaDataHandler import MetaDataHandler
from tool.algorithm.xml.CreatMetafile import CreateMetafile
from tool.config.ConfigeHandle import Config as cf
from tool.algorithm.algtools.ROIAlg import ROIAlg
from tool.file.fileHandle import fileHandle
import pyproj._compat
from tool.csv.csvHandle import csvHandle
from tool.algorithm.algtools.filter.lee_Filter import Filter
from SurfaceRoughnessALg import RoughnessAlg as alg
from SurfaceRoughnessXmlInfo import CreateDict, CreateStadardXmlFile
import os
import datetime
import numpy as np
import shutil
import scipy #解决打包错误
import scipy.spatial.transform # 用于解决打包错误
import scipy.spatial.transform._rotation_groups # 用于解决打包错误
import scipy.special.cython_special # 用于解决打包错误
import sys
from scipy.interpolate import griddata # 引入scipy中的二维插值库
from scipy.special import lambertw
import math
import multiprocessing
surface_roughness_value_min = float(cf.get('product_value_min'))
surface_roughness_value_max = float(cf.get('product_value_max'))
if cf.get('debug') == 'True':
DEBUG = True
else:
DEBUG = False
file = fileHandle(DEBUG)
EXE_NAME = cf.get('exe_name')
FILTER_SIZE = int(cf.get('filter_size'))
env_str = os.path.split(os.path.realpath(__file__))[0]
os.environ['PROJ_LIB'] = env_str
LogHandler.init_log_handler('run_log\\' + EXE_NAME)
logger = logging.getLogger("mylog")
csvh = csvHandle()
class RoughnessMain:
"""
算法主函数
"""
def __init__(self, alg_xml_path):
self.alg_xml_path = alg_xml_path
self.imageHandler = ImageHandler()
self.__alg_xml_handler = ManageAlgXML(alg_xml_path)
self.__check_handler = CheckSource(self.__alg_xml_handler)
self.__workspace_path, self.__sar_tif_name, self.__out_para = None, None, None
self.__input_paras, self.__output_paras, self.__processing_paras, self.__preprocessed_paras = {}, {}, {}, {}
# 参考影像路径,坐标系
self.__ref_img_path, self.__proj = '', ''
# 宽/列数,高/行数
self.__cols, self.__rows = 0, 0
# 影像投影变换矩阵
self.__geo = [0, 0, 0, 0, 0, 0]
def check_source(self):
"""
检查算法相关的配置文件,图像,辅助文件是否齐全
"""
env_str = os.getcwd()
logger.info("sysdir: %s", env_str)
self.__check_handler.check_alg_xml()
self.__check_handler.check_run_env()
self.__workspace_path = self.__alg_xml_handler.get_workspace_path()
self.__input_paras = self.__alg_xml_handler.get_input_paras()
Polarization = self.__input_paras['Polarization']['ParaValue']
if Polarization == "VV":
self.__sar_tif_name = "VV"
elif Polarization == "HH":
self.__sar_tif_name = "HH"
else:
raise ValueError("input Para 'Polarization' is not 'HH' or 'VV'!")
input_para_names = ["SingleSAR", "MeasuredData", "Covering", "NDVI"]
if self.__check_handler.check_input_paras(input_para_names) is False:
return False
self.__create_work_space()
self.__processing_paras = InitPara.init_processing_paras(self.__input_paras)
self.__processing_paras.update(self.get_tar_gz_inf(self.__processing_paras["sar_path0"]))
self.__out_para = os.path.join(self.__workspace_path, EXE_NAME, 'Output', r"SurfaceRoughnessProduct.tar.gz")
self.__alg_xml_handler.write_out_para("SurfaceRoughnessProduct", self.__out_para) #写入输出参数
logger.info('check_source success!')
logger.info('progress bar: 10%')
return True
def get_tar_gz_inf(self, tar_gz_path):
para_dic = {}
name = os.path.split(tar_gz_path)[1].rstrip('.tar.gz')
file_dir = os.path.join(self.__workspace_preprocessing_path, name + '\\')
file.de_targz(tar_gz_path, file_dir)
# 元文件字典
para_dic.update(InitPara.get_meta_dic(InitPara.get_meta_paths(file_dir, name), name))
# tif路径字典
pol_dic = InitPara.get_polarization_mode(InitPara.get_tif_paths(file_dir, name))
flag_list = [0, 0, 0,0]
VVVH_list = [0, 0]
# 获取极化类型
if "HH" in pol_dic.keys() and self.__sar_tif_name == 'HH':
para_dic.update({self.__sar_tif_name: pol_dic['HH']})
flag_list[0] = 1
if "VV" in pol_dic.keys() and self.__sar_tif_name == 'VV':
para_dic.update({self.__sar_tif_name: pol_dic['VV']})
flag_list[1] = 1
if "HV" in pol_dic.keys():
para_dic.update({'HV': pol_dic['HV']})
flag_list[3] = 1
if "LocalIncidenceAngle" in pol_dic.keys():
para_dic.update({'LocalIncidenceAngle': pol_dic['LocalIncidenceAngle']})
flag_list[2] = 1
if 'VH' in pol_dic.keys(): # 判断VV、VH是否存在用来计算参数L
para_dic.update({'VH': pol_dic['VH']})
VVVH_list[0] = 1
if 'VV' in pol_dic.keys():
VVVH_list[1] = 1
if self.__sar_tif_name == 'HH': # 只有手动选择的是'HH'需要把VV路径添加到字典中
para_dic.update({'VV': pol_dic['VV']})
else: # 反之代表则选择的是'VV'不需要把VV路径重复添加到字典中
pass
if flag_list != [1, 0, 1, 1] and flag_list != [0, 1, 1, 1]:
raise Exception('There are not ' + self.__sar_tif_name + '、LocalIncidenceAngle or meta.xml in path:', tar_gz_path)
if VVVH_list != [1, 1]:
raise Exception('There are not VH or VV:', tar_gz_path)
return para_dic
def __create_work_space(self):
"""
删除原有工作区文件夹,创建新工作区文件夹
"""
self.__workspace_preprocessing_path = self.__workspace_path + EXE_NAME + r"\Temporary\preprocessing""\\"
self.__workspace_preprocessed_path = self.__workspace_path + EXE_NAME + r"\Temporary\preprocessed""\\"
self.__workspace_processing_path = self.__workspace_path + EXE_NAME + r"\Temporary\processing""\\"
self.__workspace_block_tif_path = self.__workspace_path + EXE_NAME + r"\Temporary\blockTif""\\"
self.__workspace_block_tif_processed_path = self.__workspace_path + EXE_NAME + r"\Temporary\blockTifProcessed""\\"
self.__workspace_Zs_block_tif_processed_path = self.__workspace_path + EXE_NAME + r"\Temporary\ZsblockTifProcessed""\\"
self.__feature_tif_dic = self.__workspace_processing_path + 'feature_tif'
self.__product_dic = self.__workspace_processing_path + 'product\\'
path_list = [self.__workspace_preprocessing_path, self.__workspace_preprocessed_path,
self.__workspace_processing_path, self.__workspace_block_tif_path,
self.__workspace_block_tif_processed_path, self.__workspace_Zs_block_tif_processed_path,
self.__feature_tif_dic, self.__product_dic]
file.creat_dirs(path_list)
logger.info('create new workspace success!')
def del_temp_workspace(self):
"""
临时工作区
"""
if DEBUG is True:
return
path = self.__workspace_path + EXE_NAME + r"\Temporary"
if os.path.exists(path):
file.del_folder(path)
def preprocess_handle(self):
"""
预处理
"""
para_names=[]
# 读取每一张图像,检查图像坐标系
if self.__sar_tif_name == 'HH': # VH与VV参与预处理
para_names = [self.__sar_tif_name, 'VH','HV', 'VV', "Covering", "NDVI", "LocalIncidenceAngle"]
elif self.__sar_tif_name == 'VV':
para_names = [self.__sar_tif_name,'VH','HV','HH' "Covering", "NDVI", "LocalIncidenceAngle"]
# if self.__sar_tif_name == 'HH': # VH与VV参与预处理
# para_names = [self.__sar_tif_name, 'VH', 'VV', "Covering", "NDVI", "LocalIncidenceAngle"]
# elif self.__sar_tif_name == 'VV':
# para_names = [self.__sar_tif_name, 'VH', "Covering", "NDVI", "LocalIncidenceAngle"]
ref_img_name = self.__sar_tif_name
p = pp()
self.__preprocessed_paras = p.preprocessing(para_names, ref_img_name,
self.__processing_paras,
self.__workspace_preprocessing_path,
self.__workspace_preprocessed_path)
self.__ref_img_path, self.__cols, self.__rows, self.__proj, self.__geo = p.get_ref_inf(
self.__preprocessed_paras[ref_img_name])
logger.info('preprocess_handle success!')
logger.info('progress bar: 30%')
def create_roi(self):
"""
计算ROI掩膜
:return: 掩膜路径
"""
names = ['LocalIncidenceAngle', self.__sar_tif_name, 'Covering', 'NDVI']
r = ROIAlg()
bare_land_mask_path = r.roi_process(names, self.__workspace_processing_path + "/roi/", self.__processing_paras, self.__preprocessed_paras)
logger.info('create masks success!')
# 计算roi区域
ROIAlg().cal_roi(self.__preprocessed_paras["LocalIncidenceAngle"], self.__preprocessed_paras["LocalIncidenceAngle"],
bare_land_mask_path, background_value=1)
ROIAlg().cal_roi(self.__preprocessed_paras[self.__sar_tif_name], self.__preprocessed_paras[self.__sar_tif_name],
bare_land_mask_path, background_value=1)
shutil.copyfile(bare_land_mask_path, self.__workspace_preprocessed_path + 'mask.tif')
logger.info('create ROI image success!')
return bare_land_mask_path
def create_soilDLCT_tif(self):
"""
创建土壤介电常数影像
"""
# 读取实测值,从经纬度坐标系转为图像坐标系
measured_data_img = csvh.trans_measuredata(csvh.readcsv(self.__processing_paras['MeasuredData']), self.__ref_img_path)
# 插值法生成土壤介电常数二维影像
grid_x, grid_y = np.mgrid[0:self.__rows:1, 0:self.__cols:1]
points = np.array(measured_data_img)[:,0:2]
values = np.array(measured_data_img)[:,2].T
grid_z0 = griddata(points, values, (grid_x, grid_y), method='nearest')
self.__processing_paras['DLCT'] = os.path.join(self.__workspace_preprocessed_path,'DLCT.tif')
self.imageHandler.write_img(self.__processing_paras['DLCT'],self.__proj,self.__geo,grid_z0)
logger.info('create soilDLCT image success!')
def Calu_Q(self,meta_file_path):
"""计算参数交叉极化比值Q"""
VV_proj, VV_geotrans, VV_arr=self.imageHandler.read_img(self.__preprocessed_paras["VV"])
VH_proj, VH_geotrans, VH_arr = self.imageHandler.read_img(self.__preprocessed_paras["VH"])
Array_Q=VH_arr/VV_arr
Out_Q_path=os.path.join(self.__workspace_preprocessed_path,"CrossPolarRatior_q.tif")
self.imageHandler.write_img(Out_Q_path, VV_proj, VV_geotrans, Array_Q)
self.__preprocessed_paras.update({"Ratior_q": Out_Q_path})
return Out_Q_path
def Calu_H(self,Q_path,angle_path,lamda):
"""
计算几何特征复合因子H
Q_path交叉极化比值Q数据
angle_path角度文件
lamda波长
"""
wave_k=2*math.pi/lamda
array_angle=self.imageHandler.get_data(angle_path) # 弧度
Q_proj, Q_geo, Q_arr = self.imageHandler.read_img(Q_path)
temp_val=np.power((0.13 + np.sin(1.5 * array_angle)),1.4)
temp_A=Q_arr/(0.095*temp_val)
Array_H=np.power((-1*np.log(1-temp_A)/1.3),10/9)/wave_k
Out_H_path=os.path.join(self.__workspace_preprocessed_path, "Factor_H.tif")
self.imageHandler.write_img(Out_H_path, Q_proj, Q_geo, Array_H)
def Calu_L_Zs(self, Zs_path,L_path, H_path, Fr_path, lamda, seita_Path):
"""
计算几何特征复合因子L、Zs
Zs_path输出几何特征复合因子 L文件
H_path输入几何特征复合因子 Fr文件
Fr_path输入的Fr_path
lamda输入的波长
seita_Path输入的入射角
"""
H_proj, H_geo, H_arr = self.imageHandler.read_img(H_path)
Fr_proj, Fr_geo, Fr_arr = self.imageHandler.read_img(Fr_path)
array_angle=self.imageHandler.get_data(seita_Path) # 弧度
k=2*math.pi/lamda
a=0.5*H_arr*H_arr
b=-k*np.sin(array_angle)
y=Fr_arr
ans1 = 2 * lambertw(-b * np.sqrt(y / a) / 2) / b # 计算L的两个值
ans2 = 2 * lambertw(b * np.sqrt(y / a) / 2) / b # 计算L的两个值
if "complex" in ans1.dtype.name:
ans1_real=ans1.real
ans2_real = ans2.real
else:
ans1_real=ans1
ans2_real = ans2
chazhi=ans1_real-ans2_real
L=np.where(chazhi>0,ans1_real,ans2_real)
L[np.isnan(L)] = 0 # 必须剔除异常值否则无法写入到tif中
self.imageHandler.write_img(L_path, Fr_proj, Fr_geo, L)
Zs=np.power(H_arr, 2)/L
Zs[np.isnan(Zs)] = 0 # 必须剔除异常值否则无法写入到tif中
self.imageHandler.write_img(Zs_path, Fr_proj, Fr_geo, Zs)
def process_handle(self, start):
"""
算法主处理函数
:return: True or False
"""
# 单视复数转DB
meta_file_path = self.__processing_paras['META']
# 获取元文件波长数据,单位转为cm
lamda = MetaDataHandler.get_lamda(meta_file_path) * 100
# 创建土壤介电常数影像
# self.create_soilDLCT_tif()
logger.info('progress bar: 50%')
# 计算roi
bare_land_mask_path = self.create_roi()
# 计算参数交叉极化比值Q、几何特征复合因子H,参考论文2.3 Oh模型
# Out_Q_path=self.Calu_Q(meta_file_path)
# self.Calu_H(Out_Q_path, self.__preprocessed_paras['LocalIncidenceAngle'], self.__processing_paras['lamda'])
# 分块
bp = BlockProcess()
block_size = bp.get_block_size(self.__rows, self.__cols)
bp.cut(self.__workspace_preprocessed_path, self.__workspace_block_tif_path, ['tif', 'tiff'], 'tif', block_size) # 分块裁剪
logger.info('blocking tifs success!')
img_dir, img_name = bp.get_file_names(self.__workspace_block_tif_path, ['tif'])
dir_dict = bp.get_same_img(img_dir, img_name) # 同一类别放在一个字典下
#改2-取分块的影像VV,VH
hh_list, vv_list, vh_list, hv_list, mask_list = None, None, None, None, None
angle_list = None
sar_tif_list = None
dlct_list = None
Factor_H_list = None
for key in dir_dict.keys():
tmp = key.split("_", 2)[0]
if tmp == "LocalIncidenceAngle":
angle_list = dir_dict[key]
elif tmp == 'HH':
hh_list = dir_dict[key]
elif tmp == 'VV':
vv_list = dir_dict[key]
elif tmp == 'VH':
vh_list = dir_dict[key]
elif tmp == 'HV':
hv_list = dir_dict[key]
elif tmp == 'mask':
mask_list = dir_dict[key]
# elif tmp == self.__sar_tif_name:
# sar_tif_list = dir_dict[key]
elif tmp == "DLCT":
dlct_list = dir_dict[key]
elif tmp == "Factor":
Factor_H_list = dir_dict[key]
# if angle_list is None or sar_tif_list is None or dlct_list is None or Factor_H_list is None:
# raise ValueError('angle_list is None or sar_tif_list is None or dlct_list or Factor_H_list is None')
#
# if not len(angle_list) == len(sar_tif_list) == len(dlct_list) == len(dlct_list):
# raise ValueError('[en(angle_list) == len(sar_tif_list) == len(dlct_list)] is False!') #原方法
if hh_list is None or vv_list is None or vh_list is None or hv_list is None or mask_list is None:
logger.info('angle_list is None or hh_list is None or vv_list is None or vh_list is None or hv_list is None or ndwi_list is None')
return False
if not len(hh_list) == len(vv_list) == len(vh_list) == len(hv_list) == len(mask_list):
logger.info('[len(angle_list) == len(hh_list) == len(vv_list) == len(vh_list) == len(hv_list) == len(ndwi_list)] is False!')
return False
#lee滤波
f = Filter()
processes_num = min([len(hh_list), 4])
# f.lee_filter_multiprocess(sar_tif_list, sar_tif_list, FILTER_SIZE, processes_num)
f.lee_filter_multiprocess(hh_list, hh_list, FILTER_SIZE, processes_num)
f.lee_filter_multiprocess(vv_list, vv_list, FILTER_SIZE, processes_num)
f.lee_filter_multiprocess(vh_list, vh_list, FILTER_SIZE, processes_num)
f.lee_filter_multiprocess(hv_list, hv_list, FILTER_SIZE, processes_num)
pool = multiprocessing.Pool(processes=processes_num)
pl = []
# 计算地表粗糙度
for i in range(len(angle_list)):
name = os.path.basename(angle_list[i])
suffix = '_' + name.split('_')[-4] + "_" + name.split('_')[-3] + "_" + name.split('_')[-2] + "_" + \
name.split('_')[-1]
# dielectric_const_factor_path = self.__workspace_processing_path + "dielectric_const_factor.tif"
# alg.cal_dielectric_const_factor(dielectric_const_factor_path, dlct_list[i],
# angle_list[i], self.__sar_tif_name)
surface_roughness_path = self.__workspace_block_tif_processed_path + "surface_roughness" + suffix
pl.append(pool.apply_async(alg.cal_soil_roug, (surface_roughness_path, hh_list[i], vv_list[i], hv_list[i], vh_list[i], angle_list[i], mask_list[i], lamda)))
# alg.cal_soil_roug(surface_roughness_path, hh_list[i], vv_list[i], hv_list[i], vh_list[i], angle_list[i],
# mask_list[i], lamda)
# alg.cal_soil_roughness(surface_roughness_path, sar_tif_list[i],
# dielectric_const_factor_path, angle_list[i],
# self.__processing_paras['lamda'])
# #改5- 用l和h计算出ZS参考论文2.2 公式7
# H_path=Factor_H_list[i]
# Fr_path=surface_roughness_path
# k=self.__processing_paras['lamda']
# seita_Path=angle_list[i]
#
# Zs_path=self.__workspace_Zs_block_tif_processed_path + "Zs" + suffix
# L_path = self.__workspace_Zs_block_tif_processed_path + "Param_L" + suffix
# self.Calu_L_Zs(Zs_path,L_path, H_path, Fr_path,k,seita_Path)
logger.info('total:%s, block:%s cal surfaceRoughness success!', len(angle_list), i)
pool.close()
pool.join()
# 合并处理后的影像
data_dir = self.__workspace_block_tif_processed_path
w = ImageHandler.get_img_width(self.__preprocessed_paras['HH'])
h = ImageHandler.get_img_height(self.__preprocessed_paras["HH"])
out_path = self.__workspace_processing_path[0:-1]
tif_type = bp.get_tif_dtype(self.__preprocessed_paras['HH'])
bp.combine(data_dir, w, h, out_path, file_type=['tif'], datetype=tif_type)
# 添加地理信息
surface_roughness_path = self.__workspace_processing_path + "surface_roughness.tif"
bp.assign_spatial_reference_byfile(self.__preprocessed_paras['HH'], surface_roughness_path)
logger.info('progress bar: 80%')
# # Zs拼接成一幅tif数据
# Zs_data_dir = self.__workspace_Zs_block_tif_processed_path
# ref_proj, ref_geo, im_arr = ImageHandler.read_img(surface_roughness_path)
# bp.combine_Tif(Zs_data_dir, w, h, out_path, ref_proj, ref_geo, out_type='tif', file_type=['tif', 'tiff'], datetype='float16')
# Zs_path = self.__workspace_processing_path + "Zs.tif"
# L_path = self.__workspace_processing_path + "Param_L.tif"
# Out_H_path = os.path.join(self.__workspace_preprocessed_path, "Factor_H.tif")
#
# # product_Zs_path = os.path.join(self.__product_dic, "Zs.tif")
# product_L_path = os.path.join(self.__product_dic, "L.tif")
# product_H_path = os.path.join(self.__product_dic, "H.tif")
# # alg.cal_roi(product_Zs_path, Zs_path, bare_land_mask_path, background_value=np.nan)
# ROIAlg().cal_roi(product_L_path, L_path, bare_land_mask_path, background_value=np.nan)
# ROIAlg().cal_roi(product_H_path, Out_H_path, bare_land_mask_path, background_value=np.nan)
#生成roi区域
product_mask_path = self.__workspace_processing_path + 'SurfaceRoughnessProductMask.tif'
ROIAlg().cal_roi(product_mask_path, surface_roughness_path, bare_land_mask_path, background_value=np.nan)
product_path = os.path.join(self.__product_dic, 'SurfaceRoughnessProduct.tif')
self.imageHandler.limit_field(product_path, product_mask_path, surface_roughness_value_min, surface_roughness_value_max)
logger.info('cal soil_roughness success!')
# 生成快视图
self.imageHandler.write_quick_view(product_path)
# self.imageHandler.write_quick_view(product_Zs_path) # 新增加三个
# self.imageHandler.write_quick_view(product_L_path)
# self.imageHandler.write_quick_view(product_H_path)
logger.info('packing!')
xml_path = "./model_meta.xml"
tem_folder = self.__workspace_path + EXE_NAME + r"\Temporary""\\"
image_path = product_path
out_path1 = os.path.join(tem_folder, "trans_geo_projcs.tif")
out_path2 = os.path.join(tem_folder, "trans_projcs_geo.tif")
par_dict = CreateDict(image_path, out_path1, out_path2).calu_nature(start)
model_xml_path = os.path.join(tem_folder, "creat_standard.meta.xml") # 输出xml路径
CreateStadardXmlFile(xml_path, self.alg_xml_path, par_dict, model_xml_path).create_standard_xml()
# 文件夹打包
SrcImagePath = self.__input_paras["SingleSAR"]['ParaValue']
paths = SrcImagePath.split(';')
SrcImageName = os.path.split(paths[0])[1].split('.tar.gz')[0]
if len(paths) >= 2:
for i in range(1, len(paths)):
SrcImageName=SrcImageName+";"+os.path.split(paths[i])[1].split('.tar.gz')[0]
meta_xml_path = self.__product_dic+EXE_NAME+"Product.meta.xml"
CreateMetafile(self.__processing_paras['META'], self.alg_xml_path, model_xml_path, meta_xml_path).process(SrcImageName)
file.make_targz(self.__out_para, self.__product_dic)
logger.info('process_handle success!')
logger.info('progress bar: 100%')
if __name__ == '__main__':
multiprocessing.freeze_support() #解决多进程打包成exe后运行错误
start = datetime.datetime.now()
try:
if len(sys.argv) < 2:
xml_path = 'SurfaceRoughness.xml'
else:
xml_path = sys.argv[1]
main_handler = RoughnessMain(xml_path)
if main_handler.check_source() is False:
raise Exception('check_source() failed!')
if main_handler.preprocess_handle() is False:
raise Exception('preprocess_handle() failed!')
if main_handler.process_handle(start) is False:
raise Exception('process_handle() failed!')
logger.info('successful production of ' + EXE_NAME + ' products!')
except Exception:
logger.exception("run-time error!")
finally:
main_handler.del_temp_workspace()
end = datetime.datetime.now()
msg = 'running use time: %s ' % (end - start)
logger.info(msg)