def mt_metrics(stack, out_prefix, metrics, rescale_to_datatype=False, to_power=False, outlier_removal=False): with rasterio.open(stack) as src: # get metadata meta = src.meta # update driver and reduced band count meta.update({'driver': 'GTiff'}) meta.update({'count': 1}) # write all different output files into a dictionary metric_dict = {} for metric in metrics: metric_dict[metric] = rasterio.open( out_prefix + '.' + metric + '.tif', 'w', **meta) # scaling factors in case we have to rescale to integer minimums = { 'avg': -30, 'max': -30, 'min': -30, 'std': 0.00001, 'cov': 0.00001 } maximums = {'avg': 5, 'max': 5, 'min': 5, 'std': 15, 'cov': 1} # loop through blocks for _, window in src.block_windows(1): # read array with all bands stack = src.read(range(1, src.count + 1), window=window) if rescale_to_datatype is True and meta['dtype'] != 'float32': stack = ras.rescale_to_float(stack, meta['dtype']) # transform to power if to_power is True: stack = ras.convert_to_power(stack) # outlier removal (only applies if there are more than 5 bands) if outlier_removal is True and src.count >= 5: stack = remove_outliers(stack) # get stats arr = {} arr['avg'] = (np.nan_to_num(np.nanmean(stack, axis=0)) if 'avg' in metrics else False) arr['max'] = (np.nan_to_num(np.nanmax(stack, axis=0)) if 'max' in metrics else False) arr['min'] = (np.nan_to_num(np.nanmin(stack, axis=0)) if 'min' in metrics else False) arr['std'] = (np.nan_to_num(np.nanstd(stack, axis=0)) if 'std' in metrics else False) arr['cov'] = (np.nan_to_num( stats.variation(stack, axis=0, nan_policy='omit')) if 'cov' in metrics else False) # the metrics to be re-turned to dB, in case to_power is True metrics_to_convert = ['avg', 'min', 'max'] # do the back conversions and write to disk loop for metric in metrics: if to_power is True and metric in metrics_to_convert: arr[metric] = ras.convert_to_db(arr[metric]) if rescale_to_datatype is True and meta['dtype'] != 'float32': arr[metric] = ras.scale_to_int(arr[metric], meta['dtype'], minimums[metric], maximums[metric]) # write to dest metric_dict[metric].write(np.float32(arr[metric]), window=window, indexes=1) # close the output files for metric in metrics: metric_dict[metric].close()
def mt_metrics(stack, out_prefix, metrics, rescale_to_datatype=False, to_power=False, outlier_removal=False, datelist=None): # from datetime import datetime with rasterio.open(stack) as src: harmonics = False if 'harmonics' in metrics: logger.debug('INFO: Calculating harmonics') if not datelist: logger.debug('WARNING: Harmonics need the datelist. ' 'Harmonics will not be calculated') else: harmonics = True metrics.remove('harmonics') metrics.extend(['amplitude', 'phase', 'residuals']) if 'percentiles' in metrics: metrics.remove('percentiles') metrics.extend(['p95', 'p5']) # get metadata meta = src.profile # update driver and reduced band count meta.update({'driver': 'GTiff'}) meta.update({'count': 1}) # write all different output files into a dictionary metric_dict = {} for metric in metrics: filename = '{}.{}.tif'.format(out_prefix, metric) metric_dict[metric] = rasterio.open(filename, 'w', **meta) # scaling factors in case we have to rescale to integer minimums = { 'avg': -30, 'max': -30, 'min': -30, 'std': 0.00001, 'cov': 0.00001, 'count': 0 } maximums = { 'avg': 5, 'max': 5, 'min': 5, 'std': 15, 'cov': 1, 'count': 64000 } if harmonics: # construct independent variables dates, sines, cosines = [], [], [] two_pi = np.multiply(2, np.pi) for date in sorted(datelist): delta = difference_in_years( datetime.strptime('700101', "%y%m%d"), datetime.strptime(date, "%y%m%d")) dates.append(delta) sines.append(np.sin(np.multiply(two_pi, delta - 0.5))) cosines.append(np.cos(np.multiply(two_pi, delta - 0.5))) arr = np.array([dates, cosines, sines]) # loop through blocks for _, window in src.block_windows(1): # read array with all bands stack = src.read(range(1, src.count + 1), window=window) if rescale_to_datatype is True and meta['dtype'] != 'float32': stack = ras.rescale_to_float(stack, meta['dtype']) # transform to power if to_power is True: stack = ras.convert_to_power(stack) # outlier removal (only applies if there are more than 5 bands) if outlier_removal is True and src.count >= 5: stack = remove_outliers(stack) # get stats np.seterr(divide='ignore', invalid='ignore') arr = {} arr['p95'], arr['p5'] = (np.nan_to_num( nan_percentile(stack, [95, 5])) if 'p95' in metrics else (False, False)) arr['median'] = (np.nan_to_num(np.nanmedian(stack, axis=0)) if 'median' in metrics else False) arr['avg'] = (np.nan_to_num(np.nanmean(stack, axis=0)) if 'avg' in metrics else False) arr['max'] = (np.nan_to_num(np.nanmax(stack, axis=0)) if 'max' in metrics else False) arr['min'] = (np.nan_to_num(np.nanmin(stack, axis=0)) if 'min' in metrics else False) arr['std'] = (np.nan_to_num(np.nanstd(stack, axis=0)) if 'std' in metrics else False) arr['cov'] = (np.nan_to_num( stats.variation(stack, axis=0, nan_policy='omit')) if 'cov' in metrics else False) arr['count'] = (np.nan_to_num(np.count_nonzero(stack, axis=0)) if 'count' in metrics else False) if harmonics: stack_size = (stack.shape[1], stack.shape[2]) if to_power is True: y = ras.convert_to_db(stack).reshape(stack.shape[0], -1) else: y = stack.reshape(stack.shape[0], -1) arr, residuals, _, _ = np.linalg.lstsq(arr.T, y) arr['amplitude'] = np.hypot(arr[1], arr[2]).reshape(stack_size) arr['phase'] = np.arctan2(arr[2], arr[1]).reshape(stack_size) arr['residuals'] = np.sqrt(np.divide( residuals, stack.shape[0])).reshape(stack_size) # the metrics to be re-turned to dB, in case to_power is True metrics_to_convert = ['avg', 'min', 'max', 'p95', 'p5', 'median'] # do the back conversions and write to disk loop for metric in metrics: if to_power is True and metric in metrics_to_convert: arr[metric] = ras.convert_to_db(arr[metric]) if rescale_to_datatype is True and meta['dtype'] != 'float32': arr[metric] = ras.scale_to_int(arr[metric], meta['dtype'], minimums[metric], maximums[metric]) # write to dest metric_dict[metric].write(np.float32(arr[metric]), window=window, indexes=1) metric_dict[metric].update_tags( 1, BAND_NAME='{}_{}'.format(os.path.basename(out_prefix), metric)) metric_dict[metric].set_band_description( 1, '{}_{}'.format(os.path.basename(out_prefix), metric)) # close the output files for metric in metrics: # close rio opening metric_dict[metric].close() dirname = os.path.dirname(out_prefix) check_file = opj(dirname, '.{}.processed'.format(os.path.basename(out_prefix))) with open(str(check_file), 'w') as file: file.write('passed all tests \n')