Beispiel #1
0
def get_phenology(
    date, result_location, image_ds, after=False, before=False, qa=False, ndv=-9999, pattern=_result_record
):
    """ Output a raster containing phenology information

    Phenology information includes spring_doy, autumn_doy, pheno_cor, peak_evi,
    peak_doy, and pheno_nobs.

    Args:
      date (int): Ordinal date for prediction image
      result_location (str): Location of the results
      image_ds (gdal.Dataset): Example dataset
      after (bool, optional): If date intersects a disturbed period, use next
        available time segment
      before (bool, optional): If date does not intersect a model, use previous
        non-disturbed time segment
      qa (bool, optional): Add QA flag specifying segment type (intersect,
        after, or before)
      ndv (int, optional): NoDataValue
      pattern (str, optional): filename pattern of saved record results

    Returns:
      tuple (np.ndarray, list): A tuple (np.ndarray, list) containing the 3D
        np.ndarray of the phenology metrics, and the band names for
        the output dataset

    """
    # Find results
    records = find_results(result_location, pattern)

    n_bands = 7
    attributes = ["spring_doy", "autumn_doy", "pheno_cor", "peak_evi", "peak_doy", "pheno_nobs"]
    band_names = ["SpringDOY", "AutumnDOY", "Pheno_R*10000", "Peak_EVI*10000", "Peak_DOY", "Pheno_NObs", "GrowingDOY"]
    if qa:
        n_bands += 1
        band_names.append("SegmentQAQC")

    logger.debug("Allocating memory")
    raster = np.ones((image_ds.RasterYSize, image_ds.RasterXSize, n_bands), dtype=np.int32) * int(ndv)

    logger.debug("Processing results")
    for rec in iter_records(records, warn_on_empty=WARN_ON_EMPTY):
        if not all([_attr in rec.dtype.names for _attr in attributes]):
            raise ValueError("Results do not have phenology metrics")

        for _qa, index in find_indices(rec, date, after=after, before=before):
            if index.shape[0] == 0:
                continue

            # Apply scale factors for R and peak EVI
            rec["pheno_cor"][index] *= 10000.0
            rec["peak_evi"][index] *= 10000.0

            for _b, _attr in enumerate(attributes):
                raster[rec["py"][index], rec["px"][index], _b] = rec[_attr][index]
            raster[rec["py"][index], rec["px"][index], 6] = rec["autumn_doy"][index] - rec["spring_doy"][index]
            if qa:
                raster[rec["py"][index], rec["px"][index], -1] = _qa

    return raster, band_names
Beispiel #2
0
def get_numchangemap(start,
                     end,
                     result_location,
                     image_ds,
                     ndv=-9999,
                     pattern=_result_record):
    """ Output raster with changemap

    Args:
      start (int): Ordinal date for start of map records
      end (int): Ordinal date for end of map records
      result_location (str): Location of results
      image_ds (gdal.Dataset): Example dataset
      ndv (int, optional): NoDataValue
      pattern (str, optional): filename pattern of saved record results

    Returns:
      np.ndarray: 2D numpy array containing the number of changes
        between the start and end date; list containing band names

    """
    # Find results
    records = find_results(result_location, pattern)

    logger.debug('Allocating memory...')
    raster = np.ones((image_ds.RasterYSize, image_ds.RasterXSize),
                     dtype=np.int32) * int(ndv)

    logger.debug('Processing results')
    for rec in iter_records(records):
        # X location of each changed model
        px_changed = rec['px'][(rec['break'] >= start) & (rec['break'] <= end)]
        # Count occurrences of changed pixel locations
        bincount = np.bincount(px_changed)
        # How many changes for unique values of px_changed?
        n_change = bincount[np.nonzero(bincount)[0]]

        # Add in the values
        px = np.unique(px_changed)
        py = rec['py'][np.in1d(px, rec['px'])]
        raster[py, px] = n_change

    return raster
