Skip to content

Commit

Permalink
Code lint updates
Browse files Browse the repository at this point in the history
  • Loading branch information
tboggs committed Aug 27, 2023
1 parent 6d8de16 commit 1b25497
Show file tree
Hide file tree
Showing 54 changed files with 577 additions and 516 deletions.
2 changes: 2 additions & 0 deletions spectral/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
Basic package setup and global imports.
'''

# flake8: noqa

from __future__ import absolute_import, division, print_function, unicode_literals

__version__ = '0.23.1'
Expand Down
10 changes: 6 additions & 4 deletions spectral/algorithms/__init__.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
# flake8: noqa

from __future__ import absolute_import, division, print_function, unicode_literals

from .algorithms import (mean_cov, covariance, principal_components, bdist,
linear_discriminant, create_training_classes, ndvi,
orthogonalize, transform_image, unmix, spectral_angles,
calc_stats, cov_avg, msam, noise_from_diffs, mnf,
GaussianStats, ppi, smacc)
linear_discriminant, create_training_classes, ndvi,
orthogonalize, transform_image, unmix, spectral_angles,
calc_stats, cov_avg, msam, noise_from_diffs, mnf,
GaussianStats, ppi, smacc)
from .classifiers import *
from .clustering import L1, L2, kmeans
from .resampling import BandResampler
Expand Down
34 changes: 20 additions & 14 deletions spectral/algorithms/algorithms.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from .spymath import matrix_sqrt
from .transforms import LinearTransform


class Iterator:
'''
Base class for iterators over pixels (spectra).
Expand Down Expand Up @@ -50,7 +51,6 @@ def get_num_bands(self):

def __iter__(self):
(M, N) = self.image.shape[:2]
count = 0
for i in range(M):
self.row = i
for j in range(N):
Expand Down Expand Up @@ -86,6 +86,7 @@ def __iter__(self):
(self.row, self.col) = (i, j)
yield self.image[i, j].astype(self.image.dtype).squeeze()


def iterator(image, mask=None, index=None):
'''
Returns an iterator over pixels in the image.
Expand Down Expand Up @@ -292,6 +293,7 @@ def cov_avg(image, mask, weighted=True):
else:
return np.mean([c.cov for c in classes], axis=0, dtype=np.float64)


def covariance(*args):
'''
Returns the covariance of the set of vectors.
Expand Down Expand Up @@ -641,7 +643,6 @@ class covariances, mean vector, and a callable transform to convert data to
Richards, J.A. & Jia, X. Remote Sensing Digital Image Analysis: An
Introduction. (Springer: Berlin, 1999).
'''
C = len(classes) # Number of training sets
rank = len(classes) - 1

classes.calc_stats()
Expand Down Expand Up @@ -677,13 +678,13 @@ class covariances, mean vector, and a callable transform to convert data to

return FisherLinearDiscriminant(vals.real, vecs.real, mean, cov_b, cov_w)


# Alias for Linear Discriminant Analysis (LDA)
lda = linear_discriminant


def log_det(x):
return sum(np.log([eigv for eigv in np.linalg.eigvals(x)
if eigv > 0]))
return sum(np.log([eigv for eigv in np.linalg.eigvals(x) if eigv > 0]))


class GaussianStats(object):
Expand Down Expand Up @@ -933,7 +934,6 @@ def size(self):
else:
return np.sum(np.not_equal(self.mask, 0).ravel())


def calc_stats(self):
'''
Calculates statistics for the class.
Expand Down Expand Up @@ -1050,13 +1050,13 @@ def calc_stats(self):
def save(self, filename, calc_stats=False):
for c in list(self.classes.values()):
if c.stats is None:
if calc_stats == False:
if calc_stats is False:
msg = 'Class statistics are missing from at least one ' \
'class and are required to save the training class ' \
'data. Call the `save` method with keyword ' \
'`calc_stats=True` if you want to compute them and ' \
'then save the class data.'
raise Exception (msg)
raise Exception(msg)
else:
c.calc_stats()
f = open(filename, 'wb')
Expand Down Expand Up @@ -1195,6 +1195,7 @@ def bdist(class1, class2):
terms = bdist_terms(class1, class2)
return terms[0] + terms[1]


