def interp_atm_lut(atm_lut_file, WVC, VIS, VZA, RAA): """ Interpolate atmosphere look-up-table to different water vapor columns (WVC), visibilities (VIS), view zenith angles (VZA) and relative azimuth angles (RAA). Parameters ---------- atm_lut_file: str Atmosphere look-up-table filename. WVC, VIS, VZA, RAA: list of floats Water vapor column, visibility, view zenith angles and relative azimuth angles. Returns ------- WAVE: array Wavelengths of the atmosphere look-up-table radiance. lut_rdn: 2D array Interpolated path radiance (albedo=0.0, 0.5, 1.0). """ from AtmLUT import read_binary_metadata, get_interp_range, combos # Read atmospheric lookup table grids atm_lut_metadata = read_binary_metadata(atm_lut_file + '.meta') atm_lut_metadata['shape'] = tuple( [int(v) for v in atm_lut_metadata['shape']]) atm_lut_WVC = np.array([float(v) for v in atm_lut_metadata['WVC']]) atm_lut_VIS = np.array([float(v) for v in atm_lut_metadata['VIS']]) atm_lut_VZA = np.array([float(v) for v in atm_lut_metadata['VZA']]) atm_lut_RAA = np.array([float(v) for v in atm_lut_metadata['RAA']]) atm_lut_WAVE = np.array([float(v) for v in atm_lut_metadata['WAVE']]) # Read atmospheric lookup table data atm_lut = np.memmap(atm_lut_file, dtype=atm_lut_metadata['dtype'], mode='r', shape=atm_lut_metadata['shape'] ) # shape=(RHO, WVC, VIS, VZA, RAA, WAVE) # Initialize interpolated radiance interp_rdn = np.zeros((len(WVC), len(atm_lut_WAVE)), dtype='float32') # Do interpolation for i in range(len(WVC)): wvc, vis, vza, raa = WVC[i], VIS[i], VZA[i], RAA[i] # Get interpolation ranges wvc_dict = get_interp_range(atm_lut_WVC, wvc) vis_dict = get_interp_range(atm_lut_VIS, vis) vza_dict = get_interp_range(atm_lut_VZA, vza) raa_dict = get_interp_range(atm_lut_RAA, raa) # Get combos index_combos = combos([ list(wvc_dict.keys()), list(vis_dict.keys()), list(vza_dict.keys()), list(raa_dict.keys()) ]) # Update interpolated radiance for index_combo in index_combos: wvc_index, vis_index, vza_index, raa_index = index_combo interp_rdn[i, :] += atm_lut[ 1, wvc_index, vis_index, vza_index, raa_index, :] * wvc_dict[wvc_index] * vis_dict[ vis_index] * vza_dict[vza_index] * raa_dict[raa_index] del index_combo, index_combos # Clear atmosphere look-up table atm_lut.flush() del atm_lut return atm_lut_WAVE, interp_rdn
def atm_corr_image(flight_dict): """ Do atmospheric corrections on the whole image. Arguments: flight_dict: dict Flight dictionary. """ if os.path.exists(flight_dict['refl_file']): logger.info('Write the reflectance image to %s.' % flight_dict['refl_file']) return from ENVI import read_envi_header, write_envi_header from AtmLUT import read_binary_metadata # Read radiance image. rdn_header = read_envi_header( os.path.splitext(flight_dict['merged_rdn_file'])[0] + '.hdr') # rdn_image = np.memmap(flight_dict['merged_rdn_file'], # dtype='float32', # mode='r', # shape=(rdn_header['bands'], # rdn_header['lines'], # rdn_header['samples'])) # Read atmospheric lookup table. atm_lut_metadata = read_binary_metadata( flight_dict['resampled_atm_lut_file'] + '.meta') atm_lut_metadata['shape'] = tuple( [int(v) for v in atm_lut_metadata['shape']]) atm_lut_WVC = np.array([float(v) for v in atm_lut_metadata['WVC']]) atm_lut_VIS = np.array([float(v) for v in atm_lut_metadata['VIS']]) atm_lut_VZA = np.array([float(v) for v in atm_lut_metadata['VZA']]) atm_lut_RAA = np.array([float(v) for v in atm_lut_metadata['RAA']]) atm_lut = np.memmap(flight_dict['resampled_atm_lut_file'], dtype=atm_lut_metadata['dtype'], mode='r', shape=atm_lut_metadata['shape'] ) # shape = (RHO, WVC, VIS, VZA, RAA, WAVE) # Read VZA and RAA image. sca_header = read_envi_header( os.path.splitext(flight_dict['merged_sca_file'])[0] + '.hdr') saa = float(sca_header['sun azimuth']) sca_image = np.memmap(flight_dict['merged_sca_file'], dtype='float32', shape=(sca_header['bands'], sca_header['lines'], sca_header['samples'])) # vza vza_image = np.copy(sca_image[0, :, :]) # raa raa_image = saa - sca_image[1, :, :] raa_image[raa_image < 0] += 360.0 raa_image[raa_image > 180] = 360.0 - raa_image[raa_image > 180] # clear data sca_image.flush() del sca_header, saa del sca_image # Read wvc and vis image. wvc_header = read_envi_header( os.path.splitext(flight_dict['wvc_file'])[0] + '.hdr') tmp_wvc_image = np.memmap(flight_dict['wvc_file'], mode='r', dtype='float32', shape=(wvc_header['lines'], wvc_header['samples'])) wvc_image = np.copy(tmp_wvc_image) vis_header = read_envi_header( os.path.splitext(flight_dict['vis_file'])[0] + '.hdr') tmp_vis_image = np.memmap(flight_dict['vis_file'], dtype='float32', mode='r', shape=(vis_header['lines'], vis_header['samples'])) vis_image = np.copy(tmp_vis_image) tmp_wvc_image.flush() tmp_vis_image.flush() del wvc_header, vis_header del tmp_vis_image, tmp_wvc_image # Read background mask. bg_header = read_envi_header( os.path.splitext(flight_dict['background_mask_file'])[0] + '.hdr') bg_mask = np.memmap(flight_dict['background_mask_file'], dtype='bool', mode='r', shape=(bg_header['lines'], bg_header['samples'])) idx = ~bg_mask max_WVC = atm_lut_WVC.max() max_VIS = atm_lut_VIS.max() max_VZA = atm_lut_VZA.max() max_RAA = atm_lut_RAA.max() wvc_image[wvc_image >= max_WVC] = max_WVC - 0.1 vis_image[vis_image >= max_VIS] = max_VIS - 0.1 vza_image[vza_image >= max_VZA] = max_VZA - 0.1 raa_image[raa_image >= max_RAA] = max_RAA - 0.1 del max_WVC, max_VIS, max_VZA, max_RAA # remove outliers in wvc and vis. wvc = wvc_image[idx] avg_wvc = wvc.mean() std_wvc = wvc.std() index = (np.abs(wvc_image - avg_wvc) > 2 * std_wvc) & (idx) wvc_image[index] = avg_wvc del wvc vis = vis_image[idx] avg_vis = vis.mean() std_vis = vis.std() index = (np.abs(vis_image - avg_vis) > 2 * std_vis) & (idx) vis_image[index] = avg_vis del vis del index del idx fid = open(flight_dict['refl_file'], 'wb') # Do atmosphere correction. info = 'Bands = ' for band in range(rdn_header['bands']): if band % 20 == 0: info += '%d, ' % (band + 1) if (rdn_header['wavelength'][band] >= 1340.0 and rdn_header['wavelength'][band] <= 1440.0) or ( rdn_header['wavelength'][band] >= 1800.0 and rdn_header['wavelength'][band] <= 1980.0 ) or rdn_header['wavelength'][band] >= 2460.0: # fid.write(np.zeros((rdn_header['lines'], rdn_header['samples'])).astype('float32').tostring()) fid.write( np.zeros((rdn_header['lines'], rdn_header['samples'] )).astype('int16').tostring()) # in int, by Ting else: # offset = rdn_header['header offset']+4*band*rdn_header['lines']*rdn_header['samples']# in bytes offset = rdn_header[ 'header offset'] + 2 * band * rdn_header['lines'] * rdn_header[ 'samples'] # in bytes, int16 consists 2 bytes, by Ting rdn_image = np.memmap( flight_dict['merged_rdn_file'], # dtype='float32', dtype='int16', # in int, by Ting mode='r', offset=offset, shape=(rdn_header['lines'], rdn_header['samples'])) refl = atm_corr_band( atm_lut_WVC, atm_lut_VIS, atm_lut_VZA, atm_lut_RAA, np.copy(atm_lut[..., band]), wvc_image, vis_image, vza_image, raa_image, rdn_image / 1000, # divided by 1000 to convert back to original rdn, by Ting. bg_mask) refl = refl * 10000 # reflectance times 10000 to convert to int, by Ting # fid.write(refl.astype('float32').tostring()) fid.write(refl.astype('int16').tostring()) # save in int, by Ting rdn_image.flush() del refl, rdn_image fid.close() info += '%d, Done!' % band logger.info(info) # Clear data del wvc_image, vis_image, vza_image, raa_image atm_lut.flush() bg_mask.flush() del atm_lut, bg_mask rdn_header['description'] = 'Reflectance [0-1]' write_envi_header( os.path.splitext(flight_dict['refl_file'])[0] + '.hdr', rdn_header) logger.info('Write the reflectance image to %s.' % flight_dict['refl_file'])
def build_wvc_model(wvc_model_file, atm_lut_file, rdn_header_file, vis=40): """ Build water vapor models. Parameters ---------- wvc_model_file: str Water vapor column model filename. atm_lut_file: str Atmosphere lookup table file. rdn_header_file: str Radiance header filename. vis: float Visibility in [km]. """ if os.path.exists(wvc_model_file): logger.info('Write WVC models to %s.' % wvc_model_file) return from AtmLUT import read_binary_metadata, get_interp_range from ENVI import read_envi_header from Spectra import get_closest_wave, resample_spectra import json # Get sensor wavelengths & FWHMs header = read_envi_header(rdn_header_file) sensor_waves = np.array(header['wavelength']) sensor_fwhms = np.array(header['fwhm']) # Read atmospheric lookup table (ALT) metadata metadata = read_binary_metadata(atm_lut_file + '.meta') metadata['shape'] = tuple([int(v) for v in metadata['shape']]) atm_lut_WVC = np.array([float(v) for v in metadata['WVC']]) atm_lut_VIS = np.array([float(v) for v in metadata['VIS']]) atm_lut_VZA = np.array([float(v) for v in metadata['VZA']]) atm_lut_RAA = np.array([float(v) for v in metadata['RAA']]) atm_lut_WAVE = np.array([float(v) for v in metadata['WAVE']]) # VZA index vza_index = np.where(atm_lut_VZA == min(atm_lut_VZA))[0][-1] # RAA index raa_index = np.where(atm_lut_RAA == min(atm_lut_RAA))[0][-1] # Load atmospheric lookup table atm_lut = np.memmap( atm_lut_file, dtype='float32', mode='r', shape=metadata['shape']) # shape=(RHO, WVC, VIS, VZA, RAA, WAVE) # Subtract path radiance atm_lut_rdn = atm_lut[1, :, vza_index, raa_index, :] - atm_lut[ 0, :, vza_index, raa_index, :] # shape=(WVC, VIS, WAVE) atm_lut.flush() del atm_lut # VIS interpolation range vis_dict = get_interp_range(atm_lut_VIS, vis) # Do interpolation interp_rdn = np.zeros((len(atm_lut_WVC), len(atm_lut_WAVE))) for vis_index, vis_delta in vis_dict.items(): interp_rdn += atm_lut_rdn[:, vis_index, :] * vis_delta del atm_lut_rdn, vis_index, vis_delta # Build WVC models model_waves = [(890, 940, 1000), (1070, 1130, 1200)] wvc_model = dict() for waves in model_waves: # Get model wavelengths wave_1, wave_2, wave_3 = waves left_wave, left_band = get_closest_wave(sensor_waves, wave_1) middle_wave, middle_band = get_closest_wave(sensor_waves, wave_2) right_wave, right_band = get_closest_wave(sensor_waves, wave_3) # Build the model if np.abs(left_wave - wave_1) < 20 and np.abs( middle_wave - wave_2) < 20 and np.abs(right_wave - wave_3) < 20: model = dict() # Bands model['band'] = [int(left_band), int(middle_band), int(right_band)] # Wavelengths model['wavelength'] = [left_wave, middle_wave, right_wave] # Weights left_weight = (right_wave - middle_wave) / (right_wave - left_wave) right_weight = (middle_wave - left_wave) / (right_wave - left_wave) model['weight'] = [left_weight, right_weight] # Ratios & WVCs resampled_rdn = resample_spectra(interp_rdn, atm_lut_WAVE, sensor_waves[model['band']], sensor_fwhms[model['band']]) ratio = resampled_rdn[:, 1] / (left_weight * resampled_rdn[:, 0] + right_weight * resampled_rdn[:, 2]) index = np.argsort(ratio) model['ratio'] = list(ratio[index]) model['wvc'] = list(atm_lut_WVC[index]) # Save model parameters wvc_model['WVC_Model_%d' % wave_2] = model # Clear data del left_weight, right_weight, resampled_rdn, ratio, index, model del interp_rdn # Save WVC models to a .JSON file with open(wvc_model_file, 'w') as fid: json.dump(wvc_model, fid, indent=4) logger.info('Write WVC models to %s.' % wvc_model_file)
def atm_corr_image(flight_dict): """ Whole-image atmospheric correction. Parameters ---------- flight_dict: dict Flight dictionary. """ if os.path.exists(flight_dict['refl_file']): logger.info('Write the reflectance image to %s.' % flight_dict['refl_file']) return from ENVI import read_envi_header, write_envi_header from AtmLUT import read_binary_metadata # Read radiance image header rdn_header = read_envi_header( os.path.splitext(flight_dict['merged_rdn_file'])[0] + '.hdr') # Read atmospheric lookup table atm_lut_metadata = read_binary_metadata( flight_dict['resampled_atm_lut_file'] + '.meta') atm_lut_metadata['shape'] = tuple( [int(v) for v in atm_lut_metadata['shape']]) atm_lut_WVC = np.array([float(v) for v in atm_lut_metadata['WVC']]) atm_lut_VIS = np.array([float(v) for v in atm_lut_metadata['VIS']]) atm_lut_VZA = np.array([float(v) for v in atm_lut_metadata['VZA']]) atm_lut_RAA = np.array([float(v) for v in atm_lut_metadata['RAA']]) atm_lut = np.memmap(flight_dict['resampled_atm_lut_file'], dtype=atm_lut_metadata['dtype'], mode='r', shape=atm_lut_metadata['shape'] ) # shape=(RHO, WVC, VIS, VZA, RAA, WAVE) # Read scan angles (SCA) image sca_header = read_envi_header( os.path.splitext(flight_dict['merged_sca_file'])[0] + '.hdr') saa = float(sca_header['sun azimuth']) sca_image = np.memmap(flight_dict['merged_sca_file'], dtype='float32', shape=(sca_header['bands'], sca_header['lines'], sca_header['samples'])) # View zenith angle (VZA) vza_image = np.copy(sca_image[0, :, :]) # Relative azimuth angle (RAA) raa_image = saa - sca_image[1, :, :] raa_image[raa_image < 0] += 360.0 raa_image[raa_image > 180] = 360.0 - raa_image[raa_image > 180] # Clear data sca_image.flush() del sca_header, saa del sca_image # Read WVC & VIS images wvc_header = read_envi_header( os.path.splitext(flight_dict['wvc_file'])[0] + '.hdr') tmp_wvc_image = np.memmap(flight_dict['wvc_file'], mode='r', dtype='float32', shape=(wvc_header['lines'], wvc_header['samples'])) wvc_image = np.copy(tmp_wvc_image) vis_header = read_envi_header( os.path.splitext(flight_dict['vis_file'])[0] + '.hdr') tmp_vis_image = np.memmap(flight_dict['vis_file'], dtype='float32', mode='r', shape=(vis_header['lines'], vis_header['samples'])) vis_image = np.copy(tmp_vis_image) tmp_wvc_image.flush() tmp_vis_image.flush() del wvc_header, vis_header del tmp_vis_image, tmp_wvc_image # Read background mask bg_header = read_envi_header( os.path.splitext(flight_dict['background_mask_file'])[0] + '.hdr') bg_mask = np.memmap(flight_dict['background_mask_file'], dtype='bool', mode='r', shape=(bg_header['lines'], bg_header['samples'])) idx = ~bg_mask max_WVC = atm_lut_WVC.max() max_VIS = atm_lut_VIS.max() max_VZA = atm_lut_VZA.max() max_RAA = atm_lut_RAA.max() # Enforce cutoffs in ALT parameters wvc_image[wvc_image >= max_WVC] = max_WVC - 0.1 vis_image[vis_image >= max_VIS] = max_VIS - 0.1 vza_image[vza_image >= max_VZA] = max_VZA - 0.1 raa_image[raa_image >= max_RAA] = max_RAA - 0.1 del max_WVC, max_VIS, max_VZA, max_RAA # Remove outliers in WVC and VIS wvc = wvc_image[idx] avg_wvc = wvc.mean() std_wvc = wvc.std() wvc_image[(np.abs(wvc_image - avg_wvc) > 2 * std_wvc) & (~bg_mask)] = avg_wvc del wvc vis = vis_image[idx] avg_vis = vis.mean() std_vis = vis.std() vis_image[(np.abs(vis_image - avg_vis) > 2 * std_vis) & (~bg_mask)] = avg_vis del vis del idx fid = open(flight_dict['refl_file'], 'wb') # Do atmospheric correction info = 'Bands = ' for band in range(rdn_header['bands']): if band % 20 == 0: info += '%d, ' % (band + 1) if (rdn_header['wavelength'][band] >= 1340.0 and rdn_header['wavelength'][band] <= 1440.0) or ( rdn_header['wavelength'][band] >= 1800.0 and rdn_header['wavelength'][band] <= 1980.0 ) or rdn_header['wavelength'][band] >= 2460.0: fid.write( np.zeros((rdn_header['lines'], rdn_header['samples'])).astype('float32').tostring()) else: offset = rdn_header['header offset'] + 4 * band * rdn_header[ 'lines'] * rdn_header['samples'] # in bytes rdn_image = np.memmap(flight_dict['merged_rdn_file'], dtype='float32', mode='r', offset=offset, shape=(rdn_header['lines'], rdn_header['samples'])) refl = atm_corr_band(atm_lut_WVC, atm_lut_VIS, atm_lut_VZA, atm_lut_RAA, np.copy(atm_lut[..., band]), wvc_image, vis_image, vza_image, raa_image, rdn_image, bg_mask) fid.write(refl.astype('float32').tostring()) rdn_image.flush() del refl, rdn_image fid.close() info += '%d, Done!' % band logger.info(info) # Clear data del wvc_image, vis_image, vza_image, raa_image atm_lut.flush() bg_mask.flush() del atm_lut, bg_mask rdn_header['description'] = 'Reflectance [0-1]' write_envi_header( os.path.splitext(flight_dict['refl_file'])[0] + '.hdr', rdn_header) logger.info('Write the reflectance image to %s.' % flight_dict['refl_file'])
def estimate_vis(vis_file, ddv_file, atm_lut_file, rdn_file, sca_file, background_mask_file): """ Estimate visibility. Arguments: vis_file: str Visibility map filename. ddv_file: str Dark dense vegetation map filename. atm_lut_file: str Atmospheric lookup table filename. rdn_file: str Radiance filename. sca_file: str Scan angle filename. background_mask_file: Background mask filename. """ if os.path.exists(ddv_file) and os.path.exists(vis_file): logger.info('Write the visibility map to %s.' % vis_file) logger.info('Write the DDV map to %s.' % ddv_file) return from ENVI import read_envi_header, empty_envi_header, write_envi_header from AtmLUT import read_binary_metadata from Spectra import get_closest_wave from AtmCorr import atm_corr_band # Read radiance header. rdn_header = read_envi_header(os.path.splitext(rdn_file)[0] + '.hdr') # Find VNIR and SWIR sensor wavelengths. red_wave, red_band = get_closest_wave(rdn_header['wavelength'], 660) nir_wave, nir_band = get_closest_wave(rdn_header['wavelength'], 850) swir1_wave, swir1_band = get_closest_wave(rdn_header['wavelength'], 1650) swir2_wave, swir2_band = get_closest_wave(rdn_header['wavelength'], 2130) # Determine the sensor type. if_vnir = abs(red_wave - 660) < 20 and abs(nir_wave - 850) < 20 if_swir = abs(swir1_wave - 1650) < 20 or abs(swir2_wave - 2130) < 20 if if_vnir and if_swir: logger.info( 'Both VNIR and SWIR bands are used for estimating visibility.') elif if_vnir: logger.info('Only VNIR bands are used for estimating visibility.') elif if_swir: logger.info( 'Only SWIR bands are available, a constant visibility (23 km) is used.' ) else: logger.error( 'Cannot find appropriate bands for estimating visibility.') # Read atmospheric lookup table. atm_lut_metadata = read_binary_metadata(atm_lut_file + '.meta') atm_lut_metadata['shape'] = tuple( [int(v) for v in atm_lut_metadata['shape']]) atm_lut_RHO = np.array([float(v) for v in atm_lut_metadata['RHO']]) atm_lut_WVC = np.array([float(v) for v in atm_lut_metadata['WVC']]) atm_lut_VIS = np.array([float(v) for v in atm_lut_metadata['VIS']]) atm_lut_VZA = np.array([float(v) for v in atm_lut_metadata['VZA']]) atm_lut_RAA = np.array([float(v) for v in atm_lut_metadata['RAA']]) atm_lut = np.memmap(atm_lut_file, dtype=atm_lut_metadata['dtype'], mode='r', shape=atm_lut_metadata['shape'] ) # shape = (RHO, WVC, VIS, VZA, RAA, WAVE) # Read radiance image. rdn_image = np.memmap( rdn_file, # dtype='float32', dtype='int16', # in int, by Ting mode='r', shape=(rdn_header['bands'], rdn_header['lines'], rdn_header['samples'])) # Read VZA and RAA image. sca_header = read_envi_header(os.path.splitext(sca_file)[0] + '.hdr') saa = float(sca_header['sun azimuth']) sca_image = np.memmap(sca_file, dtype='float32', offset=0, shape=(sca_header['bands'], sca_header['lines'], sca_header['samples'])) # vza vza_image = np.copy(sca_image[0, :, :]) # raa raa_image = saa - sca_image[1, :, :] raa_image[raa_image < 0] += 360.0 raa_image[raa_image > 180] = 360.0 - raa_image[raa_image > 180] raa_image[raa_image == 180] = 179.0 # Constrain RAA within bounds of ALT raa_max = atm_lut_RAA.max() raa_image[raa_image > raa_max] = raa_max - 5e-2 # clear data sca_image.flush() del sca_header, saa, sca_image # Set visibility and water vapor column values. metadata = read_binary_metadata(atm_lut_file + '.meta') tmp_wvc_image = np.ones( vza_image.shape) * atm_db_wvc_lut[metadata['atm_mode']] tmp_vis_image = np.ones(vza_image.shape) * 23 del metadata # Read background mask. bg_header = read_envi_header( os.path.splitext(background_mask_file)[0] + '.hdr') bg_mask = np.memmap(background_mask_file, dtype='bool', mode='r', shape=(bg_header['lines'], bg_header['samples'])) # Calculate NDVI. red_refl = atm_corr_band( atm_lut_WVC, atm_lut_VIS, atm_lut_VZA, atm_lut_RAA, atm_lut[..., red_band], tmp_wvc_image, tmp_vis_image, vza_image, raa_image, rdn_image[red_band, :, :] / 1000, # divided by 1000 to convert to original rdn, by Ting bg_mask) nir_refl = atm_corr_band(atm_lut_WVC, atm_lut_VIS, atm_lut_VZA, atm_lut_RAA, atm_lut[..., nir_band], tmp_wvc_image, tmp_vis_image, vza_image, raa_image, rdn_image[nir_band, :, :] / 1000, bg_mask) ndvi = (nir_refl - red_refl) / (nir_refl + red_refl + 1e-10) vis_image = np.zeros((rdn_header['lines'], rdn_header['samples'])) if if_vnir and if_swir: # Decide which SWIR band to use. if abs(swir2_wave - 2130) < 20: swir_wave = swir2_wave swir_band = swir2_band swir_refl_upper_bounds = [0.05, 0.10, 0.12] red_swir_ratio = 0.50 else: swir_wave = swir1_wave swir_band = swir1_band swir_refl_upper_bounds = [0.10, 0.15, 0.18] red_swir_ratio = 0.25 # Calculate swir refletance. swir_refl = atm_corr_band( atm_lut_WVC, atm_lut_VIS, atm_lut_VZA, atm_lut_RAA, atm_lut[..., swir_band], tmp_wvc_image, tmp_vis_image, vza_image, raa_image, rdn_image[swir_band, :, :] / 1000, # divided by 1000 to convert to original rdn, by Ting bg_mask) # Get DDV mask. for swir_refl_upper_bound in swir_refl_upper_bounds: ddv_mask = (ndvi > 0.10) & (swir_refl < swir_refl_upper_bound) & ( swir_refl > 0.01) percentage = np.sum(ddv_mask[~bg_mask]) / np.sum(~bg_mask) if percentage > 0.02: logger.info( 'The SWIR wavelength %.2f is used for detecting dark dense vegetation.' % swir_wave) logger.info('The SWIR reflectance upper boundary is %.2f.' % swir_refl_upper_bound) logger.info('The number of DDV pixels is %.2f%%.' % (percentage * 100)) break # Estimate Visibility. rows, columns = np.where(ddv_mask) # Estimate red reflectance. red_refl[rows, columns] = red_swir_ratio * swir_refl[rows, columns] del swir_refl for row, column in zip(rows, columns): interp_rdn = interp_atm_lut(atm_lut_RHO, atm_lut_WVC, atm_lut_VZA, atm_lut_RAA, atm_lut[..., red_band], red_refl[row, column], tmp_wvc_image[row, column], vza_image[row, column], raa_image[row, column]) vis_image[row, column] = np.interp( rdn_image[red_band, row, column] / 1000, interp_rdn[::-1], atm_lut_VIS[::-1] ) # divided by 1000 to convert to original rdn, by Ting rdn_image.flush() del rdn_image logger.info( 'Visibility [km] statistics: min=%.2f, max=%.2f, avg=%.2f, sd=%.2f.' % (vis_image[ddv_mask].min(), vis_image[ddv_mask].max(), vis_image[ddv_mask].mean(), vis_image[ddv_mask].std())) # Fill gaps with average values. vis_image[~ddv_mask] = vis_image[ddv_mask].mean() vis_image[bg_mask] = -1000.0 # Write the visibility data. fid = open(vis_file, 'wb') fid.write(vis_image.astype('float32').tostring()) fid.close() del vis_image vis_header = empty_envi_header() vis_header['description'] = 'Visibility [km]' vis_header['samples'] = rdn_header['samples'] vis_header['lines'] = rdn_header['lines'] vis_header['bands'] = 1 vis_header['byte order'] = 0 vis_header['header offset'] = 0 vis_header['interleave'] = 'bsq' vis_header['data ignore value'] = -1000.0 vis_header['data type'] = 4 vis_header['map info'] = rdn_header['map info'] vis_header['coordinate system string'] = rdn_header[ 'coordinate system string'] write_envi_header(os.path.splitext(vis_file)[0] + '.hdr', vis_header) logger.info('Write the visibility image to %s.' % vis_file) # Write the DDV data. fid = open(ddv_file, 'wb') fid.write(ddv_mask.tostring()) fid.close() del ddv_mask ddv_header = empty_envi_header() ddv_header[ 'description'] = 'DDV mask (1: Dark dense vegetaion; 0: non-dark dense vegetation)' ddv_header['samples'] = rdn_header['samples'] ddv_header['lines'] = rdn_header['lines'] ddv_header['bands'] = 1 ddv_header['byte order'] = 0 ddv_header['header offset'] = 0 ddv_header['interleave'] = 'bsq' ddv_header['data type'] = 1 ddv_header['map info'] = rdn_header['map info'] ddv_header['coordinate system string'] = rdn_header[ 'coordinate system string'] write_envi_header(os.path.splitext(ddv_file)[0] + '.hdr', ddv_header) logger.info('Write the DDV mask to %s.' % ddv_file) elif if_vnir: pass elif if_swir: pass # Clear data del ndvi, red_refl, nir_refl, rdn_header