Ejemplo n.º 1
0
def difference_dems(dem1, dem2, out_dem=None, in_mem=False):
    logger.debug('Difference DEMs:\nDEM1: {}\nDEM2:{}'.format(dem1, dem2))
    clipped = clip_minbb([dem1, dem2], in_mem=True)
    dem1_clipped = Raster(clipped[0])
    dem2_clipped = Raster(clipped[1])

    diff = dem1_clipped.MaskedArray - dem2_clipped.MaskedArray

    if out_dem:
        logger.debug('Writing difference to: {}'.format(out_dem))
        dem1_clipped.WriteArray(diff, out_path=out_dem)

    return out_dem
Ejemplo n.º 2
0
def dem_rmse(dem1_path,
             dem2_path,
             max_diff=None,
             outfile=None,
             out_diff=None,
             plot=False,
             show_plot=False,
             save_plot=None,
             bins=10,
             log_scale=True):
    # Load DEMs as arrays
    logger.info('Loading DEMs...')
    dem1 = Raster(dem1_path)
    dem2 = Raster(dem2_path)

    if dem1.geotransform != dem2.geotransform:
        logger.warning('''DEM geotransforms do not match. 
                          Clipping to minimum bounding box in memory....''')
        dem1 = None
        dem2 = None
        clipped = clip_minbb(rasters=[dem1_path, dem2_path],
                             in_mem=True,
                             out_format='vrt')
        logger.debug('Clipping complete. Reloading DEMs...')
        dem1 = Raster(clipped[0])
        arr1 = dem1.MaskedArray
        dem1 = None
        logger.debug('DEM1 loaded and array extracted...')
        dem2 = Raster(clipped[1])
        arr2 = dem2.MaskedArray
        dem2 = None
        logger.debug('DEM2 loaded and array extracted...')
    else:
        arr1 = dem1.MaskedArray
        dem1 = None
        arr2 = dem2.MaskedArray
        dem2 = None

    # Compute RMSE
    logger.info('Computing RMSE...')
    diffs = arr1 - arr2

    # Remove any differences bigger than max_diff
    if max_diff:
        logger.debug(
            'Checking for large differences, max_diff: {}'.format(max_diff))
        size_uncleaned = diffs.size
        diffs = diffs[abs(diffs) < max_diff]
        size_cleaned = diffs.size
        if size_uncleaned != size_cleaned:
            logger.debug(
                'Removed differences over max_diff ({}) from RMSE calculation...'
                .format(max_diff))
            logger.debug('Size before: {:,}'.format(size_uncleaned))
            logger.debug('Size after:  {:,}'.format(size_cleaned))
            logger.debug('Pixels removed: {:.2f}% of overlap area'.format(
                ((size_uncleaned - size_cleaned) / size_uncleaned) * 100))

    sq_diff = diffs**2
    mean_sq = sq_diff.sum() / sq_diff.count()
    logger.debug('Mean square error: {}'.format(mean_sq))
    rmse = np.sqrt(mean_sq)

    # Report differences
    diffs_valid_count = diffs.count()
    min_diff = diffs.min()
    max_diff = diffs.max()
    logger.debug('Minimum difference: {:.2f}'.format(min_diff))
    logger.debug('Maximum difference: {:.2f}'.format(max_diff))
    logger.debug('Pixels considered: {:,}'.format(diffs_valid_count))
    logger.info('RMSE: {:.2f}'.format(rmse))

    # Write text file of results
    if outfile:
        with open(outfile, 'w') as of:
            of.write("DEM1: {}\n".format(dem1_path))
            of.write("DEM2: {}\n".format(dem2_path))
            of.write('RMSE: {:.2f}\n'.format(rmse))
            of.write('Pixels considered: {:,}\n'.format(diffs_valid_count))
            of.write('Minimum difference: {:.2f}\n'.format(min_diff))
            of.write('Maximum difference: {:.2f}\n'.format(max_diff))

    # Write raster file of results
    if out_diff:
        logger.info('Out diff not supported, skipping writing.')
        # dem1.WriteArray(diffs, out_diff)

    # Plot results
    # TODO: Add legend
    # TODO: Incorporate min/max differences based on max_diff argument
    if plot:
        plt.style.use('ggplot')
        fig, ax = plt.subplots(1, 1)
        ax.hist(diffs.compressed().flatten(),
                log=log_scale,
                bins=bins,
                edgecolor='white',
                alpha=0.875)
        ax.annotate('RMSE: {:.3f}'.format(rmse),
                    xy=(76, 0.75),
                    xycoords='axes fraction')
        plt.legend(loc="upper left")
        plt.tight_layout()

        if save_plot:
            plt.savefig(save_plot)
        if show_plot:
            plt.show()

    return rmse
