Initial commit
This commit is contained in:
19
Flexbrdf/hytools/brdf/__init__.py
Normal file
19
Flexbrdf/hytools/brdf/__init__.py
Normal file
@ -0,0 +1,19 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
HyTools: 高光谱图像处理库
|
||||
版权所有 (C) 2021 威斯康星大学
|
||||
|
||||
作者:Adam Chlus, Zhiwei Ye, Philip Townsend。
|
||||
|
||||
本程序是自由软件:您可以根据自由软件基金会发布的 GNU 通用公共许可证第 3 版条款重新分发和/或修改它。
|
||||
|
||||
本程序的分发是希望它会有用,但没有任何保证;甚至没有对适销性或特定用途适用性的暗示保证。有关更多详细信息,请参阅 GNU 通用公共许可证。
|
||||
|
||||
您应该已经随本程序收到了 GNU 通用公共许可证副本。如果没有,请参见 <https://www.gnu.org/licenses/>。
|
||||
|
||||
:mod:`hytools.correction` 模块包含用于图像校正的函数。
|
||||
"""
|
||||
from .brdf import *
|
||||
from .kernels import *
|
||||
from .universal import *
|
||||
from .flex import *
|
||||
246
Flexbrdf/hytools/brdf/brdf.py
Normal file
246
Flexbrdf/hytools/brdf/brdf.py
Normal file
@ -0,0 +1,246 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
HyTools: Hyperspectral image processing library
|
||||
Copyright (C) 2021 University of Wisconsin
|
||||
|
||||
Authors: Adam Chlus, Zhiwei Ye, Philip Townsend.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, version 3 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
BRDF 校正
|
||||
"""
|
||||
import json
|
||||
import ray
|
||||
import numpy as np
|
||||
import h5py
|
||||
from .universal import universal_brdf,apply_universal
|
||||
from .flex import flex_brdf,apply_flex,ndvi_stratify, get_kernel_samples, ndvi_bins, get_band_samples
|
||||
from ..masks import mask_create
|
||||
from ..misc import set_brdf, update_brdf, progbar
|
||||
|
||||
def apply_brdf_correct(hy_obj,data,dimension,index):
|
||||
''' 在内存中应用 BRDF 校正。
|
||||
'''
|
||||
|
||||
if hy_obj.brdf['type'] == 'universal':
|
||||
data = apply_universal(hy_obj,data,dimension,index)
|
||||
elif hy_obj.brdf['type'] == 'flex':
|
||||
data = apply_flex(hy_obj,data,dimension,index)
|
||||
elif hy_obj.brdf['type'] == 'local':
|
||||
print('Local/class BRDF correction....under development')
|
||||
return data
|
||||
|
||||
def load_brdf_precomputed(hy_obj,brdf_dict):
|
||||
with open(brdf_dict['coeff_files'][hy_obj.file_name], 'r') as outfile:
|
||||
hy_obj.brdf = json.load(outfile)
|
||||
|
||||
def set_solar_zn(hy_obj):
|
||||
"""设置太阳天顶角归一化值"""
|
||||
solar_zn = hy_obj.get_anc('solar_zn')
|
||||
solar_zn = np.mean(solar_zn[hy_obj.mask['no_data']])
|
||||
hy_obj.brdf['solar_zn_norm_radians'] = float(solar_zn)
|
||||
return solar_zn
|
||||
|
||||
def ndvi_stratify_samples(combine_dict):
|
||||
'''创建 NDVI 分箱分层掩膜
|
||||
'''
|
||||
|
||||
ndvi = combine_dict["ndi_samples"]
|
||||
class_mask = np.zeros(ndvi.shape)
|
||||
|
||||
for bin_num in combine_dict['brdf_dict']['bins']:
|
||||
start,end = combine_dict['brdf_dict']['bins'][bin_num]
|
||||
class_mask[(ndvi > start) & (ndvi <= end)] = bin_num
|
||||
|
||||
class_mask = class_mask.astype(np.int8)
|
||||
combine_dict['ndvi_classes'] = class_mask
|
||||
|
||||
def get_topo_var_samples_pre(hy_obj):
|
||||
'''获取分组地形校正变量,在 ndvi_stratify() 之后运行
|
||||
'''
|
||||
slope = hy_obj.get_anc('slope')
|
||||
cosine_i = hy_obj.cosine_i()
|
||||
sample_ind = (hy_obj.ancillary['ndvi_classes'] !=0)
|
||||
|
||||
return slope[sample_ind], cosine_i[sample_ind]
|
||||
|
||||
def calc_flex_single_post(combine_data_dict,brdf_dict,load_reflectance_mode):
|
||||
|
||||
combine_data_dict["brdf_dict"] = brdf_dict
|
||||
bad_bands = combine_data_dict['bad_bands']
|
||||
# 确定分箱维度并创建类别掩膜
|
||||
if brdf_dict['bin_type'] == 'dynamic':
|
||||
bins = ndvi_bins(combine_data_dict["ndi_samples"],brdf_dict)
|
||||
# 更新分箱数量
|
||||
#print(bins)
|
||||
combine_data_dict["brdf_dict"]['num_bins']=len(bins) #hy_obj.brdf['num_bins'] = len(bins)
|
||||
else:
|
||||
bins = brdf_dict['bins']
|
||||
|
||||
combine_data_dict['brdf_dict']['bins'] = {k:v for (k,v) in enumerate(bins,start=1)}
|
||||
|
||||
ndvi_stratify_samples(combine_data_dict)
|
||||
|
||||
coeffs = {}
|
||||
good_band_count=0
|
||||
for band_num,band in enumerate(bad_bands):
|
||||
if ~band:
|
||||
coeffs[band_num] = {}
|
||||
|
||||
if load_reflectance_mode==0:
|
||||
band_samples = combine_data_dict["reflectance_samples"][:,good_band_count] #ray.get([a.do.remote(get_band_samples,
|
||||
#{'band_num':band_num}) for a in actors])
|
||||
else:
|
||||
combine_refl = []
|
||||
for h5name in combine_data_dict["reflectance_samples"]:
|
||||
h5_obj = h5py.File(h5name, "r")
|
||||
sub_refl_samples = h5_obj["reflectance_samples"][()][:,good_band_count]
|
||||
combine_refl += [sub_refl_samples]
|
||||
h5_obj.close()
|
||||
band_samples = np.concatenate(combine_refl,axis=0)
|
||||
|
||||
band_coeffs= []
|
||||
for bin_num in combine_data_dict['brdf_dict']['bins']:
|
||||
|
||||
bin_mask = (combine_data_dict["ndvi_classes"]== bin_num)
|
||||
|
||||
X = np.concatenate([combine_data_dict["kernels_samples"],np.ones((bin_mask.shape[0],1))],axis=1)[bin_mask] #kernel_samples[:,:3][bin_mask]
|
||||
y = band_samples[bin_mask]
|
||||
band_coeffs.append(np.linalg.lstsq(X, y,rcond=-1)[0].flatten().tolist())
|
||||
coeffs[band_num] = band_coeffs
|
||||
progbar(np.sum(~bad_bands[:band_num+1]),np.sum(~bad_bands))
|
||||
good_band_count+=1
|
||||
|
||||
print('\n')
|
||||
|
||||
combine_data_dict["brdf_dict"]['coeffs'] = coeffs
|
||||
|
||||
|
||||
|
||||
def calc_flex_single_pre(hy_obj,brdf_dict):
|
||||
''' 获取单个图像的样本,用于未来的 BRDF 系数估计
|
||||
'''
|
||||
hy_obj.brdf['coeffs'] ={}
|
||||
|
||||
# 确定分箱维度并创建类别掩膜
|
||||
if hy_obj.brdf['bin_type'] == 'dynamic':
|
||||
bins = ndvi_bins(hy_obj.ndi()[hy_obj.mask['no_data']],brdf_dict)
|
||||
# 更新分箱数量
|
||||
hy_obj.brdf['num_bins'] = len(bins)
|
||||
else:
|
||||
bins = brdf_dict['bins']
|
||||
|
||||
hy_obj.brdf['bins'] = {k:v for (k,v) in enumerate(bins,start=1)}
|
||||
ndvi_stratify(hy_obj)
|
||||
kernel_samples= get_kernel_samples(hy_obj)
|
||||
|
||||
# 循环每个波段
|
||||
refl_samples_list = []
|
||||
used_band = []
|
||||
for band_num,band in enumerate(hy_obj.bad_bands):
|
||||
if ~band:
|
||||
band_samples = hy_obj.do(get_band_samples, {'band_num':band_num})
|
||||
refl_samples_list+=[band_samples[:,None]]
|
||||
used_band+=[hy_obj.wavelengths[band_num]]
|
||||
|
||||
refl_samples = np.concatenate(refl_samples_list,axis=1)
|
||||
|
||||
slope_samples, cos_i_samples = get_topo_var_samples_pre(hy_obj) # 坡度和余弦i
|
||||
|
||||
return kernel_samples[:,:2], refl_samples, used_band, slope_samples, cos_i_samples
|
||||
|
||||
|
||||
def calc_brdf_coeffs(actors,config_dict):
|
||||
|
||||
brdf_dict = config_dict['brdf']
|
||||
|
||||
if brdf_dict['type'] == 'precomputed':
|
||||
print("使用预计算的 BRDF 系数")
|
||||
_ = ray.get([a.do.remote(load_brdf_precomputed,
|
||||
config_dict['brdf']) for a in actors])
|
||||
else:
|
||||
# 设置 BRDF 字典
|
||||
_ = ray.get([a.do.remote(set_brdf,brdf_dict) for a in actors])
|
||||
|
||||
# 创建用于计算系数的掩膜
|
||||
_ = ray.get([a.gen_mask.remote(mask_create,'calc_brdf',
|
||||
brdf_dict['calc_mask']) for a in actors])
|
||||
|
||||
# 计算平均太阳天顶角
|
||||
if isinstance(brdf_dict['solar_zn_type'],str):
|
||||
|
||||
# 分配每条线的平均太阳天顶角
|
||||
solar_zn_samples = ray.get([a.do.remote(set_solar_zn) for a in actors])
|
||||
# 计算并分配场景平均太阳天顶角
|
||||
if brdf_dict['solar_zn_type'] == 'scene':
|
||||
scene_mean = float(np.mean(solar_zn_samples))
|
||||
_ = ray.get([a.do.remote(update_brdf,{'key':'solar_zn_norm_radians',
|
||||
'value': scene_mean }) for a in actors])
|
||||
print("场景平均太阳天顶角 : %s 度" % round(np.degrees(scene_mean),3))
|
||||
|
||||
elif isinstance(brdf_dict['solar_zn_type'],float):
|
||||
_ = ray.get([a.do.remote(update_brdf,{'key':'solar_zn_norm_radians',
|
||||
'value': brdf_dict['solar_zn_type']}) for a in actors])
|
||||
else:
|
||||
print('无法识别的太阳天顶角归一化')
|
||||
|
||||
print("计算 BRDF 系数")
|
||||
if brdf_dict['type']== 'universal':
|
||||
universal_brdf(actors,config_dict)
|
||||
elif brdf_dict['type'] == 'flex':
|
||||
flex_brdf(actors,config_dict)
|
||||
elif brdf_dict['type'] == 'local':
|
||||
print('本地/类别 BRDF 校正....开发中')
|
||||
|
||||
_ = ray.get([a.do.remote(lambda x: x.corrections.append('brdf')) for a in actors])
|
||||
|
||||
def calc_brdf_coeffs_pre(hy_obj,config_dict):
|
||||
|
||||
brdf_dict = config_dict['brdf']
|
||||
|
||||
if brdf_dict['type'] == 'precomputed':
|
||||
print("使用预计算的 BRDF 系数")
|
||||
load_brdf_precomputed(hy_obj,config_dict['brdf'])
|
||||
|
||||
else:
|
||||
# 设置 BRDF 字典
|
||||
|
||||
set_brdf(hy_obj,brdf_dict)
|
||||
set_solar_zn_0 = set_solar_zn(hy_obj)
|
||||
|
||||
# 创建用于计算系数的掩膜
|
||||
hy_obj.gen_mask(mask_create,'calc_brdf',brdf_dict['calc_mask'])
|
||||
|
||||
kernel_samples, reflectance_samples, used_band, slope_samples, cos_i_samples = calc_flex_single_pre(hy_obj,brdf_dict)
|
||||
|
||||
hy_obj.corrections.append('brdf')
|
||||
|
||||
return {
|
||||
"set_solar_zn":set_solar_zn_0,
|
||||
#"ndvi":hy_obj.ndi(),
|
||||
"kernel_samples":kernel_samples,
|
||||
"reflectance_samples":reflectance_samples,
|
||||
"used_band":used_band,
|
||||
"slope_samples":slope_samples,
|
||||
"cos_i_samples":cos_i_samples,
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
363
Flexbrdf/hytools/brdf/flex.py
Normal file
363
Flexbrdf/hytools/brdf/flex.py
Normal file
@ -0,0 +1,363 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
HyTools: Hyperspectral image processing library
|
||||
Copyright (C) 2021 University of Wisconsin
|
||||
|
||||
Authors: Adam Chlus, Zhiwei Ye, Philip Townsend.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, version 3 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
本模块包含应用经验性 BRDF 校正的函数,如下论文所述:
|
||||
|
||||
方程和常数可在以下论文中找到:
|
||||
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
import ray
|
||||
from scipy.interpolate import interp1d
|
||||
from .kernels import calc_volume_kernel,calc_geom_kernel
|
||||
from ..masks import mask_create
|
||||
from ..misc import progbar, pairwise
|
||||
from ..misc import update_brdf
|
||||
from ..plotting import flex_diagno_plot
|
||||
|
||||
def flex_brdf(actors,config_dict):
|
||||
brdf_dict= config_dict['brdf']
|
||||
if brdf_dict['grouped']:
|
||||
calc_flex_group(actors,brdf_dict)
|
||||
else:
|
||||
_ = ray.get([a.do.remote(calc_flex_single,brdf_dict) for a in actors])
|
||||
|
||||
if "diagnostic_plots" in brdf_dict:
|
||||
if brdf_dict['diagnostic_plots']:
|
||||
print('Exporting diagnostic plots.')
|
||||
_ = ray.get([a.do.remote(flex_diagno_plot,config_dict) for a in actors])
|
||||
|
||||
|
||||
def ndvi_stratify(hy_obj):
|
||||
'''创建 NDVI 分箱分层掩膜
|
||||
'''
|
||||
|
||||
ndvi = hy_obj.ndi()
|
||||
class_mask = np.zeros((hy_obj.lines, hy_obj.columns))
|
||||
|
||||
for bin_num in hy_obj.brdf['bins']:
|
||||
start,end = hy_obj.brdf['bins'][bin_num]
|
||||
class_mask[(ndvi > start) & (ndvi <= end)] = bin_num
|
||||
|
||||
class_mask[~hy_obj.mask['calc_brdf']] = 0
|
||||
|
||||
#Subsample data
|
||||
idx = np.array(np.where(class_mask!=0)).T
|
||||
idxRand= idx[np.random.choice(range(len(idx)),int(len(idx)*(1-hy_obj.brdf['sample_perc'])), replace = False)].T
|
||||
class_mask[idxRand[0],idxRand[1]] = 0
|
||||
class_mask = class_mask.astype(np.int8)
|
||||
hy_obj.ancillary['ndvi_classes'] = class_mask
|
||||
|
||||
|
||||
def ndvi_2nd_split(ndvi_bins_dynamic, all_ndvi_array, ndvi_bin_range_thres=0.15):
|
||||
''' 执行第二次 NDVI 分割
|
||||
'''
|
||||
|
||||
ndvi_bin_range_thres = -0.015625 * (len(ndvi_bins_dynamic)-1) + 0.43125
|
||||
ndvi_bin_range = np.array(ndvi_bins_dynamic[1:]) - np.array(ndvi_bins_dynamic[:-1])
|
||||
|
||||
bin_for_split = np.argwhere(ndvi_bin_range>=ndvi_bin_range_thres).ravel()
|
||||
|
||||
new_break = []
|
||||
if bin_for_split.shape[0]>0:
|
||||
for bin_id in bin_for_split:
|
||||
# Use median of the bin as the new break point
|
||||
new_break += [np.median(all_ndvi_array[(all_ndvi_array > ndvi_bins_dynamic[bin_id]) & (all_ndvi_array < ndvi_bins_dynamic[bin_id+1])]).astype(np.float64)]
|
||||
|
||||
# New list of bin break points
|
||||
ndvi_bins_dynamic = sorted(ndvi_bins_dynamic + new_break)
|
||||
|
||||
return ndvi_bins_dynamic
|
||||
|
||||
def ndvi_bins(ndvi,brdf_dict):
|
||||
'''计算 NDVI 分箱范围
|
||||
'''
|
||||
perc_range = brdf_dict['ndvi_perc_max'] - brdf_dict['ndvi_perc_min'] + 1
|
||||
|
||||
ndvi_break_dyn_bin = np.percentile(ndvi[ndvi > 0],
|
||||
np.arange(brdf_dict['ndvi_perc_min'],
|
||||
brdf_dict['ndvi_perc_max'] + 1,
|
||||
perc_range / (brdf_dict['num_bins'] - 1)))
|
||||
ndvi_thres = [brdf_dict['ndvi_bin_min']]
|
||||
ndvi_thres += ndvi_break_dyn_bin.tolist()
|
||||
ndvi_thres += [brdf_dict['ndvi_bin_max']]
|
||||
ndvi_thres = sorted(list(set(ndvi_thres)))
|
||||
|
||||
# 对 NDVI 分箱进行第二次分割
|
||||
ndvi_thres = ndvi_2nd_split(ndvi_thres, ndvi)
|
||||
|
||||
bins = [[x,y] for x,y in pairwise(ndvi_thres)]
|
||||
return bins
|
||||
|
||||
def get_kernel_samples(hy_obj):
|
||||
'''计算并采样 BRDF 核函数
|
||||
'''
|
||||
geom_kernel = hy_obj.geom_kernel(hy_obj.brdf['geometric'],
|
||||
b_r=hy_obj.brdf["b/r"] ,
|
||||
h_b =hy_obj.brdf["h/b"])
|
||||
geom_kernel = geom_kernel[hy_obj.ancillary['ndvi_classes'] !=0]
|
||||
|
||||
vol_kernel = hy_obj.volume_kernel(hy_obj.brdf['volume'])
|
||||
vol_kernel = vol_kernel[hy_obj.ancillary['ndvi_classes'] !=0]
|
||||
|
||||
classes = hy_obj.ancillary['ndvi_classes'][hy_obj.ancillary['ndvi_classes'] !=0]
|
||||
X = np.vstack([vol_kernel,geom_kernel,
|
||||
np.ones(vol_kernel.shape),classes]).T
|
||||
return X
|
||||
|
||||
def get_band_samples(hy_obj,args):
|
||||
band = hy_obj.get_band(args['band_num'],
|
||||
corrections = hy_obj.corrections)
|
||||
return band[hy_obj.ancillary['ndvi_classes'] !=0]
|
||||
|
||||
def calc_flex_single(hy_obj,brdf_dict):
|
||||
''' 计算单个图像的 BRDF 系数
|
||||
'''
|
||||
hy_obj.brdf['coeffs'] ={}
|
||||
|
||||
# 确定分箱维度并创建类别掩膜
|
||||
if hy_obj.brdf['bin_type'] == 'dynamic':
|
||||
bins = ndvi_bins(hy_obj.ndi()[hy_obj.mask['no_data']],brdf_dict)
|
||||
# 更新分箱数量
|
||||
hy_obj.brdf['num_bins'] = len(bins)
|
||||
else:
|
||||
bins = brdf_dict['bins']
|
||||
|
||||
hy_obj.brdf['bins'] = {k:v for (k,v) in enumerate(bins,start=1)}
|
||||
ndvi_stratify(hy_obj)
|
||||
kernel_samples= get_kernel_samples(hy_obj)
|
||||
|
||||
# 计算每个波段和类别的系数
|
||||
for band_num,band in enumerate(hy_obj.bad_bands):
|
||||
if ~band:
|
||||
hy_obj.brdf['coeffs'][band_num] = {}
|
||||
band_samples = hy_obj.do(get_band_samples, {'band_num':band_num})
|
||||
coeffs= []
|
||||
|
||||
for bin_num in hy_obj.brdf['bins']:
|
||||
bin_mask = (kernel_samples[:,3] == bin_num)
|
||||
X = kernel_samples[:,:3][bin_mask]
|
||||
y = band_samples[bin_mask]
|
||||
coeffs.append(np.linalg.lstsq(X, y,rcond=-1)[0].flatten().tolist())
|
||||
hy_obj.brdf['coeffs'][band_num] = coeffs
|
||||
|
||||
def calc_flex_group(actors,brdf_dict):
|
||||
''' 计算一组图像的 BRDF 系数
|
||||
'''
|
||||
# 从图像聚合 NDVI 值
|
||||
ndvi = ray.get([a.ndi.remote(mask = 'no_data') for a in actors])
|
||||
ndvi = np.concatenate([n.flatten() for n in ndvi])
|
||||
|
||||
# 确定分箱维度
|
||||
if brdf_dict['bin_type'] == 'dynamic':
|
||||
bins = ndvi_bins(ndvi,brdf_dict)
|
||||
# 更新分箱数量
|
||||
_ = ray.get([a.do.remote(update_brdf,{'key':'num_bins',
|
||||
'value': len(bins)}) for a in actors])
|
||||
else:
|
||||
bins = brdf_dict['bins']
|
||||
|
||||
bins = {k:v for (k,v) in enumerate(bins,start=1)}
|
||||
|
||||
# 更新 BRDF 系数
|
||||
_ = ray.get([a.do.remote(update_brdf,{'key':'bins',
|
||||
'value': bins}) for a in actors])
|
||||
|
||||
# 创建 NDVI 类别掩膜并采样核函数
|
||||
_ = ray.get([a.do.remote(ndvi_stratify) for a in actors])
|
||||
kernel_samples = ray.get([a.do.remote(get_kernel_samples) for a in actors])
|
||||
kernel_samples = np.concatenate(kernel_samples)
|
||||
|
||||
bad_bands = ray.get(actors[0].do.remote(lambda x: x.bad_bands))
|
||||
coeffs = {}
|
||||
|
||||
for band_num,band in enumerate(bad_bands):
|
||||
if ~band:
|
||||
coeffs[band_num] = {}
|
||||
band_samples = ray.get([a.do.remote(get_band_samples,
|
||||
{'band_num':band_num}) for a in actors])
|
||||
band_samples = np.concatenate(band_samples)
|
||||
band_coeffs= []
|
||||
for bin_num in bins:
|
||||
bin_mask = (kernel_samples[:,3] == bin_num)
|
||||
X = kernel_samples[:,:3][bin_mask]
|
||||
y = band_samples[bin_mask]
|
||||
band_coeffs.append(np.linalg.lstsq(X, y,rcond=-1)[0].flatten().tolist())
|
||||
coeffs[band_num] = band_coeffs
|
||||
progbar(np.sum(~bad_bands[:band_num+1]),np.sum(~bad_bands))
|
||||
|
||||
print('\n')
|
||||
|
||||
# 更新 BRDF 系数
|
||||
_ = ray.get([a.do.remote(update_brdf,{'key':'coeffs',
|
||||
'value': coeffs}) for a in actors])
|
||||
|
||||
def apply_flex(hy_obj,data,dimension,index):
|
||||
''' 对数据切片应用 flex BRDF 校正
|
||||
|
||||
参数:
|
||||
hy_obj : Hytools 类对象。
|
||||
data (np.ndarray): 数据切片。
|
||||
index (int,list): 数据索引。
|
||||
|
||||
返回:
|
||||
data (np.ndarray): BRDF 校正后的数据切片。
|
||||
'''
|
||||
|
||||
if 'k_vol' not in hy_obj.ancillary:
|
||||
hy_obj.ancillary['k_vol'] = hy_obj.volume_kernel(hy_obj.brdf['volume'])
|
||||
if 'k_geom' not in hy_obj.ancillary:
|
||||
hy_obj.ancillary['k_geom'] = hy_obj.geom_kernel(hy_obj.brdf['geometric'],
|
||||
b_r=hy_obj.brdf["b/r"],
|
||||
h_b =hy_obj.brdf["h/b"])
|
||||
if ('k_vol_nadir' not in hy_obj.ancillary) or ('k_geom_nadir' not in hy_obj.ancillary):
|
||||
solar_zn = hy_obj.brdf['solar_zn_norm_radians'] * np.ones((hy_obj.lines,hy_obj.columns))
|
||||
hy_obj.ancillary['k_vol_nadir'] = calc_volume_kernel(0,solar_zn,
|
||||
0,0,hy_obj.brdf['volume'])
|
||||
hy_obj.ancillary['k_geom_nadir'] = calc_geom_kernel(0,solar_zn,
|
||||
0,0,hy_obj.brdf['geometric'],
|
||||
b_r=hy_obj.brdf["b/r"],
|
||||
h_b =hy_obj.brdf["h/b"])
|
||||
if 'apply_brdf' not in hy_obj.mask:
|
||||
hy_obj.gen_mask(mask_create,'apply_brdf',hy_obj.brdf['apply_mask'])
|
||||
|
||||
if 'ndvi' not in hy_obj.ancillary:
|
||||
hy_obj.ancillary['ndvi'] = hy_obj.ndi()
|
||||
|
||||
if 'interpolators' not in hy_obj.ancillary:
|
||||
bin_centers = np.mean(list(hy_obj.brdf['bins'].values()),axis=1)
|
||||
hy_obj.ancillary['interpolators'] ={}
|
||||
|
||||
# 生成插值器
|
||||
for i in hy_obj.brdf['coeffs']:
|
||||
coeffs= np.array(hy_obj.brdf['coeffs'][i])
|
||||
interpolator = interp1d(bin_centers, coeffs, kind = hy_obj.brdf['interp_kind'],
|
||||
axis=0,fill_value="extrapolate")
|
||||
hy_obj.ancillary['interpolators'][int(i)] = interpolator
|
||||
|
||||
# 转换为浮点数
|
||||
data = data.astype(np.float32)
|
||||
brdf_bands = [int(x) for x in hy_obj.ancillary['interpolators']]
|
||||
if dimension == 'line':
|
||||
# index= 3000
|
||||
# data = hy_obj.get_line(3000)
|
||||
|
||||
interpolated_f = [hy_obj.ancillary['interpolators'][band](hy_obj.ancillary['ndvi'][index,:]) for band in brdf_bands]
|
||||
interpolated_f = np.array(interpolated_f)
|
||||
fvol, fgeo, fiso = interpolated_f[:,:,0], interpolated_f[:,:,1], interpolated_f[:,:,2]
|
||||
|
||||
brdf = fvol*hy_obj.ancillary['k_vol'][index,:]
|
||||
brdf+= fgeo*hy_obj.ancillary['k_geom'][index,:]
|
||||
brdf+= fiso
|
||||
|
||||
brdf_nadir = fvol*hy_obj.ancillary['k_vol_nadir'][index,:]
|
||||
brdf_nadir+= fgeo*hy_obj.ancillary['k_geom_nadir'][index,:]
|
||||
brdf_nadir+= fiso
|
||||
|
||||
correction_factor = brdf_nadir/brdf
|
||||
correction_factor[:,~hy_obj.mask['apply_brdf'][index]] = 1
|
||||
|
||||
data[:,brdf_bands] = data[:,brdf_bands]*correction_factor.T
|
||||
|
||||
elif dimension == 'column':
|
||||
#index= 300
|
||||
#data = hy_obj.get_column(index)
|
||||
|
||||
interpolated_f = [hy_obj.ancillary['interpolators'][band](hy_obj.ancillary['ndvi'][:,index]) for band in brdf_bands]
|
||||
interpolated_f = np.array(interpolated_f)
|
||||
fvol, fgeo, fiso = interpolated_f[:,:,0], interpolated_f[:,:,1], interpolated_f[:,:,2]
|
||||
|
||||
brdf = fvol*hy_obj.ancillary['k_vol'][:,index]
|
||||
brdf+= fgeo*hy_obj.ancillary['k_geom'][:,index]
|
||||
brdf+= fiso
|
||||
|
||||
brdf_nadir = fvol*hy_obj.ancillary['k_vol_nadir'][:,index]
|
||||
brdf_nadir+= fgeo*hy_obj.ancillary['k_geom_nadir'][:,index]
|
||||
brdf_nadir+= fiso
|
||||
|
||||
correction_factor = brdf_nadir/brdf
|
||||
correction_factor = np.moveaxis(correction_factor,0,1)
|
||||
correction_factor[:,~hy_obj.mask['apply_brdf'][index]] = 1
|
||||
data[:,brdf_bands] = data[:,brdf_bands]*correction_factor.T
|
||||
|
||||
elif (dimension == 'band') & (index in brdf_bands):
|
||||
# index= 8
|
||||
# data = hy_obj.get_band(index)
|
||||
|
||||
interpolated_f = hy_obj.ancillary['interpolators'][index](hy_obj.ancillary['ndvi'])
|
||||
fvol, fgeo, fiso = interpolated_f[:,:,0], interpolated_f[:,:,1], interpolated_f[:,:,2]
|
||||
|
||||
brdf = fvol*hy_obj.ancillary['k_vol']
|
||||
brdf += fgeo*hy_obj.ancillary['k_geom']
|
||||
brdf += fiso
|
||||
|
||||
brdf_nadir = fvol*hy_obj.ancillary['k_vol_nadir']
|
||||
brdf_nadir += fgeo*hy_obj.ancillary['k_geom_nadir']
|
||||
brdf_nadir += fiso
|
||||
|
||||
correction_factor = brdf_nadir/brdf
|
||||
correction_factor[~hy_obj.mask['apply_brdf']] = 1
|
||||
data= data* correction_factor
|
||||
|
||||
elif dimension == 'chunk':
|
||||
# index = 200,501,3000,3501
|
||||
x1,x2,y1,y2 = index
|
||||
# data = hy_obj.get_chunk(x1,x2,y1,y2)
|
||||
|
||||
interpolated_f = [hy_obj.ancillary['interpolators'][band](hy_obj.ancillary['ndvi'][y1:y2,x1:x2]) for band in brdf_bands]
|
||||
interpolated_f = np.array(interpolated_f)
|
||||
interpolated_f = np.swapaxes(interpolated_f,0,-1)
|
||||
fvol, fgeo, fiso = interpolated_f[0,:,:,:], interpolated_f[1,:,:,:], interpolated_f[2,:,:,:]
|
||||
|
||||
brdf = fvol*hy_obj.ancillary['k_vol'][y1:y2,x1:x2,np.newaxis]
|
||||
brdf+= fgeo*hy_obj.ancillary['k_geom'][y1:y2,x1:x2,np.newaxis]
|
||||
brdf+= fiso
|
||||
|
||||
brdf_nadir = fvol*hy_obj.ancillary['k_vol_nadir'][y1:y2,x1:x2,np.newaxis]
|
||||
brdf_nadir+= fgeo*hy_obj.ancillary['k_geom_nadir'][y1:y2,x1:x2,np.newaxis]
|
||||
brdf_nadir+= fiso
|
||||
|
||||
correction_factor = brdf_nadir/brdf
|
||||
correction_factor[~hy_obj.mask['apply_brdf'][y1:y2,x1:x2]] = 1
|
||||
data[:,:,brdf_bands] = data[:,:,brdf_bands]*correction_factor
|
||||
|
||||
elif dimension == 'pixels':
|
||||
# index = [[2000,2001],[200,501]]
|
||||
y,x = index
|
||||
# data = hy_obj.get_pixels(y,x)
|
||||
|
||||
interpolated_f = [hy_obj.ancillary['interpolators'][band](hy_obj.ancillary['ndvi'][y,x]) for band in brdf_bands]
|
||||
interpolated_f = np.array(interpolated_f)
|
||||
interpolated_f = np.swapaxes(interpolated_f,0,1)
|
||||
fvol, fgeo, fiso = interpolated_f[:,:,0], interpolated_f[:,:,1], interpolated_f[:,:,2]
|
||||
|
||||
brdf = fvol*hy_obj.ancillary['k_vol'][y,x,np.newaxis]
|
||||
brdf+= fgeo*hy_obj.ancillary['k_geom'][y,x,np.newaxis]
|
||||
brdf+= fiso
|
||||
|
||||
brdf_nadir = fvol*hy_obj.ancillary['k_vol_nadir'][y,x,np.newaxis]
|
||||
brdf_nadir+= fgeo*hy_obj.ancillary['k_geom_nadir'][y,x,np.newaxis]
|
||||
brdf_nadir+= fiso
|
||||
|
||||
correction_factor = brdf_nadir/brdf
|
||||
correction_factor[~hy_obj.mask['apply_brdf'][y,x]] = 1
|
||||
data[:,brdf_bands] = data[:,brdf_bands]*correction_factor
|
||||
|
||||
return data
|
||||
167
Flexbrdf/hytools/brdf/kernels.py
Normal file
167
Flexbrdf/hytools/brdf/kernels.py
Normal file
@ -0,0 +1,167 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
HyTools: Hyperspectral image processing library
|
||||
Copyright (C) 2021 University of Wisconsin
|
||||
|
||||
Authors: Adam Chlus, Zhiwei Ye, Philip Townsend.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, version 3 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
本模块包含计算 BRDF 散射核函数的函数。
|
||||
|
||||
方程和常数可在以下论文中找到:
|
||||
|
||||
Colgan, M. S., Baldeck, C. A., Feret, J. B., & Asner, G. P. (2012).
|
||||
Mapping savanna tree species at ecosystem scales using support vector machine classification
|
||||
and BRDF correction on airborne hyperspectral and LiDAR data.
|
||||
Remote Sensing, 4(11), 3462-3480.
|
||||
https://doi.org/10.3390/rs4113462
|
||||
|
||||
Lucht, W., Schaaf, C. B., & Strahler, A. H. (2000).
|
||||
An algorithm for the retrieval of albedo from space using semiempirical BRDF models.
|
||||
IEEE Transactions on Geoscience and Remote sensing, 38(2), 977-998.
|
||||
https://doi.org/10.1109/36.841980
|
||||
|
||||
Maignan, F., Bréon, F. M., & Lacaze, R. (2004).
|
||||
Bidirectional reflectance of Earth targets: Evaluation of analytical
|
||||
models using a large set of spaceborne measurements with emphasis on the Hot Spot.
|
||||
Remote Sensing of Environment, 90(2), 210-220.
|
||||
https://doi.org/10.1016/j.rse.2003.12.006
|
||||
|
||||
Roujean, J. L., Leroy, M., & Deschamps, P. Y. (1992).
|
||||
A bidirectional reflectance model of the Earth's surface for the correction
|
||||
of remote sensing data.
|
||||
Journal of Geophysical Research: Atmospheres, 97(D18), 20455-20468.
|
||||
https://doi.org/10.1029/92JD01411
|
||||
|
||||
Schlapfer, D., Richter, R., & Feingersh, T. (2015).
|
||||
Operational BRDF effects correction for wide-field-of-view optical scanners (BREFCOR).
|
||||
IEEE Transactions on Geoscience and Remote Sensing, 53(4), 1855-1864.
|
||||
https://doi.org/10.1109/TGRS.2014.2349946
|
||||
|
||||
Wanner, W., Li, X., & Strahler, A. H. (1995).
|
||||
On the derivation of kernels for kernel-driven models of bidirectional reflectance.
|
||||
Journal of Geophysical Research: Atmospheres, 100(D10), 21077-21089.
|
||||
https://doi.org/10.1029/95JD02371
|
||||
|
||||
Zhang, X., Jiao, Z., Dong, Y., Zhang, H., Li, Y., He, D., ... & Chang, Y. (2018).
|
||||
Potential investigation of linking PROSAIL with the ross-li BRDF model for
|
||||
vegetation characterization.
|
||||
Remote Sensing, 10(3), 437.
|
||||
https://doi.org/10.3390/rs10030437SSS
|
||||
|
||||
"""
|
||||
import numpy as np
|
||||
|
||||
def calc_geom_kernel(solar_az,solar_zn,sensor_az,sensor_zn,kernel,b_r=1.,h_b =2.):
|
||||
"""计算几何散射核函数。
|
||||
常数 b_r (b/r) 和 h_b (h/b) 来自 Colgan 等人 RS 2012
|
||||
替代方案包括 MODIS 规范:
|
||||
b/r : 稀疏: 1, 密集: 2.5
|
||||
h/b : 稀疏, 密集 : 2
|
||||
|
||||
所有输入几何单位必须以弧度为单位。
|
||||
|
||||
参数:
|
||||
solar_az (numpy.ndarray): 太阳方位角。
|
||||
solar_zn (numpy.ndarray): 太阳天顶角。
|
||||
sensor_az (numpy.ndarray): 传感器视角方位角。
|
||||
sensor_zn (numpy.ndarray): 传感器视角天顶角。
|
||||
kernel (str): Li 几何散射核类型 [li_dense,li_sparse, roujean]。
|
||||
b_r (float, 可选): 物体高度。默认为 10。
|
||||
h_b (float, 可选): 物体形状。默认为 2。
|
||||
|
||||
返回:
|
||||
numpy.ndarray: 几何散射核。
|
||||
|
||||
"""
|
||||
|
||||
relative_az = sensor_az - solar_az
|
||||
|
||||
# Eq. 37,52. Wanner et al. JGRA 1995
|
||||
solar_zn_p = np.arctan(b_r * np.tan(solar_zn))
|
||||
sensor_zn_p = np.arctan(b_r * np.tan(sensor_zn))
|
||||
# Eq 50. Wanner et al. JGRA 1995
|
||||
D = np.sqrt((np.tan(solar_zn_p)**2) + (np.tan(sensor_zn_p)**2) - 2*np.tan(solar_zn_p)*np.tan(sensor_zn_p)*np.cos(relative_az))
|
||||
# Eq 49. Wanner et al. JGRA 1995
|
||||
t_num = h_b * np.sqrt(D**2 + (np.tan(solar_zn_p)*np.tan(sensor_zn_p)*np.sin(relative_az))**2)
|
||||
t_denom = (1/np.cos(solar_zn_p)) + (1/np.cos(sensor_zn_p))
|
||||
t = np.arccos(np.clip(t_num/t_denom,-1,1))
|
||||
# Eq 33,48. Wanner et al. JGRA 1995
|
||||
O = (1/np.pi) * (t - np.sin(t)*np.cos(t)) * t_denom
|
||||
# Eq 51. Wanner et al. JGRA 1995
|
||||
cos_phase_p = np.cos(solar_zn_p)*np.cos(sensor_zn_p) + np.sin(solar_zn_p)*np.sin(sensor_zn_p)*np.cos(relative_az)
|
||||
|
||||
if kernel == 'li_sparse':
|
||||
# Eq 32. Wanner et al. JGRA 1995
|
||||
k_geom = O - (1/np.cos(solar_zn_p)) - (1/np.cos(sensor_zn_p)) + .5*(1+ cos_phase_p) * (1/np.cos(sensor_zn_p))
|
||||
elif kernel == 'li_dense':
|
||||
# Eq 47. Wanner et al. JGRA 1995
|
||||
k_geom = (((1+cos_phase_p) * (1/np.cos(sensor_zn_p)))/ (t_denom - O)) - 2
|
||||
elif kernel == 'li_sparse_r':
|
||||
# Eq 39. Lucht et al. TGRS 2000
|
||||
k_geom = O - (1/np.cos(solar_zn_p)) - (1/np.cos(sensor_zn_p)) + .5*(1+ cos_phase_p) * (1/np.cos(sensor_zn_p)) * (1/np.cos(solar_zn_p))
|
||||
elif kernel == 'li_dense_r':
|
||||
# Eq 5. Zhang et al. RS 2018 <-- Find a more original reference
|
||||
k_geom = (((1+cos_phase_p) * (1/np.cos(sensor_zn_p)) * (1/np.cos(solar_zn_p)))/ (t_denom - O)) - 2
|
||||
elif kernel == 'roujean':
|
||||
# Eq 2 Roujean et al. JGR 1992
|
||||
k_geom1 = (1/(2*np.pi)) * ((np.pi - relative_az)*np.cos(relative_az)+np.sin(relative_az)) *np.tan(solar_zn)*np.tan(sensor_zn)
|
||||
k_geom2 = (1/np.pi) * (np.tan(solar_zn) + np.tan(sensor_zn) + np.sqrt(np.tan(solar_zn)**2 + np.tan(sensor_zn)**2 - 2*np.tan(solar_zn)*np.tan(sensor_zn)*np.cos(relative_az)))
|
||||
k_geom = k_geom1 - k_geom2
|
||||
else:
|
||||
print("Unrecognized kernel type: %s" % kernel)
|
||||
k_geom = None
|
||||
return k_geom
|
||||
|
||||
|
||||
def calc_volume_kernel(solar_az,solar_zn,sensor_az,sensor_zn,kernel):
|
||||
"""计算体积散射核函数。
|
||||
|
||||
所有输入几何单位必须以弧度为单位。
|
||||
|
||||
参数:
|
||||
solar_az (numpy.ndarray): 太阳方位角。
|
||||
solar_zn (numpy.ndarray): 太阳天顶角。
|
||||
sensor_az (numpy.ndarray): 传感器视角方位角。
|
||||
sensor_zn (numpy.ndarray): 传感器视角天顶角。
|
||||
kernel (str): 体积散射核类型 [ross_thick,ross_thin]。
|
||||
|
||||
返回:
|
||||
numpy.ndarray: 体积散射核。
|
||||
|
||||
"""
|
||||
|
||||
relative_az = sensor_az - solar_az
|
||||
|
||||
# Eq 2. Schlapfer et al. IEEE-TGARS 2015
|
||||
phase = np.arccos(np.cos(solar_zn)*np.cos(sensor_zn) + np.sin(solar_zn)*np.sin(sensor_zn)* np.cos(relative_az))
|
||||
|
||||
if kernel == 'ross_thin':
|
||||
# Eq 13. Wanner et al. JGRA 1995
|
||||
k_vol = ((np.pi/2 - phase)*np.cos(phase) + np.sin(phase))/ (np.cos(sensor_zn)*np.cos(solar_zn)) - (np.pi/2)
|
||||
elif kernel == 'ross_thick':
|
||||
# Eq 7. Wanner et al. JGRA 1995
|
||||
k_vol = ((np.pi/2 - phase)*np.cos(phase) + np.sin(phase))/ (np.cos(sensor_zn)+np.cos(solar_zn)) - (np.pi/4)
|
||||
elif kernel in ('hotspot','roujean'):
|
||||
# Eq 8 Roujean et al. JGR 1992
|
||||
k_vol1 = (4/(3*np.pi)) * (1/(np.cos(solar_zn) + np.cos(sensor_zn)))
|
||||
k_vol2 = (((np.pi/2) - phase) * np.cos(phase) + np.sin(phase))
|
||||
k_vol = k_vol1*(k_vol2- (1/3))
|
||||
if kernel == 'hotspot':
|
||||
# Eq. 12 Maignan et al. RSE 2004
|
||||
k_vol = k_vol1* k_vol2 * (1 + (1 + (phase/np.radians(1.5)))**-1) - (1/3)
|
||||
else:
|
||||
print("Unrecognized kernel type: %s" % kernel)
|
||||
k_vol = None
|
||||
return k_vol
|
||||
21
Flexbrdf/hytools/brdf/local.py
Normal file
21
Flexbrdf/hytools/brdf/local.py
Normal file
@ -0,0 +1,21 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
HyTools: Hyperspectral image processing library
|
||||
Copyright (C) 2021 University of Wisconsin
|
||||
|
||||
Authors: Adam Chlus, Zhiwei Ye, Philip Townsend.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, version 3 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
本地/类别 BRDF 校正占位符....开发中。
|
||||
'''
|
||||
220
Flexbrdf/hytools/brdf/universal.py
Normal file
220
Flexbrdf/hytools/brdf/universal.py
Normal file
@ -0,0 +1,220 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
HyTools: Hyperspectral image processing library
|
||||
Copyright (C) 2021 University of Wisconsin
|
||||
|
||||
Authors: Adam Chlus, Zhiwei Ye, Philip Townsend.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, version 3 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
本模块包含用于计算和应用单一(“通用”)组乘法 BRDF 校正系数的函数。系数可以按飞行线计算,也可以跨多个飞行线计算。
|
||||
|
||||
"""
|
||||
from itertools import product
|
||||
from copy import deepcopy
|
||||
import numpy as np
|
||||
import ray
|
||||
from scipy.optimize import minimize
|
||||
from .kernels import calc_volume_kernel,calc_geom_kernel
|
||||
from ..misc import progbar
|
||||
from ..misc import update_brdf
|
||||
from ..masks import mask_create
|
||||
from ..plotting import universal_diagno_plot
|
||||
|
||||
def universal_brdf(actors,config_dict):
|
||||
brdf_dict = config_dict['brdf']
|
||||
|
||||
if brdf_dict['grouped']:
|
||||
actors = calc_universal_group(actors)
|
||||
else:
|
||||
_ = ray.get([a.do.remote(calc_universal_single) for a in actors])
|
||||
|
||||
if brdf_dict['diagnostic_plots']:
|
||||
print('Exporting diagnostic plots.')
|
||||
_ = ray.get([a.do.remote(universal_diagno_plot,config_dict) for a in actors])
|
||||
|
||||
def sample_kernels(hy_obj):
|
||||
'''计算并采样 BRDF 核函数
|
||||
'''
|
||||
#Sample kernel images
|
||||
geom_kernel = hy_obj.geom_kernel(hy_obj.brdf['geometric'],
|
||||
b_r=hy_obj.brdf["b/r"],
|
||||
h_b =hy_obj.brdf["h/b"])[hy_obj.mask['calc_brdf']]
|
||||
vol_kernel = hy_obj.volume_kernel(hy_obj.brdf['volume'])[hy_obj.mask['calc_brdf']]
|
||||
X = np.vstack([vol_kernel,geom_kernel,
|
||||
np.ones(vol_kernel.shape)]).T
|
||||
return X
|
||||
|
||||
def subsample_mask(hy_obj):
|
||||
'''对计算掩膜进行子采样并更新
|
||||
'''
|
||||
if hy_obj.brdf['sample_perc'] < 1:
|
||||
idx = np.array(np.where(hy_obj.mask['calc_brdf'])).T
|
||||
idx_rand= idx[np.random.choice(range(len(idx)),
|
||||
int(len(idx)*(1- hy_obj.brdf['sample_perc'])),
|
||||
replace = False)].T
|
||||
hy_obj.mask['calc_brdf'][idx_rand[0],idx_rand[1]] = False
|
||||
|
||||
def calc_universal_single(hy_obj):
|
||||
'''逐条飞行线计算 BRDF 系数。
|
||||
'''
|
||||
subsample_mask(hy_obj)
|
||||
X = sample_kernels(hy_obj)
|
||||
|
||||
hy_obj.brdf['coeffs'] = {}
|
||||
for band_num,band in enumerate(hy_obj.bad_bands):
|
||||
if ~band:
|
||||
band = hy_obj.get_band(band_num,
|
||||
corrections = hy_obj.corrections, mask='calc_brdf')
|
||||
brdf_coeff = np.linalg.lstsq(X, band,rcond=None)[0].flatten().tolist()
|
||||
hy_obj.brdf['coeffs'][band_num] = brdf_coeff
|
||||
|
||||
def calc_universal_group(actors):
|
||||
'''使用所有飞行线的合并数据计算 BRDF 系数。
|
||||
'''
|
||||
_ = ray.get([a.do.remote(subsample_mask) for a in actors])
|
||||
X = ray.get([a.do.remote(sample_kernels) for a in actors])
|
||||
X = np.concatenate(X)
|
||||
|
||||
bad_bands = ray.get(actors[0].do.remote(lambda x: x.bad_bands))
|
||||
corections = ray.get(actors[0].do.remote(lambda x: x.corrections))
|
||||
|
||||
coeffs = {}
|
||||
|
||||
for band_num,band in enumerate(bad_bands):
|
||||
if ~band:
|
||||
y = ray.get([a.get_band.remote(band_num,mask='calc_brdf',
|
||||
corrections = corections) for a in actors])
|
||||
y = np.concatenate(y)
|
||||
coeffs[band_num] = np.linalg.lstsq(X, y)[0].flatten().tolist()
|
||||
progbar(np.sum(~bad_bands[:band_num+1]),np.sum(~bad_bands))
|
||||
print('\n')
|
||||
|
||||
# 更新 BRDF 系数
|
||||
_ = ray.get([a.do.remote(update_brdf,{'key':'coeffs',
|
||||
'value': coeffs}) for a in actors])
|
||||
|
||||
return actors
|
||||
|
||||
|
||||
def apply_universal(hy_obj,data,dimension,index):
|
||||
''' 对数据切片应用通用 BRDF 校正
|
||||
|
||||
参数:
|
||||
hy_obj : Hytools 类对象。
|
||||
data (np.ndarray): 数据切片。
|
||||
index (int,list): 数据索引。
|
||||
|
||||
返回:
|
||||
data (np.ndarray): BRDF 校正后的数据切片。
|
||||
'''
|
||||
|
||||
if 'k_vol' not in hy_obj.ancillary:
|
||||
hy_obj.ancillary['k_vol'] = hy_obj.volume_kernel(hy_obj.brdf['volume'])
|
||||
if 'k_geom' not in hy_obj.ancillary:
|
||||
hy_obj.ancillary['k_geom'] = hy_obj.geom_kernel(hy_obj.brdf['geometric'],
|
||||
b_r=hy_obj.brdf["b/r"],
|
||||
h_b =hy_obj.brdf["h/b"])
|
||||
if ('k_vol_nadir' not in hy_obj.ancillary) or ('k_geom_nadir' not in hy_obj.ancillary):
|
||||
solar_zn = hy_obj.brdf['solar_zn_norm_radians'] * np.ones((hy_obj.lines,hy_obj.columns))
|
||||
hy_obj.ancillary['k_vol_nadir'] = calc_volume_kernel(0,solar_zn,
|
||||
0,0,hy_obj.brdf['volume'])
|
||||
hy_obj.ancillary['k_geom_nadir'] = calc_geom_kernel(0,solar_zn,
|
||||
0,0,hy_obj.brdf['geometric'],
|
||||
b_r=hy_obj.brdf["b/r"],
|
||||
h_b =hy_obj.brdf["h/b"])
|
||||
if 'apply_brdf' not in hy_obj.mask:
|
||||
hy_obj.gen_mask(mask_create,'apply_brdf',hy_obj.brdf['apply_mask'])
|
||||
|
||||
brdf_bands = [int(x) for x in hy_obj.brdf['coeffs'].keys()]
|
||||
fvol, fgeo, fiso = np.array([hy_obj.brdf['coeffs'][band] for band in hy_obj.brdf['coeffs'].keys()]).T
|
||||
|
||||
# 转换为浮点数
|
||||
data = data.astype(np.float32)
|
||||
|
||||
if dimension == 'line':
|
||||
|
||||
brdf = fvol[:,np.newaxis]*hy_obj.ancillary['k_vol'][[index],:]
|
||||
brdf+= fgeo[:,np.newaxis]*hy_obj.ancillary['k_geom'][[index],:]
|
||||
brdf+= fiso[:,np.newaxis]
|
||||
|
||||
brdf_nadir = fvol[:,np.newaxis]*hy_obj.ancillary['k_vol_nadir'][[index],:]
|
||||
brdf_nadir+= fgeo[:,np.newaxis]*hy_obj.ancillary['k_geom_nadir'][[index],:]
|
||||
brdf_nadir+= fiso[:,np.newaxis]
|
||||
|
||||
correction_factor = brdf_nadir/brdf
|
||||
correction_factor[:,~hy_obj.mask['apply_brdf'][index,:]] = 1
|
||||
data[:,brdf_bands] = data[:,brdf_bands]*correction_factor.T
|
||||
|
||||
elif dimension == 'column':
|
||||
|
||||
brdf = fvol[np.newaxis,:]*hy_obj.ancillary['k_vol'][:,[index]]
|
||||
brdf+= fgeo[np.newaxis,:]*hy_obj.ancillary['k_geom'][:,[index]]
|
||||
brdf+= fiso[np.newaxis,:]
|
||||
|
||||
brdf_nadir = fvol[np.newaxis,:]*hy_obj.ancillary['k_vol_nadir'][:,[index]]
|
||||
brdf_nadir+= fgeo[np.newaxis,:]*hy_obj.ancillary['k_geom_nadir'][:,[index]]
|
||||
brdf_nadir+= fiso[np.newaxis,:]
|
||||
|
||||
correction_factor = brdf_nadir/brdf
|
||||
correction_factor[~hy_obj.mask['apply_brdf'][:,index],:] = 1
|
||||
|
||||
data[:,brdf_bands] = data[:,brdf_bands]*correction_factor.T
|
||||
|
||||
elif dimension == 'band':
|
||||
fvol, fgeo, fiso = hy_obj.brdf['coeffs'][index]
|
||||
brdf = fvol*hy_obj.ancillary['k_vol']
|
||||
brdf += fgeo*hy_obj.ancillary['k_geom']
|
||||
brdf+=fiso
|
||||
|
||||
brdf_nadir = fvol*hy_obj.ancillary['k_vol_nadir']
|
||||
brdf_nadir+= fgeo*hy_obj.ancillary['k_geom_nadir']
|
||||
brdf_nadir+= fiso
|
||||
|
||||
correction_factor = brdf_nadir/brdf
|
||||
correction_factor[~hy_obj.mask['apply_brdf']] = 1
|
||||
data= data* correction_factor
|
||||
|
||||
elif dimension == 'chunk':
|
||||
x1,x2,y1,y2 = index
|
||||
|
||||
brdf = fvol[np.newaxis,np.newaxis,:]*hy_obj.ancillary['k_vol'][y1:y2,x1:x2,np.newaxis]
|
||||
brdf+= fgeo[np.newaxis,np.newaxis,:]*hy_obj.ancillary['k_geom'][y1:y2,x1:x2,np.newaxis]
|
||||
brdf+= fiso[np.newaxis,np.newaxis,:]
|
||||
|
||||
brdf_nadir = fvol[np.newaxis,np.newaxis,:]*hy_obj.ancillary['k_vol_nadir'][y1:y2,x1:x2,np.newaxis]
|
||||
brdf_nadir+= fgeo[np.newaxis,np.newaxis,:]*hy_obj.ancillary['k_geom_nadir'][y1:y2,x1:x2,np.newaxis]
|
||||
brdf_nadir+= fiso[np.newaxis,np.newaxis,:]
|
||||
|
||||
correction_factor = brdf_nadir/brdf
|
||||
correction_factor[~hy_obj.mask['apply_brdf'][y1:y2,x1:x2]] = 1
|
||||
|
||||
data[:,:,brdf_bands] = data[:,:,brdf_bands]*correction_factor
|
||||
|
||||
elif dimension == 'pixels':
|
||||
y,x = index
|
||||
|
||||
brdf = fvol[np.newaxis,:]*hy_obj.ancillary['k_vol'][y,x,np.newaxis]
|
||||
brdf+= fgeo[np.newaxis,:]*hy_obj.ancillary['k_geom'][y,x,np.newaxis]
|
||||
brdf+= fiso[np.newaxis,:]
|
||||
|
||||
brdf_nadir = fvol[np.newaxis,:]*hy_obj.ancillary['k_vol_nadir'][y,x,np.newaxis]
|
||||
brdf_nadir+= fgeo[np.newaxis,:]*hy_obj.ancillary['k_geom_nadir'][y,x,np.newaxis]
|
||||
brdf_nadir+= fiso[np.newaxis,:]
|
||||
|
||||
correction_factor = brdf_nadir/brdf
|
||||
correction_factor[~hy_obj.mask['apply_brdf'][y,x]] = 1
|
||||
|
||||
data[:,brdf_bands] = data[:,brdf_bands]*correction_factor
|
||||
|
||||
return data
|
||||
Reference in New Issue
Block a user