Beispiel #3
0
def get_numchangemap(start, end, result_location, image_ds,
                     ndv=-9999, pattern=_result_record):
    """ Output raster with changemap

    Args:
      start (int): Ordinal date for start of map records
      end (int): Ordinal date for end of map records
      result_location (str): Location of results
      image_ds (gdal.Dataset): Example dataset
      ndv (int, optional): NoDataValue
      pattern (str, optional): filename pattern of saved record results

    Returns:
      np.ndarray: 2D numpy array containing the number of changes
        between the start and end date; list containing band names

    """
    # Find results
    records = find_results(result_location, pattern)

    logger.debug('Allocating memory...')
    raster = np.ones((image_ds.RasterYSize, image_ds.RasterXSize),
                     dtype=np.int32) * int(ndv)

    logger.debug('Processing results')
    for rec in iter_records(records):
        # X location of each changed model
        px_changed = rec['px'][(rec['break'] >= start) & (rec['break'] <= end)]
        # Count occurrences of changed pixel locations
        bincount = np.bincount(px_changed)
        # How many changes for unique values of px_changed?
        n_change = bincount[np.nonzero(bincount)[0]]

        # Add in the values
        px = np.unique(px_changed)
        py = rec['py'][np.in1d(px, rec['px'])]
        raster[py, px] = n_change

    return raster
Beispiel #4
0
def get_prediction(
    date,
    result_location,
    image_ds,
    bands="all",
    use_robust=False,
    after=False,
    before=False,
    qa=False,
    ndv=-9999,
    pattern=_result_record,
):
    """ Output a raster with the predictions from model fit for a given date

    Args:
      date (int): Ordinal date for prediction image
      result_location (str): Location of the results
      image_ds (gdal.Dataset): Example dataset
      bands (str, list): Bands to predict - 'all' for every band, or specify a
        list of bands
      use_robust (bool, optional): Map robust coefficients and RMSE instead of
        normal ones
      after (bool, optional): If date intersects a disturbed period, use next
        available time segment
      before (bool, optional): If date does not intersect a model, use previous
        non-disturbed time segment
      qa (bool, optional): Add QA flag specifying segment type (intersect,
        after, or before)
      ndv (int, optional): NoDataValue
      pattern (str, optional): filename pattern of saved record results

    Returns:
      np.ndarray: A 3D numpy.ndarray containing the prediction for each band,
        for each pixel

    """
    # Find results
    records = find_results(result_location, pattern)

    # Find result attributes to extract
    i_bands, _, _, _, design, design_info = find_result_attributes(records, bands, None, use_robust=use_robust)

    n_bands = len(i_bands)
    band_names = ["Band_{0}".format(b) for b in range(n_bands)]
    if qa:
        n_bands += 1
        band_names.append("SegmentQAQC")
    n_i_bands = len(i_bands)

    # Create X matrix from date -- ignoring categorical variables
    if re.match(r".*C\(.*\).*", design):
        logger.warning("Categorical variable found in design matrix not used" " in predicted image estimate")
    design = re.sub(r"[\+\-][\ ]+C\(.*\)", "", design)
    X = patsy.dmatrix(design, {"x": date}).squeeze()

    i_coef = []
    for k, v in design_info.iteritems():
        if not re.match("C\(.*\)", k):
            i_coef.append(v)
    i_coef = np.asarray(i_coef)

    logger.debug("Allocating memory")
    raster = np.ones((image_ds.RasterYSize, image_ds.RasterXSize, n_bands), dtype=np.int16) * int(ndv)

    logger.debug("Processing results")
    for rec in iter_records(records, warn_on_empty=WARN_ON_EMPTY):
        for _qa, index in find_indices(rec, date, after=after, before=before):
            if index.shape[0] == 0:
                continue

            # Calculate prediction
            _coef = rec["coef"].take(index, axis=0).take(i_coef, axis=1).take(i_bands, axis=2)
            raster[rec["py"][index], rec["px"][index], :n_i_bands] = np.tensordot(_coef, X, axes=(1, 0))
            if qa:
                raster[rec["py"][index], rec["px"][index], -1] = _qa

    return raster, band_names
Beispiel #5
0
def get_coefficients(
    date,
    result_location,
    image_ds,
    bands,
    coefs,
    use_robust=False,
    amplitude=False,
    after=False,
    before=False,
    qa=False,
    ndv=-9999,
    pattern=_result_record,
):
    """ Output a raster with coefficients from CCDC

    Args:
      date (int): Ordinal date for prediction image
      result_location (str): Location of the results
      bands (list): Bands to predict
      coefs (list): List of coefficients to output
      image_ds (gdal.Dataset): Example dataset
      use_robust (bool, optional): Map robust coefficients and RMSE instead of
        normal ones
      amplitude (bool, optional): Map amplitude of seasonality instead of
        individual coefficient estimates for sin/cosine pair (default: False)
      after (bool, optional): If date intersects a disturbed period, use next
        available time segment (default: False)
      before (bool, optional): If date does not intersect a model, use previous
        non-disturbed time segment (default: False)
      qa (bool, optional): Add QA flag specifying segment type (intersect,
        after, or before) (default: False)
      ndv (int, optional): NoDataValue (default: -9999)
      pattern (str, optional): filename pattern of saved record results

    Returns:
      tuple: A tuple (np.ndarray, list) containing the 3D numpy.ndarray of the
        coefficients (coefficient x band x pixel), and the band names for
        the output dataset

    """
    # Find results
    records = find_results(result_location, pattern)

    # Find result attributes to extract
    i_bands, i_coefs, use_rmse, coef_names, _, _ = find_result_attributes(records, bands, coefs, use_robust=use_robust)

    # Process amplitude transform for seasonality coefficients
    if amplitude:
        harm_coefs = []
        for i, (c, n) in enumerate(zip(i_coefs, coef_names)):
            if re.match(r"harm\(x, [0-9]+\)\[0]", n):
                harm_coefs.append(c)
                coef_names[i] = re.sub(r"harm(.*)\[.*", r"amplitude\1", n)
        # Remove sin term from each harmonic pair
        i_coefs = [c for c in i_coefs if c - 1 not in harm_coefs]
        coef_names = [n for n in coef_names if "harm" not in n]

    n_bands = len(i_bands)
    n_coefs = len(i_coefs)
    n_rmse = n_bands if use_rmse else 0

    # Setup output band names
    band_names = []
    for _c in coef_names:
        for _b in i_bands:
            band_names.append("B" + str(_b + 1) + "_" + _c.replace(" ", ""))
    if use_rmse is True:
        for _b in i_bands:
            band_names.append("B" + str(_b + 1) + "_RMSE")
    n_qa = 0
    if qa:
        n_qa += 1
        band_names.append("SegmentQAQC")
    n_out_bands = n_bands * n_coefs + n_rmse + n_qa

    _coef = "robust_coef" if use_robust else "coef"
    _rmse = "robust_rmse" if use_robust else "rmse"

    logger.debug("Allocating memory...")
    raster = np.ones((image_ds.RasterYSize, image_ds.RasterXSize, n_out_bands), dtype=np.float32) * ndv

    logger.debug("Processing results")
    for rec in iter_records(records, warn_on_empty=WARN_ON_EMPTY):
        for _qa, index in find_indices(rec, date, after=after, before=before):
            if index.shape[0] == 0:
                continue

            if n_coefs > 0:
                # Normalize intercept to mid-point in time segment
                rec[_coef][index, 0, :] += ((rec["start"][index] + rec["end"][index]) / 2.0)[:, np.newaxis] * rec[
                    _coef
                ][index, 1, :]

                # If we want amplitude, calculate it
                if amplitude:
                    for harm_coef in harm_coefs:
                        rec[_coef][index, harm_coef, :] = np.linalg.norm(
                            rec[_coef][index, harm_coef : harm_coef + 2, :], axis=1
                        )

                # Extract coefficients
                raster[rec["py"][index], rec["px"][index], : n_coefs * n_bands] = np.reshape(
                    rec[_coef][index][:, i_coefs, :][:, :, i_bands], (index.size, n_coefs * n_bands)
                )

            if use_rmse:
                raster[rec["py"][index], rec["px"][index], n_coefs * n_bands : n_out_bands - n_qa] = rec[_rmse][index][
                    :, i_bands
                ]
            if qa:
                raster[rec["py"][index], rec["px"][index], -1] = _qa

    return raster, band_names
