-
Notifications
You must be signed in to change notification settings - Fork 1
/
aster_processing_fn.py
121 lines (92 loc) · 4.41 KB
/
aster_processing_fn.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#!/usr/bin/env python
# coding: utf-8
# In[ ]:
# Steven Pestana (spestana@uw.edu)
import pandas as pd
import numpy as np
import glob
import geopandas as gpd
import rasterio as rio
import rasterio.plot as rioplt
from rasterio.mask import mask
def tir_dn2rad(DN, band):
'''Convert AST_L1T Digital Number values to At-Sensor Radiance for the TIR bands (bands 10-14).'''
ucc = [6.822e-3, 6.780e-3, 6.590e-3, 5.693e-3, 5.225e-3]
rad = (DN-1.) * ucc[band-10]
return rad
def tir_rad2tb(rad, band):
'''Convert AST_L1T At-Sensor Radiance to Brightness Temperature [K] for the TIR bands (bands 10-14).'''
k1 = [3047.47, 2480.93, 1930.80, 865.65, 649.60]
k2 = [1736.18, 1666.21, 1584.72,1349.82, 1274.49]
tb = k2[band-10] / np.log((k1[band-10]/rad) + 1)
return tb
def aster_timestamps(directory, ext='hdf'):
'''Given a directory of ASTER files, read the timestamps of ASTER observations (in UTC) from their filenames.
Option to search for HDF of TIF files.
Returns timestamp and filepath for each file found.'''
assert (ext == 'hdf') or (ext == 'tif') , "File extension must be either hdf or tif"
# Find all our ASTER files
search_path = '{directory}/**/*.{ext}'.format(directory=directory, ext=ext)
aster_files = glob.glob(search_path, recursive=True)
# Create empty list to hold timestamps as we step through all files in the list
aster_timestamps_UTC = []
# for each filepath in the list of ASTER files
for fpath in aster_files:
# Parse the date and time from ASTER filename
fn = fpath.split('/')[-1]
MM = fn.split('_')[2][3:5]
DD = fn.split('_')[2][5:7]
YYYY = fn.split('_')[2][7:11]
hh = fn.split('_')[2][11:13]
mm = fn.split('_')[2][13:15]
ss = fn.split('_')[2][15:17]
# create pandas timestamp and append to the list
aster_timestamps_UTC.append(pd.Timestamp('{}-{}-{} {}:{}:{}'.format(YYYY, MM, DD, hh, mm, ss),tz='UTC'))
# Create pandas dataframe, sort, and reset index
aster_df = pd.DataFrame({'timestampUTC': aster_timestamps_UTC, 'filepath': aster_files})
aster_df.sort_values('timestampUTC',inplace=True)
aster_df.reset_index(inplace=True, drop=True)
return aster_df
def zonal_stats(aster_filepath, aster_band, shapefile_filepath, return_masked_array=False):
'''Calculate zonal statistics for an ASTER TIR geotiff image within a single polygon from a shapefile.'''
with rio.open(aster_filepath) as src:
# Open the shapefile
zone_shape = gpd.read_file(shapefile_filepath)
# Make sure our shapefile is the same CRS as the ASTER TIR image
zone_shape = zone_shape.to_crs(src.crs)
# Mask the ASTER TIR image to the area of the shapefile
try:
masked_aster_band_DN, mask_transform = mask(dataset=src,
shapes=zone_shape.geometry,
crop=True,
all_touched=True,
filled=True)
# Note that we still have a "bands" axis (of size 1) even though there's only one band, we can remove it below
except ValueError as e:
# ValueError when shape doesn't overlap raster
return
# change data type to float64 so we can fill in DN=0 with NaN values
masked_aster_band_DN = masked_aster_band_DN.astype('float64')
masked_aster_band_DN[masked_aster_band_DN==0] = np.nan
# Convert DN to Radiance
masked_aster_band_rad = tir_dn2rad(masked_aster_band_DN, aster_band)
# Convert Radiance to Brightness Temperature
masked_aster_band_tb = tir_rad2tb(masked_aster_band_rad, aster_band)
# Remove the extra dimension (bands, we only have one band here)
masked_aster_band_tb = masked_aster_band_tb.squeeze()
# Get all pixel values in our masked area
values = masked_aster_band_tb.flatten() # flatten to 1-D
values = values[~np.isnan(values)] # remove NaN pixel values
# Calculate zonal statistics for this area (mean, max, min, std:)
try:
masked_aster_band_tb_mean = values.mean()
masked_aster_band_tb_max = values.max()
masked_aster_band_tb_min = values.min()
masked_aster_band_tb_std = values.std()
except ValueError as e:
# ValueError when the shapefile is empty I think
return
if return_masked_array == True:
return masked_aster_band_tb_mean, masked_aster_band_tb_max, masked_aster_band_tb_min, masked_aster_band_tb_std, masked_aster_band_tb
else:
return masked_aster_band_tb_mean, masked_aster_band_tb_max, masked_aster_band_tb_min, masked_aster_band_tb_std