Initial commit
This commit is contained in:
25
Flexbrdf/hytools/glint/__init__.py
Normal file
25
Flexbrdf/hytools/glint/__init__.py
Normal file
@ -0,0 +1,25 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
HyTools: Hyperspectral image processing library
|
||||
Copyright (C) 2021 University of Wisconsin
|
||||
|
||||
Authors: Evan Greenberg.
|
||||
|
||||
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/>.
|
||||
|
||||
The :mod:`hytools.correction` module include functions image correction.
|
||||
"""
|
||||
from .glint import *
|
||||
from .gao_2021 import *
|
||||
from .hedley_2005 import *
|
||||
from .hochberg_2003 import *
|
||||
216
Flexbrdf/hytools/glint/gao_2021.py
Normal file
216
Flexbrdf/hytools/glint/gao_2021.py
Normal file
@ -0,0 +1,216 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
HyTools: Hyperspectral image processing library
|
||||
Copyright (C) 2021 University of Wisconsin
|
||||
|
||||
Authors: Evan Greenberg.
|
||||
|
||||
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/>.
|
||||
"""
|
||||
import numpy as np
|
||||
from ..masks import mask_create
|
||||
|
||||
|
||||
REFRACTIVE_INDICES = np.array([
|
||||
[200, 1.396],
|
||||
[225, 1.373],
|
||||
[250, 1.362],
|
||||
[275, 1.354],
|
||||
[300, 1.349],
|
||||
[325, 1.346],
|
||||
[350, 1.343],
|
||||
[375, 1.341],
|
||||
[400, 1.339],
|
||||
[425, 1.338],
|
||||
[450, 1.337],
|
||||
[475, 1.336],
|
||||
[500, 1.335],
|
||||
[525, 1.334],
|
||||
[550, 1.333],
|
||||
[575, 1.333],
|
||||
[600, 1.332],
|
||||
[625, 1.332],
|
||||
[650, 1.331],
|
||||
[675, 1.331],
|
||||
[700, 1.331],
|
||||
[725, 1.33],
|
||||
[750, 1.33],
|
||||
[775, 1.33],
|
||||
[800, 1.329],
|
||||
[825, 1.329],
|
||||
[850, 1.329],
|
||||
[875, 1.328],
|
||||
[900, 1.328],
|
||||
[925, 1.328],
|
||||
[950, 1.327],
|
||||
[975, 1.327],
|
||||
[1000, 1.327],
|
||||
[1200, 1.324],
|
||||
[1400, 1.321],
|
||||
[1600, 1.317],
|
||||
[1800, 1.312],
|
||||
[2000, 1.306],
|
||||
[2200, 1.296],
|
||||
[2400, 1.279],
|
||||
[2600, 1.242],
|
||||
[2650, 1.219],
|
||||
[2700, 1.188],
|
||||
[2750, 1.157],
|
||||
[2800, 1.142],
|
||||
[2850, 1.149],
|
||||
[2900, 1.201],
|
||||
[2950, 1.292],
|
||||
[3000, 1.371]
|
||||
])
|
||||
|
||||
|
||||
def apply_gao_2021_correction(hy_obj, data, dimension, index):
|
||||
"""
|
||||
Glint correction algorithm following:
|
||||
|
||||
Gao BC, Li RR.
|
||||
Correction of Sunglint Effects in High Spatial Resolution
|
||||
Hyperspectral Imagery Using SWIR or NIR Bands and Taking Account of
|
||||
Spectral Variation of Refractive Index of Water.
|
||||
Adv Environ Eng Res 2021;2(3):16; doi:10.21926/aeer.2103017.
|
||||
"""
|
||||
|
||||
|
||||
if 'apply_glint' not in hy_obj.mask:
|
||||
hy_obj.gen_mask(mask_create,'apply_glint',hy_obj.glint['apply_mask'])
|
||||
|
||||
if hy_obj.mask['apply_glint'].sum() == 0:
|
||||
return data
|
||||
|
||||
hy_obj.glint['correction_band'] = hy_obj.wave_to_band(hy_obj.glint['correction_wave'])
|
||||
|
||||
if 'gao_b_simu' not in hy_obj.ancillary:
|
||||
hy_obj.ancillary['gao_b_simu'] = get_b_simu(hy_obj)
|
||||
|
||||
if 'gao_rto' not in hy_obj.ancillary:
|
||||
hy_obj.ancillary['gao_rto'] = get_rto(hy_obj)
|
||||
|
||||
if dimension == 'line':
|
||||
rto_line = hy_obj.ancillary['gao_rto'][index, :]
|
||||
rto_line = np.reshape(rto_line, (len(rto_line), 1))
|
||||
correction = rto_line * hy_obj.ancillary['gao_b_simu']
|
||||
|
||||
elif dimension == 'column':
|
||||
rto_col = hy_obj.ancillary['gao_rto'][:, index]
|
||||
rto_col = np.reshape(rto_col, (len(rto_col), 1))
|
||||
correction = rto_col * hy_obj.ancillary['gao_b_simu']
|
||||
|
||||
elif (dimension == 'band'):
|
||||
correction = (
|
||||
hy_obj.ancillary['gao_b_simu'][0, :][index]
|
||||
* hy_obj.ancillary['gao_rto']
|
||||
)
|
||||
|
||||
elif dimension == 'chunk':
|
||||
x1, x2, y1, y2 = index
|
||||
rto_chunk = hy_obj.ancillary['gao_rto'][y1:y2, x1:x2]
|
||||
rto_chunk = np.reshape(
|
||||
rto_chunk,
|
||||
(
|
||||
rto_chunk.shape[0],
|
||||
rto_chunk.shape[1],
|
||||
1
|
||||
)
|
||||
)
|
||||
correction = rto_chunk * hy_obj.ancillary['gao_b_simu']
|
||||
|
||||
elif dimension == 'pixels':
|
||||
y, x = index
|
||||
rto_pixels = hy_obj.ancillary['gao_rto'][y, x]
|
||||
rto_pixels = np.reshape(rto_pixels, (len(rto_pixels), 1))
|
||||
correction = rto_pixels * hy_obj.ancillary['gao_b_simu']
|
||||
|
||||
return data - correction
|
||||
|
||||
|
||||
def zenith_refracted(theta, n):
|
||||
"""
|
||||
Find zenith of the outgoing reflected light
|
||||
n is the refractive index of water at a specific wavelength
|
||||
"""
|
||||
theta_p = np.degrees(
|
||||
np.arcsin(np.sin(np.radians(theta)) / n)
|
||||
)
|
||||
|
||||
return theta_p
|
||||
|
||||
|
||||
def fresnel_reflectence(theta, theta_p):
|
||||
"""
|
||||
Uses the fresnel equation to find the
|
||||
percentege of incident light reflected
|
||||
"""
|
||||
theta_rad = np.radians(theta)
|
||||
theta_p_rad = np.radians(theta_p)
|
||||
|
||||
return (
|
||||
(
|
||||
(np.sin(theta_rad - theta_p_rad)**2)
|
||||
/ (np.sin(theta_rad + theta_p_rad)**2)
|
||||
) + (
|
||||
(np.tan(theta_rad - theta_p_rad)**2)
|
||||
/ (np.tan(theta_rad + theta_p_rad)**2)
|
||||
)
|
||||
) / 2
|
||||
|
||||
|
||||
def fresnel_spectra(theta, xs, ns):
|
||||
"""
|
||||
Solves for the spectrum of reflected light
|
||||
according to fresnels equations
|
||||
"""
|
||||
spectra = []
|
||||
for x in xs:
|
||||
n = np.interp(x, ns[:, 0], ns[:, 1])
|
||||
theta_p = zenith_refracted(theta, n)
|
||||
spectra.append(fresnel_reflectence(theta, theta_p))
|
||||
|
||||
return np.array(spectra)
|
||||
|
||||
|
||||
def get_b_simu(hy_obj):
|
||||
b_simu = fresnel_spectra(
|
||||
10**-5,
|
||||
hy_obj.wavelengths,
|
||||
REFRACTIVE_INDICES
|
||||
)
|
||||
|
||||
return np.reshape(
|
||||
b_simu, (1, len(b_simu))
|
||||
)
|
||||
|
||||
|
||||
def get_rto(hy_obj):
|
||||
b_ref = hy_obj.get_wave(hy_obj.glint['correction_wave'])
|
||||
|
||||
b_ref_min = np.percentile(
|
||||
b_ref[
|
||||
(hy_obj.mask['apply_glint'])
|
||||
& (b_ref > 0)
|
||||
],
|
||||
.0001
|
||||
)
|
||||
b_ref = b_ref - b_ref_min
|
||||
|
||||
rto = (
|
||||
b_ref
|
||||
/ hy_obj.ancillary['gao_b_simu'][0, :][hy_obj.glint['correction_band']]
|
||||
)
|
||||
rto[~hy_obj.mask['apply_glint']] = 0
|
||||
|
||||
return rto
|
||||
75
Flexbrdf/hytools/glint/glint.py
Normal file
75
Flexbrdf/hytools/glint/glint.py
Normal file
@ -0,0 +1,75 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
HyTools: Hyperspectral image processing library
|
||||
Copyright (C) 2021 University of Wisconsin
|
||||
|
||||
Authors: Evan Greenberg.
|
||||
|
||||
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/>.
|
||||
"""
|
||||
import ray
|
||||
from ..misc import set_glint
|
||||
from .hochberg_2003 import apply_hochberg_2003_correction
|
||||
from .gao_2021 import apply_gao_2021_correction
|
||||
from .hedley_2005 import apply_hedley_2005_correction
|
||||
|
||||
|
||||
def set_glint_parameters(actors, config_dict):
|
||||
# Assign glint dict
|
||||
glint_dict = config_dict['glint']
|
||||
|
||||
# Set Glint dict
|
||||
_ = ray.get([
|
||||
a.do.remote(set_glint, glint_dict) for a in actors
|
||||
])
|
||||
|
||||
# Add glint correction
|
||||
_ = ray.get([
|
||||
a.do.remote(lambda x: x.corrections.append('glint')) for a in actors
|
||||
])
|
||||
|
||||
def set_glint_parameters_single(hy_obj, config_dict):
|
||||
# Assign glint dict
|
||||
glint_dict = config_dict['glint']
|
||||
|
||||
# Set Glint dict
|
||||
set_glint(hy_obj, glint_dict)
|
||||
|
||||
# Add glint correction
|
||||
hy_obj.corrections.append('glint')
|
||||
|
||||
|
||||
def apply_glint_correct(hy_obj, data, dimension, index):
|
||||
''' Corrects glint based on the specified algorithm in the config.
|
||||
Options include:
|
||||
Hochberg et al., 2003: hochberg
|
||||
Gao et al., 2021: gao
|
||||
Hedley et al. 2005: hedley
|
||||
...
|
||||
'''
|
||||
|
||||
# Perform one of the corrections
|
||||
if hy_obj.glint['type'] == 'hochberg':
|
||||
data = apply_hochberg_2003_correction(hy_obj, data, dimension, index)
|
||||
|
||||
elif hy_obj.glint['type'] == 'gao':
|
||||
data = apply_gao_2021_correction(hy_obj, data, dimension, index)
|
||||
|
||||
elif hy_obj.glint['type'] == 'hedley':
|
||||
data = apply_hedley_2005_correction(hy_obj, data, dimension, index)
|
||||
|
||||
#Truncate reflectance values below 0
|
||||
if hy_obj.glint['truncate']:
|
||||
data[(data < 0) & (data != hy_obj.no_data)]= 0
|
||||
|
||||
return data
|
||||
140
Flexbrdf/hytools/glint/hedley_2005.py
Normal file
140
Flexbrdf/hytools/glint/hedley_2005.py
Normal file
@ -0,0 +1,140 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
HyTools: Hyperspectral image processing library
|
||||
Copyright (C) 2021 University of Wisconsin
|
||||
|
||||
Authors: Evan Greenberg.
|
||||
|
||||
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/>.
|
||||
"""
|
||||
import numpy as np
|
||||
from scipy import stats
|
||||
from ..masks import mask_create
|
||||
|
||||
|
||||
def apply_hedley_2005_correction(hy_obj, data, dimension, index):
|
||||
"""
|
||||
Glint correction algorithm following:
|
||||
|
||||
Hedley, J. D., Harborne, A. R., & Mumby, P. J. (2005).
|
||||
Simple and robust removal of sun glint for mapping shallow‐water benthos.
|
||||
International Journal of Remote Sensing, 26(10), 2107-2112.
|
||||
"""
|
||||
# Raise exception is there is no deep water sample provided
|
||||
if isinstance(hy_obj.glint.get('deep_water_sample'), type(None)):
|
||||
raise KeyError("No Deep Water Sample Provided")
|
||||
|
||||
if 'apply_glint' not in hy_obj.mask:
|
||||
hy_obj.gen_mask(mask_create,'apply_glint',hy_obj.glint['apply_mask'])
|
||||
|
||||
if hy_obj.mask['apply_glint'].sum() == 0:
|
||||
return data
|
||||
|
||||
hy_obj.glint['correction_band'] = hy_obj.wave_to_band(
|
||||
hy_obj.glint['correction_wave']
|
||||
)
|
||||
|
||||
if 'hedley_slopes' not in hy_obj.ancillary:
|
||||
hy_obj.ancillary['hedley_slopes'] = optimize_slopes(hy_obj)
|
||||
|
||||
if 'hedley_nir_swir_diff' not in hy_obj.ancillary:
|
||||
hy_obj.ancillary['hedley_nir_swir_diff'] = nir_swir_diff(hy_obj)
|
||||
|
||||
if dimension == 'line':
|
||||
correction = (
|
||||
hy_obj.ancillary['hedley_nir_swir_diff'][index, :].reshape(-1, 1)
|
||||
* hy_obj.ancillary['hedley_slopes']
|
||||
)
|
||||
correction[~hy_obj.mask['apply_glint'][index, :], :] = 0
|
||||
|
||||
elif dimension == 'column':
|
||||
correction = (
|
||||
hy_obj.ancillary['hedley_nir_swir_diff'][:, index].reshape(-1, 1)
|
||||
* hy_obj.ancillary['hedley_slopes']
|
||||
)
|
||||
correction[~hy_obj.mask['apply_glint'][:, index], :] = 0
|
||||
|
||||
elif (dimension == 'band'):
|
||||
correction = (
|
||||
hy_obj.ancillary['hedley_nir_swir_diff']
|
||||
* hy_obj.ancillary['hedley_slopes'][0, index]
|
||||
)
|
||||
correction[~hy_obj.mask['apply_glint']] = 0
|
||||
|
||||
elif dimension == 'chunk':
|
||||
x1, x2, y1, y2 = index
|
||||
corr_diff = hy_obj.ancillary['hedley_nir_swir_diff'][y1:y2, x1:x2]
|
||||
bandnums = data.shape[2]
|
||||
corr_diff = np.repeat(
|
||||
corr_diff[:, :, np.newaxis],
|
||||
bandnums,
|
||||
axis=2
|
||||
)
|
||||
|
||||
correction = corr_diff * hy_obj.ancillary['hedley_slopes']
|
||||
correction[~hy_obj.mask['apply_glint'][y1:y2, x1:x2], :] = 0
|
||||
|
||||
elif dimension == 'pixels':
|
||||
y, x = index
|
||||
|
||||
correction = (
|
||||
hy_obj.ancillary['hedley_nir_swir_diff'][y, x].reshape(-1, 1)
|
||||
* hy_obj.ancillary['hedley_slopes']
|
||||
)
|
||||
correction[~hy_obj.mask['apply_glint'][y, x], :] = 0
|
||||
|
||||
return data - correction
|
||||
|
||||
|
||||
def optimize_slopes(hy_obj):
|
||||
deep_water = hy_obj.get_chunk(
|
||||
*hy_obj.glint['deep_water_sample'][hy_obj.file_name]
|
||||
)
|
||||
|
||||
deep_correction = (
|
||||
deep_water[:, :, hy_obj.glint['correction_band']].flatten()
|
||||
)
|
||||
|
||||
# Iterate through each band to find the band-slope
|
||||
slopes = np.empty([1, len(hy_obj.wavelengths)])
|
||||
for i, band in enumerate(hy_obj.wavelengths):
|
||||
# Get flattened deep water sample of band
|
||||
wave_num = np.argmin(
|
||||
np.abs(hy_obj.wavelengths - band)
|
||||
)
|
||||
wave = deep_water[:, :, wave_num].flatten()
|
||||
|
||||
# Regress
|
||||
(
|
||||
slope,
|
||||
intercept,
|
||||
r_value,
|
||||
p_value,
|
||||
std_err
|
||||
) = stats.linregress(
|
||||
deep_correction,
|
||||
wave
|
||||
)
|
||||
slopes[0, i] = slope
|
||||
|
||||
return slopes
|
||||
|
||||
|
||||
def nir_swir_diff(hy_obj):
|
||||
nir_swir_array = np.copy(
|
||||
hy_obj.get_wave(hy_obj.glint['correction_wave'])
|
||||
)
|
||||
nir_swir_array[~hy_obj.mask['apply_glint']] = 0
|
||||
nir_swir_min = np.percentile(nir_swir_array[nir_swir_array > 0], .0001)
|
||||
|
||||
return nir_swir_array - nir_swir_min
|
||||
88
Flexbrdf/hytools/glint/hochberg_2003.py
Normal file
88
Flexbrdf/hytools/glint/hochberg_2003.py
Normal file
@ -0,0 +1,88 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
HyTools: Hyperspectral image processing library
|
||||
Copyright (C) 2021 University of Wisconsin
|
||||
|
||||
Authors: Evan Greenberg.
|
||||
|
||||
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/>.
|
||||
"""
|
||||
import numpy as np
|
||||
from ..masks import mask_create
|
||||
|
||||
|
||||
def apply_hochberg_2003_correction(hy_obj, data, dimension, index):
|
||||
"""
|
||||
Glint correction algorithm following:
|
||||
|
||||
Hochberg, EJ, Andréfouët, S and Tyler, MR. 2003.
|
||||
Sea surface correction of high spatial resolution Ikonos images to
|
||||
improve bottom mapping in near‐shore environments..
|
||||
IEEE Transactions on Geoscience and Remote Sensing, 41: 1724–1729.
|
||||
"""
|
||||
|
||||
if 'apply_glint' not in hy_obj.mask:
|
||||
hy_obj.gen_mask(mask_create,'apply_glint',hy_obj.glint['apply_mask'])
|
||||
|
||||
if hy_obj.mask['apply_glint'].sum() == 0:
|
||||
return data
|
||||
|
||||
if 'hochberg_correction' not in hy_obj.ancillary:
|
||||
hy_obj.ancillary['hochberg_correction'] = (
|
||||
get_hochberg_correction(hy_obj)
|
||||
)
|
||||
|
||||
if dimension == 'line':
|
||||
correction = hy_obj.ancillary['hochberg_correction'][index, :][:,np.newaxis]
|
||||
|
||||
elif dimension == 'column':
|
||||
correction = hy_obj.ancillary['hochberg_correction'][:, index][np.newaxis,:]
|
||||
|
||||
elif dimension == 'band':
|
||||
correction = hy_obj.ancillary['hochberg_correction']
|
||||
|
||||
elif dimension == 'chunk':
|
||||
x1, x2, y1, y2 = index
|
||||
correction = hy_obj.ancillary['hochberg_correction'][y1:y2, x1:x2]
|
||||
|
||||
elif dimension == 'pixels':
|
||||
y, x = index
|
||||
correction = hy_obj.ancillary['hochberg_correction'][y, x]
|
||||
|
||||
return data - correction
|
||||
|
||||
def get_hochberg_correction(hy_obj):
|
||||
"""
|
||||
Calculates the hochberg correction across entire image.
|
||||
Uses the NIR or SWIR wavelengths to find the amount of signal
|
||||
attributed to glint. Zeros out non-water pixels
|
||||
"""
|
||||
|
||||
if isinstance(hy_obj.glint['correction_wave'],list):
|
||||
nir_swir_array = np.zeros((hy_obj.lines,hy_obj.columns))
|
||||
for wave in hy_obj.glint['correction_wave']:
|
||||
nir_swir_array+= hy_obj.get_wave(wave)
|
||||
nir_swir_array/=len(hy_obj.glint['correction_wave'])
|
||||
else:
|
||||
nir_swir_array = np.copy(hy_obj.get_wave(hy_obj.glint['correction_wave']))
|
||||
|
||||
nir_swir_array[~hy_obj.mask['apply_glint']] = 0
|
||||
|
||||
nir_swir_min = np.percentile(
|
||||
nir_swir_array[nir_swir_array > 0], .001
|
||||
)
|
||||
|
||||
hochberg_correction = nir_swir_array - nir_swir_min
|
||||
hochberg_correction[~hy_obj.mask['apply_glint']] = 0
|
||||
|
||||
return hochberg_correction
|
||||
Reference in New Issue
Block a user