Ejemplo n.º 3
0
def stack_rasters(rasters, minbb=True, rescale=False):
    """
    Stack single band rasters into a multiband raster.

    Parameters
    ----------
    rasters : list
        List of rasters to stack. Reference raster for NoData value, projection, etc.
        is the first raster provided.
    rescale : bool
        True to rescale rasters to 0 to 1.

    Returns
    -------
    np.array : path.abspath : path to write multiband raster to.

    """
    # TODO: Add default clipping to reference window
    if minbb:
        logger.info('Clipping to overlap area...')
        rasters = clip_minbb(rasters, in_mem=True, out_format='vrt')

    # Determine a raster to use for reference
    ref = Raster(rasters[0])

    # Check for SRS match between reference and other rasters
    srs_matches = [same_srs(rasters[0], r) for r in rasters[1:]]
    if not all(srs_matches):
        logger.warning("""Spatial references do not match, match status between
                          reference and rest:\n{}""".format(
            '\n'.join(srs_matches)))

    # Initialize the stacked array with just the reference array
    if ref.depth > 1:
        stacked = ref.GetBandAsArray(1, mask=True)
        if rescale:
            stacked = (stacked - stacked.min()) / (stacked.max() -
                                                   stacked.min())

        for i in range(ref.depth - 1):
            band = ref.GetBandAsArray(i + 2, mask=True)
            if rescale:
                band = (band - band.min()) / (band.max() - band.min())
            stacked = np.ma.dstack([stacked, band])

    for i, rast in enumerate(rasters[1:]):
        ma = Raster(rast).MaskedArray
        if np.ma.isMaskedArray(ma):
            if rescale:
                # Rescale to between 0 and 1
                ma = (ma - ma.min()) / (ma.max() - ma.min())
            # Replace mask/nodata value in array with reference values
            # ma_mask = ma.mask
            # ma = np.ma.masked_where(ma_mask, ma)
            # ma.set_fill_value(ref.nodata_val)
            # ma = ma.filled(ma.fill_value)

        stacked = np.ma.dstack([stacked, ma])

        ma = None

    # Revert to original NoData value (stacking changes)
    # stacked.set_fill_value(ref.nodata_val)
    ref = None

    return stacked
