# -*- 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 .
Cloud masks
'''
from scipy.ndimage import median_filter
import numpy as np
def zhai_cloud(hy_obj,cloud,shadow,T1=0.01,t2=.1,t3=.25,t4=.5,T7= 9,T8= 9):
'''This function replicates the method of Zhai et al. (2018) for detecting clouds and shadows in
multispectral and hyperspectral imagery but does not apply shadow spatial refinement.
Suggested values for coefficients and params:
T1 : 0.01, 0.1, 1, 10, 100
t2 : 1/10, 1/9, 1/8, 1/7, 1/6, 1/5, 1/4, 1/3, 1/2
t3 : 1/4, 1/3, 1/2, 2/3, 3/4
t4 : 1/2, 2/3, 3/4, 4/5, 5/6
T7 : 3, 5, 7, 9, 11
T8 : 3, 5, 7, 9, 11
Zhai, H., Zhang, H., Zhang, L., & Li, P. (2018).
Cloud/shadow detection based on spectral indices for multi/hyperspectral optical remote sensing imagery.
ISPRS journal of photogrammetry and remote sensing, 144, 235-253.
https://doi.org/10.1016/j.isprsjprs.2018.07.006
Args:
hy_obj : HyTools data container object:
cloud (bool): Detect clouds.
shadow (bool): Detect clouds.
T1 (float): Threshold T1.
t2 (float): Adjusting coefficient t2.
t3 (float): Adjusting coefficient t3.
t4 (float): Adjusting coefficient t4.
T7 (float): Parameter T7.
T8 (float): Parameter T8.
Returns:
mask (nd.array): Boolean array where detected clouds and/or shadows = True.
'''
blue= hy_obj.get_wave(440)
green= hy_obj.get_wave(550)
red= hy_obj.get_wave(660)
nir = hy_obj.get_wave(850)
#If SWIR not available
if hy_obj.wavelengths.max() < 1570:
# Zhai et al. 2018 Eq. 1a,b
CI_1 = (3*nir)/(blue+green+red)
CI_2 = (blue+green+red+nir)/4
# Zhai et al. 2018 Eq. 3
CSI = nir
else:
swir1 = hy_obj.get_wave(1570)
swir2= hy_obj.get_wave(2110)
# Zhai et al. 2018 Eq. 1a,b
CI_1 = (nir+ 2*swir1)/(blue+green+red)
CI_2 = (blue+green+red+nir+swir1+swir2)/6
# Zhai et al. 2018 Eq. 3
CSI = (nir + swir1)/2
# Zhai et al. 2018 Eq.5
T2 = np.mean(CI_2[hy_obj.mask['no_data']]) + t2*(np.max(CI_2[hy_obj.mask['no_data']])-np.mean(CI_2[hy_obj.mask['no_data']]))
# Zhai et al. 2018 Eq.6
T3 = np.min(CSI[hy_obj.mask['no_data']]) + t3*(np.mean(CSI[hy_obj.mask['no_data']])-np.min(CSI[hy_obj.mask['no_data']]))
# Zhai et al. 2018 Eq.7
T4 = np.min(blue[hy_obj.mask['no_data']]) + t4*(np.mean(blue[hy_obj.mask['no_data']])-np.min(blue[hy_obj.mask['no_data']]))
mask = np.zeros((hy_obj.lines,hy_obj.columns)).astype(bool)
if cloud:
clouds = (np.abs(CI_1) < T1) | (CI_2 > T2)
clouds = median_filter(clouds, T7)
mask[clouds] = True
if shadow:
shadows = (CSI