|
15 | 15 | from .spymath import matrix_sqrt
|
16 | 16 | from .transforms import LinearTransform
|
17 | 17 |
|
| 18 | + |
18 | 19 | class Iterator:
|
19 | 20 | '''
|
20 | 21 | Base class for iterators over pixels (spectra).
|
@@ -50,7 +51,6 @@ def get_num_bands(self):
|
50 | 51 |
|
51 | 52 | def __iter__(self):
|
52 | 53 | (M, N) = self.image.shape[:2]
|
53 |
| - count = 0 |
54 | 54 | for i in range(M):
|
55 | 55 | self.row = i
|
56 | 56 | for j in range(N):
|
@@ -86,6 +86,7 @@ def __iter__(self):
|
86 | 86 | (self.row, self.col) = (i, j)
|
87 | 87 | yield self.image[i, j].astype(self.image.dtype).squeeze()
|
88 | 88 |
|
| 89 | + |
89 | 90 | def iterator(image, mask=None, index=None):
|
90 | 91 | '''
|
91 | 92 | Returns an iterator over pixels in the image.
|
@@ -292,6 +293,7 @@ def cov_avg(image, mask, weighted=True):
|
292 | 293 | else:
|
293 | 294 | return np.mean([c.cov for c in classes], axis=0, dtype=np.float64)
|
294 | 295 |
|
| 296 | + |
295 | 297 | def covariance(*args):
|
296 | 298 | '''
|
297 | 299 | Returns the covariance of the set of vectors.
|
@@ -641,7 +643,6 @@ class covariances, mean vector, and a callable transform to convert data to
|
641 | 643 | Richards, J.A. & Jia, X. Remote Sensing Digital Image Analysis: An
|
642 | 644 | Introduction. (Springer: Berlin, 1999).
|
643 | 645 | '''
|
644 |
| - C = len(classes) # Number of training sets |
645 | 646 | rank = len(classes) - 1
|
646 | 647 |
|
647 | 648 | classes.calc_stats()
|
@@ -677,13 +678,13 @@ class covariances, mean vector, and a callable transform to convert data to
|
677 | 678 |
|
678 | 679 | return FisherLinearDiscriminant(vals.real, vecs.real, mean, cov_b, cov_w)
|
679 | 680 |
|
| 681 | + |
680 | 682 | # Alias for Linear Discriminant Analysis (LDA)
|
681 | 683 | lda = linear_discriminant
|
682 | 684 |
|
683 | 685 |
|
684 | 686 | def log_det(x):
|
685 |
| - return sum(np.log([eigv for eigv in np.linalg.eigvals(x) |
686 |
| - if eigv > 0])) |
| 687 | + return sum(np.log([eigv for eigv in np.linalg.eigvals(x) if eigv > 0])) |
687 | 688 |
|
688 | 689 |
|
689 | 690 | class GaussianStats(object):
|
@@ -933,7 +934,6 @@ def size(self):
|
933 | 934 | else:
|
934 | 935 | return np.sum(np.not_equal(self.mask, 0).ravel())
|
935 | 936 |
|
936 |
| - |
937 | 937 | def calc_stats(self):
|
938 | 938 | '''
|
939 | 939 | Calculates statistics for the class.
|
@@ -1050,13 +1050,13 @@ def calc_stats(self):
|
1050 | 1050 | def save(self, filename, calc_stats=False):
|
1051 | 1051 | for c in list(self.classes.values()):
|
1052 | 1052 | if c.stats is None:
|
1053 |
| - if calc_stats == False: |
| 1053 | + if calc_stats is False: |
1054 | 1054 | msg = 'Class statistics are missing from at least one ' \
|
1055 | 1055 | 'class and are required to save the training class ' \
|
1056 | 1056 | 'data. Call the `save` method with keyword ' \
|
1057 | 1057 | '`calc_stats=True` if you want to compute them and ' \
|
1058 | 1058 | 'then save the class data.'
|
1059 |
| - raise Exception (msg) |
| 1059 | + raise Exception(msg) |
1060 | 1060 | else:
|
1061 | 1061 | c.calc_stats()
|
1062 | 1062 | f = open(filename, 'wb')
|
@@ -1195,6 +1195,7 @@ def bdist(class1, class2):
|
1195 | 1195 | terms = bdist_terms(class1, class2)
|
1196 | 1196 | return terms[0] + terms[1]
|
1197 | 1197 |
|
| 1198 | + |
1198 | 1199 | bDistance = bdist
|
1199 | 1200 |
|
1200 | 1201 |
|
@@ -1364,6 +1365,7 @@ def spectral_angles(data, members):
|
1364 | 1365 | dots = np.clip(dots / norms[:, :, np.newaxis], -1, 1)
|
1365 | 1366 | return np.arccos(dots)
|
1366 | 1367 |
|
| 1368 | + |
1367 | 1369 | def msam(data, members):
|
1368 | 1370 | '''Modified SAM scores according to Oshigami, et al [1]. Endmembers are
|
1369 | 1371 | mean-subtracted prior to spectral angle calculation. Results are
|
@@ -1417,17 +1419,18 @@ def msam(data, members):
|
1417 | 1419 |
|
1418 | 1420 | for i in range(M):
|
1419 | 1421 | for j in range(N):
|
1420 |
| - #Fisher z trafo type operation |
| 1422 | + # Fisher z trafo type operation |
1421 | 1423 | v = data[i, j] - np.mean(data[i, j])
|
1422 | 1424 | v /= np.sqrt(v.dot(v))
|
1423 | 1425 | v = np.clip(v, -1, 1)
|
1424 | 1426 | for k in range(C):
|
1425 | 1427 | # Calculate Mineral Index according to Oshigami et al.
|
1426 | 1428 | # (Intnl. J. of Remote Sens. 2013)
|
1427 | 1429 | a = np.clip(v.dot(m[k]), -1, 1)
|
1428 |
| - angles[i,j,k]= 1.0 - np.arccos(a) / (math.pi / 2) |
| 1430 | + angles[i, j, k] = 1.0 - np.arccos(a) / (math.pi / 2) |
1429 | 1431 | return angles
|
1430 | 1432 |
|
| 1433 | + |
1431 | 1434 | def noise_from_diffs(X, direction='lowerright'):
|
1432 | 1435 | '''Estimates noise statistcs by taking differences of adjacent pixels.
|
1433 | 1436 |
|
@@ -1469,6 +1472,7 @@ def noise_from_diffs(X, direction='lowerright'):
|
1469 | 1472 | stats.cov /= 2.0
|
1470 | 1473 | return stats
|
1471 | 1474 |
|
| 1475 | + |
1472 | 1476 | class MNFResult(object):
|
1473 | 1477 | '''Result object returned by :func:`~spectral.algorithms.algorithms.mnf`.
|
1474 | 1478 |
|
@@ -1504,7 +1508,7 @@ def _num_from_kwargs(self, **kwargs):
|
1504 | 1508 | raise Exception('Keyword not recognized.')
|
1505 | 1509 | num = kwargs.get('num', None)
|
1506 | 1510 | snr = kwargs.get('snr', None)
|
1507 |
| - if num == snr == None: |
| 1511 | + if num == snr is None: |
1508 | 1512 | raise Exception('Must specify either `num` or `snr` keyword.')
|
1509 | 1513 | if None not in (num, snr):
|
1510 | 1514 | raise Exception('Can not specify both `num` and `snr` keywords.')
|
@@ -1563,8 +1567,8 @@ def get_denoising_transform(self, **kwargs):
|
1563 | 1567 | V = self.napc.eigenvectors
|
1564 | 1568 | Vr = np.array(V)
|
1565 | 1569 | Vr[:, N:] = 0.
|
1566 |
| - f = LinearTransform(self.noise.sqrt_cov.dot(Vr).dot(V.T) \ |
1567 |
| - .dot(self.noise.sqrt_inv_cov), |
| 1570 | + f = LinearTransform(self.noise.sqrt_cov.dot(Vr).dot(V.T) |
| 1571 | + .dot(self.noise.sqrt_inv_cov), |
1568 | 1572 | pre=-self.signal.mean,
|
1569 | 1573 | post=self.signal.mean)
|
1570 | 1574 | return f
|
@@ -1626,6 +1630,7 @@ def num_with_snr(self, snr):
|
1626 | 1630 | '''Returns the number of components with SNR >= `snr`.'''
|
1627 | 1631 | return np.sum(self.napc.eigenvalues >= (snr + 1))
|
1628 | 1632 |
|
| 1633 | + |
1629 | 1634 | def mnf(signal, noise):
|
1630 | 1635 | '''Computes Minimum Noise Fraction / Noise-Adjusted Principal Components.
|
1631 | 1636 |
|
@@ -1686,6 +1691,7 @@ def mnf(signal, noise):
|
1686 | 1691 | napc = PrincipalComponents(L, V, wstats)
|
1687 | 1692 | return MNFResult(signal, noise, napc)
|
1688 | 1693 |
|
| 1694 | + |
1689 | 1695 | def ppi(X, niters, threshold=0, centered=False, start=None, display=0,
|
1690 | 1696 | **imshow_kwargs):
|
1691 | 1697 | '''Returns pixel purity indices for an image.
|
@@ -1759,7 +1765,7 @@ def ppi(X, niters, threshold=0, centered=False, start=None, display=0,
|
1759 | 1765 | '''
|
1760 | 1766 | if display is not None:
|
1761 | 1767 | if not isinstance(display, Integral) or isinstance(display, bool) or \
|
1762 |
| - display < 0: |
| 1768 | + display < 0: |
1763 | 1769 | msg = '`display` argument must be a non-negative integer.'
|
1764 | 1770 | raise ValueError(msg)
|
1765 | 1771 |
|
@@ -1941,7 +1947,7 @@ def smacc(spectra, min_endmembers=None, max_residual_norm=float('Inf')):
|
1941 | 1947 | residual_norms[:] = np.sqrt(np.einsum('ij,ij->i', R, R))
|
1942 | 1948 | current_max_residual_norm = np.max(residual_norms)
|
1943 | 1949 | print('Found {0} endmembers, current max residual norm is {1:.4f}\r'
|
1944 |
| - .format(len(q), current_max_residual_norm), end='') |
| 1950 | + .format(len(q), current_max_residual_norm), end='') |
1945 | 1951 |
|
1946 | 1952 | # Correction as suggested in the SMACC paper.
|
1947 | 1953 | for k, s in enumerate(q):
|
|
0 commit comments