bDistance = bdist


Expand Down Expand Up @@ -1364,6 +1365,7 @@ def spectral_angles(data, members):
dots = np.clip(dots / norms[:, :, np.newaxis], -1, 1)
return np.arccos(dots)


def msam(data, members):
'''Modified SAM scores according to Oshigami, et al [1]. Endmembers are
mean-subtracted prior to spectral angle calculation. Results are
Expand Down Expand Up @@ -1417,17 +1419,18 @@ def msam(data, members):

for i in range(M):
for j in range(N):
#Fisher z trafo type operation
# Fisher z trafo type operation
v = data[i, j] - np.mean(data[i, j])
v /= np.sqrt(v.dot(v))
v = np.clip(v, -1, 1)
for k in range(C):
# Calculate Mineral Index according to Oshigami et al.
# (Intnl. J. of Remote Sens. 2013)
a = np.clip(v.dot(m[k]), -1, 1)
angles[i,j,k]= 1.0 - np.arccos(a) / (math.pi / 2)
angles[i, j, k] = 1.0 - np.arccos(a) / (math.pi / 2)
return angles


def noise_from_diffs(X, direction='lowerright'):
'''Estimates noise statistcs by taking differences of adjacent pixels.
Expand Down Expand Up @@ -1469,6 +1472,7 @@ def noise_from_diffs(X, direction='lowerright'):
stats.cov /= 2.0
return stats


class MNFResult(object):
'''Result object returned by :func:`~spectral.algorithms.algorithms.mnf`.
Expand Down Expand Up @@ -1504,7 +1508,7 @@ def _num_from_kwargs(self, **kwargs):
raise Exception('Keyword not recognized.')
num = kwargs.get('num', None)
snr = kwargs.get('snr', None)
if num == snr == None:
if num == snr is None:
raise Exception('Must specify either `num` or `snr` keyword.')
if None not in (num, snr):
raise Exception('Can not specify both `num` and `snr` keywords.')
Expand Down Expand Up @@ -1563,8 +1567,8 @@ def get_denoising_transform(self, **kwargs):
V = self.napc.eigenvectors
Vr = np.array(V)
Vr[:, N:] = 0.
f = LinearTransform(self.noise.sqrt_cov.dot(Vr).dot(V.T) \
.dot(self.noise.sqrt_inv_cov),
f = LinearTransform(self.noise.sqrt_cov.dot(Vr).dot(V.T)
.dot(self.noise.sqrt_inv_cov),
pre=-self.signal.mean,
post=self.signal.mean)
return f
Expand Down Expand Up @@ -1626,6 +1630,7 @@ def num_with_snr(self, snr):
'''Returns the number of components with SNR >= `snr`.'''
return np.sum(self.napc.eigenvalues >= (snr + 1))


def mnf(signal, noise):
'''Computes Minimum Noise Fraction / Noise-Adjusted Principal Components.
Expand Down Expand Up @@ -1686,6 +1691,7 @@ def mnf(signal, noise):
napc = PrincipalComponents(L, V, wstats)
return MNFResult(signal, noise, napc)


def ppi(X, niters, threshold=0, centered=False, start=None, display=0,
**imshow_kwargs):
'''Returns pixel purity indices for an image.
Expand Down Expand Up @@ -1759,7 +1765,7 @@ def ppi(X, niters, threshold=0, centered=False, start=None, display=0,
'''
if display is not None:
if not isinstance(display, Integral) or isinstance(display, bool) or \
display < 0:
display < 0:
msg = '`display` argument must be a non-negative integer.'
raise ValueError(msg)