Beispiel #6
0
def get_classification(
    date,
    result_location,
    image_ds,
    after=False,
    before=False,
    qa=False,
    pred_proba=False,
    ndv=0,
    pattern=_result_record,
):
    """ Output raster with classification results

    Args:
      date (int): ordinal date for prediction image
      result_location (str): Location of the results
      image_ds (gdal.Dataset): Example dataset
      after (bool, optional): If date intersects a disturbed period, use next
        available time segment
      before (bool, optional): If date does not intersect a model, use previous
        non-disturbed time segment
      qa (bool, optional): Add QA flag specifying segment type (intersect,
        after, or before)
      pred_proba (bool, optional): Include additional band with classification
        value probabilities
      ndv (int, optional): NoDataValue
      pattern (str, optional): filename pattern of saved record results

    Returns:
      np.ndarray: 2D numpy array containing the classification map for the date
        specified

    """
    # Find results
    records = find_results(result_location, pattern)

    n_bands = 2 if pred_proba else 1
    dtype = np.uint16 if pred_proba else np.uint8

    band_names = ["Classification"]
    if pred_proba:
        band_names.append("Pred Proba (x10,000)")
    if qa:
        n_bands += 1
        band_names.append("SegmentQAQC")

    logger.debug("Allocating memory...")
    raster = np.ones((image_ds.RasterYSize, image_ds.RasterXSize, n_bands), dtype=dtype) * int(ndv)

    logger.debug("Processing results")
    for rec, fname in iter_records(records, warn_on_empty=WARN_ON_EMPTY, yield_filename=True):
        if "class" not in rec.dtype.names:
            logger.warning("Results in {f} do not have classification labels".format(f=fname))
            continue
        if "class_proba" not in rec.dtype.names and pred_proba:
            raise ValueError("Results do not have classification prediction" " probability values")

        for _qa, index in find_indices(rec, date, after=after, before=before):
            if index.shape[0] == 0:
                continue

            raster[rec["py"][index], rec["px"][index], 0] = rec["class"][index]
            if pred_proba:
                raster[rec["py"][index], rec["px"][index], 1] = rec["class_proba"][index].max(axis=1) * 10000
            if qa:
                raster[rec["py"][index], rec["px"][index], -1] = _qa

    return raster, band_names
Beispiel #7
0
def get_datechangemap(start, end, result_location, image_ds,
                      first=False,
                      out_format='%Y%j',
                      magnitude=False,
                      ndv=-9999, pattern=_result_record):
    """ Output raster with changemap

    Args:
      start (int): Ordinal date for start of map records
      end (int): Ordinal date for end of map records
      result_location (str): Location of results
      image_ds (gdal.Dataset): Example dataset
      first (bool): Use first change instead of last
      out_format (str, optional): Output date format
      magnitude (bool, optional): output magnitude of each change?
      ndv (int, optional): NoDataValue
      pattern (str, optional): filename pattern of saved record results

    Returns:
      tuple: A 2D np.ndarray array containing the changes between the
        start and end date. Also includes, if specified, a 3D np.ndarray of
        the magnitude of each change plus the indices of these magnitudes

    """
    # Find results
    records = find_results(result_location, pattern)

    logger.debug('Allocating memory...')
    datemap = np.ones((image_ds.RasterYSize, image_ds.RasterXSize),
                      dtype=np.int32) * int(ndv)
    # Determine what magnitude information to output if requested
    if magnitude:
        magnitude_indices = get_magnitude_indices(records)
        magnitudemap = np.ones((image_ds.RasterYSize, image_ds.RasterXSize,
                                magnitude_indices.size),
                               dtype=np.float32) * float(ndv)

    logger.debug('Processing results')
    for rec in iter_records(records):

        index = np.where((rec['break'] >= start) &
                         (rec['break'] <= end))[0]

        if first:
            _, _index = np.unique(rec['px'][index], return_index=True)
            index = index[_index]

        if index.shape[0] != 0:
            if out_format != 'ordinal':
                dates = np.array([int(dt.fromordinal(_d).strftime(out_format))
                                  for _d in rec['break'][index]])
                datemap[rec['py'][index], rec['px'][index]] = dates
            else:
                datemap[rec['py'][index], rec['px'][index]] = \
                    rec['break'][index]
            if magnitude:
                magnitudemap[rec['py'][index], rec['px'][index], :] = \
                    rec[index]['magnitude'][:, magnitude_indices]

    if magnitude:
        return datemap, magnitudemap, magnitude_indices
    else:
        return datemap, None, None
