コード例 #1
0
ファイル: visualize.py プロジェクト: isall/unmixing
def cumulative_freq_plot(rast,
                         band=0,
                         mask=None,
                         bins=100,
                         xlim=None,
                         nodata=-9999):
    '''
    Plots an empirical cumulative frequency curve for the input raster array
    in a given band.
    '''
    if mask is not None:
        arr = binary_mask(rast, mask)

    else:
        arr = rast.copy()

    if nodata is not None:
        arr = subarray(arr)

    values, base = np.histogram(arr, bins=bins)
    cumulative = np.cumsum(values)  # Evaluate the cumulative distribution
    plt.plot(base[:-1], cumulative, c='blue')  # Plot the cumulative function
    plt.set_title('Empirical Cumulative Distribution: Band %d' % band)

    if xlim is not None:
        axes = plt.gca()
        axes.set_xlim(xlim)

    plt.show()
    return arr
コード例 #2
0
def interpolate_endmember_map(
        spectra, em_locations, window, q=3, n=2, labels=None, cval=0,
        nodata=-9999, multiprocess=False):
    '''
    Creates synthetic image endmember maps (arrays); these endmembers are
    spatially interpolated from known endmember candidates. The end goal
    is a map (array) with an endmember spectra at every pixel, for one or
    more endmembers. Arguments:
        spectra         The multi-band raster from which candidate endmember
                        spectra will be synthesized; a (p x m x n) array.
        em_locations    A single band, classified raster array denoting the
                        locations of endmember candidates; a (1 x m x n) array.
        window          A 2D NumPy array that serves as the moving window,
                        kernel, or filter used in SASMA.
        q               The number of endmember classes to synthesize.
        n               The dimensionality of the spectral subspace.
        labels          The values in em_locations that uniquely identify.
                        each endmember class; default is [1,2,...,q]
        cval            The constant value: Replaces NoData and used in areas
                        outside the window; see NOTE below.
        nodata          The NoData value.
        multiprocess    True to generate multiple processes, one per
                        endmember-band combination, i.e., q*n processes.

    Example of this routine on a tiny numeric array:
        ex = np.where(np.ndarray((1,5,5), dtype=np.int16) % 2 == 0, 0, 1)
        em_map = np.multiply(ex.repeat(ex, 3, 0),
            np.round(np.random.rand(3,5,5), 2))
        NODATA = 0 # Example of a NoData value to filter
        window = np.ravel(kernel_idw_l1(3, band_num=1))
        avg_map = generic_filter(em_map[0,...],
            lambda x: np.sum(np.multiply(x, window)) / np.sum(
                np.multiply(np.where(x == NODATA, 0, 1), window)),
            mode = 'constant', cval = 0, footprint = np.ones((3,3)))
        # If you want to place the original (raw) values into the averaged map
        np.where(em_map[0,...] > 0, em_map[0,...], avg_map)

    NOTE: For performance, NoData areas are filled with zero (0); this way,
    they do not contribute to the spatial sum (i.e., sum([0,...,0]) == 0) and
    they can also be removed from the sum of weights that is the divisor. In
    most cases, this shouldn't be an issue (minimum noise fraction components
    almost never equal zero); however, if areas that equal zero should be
    considered in the weighted sum, simply change cval.
    '''
    shp = spectra.shape
    if labels is None:
        # In absence of user-defined endmember class labels, use integers
        labels = range(1, (q + 1))

    assert len(labels) <= spectra.shape[0], 'The spectra array must have p bands for p endmember class labels'
    masked_spectra = [ # Extract the individual endmember "band" images
        binary_mask(spectra[j,...].reshape((1, shp[1], shp[2])),
            np.where(em_locations == i, 1, 0), nodata = nodata,
                invert = True) for i, j in list(product(labels, range(0, n)))
    ]

    if multiprocess:
        with ProcessPoolExecutor(max_workers = len(masked_spectra)) as executor:
            result = executor.map(
                partial(interpolate_endmember_spectra, window = window,
                    nodata = nodata),
                masked_spectra)

        result = list(result)

    else:
        result = []
        for em_map in masked_spectra:
            result.append(
                interpolate_endmember_spectra(em_map, window, cval, nodata))

    # "Let's get the band back together again"
    synth_ems = []
    for i in range(0, q): # Group bands by endmember type
        synth_ems.append(np.concatenate(result[(i*n):((i+1)*n)], axis = 0))

    return synth_ems
コード例 #3
0
ファイル: visualize.py プロジェクト: isall/unmixing
    def __init__(self,
                 path=None,
                 mask=None,
                 cut_dim=None,
                 ravel=True,
                 transform=True,
                 nodata=None,
                 feature_limit=90000,
                 selected_feature_limit=30,
                 epsg=None,
                 keyword=None,
                 verbose=False):
        self.__nodata__ = nodata
        self.__raveled__ = ravel
        self.__limit__ = feature_limit
        self.__sel_limit__ = selected_feature_limit
        self.__verbose__ = verbose
        self.epsg = epsg
        self.size = (9, 9)
        self.dpi = 72

        if path is not None:
            assert os.path.exists(path), 'No such file or directory'
            ds = gdal.Open(path)  # (p, lat, lng)
            self.keyword = keyword  # A "nickname" for this raster
            self.__wd__ = os.path.dirname(path)
            self.__gt__ = ds.GetGeoTransform()
            self.__wkt__ = ds.GetProjection()
            self.spatial_ref = {'gt': self.__gt__, 'wkt': self.__wkt__}

            if keyword is None:
                # Look for a date (7-8 numbers) set off by underscores
                date_match = re.compile(r'.*_(?P<date>\d{7,8})_.*').match(
                    os.path.basename(path))
                if date_match is not None:
                    self.keyword = date_match.groups()[0]

            # Apply the MNF transformation?
            if transform:
                self.features = mnf_rotation(ds.ReadAsArray())  # (lng, lat, p)

            else:
                self.features = ds.ReadAsArray().transpose()

            if cut_dim:
                # Get rid of extraneous dimensionality
                self.features = self.features[..., 0:cut_dim]
                ds = None

            # Apply a mask?
            if mask is not None:
                if type(mask) == str:
                    mask, gt, wkt = as_array(mask)

                else:
                    if not isinstance(mask, np.ndarray):
                        mask = mask.ReadAsArray()

                self.features = binary_mask(self.features.transpose(),
                                            mask,
                                            nodata=nodata).transpose()
                mask = None

            # Create random features
            self.rfeatures = self.features.copy().reshape(
                (self.features.shape[0] * self.features.shape[1],
                 self.features.shape[2]))
            np.random.shuffle(self.rfeatures)

            # Limit the size of the stored array; keep first 90,000 (300*300)
            if ravel and nodata is not None:
                # Remove all "rows" (pixels) where there is a NoData value in any "column" (band)
                self.rfeatures = self.rfeatures[(self.rfeatures != nodata).any(
                    axis=1), :]

                if self.__limit__ is not None:
                    self.rfeatures = self.rfeatures[0:self.__limit__, :]

            else:
                self.rfeatures = self.rfeatures.reshape(self.features.shape)
                # If a limit was specified, select the first N random pixels
                if self.__limit__ is not None:
                    r = int(np.sqrt(self.__limit__))
                    self.rfeatures = self.rfeatures.reshape(
                        self.features.shape)[0:r, 0:r, :]

            ds = None