Esempio n. 1
0
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()
Esempio n. 2
0
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')