Beispiel #8
0
def get_phenology(date,
                  result_location,
                  image_ds,
                  after=False,
                  before=False,
                  qa=False,
                  ndv=-9999,
                  pattern=_result_record):
    """ Output a raster containing phenology information

    Phenology information includes spring_doy, autumn_doy, pheno_cor, peak_evi,
    peak_doy, and pheno_nobs.

    Args:
      date (int): Ordinal date for prediction image
      result_location (str): Location of the results
      image_ds (gdal.Dataset): Example dataset
      after (bool, optional): If date intersects a disturbed period, use next
        available time segment
      before (bool, optional): If date does not intersect a model, use previous
        non-disturbed time segment
      qa (bool, optional): Add QA flag specifying segment type (intersect,
        after, or before)
      ndv (int, optional): NoDataValue
      pattern (str, optional): filename pattern of saved record results

    Returns:
      tuple (np.ndarray, list): A tuple (np.ndarray, list) containing the 3D
        np.ndarray of the phenology metrics, and the band names for
        the output dataset

    """
    # Find results
    records = find_results(result_location, pattern)

    n_bands = 7
    attributes = [
        'spring_doy', 'autumn_doy', 'pheno_cor', 'peak_evi', 'peak_doy',
        'pheno_nobs'
    ]
    band_names = [
        'SpringDOY', 'AutumnDOY', 'Pheno_R*10000', 'Peak_EVI*10000',
        'Peak_DOY', 'Pheno_NObs', 'GrowingDOY'
    ]
    if qa:
        n_bands += 1
        band_names.append('SegmentQAQC')

    logger.debug('Allocating memory')
    raster = np.ones((image_ds.RasterYSize, image_ds.RasterXSize, n_bands),
                     dtype=np.int32) * int(ndv)

    logger.debug('Processing results')
    for rec in iter_records(records, warn_on_empty=WARN_ON_EMPTY):
        if not all([_attr in rec.dtype.names for _attr in attributes]):
            raise ValueError('Results do not have phenology metrics')

        for _qa, index in find_indices(rec, date, after=after, before=before):
            if index.shape[0] == 0:
                continue

            # Apply scale factors for R and peak EVI
            rec['pheno_cor'][index] *= 10000.0
            rec['peak_evi'][index] *= 10000.0

            for _b, _attr in enumerate(attributes):
                raster[rec['py'][index], rec['px'][index],
                       _b] = rec[_attr][index]
            raster[rec['py'][index],
                   rec['px'][index], 6] = \
                rec['autumn_doy'][index] - rec['spring_doy'][index]
            if qa:
                raster[rec['py'][index], rec['px'][index], -1] = _qa

    return raster, band_names
Beispiel #9
0
def get_prediction(date,
                   result_location,
                   image_ds,
                   bands='all',
                   use_robust=False,
                   after=False,
                   before=False,
                   qa=False,
                   ndv=-9999,
                   pattern=_result_record):
    """ Output a raster with the predictions from model fit for a given date

    Args:
      date (int): Ordinal date for prediction image
      result_location (str): Location of the results
      image_ds (gdal.Dataset): Example dataset
      bands (str, list): Bands to predict - 'all' for every band, or specify a
        list of bands
      use_robust (bool, optional): Map robust coefficients and RMSE instead of
        normal ones
      after (bool, optional): If date intersects a disturbed period, use next
        available time segment
      before (bool, optional): If date does not intersect a model, use previous
        non-disturbed time segment
      qa (bool, optional): Add QA flag specifying segment type (intersect,
        after, or before)
      ndv (int, optional): NoDataValue
      pattern (str, optional): filename pattern of saved record results

    Returns:
      np.ndarray: A 3D numpy.ndarray containing the prediction for each band,
        for each pixel

    """
    # Find results
    records = find_results(result_location, pattern)

    # Find result attributes to extract
    i_bands, _, _, _, design, design_info = find_result_attributes(
        records, bands, None, use_robust=use_robust)

    n_bands = len(i_bands)
    band_names = ['Band_{0}'.format(b) for b in range(n_bands)]
    if qa:
        n_bands += 1
        band_names.append('SegmentQAQC')
    n_i_bands = len(i_bands)

    # Create X matrix from date -- ignoring categorical variables
    if re.match(r'.*C\(.*\).*', design):
        logger.warning('Categorical variable found in design matrix not used'
                       ' in predicted image estimate')
    design = re.sub(r'[\+\-][\ ]+C\(.*\)', '', design)
    X = patsy.dmatrix(design, {'x': date}).squeeze()

    i_coef = []
    for k, v in design_info.iteritems():
        if not re.match('C\(.*\)', k):
            i_coef.append(v)
    i_coef = np.asarray(i_coef)

    logger.debug('Allocating memory')
    raster = np.ones((image_ds.RasterYSize, image_ds.RasterXSize, n_bands),
                     dtype=np.int16) * int(ndv)

    logger.debug('Processing results')
    for rec in iter_records(records, warn_on_empty=WARN_ON_EMPTY):
        for _qa, index in find_indices(rec, date, after=after, before=before):
            if index.shape[0] == 0:
                continue

            # Calculate prediction
            _coef = rec['coef'].take(index, axis=0).\
                take(i_coef, axis=1).take(i_bands, axis=2)
            raster[rec['py'][index], rec['px'][index], :n_i_bands] = \
                np.tensordot(_coef, X, axes=(1, 0))
            if qa:
                raster[rec['py'][index], rec['px'][index], -1] = _qa

    return raster, band_names
Beispiel #10
0
def get_coefficients(date,
                     result_location,
                     image_ds,
                     bands,
                     coefs,
                     use_robust=False,
                     amplitude=False,
                     after=False,
                     before=False,
                     qa=False,
                     ndv=-9999,
                     pattern=_result_record):
    """ Output a raster with coefficients from CCDC

    Args:
      date (int): Ordinal date for prediction image
      result_location (str): Location of the results
      bands (list): Bands to predict
      coefs (list): List of coefficients to output
      image_ds (gdal.Dataset): Example dataset
      use_robust (bool, optional): Map robust coefficients and RMSE instead of
        normal ones
      amplitude (bool, optional): Map amplitude of seasonality instead of
        individual coefficient estimates for sin/cosine pair (default: False)
      after (bool, optional): If date intersects a disturbed period, use next
        available time segment (default: False)
      before (bool, optional): If date does not intersect a model, use previous
        non-disturbed time segment (default: False)
      qa (bool, optional): Add QA flag specifying segment type (intersect,
        after, or before) (default: False)
      ndv (int, optional): NoDataValue (default: -9999)
      pattern (str, optional): filename pattern of saved record results

    Returns:
      tuple: A tuple (np.ndarray, list) containing the 3D numpy.ndarray of the
        coefficients (coefficient x band x pixel), and the band names for
        the output dataset

    """
    # Find results
    records = find_results(result_location, pattern)

    # Find result attributes to extract
    i_bands, i_coefs, use_rmse, coef_names, _, _ = find_result_attributes(
        records, bands, coefs, use_robust=use_robust)

    # Process amplitude transform for seasonality coefficients
    if amplitude:
        harm_coefs = []
        for i, (c, n) in enumerate(zip(i_coefs, coef_names)):
            if re.match(r'harm\(x, [0-9]+\)\[0]', n):
                harm_coefs.append(c)
                coef_names[i] = re.sub(r'harm(.*)\[.*', r'amplitude\1', n)
        # Remove sin term from each harmonic pair
        i_coefs = [c for c in i_coefs if c - 1 not in harm_coefs]
        coef_names = [n for n in coef_names if 'harm' not in n]

    n_bands = len(i_bands)
    n_coefs = len(i_coefs)
    n_rmse = n_bands if use_rmse else 0

    # Setup output band names
    band_names = []
    for _c in coef_names:
        for _b in i_bands:
            band_names.append('B' + str(_b + 1) + '_' + _c.replace(' ', ''))
    if use_rmse is True:
        for _b in i_bands:
            band_names.append('B' + str(_b + 1) + '_RMSE')
    n_qa = 0
    if qa:
        n_qa += 1
        band_names.append('SegmentQAQC')
    n_out_bands = n_bands * n_coefs + n_rmse + n_qa

    _coef = 'robust_coef' if use_robust else 'coef'
    _rmse = 'robust_rmse' if use_robust else 'rmse'

    logger.debug('Allocating memory...')
    raster = np.ones((image_ds.RasterYSize, image_ds.RasterXSize, n_out_bands),
                     dtype=np.float32) * ndv

    logger.debug('Processing results')
    for rec in iter_records(records, warn_on_empty=WARN_ON_EMPTY):
        for _qa, index in find_indices(rec, date, after=after, before=before):
            if index.shape[0] == 0:
                continue

            if n_coefs > 0:
                # Normalize intercept to mid-point in time segment
                rec[_coef][index, 0, :] += (
                    (rec['start'][index] + rec['end'][index])
                        / 2.0)[:, np.newaxis] * \
                    rec[_coef][index, 1, :]

                # If we want amplitude, calculate it
                if amplitude:
                    for harm_coef in harm_coefs:
                        rec[_coef][index, harm_coef, :] = np.linalg.norm(
                            rec[_coef][index, harm_coef:harm_coef + 2, :],
                            axis=1)

                # Extract coefficients
                raster[rec['py'][index],
                       rec['px'][index], :n_coefs * n_bands] =\
                    np.reshape(rec[_coef][index][:, i_coefs, :][:, :, i_bands],
                               (index.size, n_coefs * n_bands))

            if use_rmse:
                raster[rec['py'][index], rec['px'][index],
                       n_coefs * n_bands:n_out_bands - n_qa] =\
                    rec[_rmse][index][:, i_bands]
            if qa:
                raster[rec['py'][index], rec['px'][index], -1] = _qa

    return raster, band_names
Beispiel #11
0
def get_classification(date,
                       result_location,
                       image_ds,
                       after=False,
                       before=False,
                       qa=False,
                       pred_proba=False,
                       ndv=0,
                       pattern=_result_record):
    """ Output raster with classification results

    Args:
      date (int): ordinal date for prediction image
      result_location (str): Location of the results
      image_ds (gdal.Dataset): Example dataset
      after (bool, optional): If date intersects a disturbed period, use next
        available time segment
      before (bool, optional): If date does not intersect a model, use previous
        non-disturbed time segment
      qa (bool, optional): Add QA flag specifying segment type (intersect,
        after, or before)
      pred_proba (bool, optional): Include additional band with classification
        value probabilities
      ndv (int, optional): NoDataValue
      pattern (str, optional): filename pattern of saved record results

    Returns:
      np.ndarray: 2D numpy array containing the classification map for the date
        specified

    """
    # Find results
    records = find_results(result_location, pattern)

    n_bands = 2 if pred_proba else 1
    dtype = np.uint16 if pred_proba else np.uint8

    band_names = ['Classification']
    if pred_proba:
        band_names.append('Pred Proba (x10,000)')
    if qa:
        n_bands += 1
        band_names.append('SegmentQAQC')

    logger.debug('Allocating memory...')
    raster = np.ones((image_ds.RasterYSize, image_ds.RasterXSize, n_bands),
                     dtype=dtype) * int(ndv)

    logger.debug('Processing results')
    for rec, fname in iter_records(records,
                                   warn_on_empty=WARN_ON_EMPTY,
                                   yield_filename=True):
        if 'class' not in rec.dtype.names:
            logger.warning(
                'Results in {f} do not have classification labels'.format(
                    f=fname))
            continue
        if 'class_proba' not in rec.dtype.names and pred_proba:
            raise ValueError('Results do not have classification prediction'
                             ' probability values')

        for _qa, index in find_indices(rec, date, after=after, before=before):
            if index.shape[0] == 0:
                continue

            raster[rec['py'][index], rec['px'][index], 0] = rec['class'][index]
            if pred_proba:
                raster[rec['py'][index],
                       rec['px'][index], 1] = \
                            rec['class_proba'][index].max(axis=1) * 10000
            if qa:
                raster[rec['py'][index], rec['px'][index], -1] = _qa

    return raster, band_names
