Esempio n. 1
0
def denoise(data, num=None, snr=None):
    """
    Denoises nd array with the format n x p x b

    Parameters:
    -----------
    data : nd array
        3-d numpy array with b = band
    num : int
        number of bands used
    snr : int
        threshold
    Returns
    -------
    denoised array with same shape as data
    """
    signal = spectral.calc_stats(data)
    noise = spectral.noise_from_diffs(data)
    mnfr = spectral.mnf(signal, noise)
    if num:
        denoised, trans = mnfr.denoise(data, num=num)
        print(50*'_')
        print(trans.shape)
    elif snr:
        denoised = mnfr.denoise(data, snr=snr)
        print("--------------")
        print(mnfr.num_with_snr(snr=snr))
    else:
        raise ValueError('"snr" or "num" must be given!')
    return denoised, trans
Esempio n. 2
0
 def test_mnf_all_equals_data(self):
     '''Test that MNF transform with all components equals original data.'''
     data = self.data
     signal = spy.calc_stats(data)
     noise = spy.noise_from_diffs(data[117:137, 85:122, :])
     mnfr = spy.mnf(signal, noise)
     denoised = mnfr.denoise(data, num=data.shape[-1])
     assert_allclose(denoised, data)
Esempio n. 3
0
 def test_mnf_all_equals_data(self):
     '''Test that MNF transform with all components equals original data.'''
     data = self.data
     signal = spy.calc_stats(data)
     noise = spy.noise_from_diffs(data[117: 137, 85: 122, :])
     mnfr = spy.mnf(signal, noise)
     denoised = mnfr.denoise(data, num=data.shape[-1])
     assert(np.allclose(denoised, data))
with rasterio.open(instack) as intif:
    stack = intif.read()
    land = stack[7, :, :] > 500
    np.count_nonzero(land)
    out_meta = intif.meta.copy()
    (stack[:, land]) = 0
    t_stack = np.transpose(stack, (1, 2, 0))