Expand Down Expand Up @@ -1941,7 +1947,7 @@ def smacc(spectra, min_endmembers=None, max_residual_norm=float('Inf')):
residual_norms[:] = np.sqrt(np.einsum('ij,ij->i', R, R))
current_max_residual_norm = np.max(residual_norms)
print('Found {0} endmembers, current max residual norm is {1:.4f}\r'
.format(len(q), current_max_residual_norm), end='')
.format(len(q), current_max_residual_norm), end='')

# Correction as suggested in the SMACC paper.
for k, s in enumerate(q):
Expand Down
14 changes: 6 additions & 8 deletions spectral/algorithms/classifiers.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
import math
import numpy as np

from warnings import warn

import spectral as spy
from .algorithms import GaussianStats, ImageIterator
from .detectors import RX
Expand All @@ -18,6 +16,7 @@
__all__ = ('GaussianClassifier', 'MahalanobisDistanceClassifier',
'PerceptronClassifier')


class Classifier(object):
'''
Base class for Classifiers. Child classes must implement the
Expand Down Expand Up @@ -149,9 +148,9 @@ def classify_spectrum(self, x):
for (i, cl) in enumerate(self.classes):
delta = (x - cl.stats.mean)
scores[i] = math.log(cl.class_prob) - 0.5 * cl.stats.log_det_cov \
- 0.5 * delta.dot(cl.stats.inv_cov).dot(delta)
- 0.5 * delta.dot(cl.stats.inv_cov).dot(delta)
return self.classes[np.argmax(scores)].index

def classify_image(self, image):
'''Classifies an entire image, returning a classification map.
Expand Down Expand Up @@ -301,7 +300,7 @@ class PerceptronClassifier(Perceptron, SupervisedClassifier):
>>> classes = create_training_classes(xdata, gt)
>>> nfeatures = xdata.shape[-1]
>>> nclasses = len(classes)
>>>
>>>
>>> p = PerceptronClassifier([nfeatures, 20, 8, nclasses])
>>> p.train(classes, 20, clip=0., accuracy=100., batch=1,
>>> momentum=0.3, rate=0.3)
Expand Down Expand Up @@ -407,8 +406,8 @@ class in `training_data`. If this argument is not provided,
if class_data[i].shape[0] > samples_per_class:
class_data[i] = class_data[i][:samples_per_class]
X = np.vstack(class_data)
y = np.hstack([np.ones(c.shape[0], dtype=np.int16) * i for \
(i, c) in enumerate(class_data)])
y = np.hstack([np.ones(c.shape[0], dtype=np.int16) * i for
(i, c) in enumerate(class_data)])
Y = np.eye(np.max(y) + 1, dtype=np.int16)[y]

if 'stdout' in kwargs:
Expand Down Expand Up @@ -441,4 +440,3 @@ def classify_spectrum(self, x):

def classify(self, X, **kwargs):
return Classifier.classify(self, X, **kwargs)

3 changes: 1 addition & 2 deletions spectral/algorithms/clustering.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
import numpy as np

import spectral as spy
from .classifiers import Classifier
from ..utilities.errors import has_nan, NaNValueError


def L1(v1, v2):
'Returns L1 distance between 2 rank-1 arrays.'
return np.sum(abs((v1 - v2)))
Expand Down Expand Up @@ -360,4 +360,3 @@ def kmeans_ndarray(image, nclusters=10, max_iterations=20, **kwargs):
logger.info('kmeans terminated with %d clusters after %d iterations.',
len(set(old_clusters.ravel())), itnum - 1)
return (old_clusters.reshape(nrows, ncols), centers)

4 changes: 0 additions & 4 deletions spectral/algorithms/continuum.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,8 @@

from __future__ import absolute_import, division, print_function, unicode_literals

import logging
import numpy as np

import spectral as spy
from ..utilities.errors import has_nan, NaNValueError


def _segment_concave_region(spectrum, bands, indices, ind_fill, ibegin, iend):
# Here we don't search for local maxima w.r.t. line that connects ends of this region.
Expand Down
Loading

0 comments on commit 1b25497

Please sign in to comment.