Beispiel #12
0
def get_coefficients(
    date,
    result_location,
    image_ds,
    bands,
    coefs,
    no_scale_intercept=False,
    use_robust=False,
    after=False,
    before=False,
    qa=False,
    ndv=-9999,
    pattern=_result_record,
):
    """ Output a raster with coefficients from CCDC

    Args:
      date (int): Ordinal date for prediction image
      result_location (str): Location of the results
      bands (list): Bands to predict
      coefs (list): List of coefficients to output
      image_ds (gdal.Dataset): Example dataset
      no_scale_intercept (bool, optional): Skip scaling of intercept
        coefficient by slope (default: False)
      use_robust (bool, optional): Map robust coefficients and RMSE instead of
        normal ones
      after (bool, optional): If date intersects a disturbed period, use next
        available time segment
      before (bool, optional): If date does not intersect a model, use previous
        non-disturbed time segment
      qa (bool, optional): Add QA flag specifying segment type (intersect,
        after, or before)
      ndv (int, optional): NoDataValue
      pattern (str, optional): filename pattern of saved record results

    Returns:
      tuple: A tuple (np.ndarray, list) containing the 3D numpy.ndarray of the
        coefficients (coefficient x band x pixel), and the band names for
        the output dataset

    """
    # Find results
    records = find_results(result_location, pattern)

    # Find result attributes to extract
    i_bands, i_coefs, use_rmse, coef_names, _, _ = find_result_attributes(records, bands, coefs, use_robust=use_robust)

    n_bands = len(i_bands)
    n_coefs = len(i_coefs)
    n_rmse = n_bands if use_rmse else 0

    # Setup output band names
    band_names = []
    for _c in coef_names:
        for _b in i_bands:
            band_names.append("B" + str(_b + 1) + "_" + _c.replace(" ", ""))
    if use_rmse is True:
        for _b in i_bands:
            band_names.append("B" + str(_b + 1) + "_RMSE")
    n_qa = 0
    if qa:
        n_qa += 1
        band_names.append("SegmentQAQC")
    n_out_bands = n_bands * n_coefs + n_rmse + n_qa

    logger.debug("Band names:")
    logger.debug(band_names)

    _coef = "robust_coef" if use_robust else "coef"
    _rmse = "robust_rmse" if use_robust else "rmse"

    logger.debug("Allocating memory...")
    raster = np.ones((image_ds.RasterYSize, image_ds.RasterXSize, n_out_bands), dtype=np.float32) * ndv

    logger.debug("Processing results")
    for rec in iter_records(records, warn_on_empty=WARN_ON_EMPTY):
        for _qa, index in find_indices(rec, date, after=after, before=before):
            if index.shape[0] == 0:
                continue

            if n_coefs > 0:
                # Normalize intercept to mid-point in time segment
                if not no_scale_intercept:
                    rec[_coef][index, 0, :] += ((rec["start"][index] + rec["end"][index]) / 2.0)[:, None] * rec[_coef][
                        index, 1, :
                    ]

                # Extract coefficients
                raster[rec["py"][index], rec["px"][index], : n_coefs * n_bands] = np.reshape(
                    rec[_coef][index][:, i_coefs, :][:, :, i_bands], (index.size, n_coefs * n_bands)
                )

            if use_rmse:
                raster[rec["py"][index], rec["px"][index], n_coefs * n_bands : n_out_bands - n_qa] = rec[_rmse][index][
                    :, i_bands
                ]
            if qa:
                raster[rec["py"][index], rec["px"][index], -1] = _qa

    return raster, band_names
Beispiel #13
0
def get_datechangemap(start,
                      end,
                      result_location,
                      image_ds,
                      first=False,
                      out_format='%Y%j',
                      magnitude=False,
                      ndv=-9999,
                      pattern=_result_record):
    """ Output raster with changemap

    Args:
      start (int): Ordinal date for start of map records
      end (int): Ordinal date for end of map records
      result_location (str): Location of results
      image_ds (gdal.Dataset): Example dataset
      first (bool): Use first change instead of last
      out_format (str, optional): Output date format
      magnitude (bool, optional): output magnitude of each change?
      ndv (int, optional): NoDataValue
      pattern (str, optional): filename pattern of saved record results

    Returns:
      tuple: A 2D np.ndarray array containing the changes between the
        start and end date. Also includes, if specified, a 3D np.ndarray of
        the magnitude of each change plus the indices of these magnitudes

    """
    # Find results
    records = find_results(result_location, pattern)

    logger.debug('Allocating memory...')
    datemap = np.ones((image_ds.RasterYSize, image_ds.RasterXSize),
                      dtype=np.int32) * int(ndv)
    # Determine what magnitude information to output if requested
    if magnitude:
        magnitude_indices = get_magnitude_indices(records)
        magnitudemap = np.ones((image_ds.RasterYSize, image_ds.RasterXSize,
                                magnitude_indices.size),
                               dtype=np.float32) * float(ndv)

    logger.debug('Processing results')
    for rec in iter_records(records):

        index = np.where((rec['break'] >= start) & (rec['break'] <= end))[0]

        if first:
            _, _index = np.unique(rec['px'][index], return_index=True)
            index = index[_index]

        if index.shape[0] != 0:
            if out_format != 'ordinal':
                dates = np.array([
                    int(dt.fromordinal(_d).strftime(out_format))
                    for _d in rec['break'][index]
                ])
                datemap[rec['py'][index], rec['px'][index]] = dates
            else:
                datemap[rec['py'][index], rec['px'][index]] = \
                    rec['break'][index]
            if magnitude:
                magnitudemap[rec['py'][index], rec['px'][index], :] = \
                    rec[index]['magnitude'][:, magnitude_indices]

    if magnitude:
        return datemap, magnitudemap, magnitude_indices
    else:
        return datemap, None, None