help(spectral.calc_stats)
ss = stack.shape[0]
print(t_stack.shape)
# help(spectral.calc_stats)
#view =imshow(t_stack,(8,3,2))
signal = spectral.calc_stats(t_stack)
noise = spectral.noise_from_diffs(t_stack)
mnfr = spectral.mnf(signal, noise)
t_denoised = mnfr.denoise(t_stack, num=5)
t_reduced = mnfr.reduce(t_stack, num=5)
t_reduced.shape
t_denoised.shape
tt_denoised = np.transpose(t_denoised, (2, 0, 1))
tt_reduced = np.transpose(t_reduced, (2, 0, 1))
tt_stack = np.transpose(t_stack, (2, 0, 1))
tt_reduced.shape
out_meta['count'] = 13
tt_denoised.shape
tt_denoised.shape
np.max(tt_denoised[2:, ])
np.min(tt_denoised[1:, ])
view = spectral.imshow(t_denoised, (1, 3, 2))
for i in range(0, out_meta['count']):
Esempio n. 5
0
def MNF(hydata,
        output_bands=20,
        denoise_bands=40,
        band_range=None,
        inplace=False):
    """
    Apply a minimum noise filter to a hyperspectral image.

    *Arguments*:
     - hydata = A HyData instance containing the source dataset (e.g. image or point cloud).
     - output_bands = the number of bands to keep after MNF (dimensionality reduction). Default is 20.
     - denoise_bands = number of high-noise bands to treat as noise for denoising.
     - band_range = the spectral range to perform the MNF over. If (int,int) is passed then the values are treated as
                    min/max band IDs, if (float,float) is passed then values are treated as wavelenghts (in nm). If None is
                    passed (default) then the MNF is computed using all bands. Note that wavelengths can only be passed
                    if image is a hyImage object.
     - inplace = True if the original image should be denoised based on the MNF transform. Default is False.
    *Returns*:
     - mnf = a HyData instance containing the MNF bands.Note that only bands 0:*out_bands* will be kept in this dataset.
     - factors = A 2D numpy array containing the factors applied to the input datset. Useful
                 for plotting/interpreting the regions each MNF band is sensitive too.
    """

    # prepare data for MNF
    wav = hydata.get_wavelengths()
    decomp = False
    if hydata.is_int():
        hydata.decompress()  #MNF doesn't work very well with ints....
        decomp = True  #so we can compress again afterwards
    data = hydata.data

    # get range of bands to include in calculation
    if band_range is None:  # default to all bands
        minb = 0
        maxb = data.shape[-1]
    else:
        minb = hydata.get_band_index(band_range[0])
        maxb = hydata.get_band_index(band_range[1])

    assert minb < maxb, "Error - invalid range... band_range[0] > band_range[1]??"
    assert minb < data.shape[-1], "Error - band_range[0] out of range."
    if maxb == -1 or maxb > data.shape[-1]: maxb = data.shape[-1]

    # remove invalid bands
    valid_bands = []
    for b in range(minb, maxb):
        if np.isfinite(data[..., b]).any() \
                and not (np.nanmax(data[..., b]) == 0).all():
            valid_bands.append(b)

    #remove invalid bands
    data = np.array(data[..., valid_bands])

    # warn if bands have negative values...
    if np.nanmin(data) < 0.0:
        print(
            "Warning - image contains negative pixels. This can cause unstable behaviour..."
        )

    # calculate signal stats (as in spectral.calc_stats(...) but allowing for nans)
    X = data.reshape(
        -1, data.shape[-1]).T  # reshape to 1D list of pixels for each band
    X = X[:, np.isfinite(np.sum(X, axis=0))]  # drop columns containing nans
    X = X[:, np.sum(X, axis=0) > 0]  #drop columns containing all zeros
    mean = np.mean(X, axis=1)
    cov = np.cov(X)
    n = X.shape[1]
    signal = spectral.GaussianStats(mean, cov, n)

    # calculate noise as per spectral.noise_from_diffs (but allowing for nans)
    if len(data.shape) == 3:  # image data
        deltas = data[:-1, :-1, :] - data[
            1:, 1:, :]  #estimate noise by subtracting adjacent pixels
    elif len(data.shape) == 2:  #point cloud data
        deltas = data[:-1, :] - data[
            1:, :]  # estimate noise by subtracting adjacent points

    X = deltas.reshape(-1, deltas.shape[-1]).T
    X = X[:, np.isfinite(np.sum(X, axis=0))]  # drop columns containing nans
    X = X[:, np.sum(X, axis=0) > 0]  # drop columns containing all zeros
    X = X[:, np.sum(X, axis=0) < np.nanpercentile(np.sum(
        X, axis=0), 50)]  #drop high noise data (these relate to edges)
    mean = np.mean(X, axis=1)
    cov = np.cov(X)
    n = X.shape[1]
    noise = spectral.GaussianStats(mean, cov, n)

    mnfr = spectral.mnf(signal, noise)

    # reduce bands
    reduced = mnfr.reduce(data, num=output_bands)

    #apply sign correction so there are less positive pixels than negative ones (sign is aribrary, helps maintain
    #consistency for plotting etc. by having low-valued background with some high-value regions (<50%)
    sign = np.nanmedian(reduced /
                        np.abs(reduced))  #n.b. this will always be 1.0 or -1.0
    assert np.isfinite(sign), "Weird error - no non-nan values in MNF result?"
    reduced *= sign

    # denoise and export
    denoise = mnfr.denoise(data, num=denoise_bands)

    #update original image bands?
    if inplace:
        data[..., valid_bands] = denoise

    #calculate factors (for determining "important" bands)
    # noinspection PyProtectedMember
    factors = sign * mnfr.get_reduction_transform(num=output_bands)._A
    if not wav is None:
        wav = wav[valid_bands]

    #compress input dataset (so we don't change it)
    if decomp:
        hydata.compress()

    #prepare output
    out = hydata.copy(data=False)
    out.header.drop_all_bands()  # drop band specific attributes
    out.data = reduced
    out.push_to_header()

    return out, factors