Ejemplo n.º 4
0
def rmse_compare(dem1_path, dem2_path, dem2pca_path, max_diff=None, outfile=None, plot=False,
                 save_plot=None, show_plot=False, bins=20, log_scale=True):
    # Load DEMs as arrays
    logger.info('Loading DEMs...')
    dem1 = Raster(dem1_path)
    dem2 = Raster(dem2_path)
    dem2pca = Raster(dem2pca_path)

    if dem1.geotransform != dem2.geotransform or dem1.geotransform != dem2pca.geotransform:
        logger.warning('DEM geotransforms do not match.')
        # Check for pixel size match
        if (((dem1.geotransform[1] != dem2.geotransform[1]) or (dem1.geotransform[1] != dem2pca.geotransform[1]) or
                (dem1.geotransform[5] != dem2.geotransform[5]) or (dem2.geotransform[5] != dem2pca.geotransform[5]))):
            logger.info('DEM pixel sizes do not match, translating to match.')
            p1 = dem1.src_path
            p2 = dem2.src_path
            dem1 = None
            dem2 = None
            # max = match_pixel_size([p1, p2], r'/vsimem/matching_px.tif', resampleAlg='cubic', in_mem=True)
            dem1 = Raster(p1)
            dem2 = Raster(p2)
            logger.info('DEM1 sz: {} {}'.format(dem1.x_sz, dem1.y_sz))
            logger.info('DEM2 sz: {} {}'.format(dem2.x_sz, dem2.y_sz))

        # Check for size match
        if ((dem1.x_sz != dem2.x_sz) or (dem1.x_sz != dem2pca.x_sz) or
                (dem1.y_sz != dem2.y_sz) or (dem1.y_sz != dem2pca.y_sz)):
            logger.info('DEM sizes do not match. Clipping to minimum bounding box in memory....')
            dem1 = None
            dem2 = None
            clipped = clip_minbb(rasters=[dem1_path, dem2_path, dem2pca_path],
                                 in_mem=True,
                                 out_format='vrt')
            logger.debug('Clipping complete. Reloading DEMs...')
            dem1 = Raster(clipped[0])
            logger.debug('DEM1 loaded and array extracted...')
            dem2 = Raster(clipped[1])
            logger.debug('DEM2 loaded and array extracted...')
            dem2pca = Raster(clipped[2])

            logger.debug('DEM1 sz: {} {}'.format(dem1.x_sz, dem1.y_sz))
            logger.debug('DEM2 sz: {} {}'.format(dem2.x_sz, dem2.y_sz))

        arr1 = dem1.MaskedArray
        dem1 = None
        arr2 = dem2.MaskedArray
        dem2 = None
        arr2pca = dem2pca.MaskedArray

    else:
        arr1 = dem1.MaskedArray
        dem1 = None
        arr2 = dem2.MaskedArray
        dem2 = None
        arr2pca = dem2pca.MaskedArray
        dem2pca = None


    #### PRE-ALIGNMENT ####
    # Compute RMSE 
    logger.info('Computing RMSE pre-alignment...')
    diffs = arr1 - arr2
    # Remove any differences bigger than max_diff
    if max_diff:
        logger.debug('Checking for large differences, max_diff: '
                     '{}'.format(max_diff))
        size_uncleaned = diffs.size
        diffs = diffs[abs(diffs) < max_diff]

        size_cleaned = diffs.size
        if size_uncleaned != size_cleaned:
            logger.debug('Removed differences over max_diff ({}) from RMSE '
                         'calculation...'.format(max_diff))
            logger.debug('Size before: {:,}'.format(size_uncleaned))
            logger.debug('Size after:  {:,}'.format(size_cleaned))
            logger.debug('Pixels removed: {:.2f}% of overlap area'.format(
                ((size_uncleaned-size_cleaned)/size_uncleaned)*100))

    sq_diff = diffs**2
    mean_sq = sq_diff.sum() / sq_diff.count()
    rmse = np.sqrt(mean_sq)

    # Report differences
    diffs_valid_count = diffs.count()
    min_diff = diffs.min()
    max_diff = diffs.max()
    logger.debug('Minimum difference: {:.2f}'.format(min_diff))
    logger.debug('Maximum difference: {:.2f}'.format(max_diff))
    logger.debug('Pixels considered: {:,}'.format(diffs_valid_count))
    logger.info('RMSE: {:.2f}'.format(rmse))

    # Write text file of results
    if outfile:
        with open(outfile, 'w') as of:
            of.write("DEM1: {}\n".format(dem1_path))
            of.write("DEM2: {}\n".format(dem2_path))
            of.write('Pixels considered: {:,}\n'.format(diffs_valid_count))
            of.write('Minimum difference: {:.2f}\n'.format(min_diff))
            of.write('Maximum difference: {:.2f}\n\n'.format(max_diff))
            of.write('RMSE: {:.2f}\n'.format(rmse))

    #### POST ALIGNMENT ####
    # Compute RMSE
    logger.info('Computing RMSE post-alignment...')
    diffs_pca = arr1 - arr2pca

    # Remove any differences bigger than max_diff
    if max_diff:
        size_uncleaned = diffs.size
        diffs_pca = diffs_pca[abs(diffs_pca) < max_diff]
        size_cleaned = diffs.size
        if size_uncleaned != size_cleaned:
            logger.debug('Removed differences over max_diff ({}) from RMSE '
                         'calculation...'.format(max_diff))
            logger.debug('Size before: {:,}'.format(size_uncleaned))
            logger.debug('Size after:  {:,}'.format(size_cleaned))
            logger.debug('Pixels removed: {:.2f}% of overlap area'.format(
                ((size_uncleaned-size_cleaned)/size_uncleaned)*100))

    # Remove any differences bigger than max_diff
    if max_diff:
        logger.debug('Checking for large differences, max_diff: '
                     '{}'.format(max_diff))
        size_uncleaned = diffs.size
        diffs = diffs[abs(diffs) < max_diff]

        size_cleaned = diffs.size
        if size_uncleaned != size_cleaned:
            logger.debug('Removed differences over max_diff ({}) from RMSE '
                         'calculation...'.format(max_diff))
            logger.debug('Size before: {:,}'.format(size_uncleaned))
            logger.debug('Size after:  {:,}'.format(size_cleaned))
            logger.debug('Pixels removed: {:.2f}% of overlap area'.format(
                ((size_uncleaned-size_cleaned)/size_uncleaned)*100))


    sq_diff_pca = diffs_pca**2
    mean_sq_pca = sq_diff_pca.sum() / sq_diff_pca.count()
    rmse_pca = np.sqrt(mean_sq_pca)

    # Report differences
    diffs_pca_valid_count = diffs_pca.count()
    min_diff_pca = diffs_pca.min()
    max_diff_pca = diffs_pca.max()
    logger.debug('Minimum difference: {:.2f}'.format(min_diff_pca))
    logger.debug('Maximum difference: {:.2f}'.format(max_diff_pca))
    logger.debug('Pixels considered: {:,}'.format(diffs_pca_valid_count))
    logger.info('RMSE: {:.2f}'.format(rmse_pca))

    # Add to text file of results
    if outfile:
        with open(outfile, 'a') as of:
            of.write("DEM1: {}\n".format(dem1_path))
            of.write("DEM2pca: {}\n".format(dem2pca_path))
            of.write('Pixels considered pca: {:,}\n'.format(diffs_pca_valid_count))
            of.write('Minimum difference pca: {:.2f}\n'.format(min_diff_pca))
            of.write('Maximum difference pca: {:.2f}\n\n'.format(max_diff_pca))
            of.write('RMSEpca: {:.2f}\n'.format(rmse_pca))

    # Plot results
    # TODO: Add legend and RMSE annotations
    # TODO: Incorporate min/max differences based on max_diff argument
    if plot:
        plt.style.use('ggplot')
        fig, ax = plt.subplots(2, 1)

        # Plot unaligned differences with line at 0
        ax[0].hist(diffs.compressed().flatten(), log=log_scale, bins=bins,
                   edgecolor='white', alpha=0.75,
                   range=[min([diffs.min(), diffs_pca.min()]),
                          max([diffs.min(), diffs_pca.max()])
                          ])
        ax[0].axvline(x=0, linewidth=2, color='black')
        
        # Plot aligned differences with line at 0
        ax[1].hist(diffs_pca.compressed().flatten(), log=log_scale, bins=bins,
                   edgecolor='white', color='b', alpha=0.75,
                   range=[min([diffs.min(), diffs_pca.min()]),
                          max([diffs.min(), diffs_pca.max()])])
        ax[1].axvline(x=0, linewidth=2, color='black')

        # Annotation and titles        
        ax[0].set_title('Pre-Alignment')
        ax[0].annotate('RMSE: {:.2f}'.format(rmse), xy=(0.05, 0.95),
                       xycoords='axes fraction')
        ax[1].set_title('Post-Alignment')
        ax[1].annotate('RMSE: {:.2f}'.format(rmse_pca), xy=(0.05, 0.95),
                       xycoords='axes fraction')

        plt.legend()

        plt.tight_layout()
        
        if save_plot:
            plt.savefig(save_plot)
        if show_plot:
            plt.show()