# -*- 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 . Spectral resampling functions. """ import numpy as np from scipy.interpolate import interp1d def gaussian(x,mu,fwhm): """ Args: x (numpy.ndarray): Values along which to generate gaussian.. mu (float): Mean of the gaussian function.. fwhm (float): Full width half maximum.. Returns: numpy.ndarray: Gaussian along input range. """ c = fwhm/(2* np.sqrt(2*np.log(2))) return np.exp(-1*((x-mu)**2/(2*c**2))) def calc_resample_coeffs(in_wave,in_fwhm,out_wave,out_fwhm, spacing = 1): """Given a set of source and destination wavelengths and FWHMs this function caculates the relative contribution or each input wavelength to the output wavelength. It assumes that both input and output response functions follow a gaussian distribution. All inputs shoud be provide in nanometers. Args: in_wave (list): Input wavelength centers. in_fwhm (list): Input full width half maxes. out_wave (list): Output wavelength centers. out_fwhm (list): Output full width half maxes. spacing (int, optional): Resolution at which to model the spectral response functions. Defaults to 1. Returns: numpy.ndarray: Transform coeffiecients. """ out_matrix = [] min_spectrum = min(out_wave.min(),in_wave.min())//100 *100 - 100 max_spectrum = 100 + max(out_wave.max(),in_wave.max())//100 *100 one_nm = np.arange(min_spectrum,max_spectrum,spacing) for wave,fwhm, in zip(out_wave,out_fwhm): a = gaussian(one_nm,wave,fwhm) out_matrix.append(np.divide(a,np.sum(a))) out_matrix = np.array(out_matrix) # For each source wavelength generate the gaussion response in_matrix = [] for wave,fwhm in zip(in_wave,in_fwhm): in_matrix.append(gaussian(one_nm ,wave,fwhm)) in_matrix = np.array(in_matrix) # Calculate the relative contribution of each source response function ratio = in_matrix/in_matrix.sum(axis=0) ratio[np.isnan(ratio)] = 0 ratio2 = np.einsum('ab,cb->acb',ratio,out_matrix) # Calculate the relative contribution of each input wavelength # to each destination wavelength coeffs = np.trapz(ratio2) return coeffs def apply_resampler(hy_obj,data): ''' Apply SCSS correction to a slice of the data Args: hy_obj (TYPE): DESCRIPTION. band (TYPE): DESCRIPTION. index (TYPE): DESCRIPTION. Returns: band (TYPE): DESCRIPTION. ''' interp_types = ['linear', 'nearest', 'nearest-up', 'zero', 'slinear', 'quadratic', 'cubic'] #Convert to float data = data.astype(np.float32) if hy_obj.resampler['type'] == 'gaussian': # Load resampling coeffs to memory if needed if 'resample_coeffs' not in hy_obj.ancillary.keys(): in_wave = hy_obj.wavelengths[~hy_obj.bad_bands] in_fwhm =hy_obj.fwhm[~hy_obj.bad_bands] resample_coeffs = calc_resample_coeffs(in_wave,in_fwhm, hy_obj.resampler['out_waves'], hy_obj.resampler['out_fwhm']) hy_obj.ancillary['resample_coeffs'] = resample_coeffs data = np.dot(data, hy_obj.ancillary['resample_coeffs'] ) elif hy_obj.resampler['type'] in interp_types: interp_func = interp1d(hy_obj.wavelengths[~hy_obj.bad_bands], data, kind=hy_obj.resampler['type'], axis=2, fill_value="extrapolate") data = interp_func(hy_obj.resampler['out_waves']) return data