Commit 226a7a5b authored by Daniel Scheffler's avatar Daniel Scheffler
Browse files

Added FEDSA classifier + enhanced test for image classifiers.


Signed-off-by: Daniel Scheffler's avatarDaniel Scheffler <danschef@gfz-potsdam.de>
parent 380a4c19
Pipeline #3997 failed with stage
in 2 minutes and 22 seconds
......@@ -317,6 +317,70 @@ class SAM_Classifier(_ImageClassifier):
self._show_distance_metrics(**kwargs)
class FEDSA_Classifier(_ImageClassifier):
def __init__(self, train_spectra, CPUs=1):
# type: (np.ndarray, Union[int, None]) -> None
super(FEDSA_Classifier, self).__init__(train_spectra, np.array(range(train_spectra.shape[0])), CPUs=CPUs)
self.clf_name = 'fused euclidian distance / spectral angle (FEDSA)'
@property
def fedsa(self):
return self._distance_metrics
def _predict(self, tilepos):
assert global_shared_endmembers is not None and global_shared_im2classify is not None
(rS, rE), (cS, cE) = tilepos
tileimdata = global_shared_im2classify[rS: rE + 1, cS: cE + 1, :]
endmembers = global_shared_endmembers
if not tileimdata.shape[2] == self.train_spectra.shape[1]:
raise RuntimeError('Matrix dimensions are not aligned. Input image has %d bands but input spectra '
'have %d.' % (tileimdata.shape[2], self.train_spectra.shape[1]))
# normalize input data because SAM asserts only data between -1 and 1
train_spectra_norm, tileimdata_norm = normalize_endmembers_image(endmembers, tileimdata)
angles = np.zeros((tileimdata.shape[0], tileimdata.shape[1], self.n_samples), np.float)
ed = np.zeros((tileimdata.shape[0], tileimdata.shape[1], self.n_samples), np.float)
tileimspectra = im2spectra(tileimdata)
# if np.std(tileimdata) == 0: # skip tiles that only contain the same value
# loop over all training spectra and compute spectral angle for each pixel
for n_sample in range(self.n_samples):
train_spectrum = train_spectra_norm[n_sample, :].reshape(1, 1, self.n_features)
angles[:, :, n_sample] = calc_sam(tileimdata_norm, train_spectrum, axis=2)
ed[:, :, n_sample] = np.sqrt(np.sum((tileimspectra.astype(np.float) -
train_spectrum.flatten().astype(np.float)) ** 2, axis=1))\
.reshape(tileimdata.shape[:2])
angles_norm = angles / angles.max()
ed_norm = ed / ed.max()
fedsa = (angles_norm + ed_norm) / 2
fedsa_min = np.min(fedsa, axis=2).astype(np.float32)
cmap = np.argmin(fedsa, axis=2).astype(np.int16)
if global_shared_im2classify.nodata is not None and self._cmap_nodataVal is not None:
cmap = self.overwrite_cmap_at_nodata_positions(cmap, tileimdata,
self._cmap_nodataVal, global_shared_im2classify.nodata)
return tilepos, cmap.astype(np.int16), fedsa_min
def label_unclassified_pixels(self, label_unclassified, threshold):
# type: (int, Union[str, int, float]) -> GeoArray
return self._label_unclassified_pixels(
self.cmap, label_unclassified, threshold, self.fedsa
)
def show_fedsa_histogram(self, figsize=(10, 5), bins=100, normed=False):
self._show_distances_histogram(self.fedsa, self.cmap, figsize=figsize, bins=bins, normed=normed)
def show_fedsa(self, **kwargs):
self._show_distance_metrics(**kwargs)
class SID_Classifier(_ImageClassifier):
def __init__(self, train_spectra, CPUs=1):
# type: (np.ndarray, Union[int, None]) -> None
......
......@@ -18,7 +18,7 @@ from geoarray import GeoArray
from gms_preprocessing import set_config
from gms_preprocessing.algorithms.classification import \
MinimumDistance_Classifier, kNN_Classifier, SAM_Classifier, SID_Classifier, RF_Classifier
MinimumDistance_Classifier, kNN_Classifier, SAM_Classifier, FEDSA_Classifier, SID_Classifier, RF_Classifier
from . import db_host
......@@ -39,6 +39,9 @@ with zipfile.ZipFile(path_classifier_zip, "r") as zf, tempfile.TemporaryDirector
cluster_centers = np.array([ml.cluster_center for ml in CC.values()])
cluster_labels = list(CC.keys())
test_gA_pure_endmembers = np.zeros((1, cluster_centers.shape[0], cluster_centers.shape[1]), dtype=cluster_centers.dtype)
test_gA_pure_endmembers[:, :, :] = cluster_centers
class Test_MinimumDistance_Classifier(unittest.TestCase):
def test_classify(self):
......@@ -54,6 +57,10 @@ class Test_MinimumDistance_Classifier(unittest.TestCase):
self.assertTrue(np.array_equal(cmap_sp, cmap_mp))
MDC = MinimumDistance_Classifier(cluster_centers, cluster_labels, CPUs=None)
cmap_mp = MDC.classify(test_gA_pure_endmembers, in_nodataVal=-9999, cmap_nodataVal=-9999)
self.assertTrue(np.array_equal(cmap_mp.flatten(), cluster_labels))
def test_label_unclassified_pixels_absolute_th(self):
MDC = MinimumDistance_Classifier(cluster_centers, cluster_labels, CPUs=1)
MDC.classify(test_gA, in_nodataVal=-9999, cmap_nodataVal=-9999, tiledims=(400, 200))
......@@ -79,6 +86,10 @@ class Test_kNN_Classifier(unittest.TestCase):
self.assertTrue(np.array_equal(cmap_sp, cmap_mp))
kNNC = kNN_Classifier(cluster_centers, cluster_labels, CPUs=None)
cmap_mp = kNNC.classify(test_gA_pure_endmembers, in_nodataVal=-9999)
self.assertTrue(np.array_equal(cmap_mp.flatten(), cluster_labels))
class Test_SAM_Classifier(unittest.TestCase):
def test_classify(self):
......@@ -94,6 +105,10 @@ class Test_SAM_Classifier(unittest.TestCase):
self.assertTrue(np.array_equal(cmap_sp, cmap_mp))
SC = SAM_Classifier(cluster_centers, CPUs=None)
cmap_mp = SC.classify(test_gA_pure_endmembers, in_nodataVal=-9999, cmap_nodataVal=-9999)
self.assertTrue(np.array_equal(cmap_mp.flatten(), cluster_labels))
def test_label_unclassified_pixels_absolute_th(self):
SC = SAM_Classifier(cluster_centers, CPUs=None)
SC.classify(test_gA, in_nodataVal=-9999, cmap_nodataVal=-9999, tiledims=(400, 200))
......@@ -105,6 +120,25 @@ class Test_SAM_Classifier(unittest.TestCase):
SC.label_unclassified_pixels(label_unclassified=-1, threshold='10%')
class Test_FEDSA_Classifier(unittest.TestCase):
def test_classify(self):
FC = FEDSA_Classifier(cluster_centers, CPUs=1)
cmap_sp = FC.classify(test_gA, in_nodataVal=-9999, tiledims=(400, 200))
self.assertIsInstance(cmap_sp, GeoArray)
self.assertEqual(cmap_sp.shape, (1010, 1010))
FC = FEDSA_Classifier(cluster_centers, CPUs=None)
cmap_mp = FC.classify(test_gA, in_nodataVal=-9999, tiledims=(400, 200))
self.assertIsInstance(cmap_mp, GeoArray)
self.assertEqual(cmap_mp.shape, (1010, 1010))
self.assertTrue(np.array_equal(cmap_sp, cmap_mp))
FC = FEDSA_Classifier(cluster_centers, CPUs=None)
cmap_mp = FC.classify(test_gA_pure_endmembers, in_nodataVal=-9999, tiledims=(400, 200))
self.assertTrue(np.array_equal(cmap_mp.flatten(), cluster_labels))
class Test_SID_Classifier(unittest.TestCase):
def test_classify(self):
SC = SID_Classifier(cluster_centers, CPUs=1)
......@@ -119,6 +153,10 @@ class Test_SID_Classifier(unittest.TestCase):
self.assertTrue(np.array_equal(cmap_sp, cmap_mp))
SC = SID_Classifier(cluster_centers, CPUs=None)
cmap_mp = SC.classify(test_gA_pure_endmembers, in_nodataVal=-9999, tiledims=(400, 200))
self.assertTrue(np.array_equal(cmap_mp.flatten(), cluster_labels))
class Test_RF_Classifier(unittest.TestCase):
def test_classify(self):
......@@ -133,3 +171,7 @@ class Test_RF_Classifier(unittest.TestCase):
self.assertEqual(cmap_mp.shape, (1010, 1010))
self.assertTrue(np.array_equal(cmap_sp, cmap_mp))
RFC = RF_Classifier(cluster_centers, cluster_labels, CPUs=None, **dict(random_state=0))
cmap_mp = RFC.classify(test_gA_pure_endmembers, in_nodataVal=-9999, tiledims=(400, 200))
self.assertTrue(np.array_equal(cmap_mp.flatten(), cluster_labels))
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment