Commit fab1813e authored by Daniel Scheffler's avatar Daniel Scheffler
Browse files

Cluster classifiers can now be saved as JSON files. Added attributes...


Cluster classifiers can now be saved as JSON files. Added attributes 'spechomo_version' and 'spechomo_versionalias' to ClusterLearner.
Signed-off-by: Daniel Scheffler's avatarDaniel Scheffler <danschef@gfz-potsdam.de>
parent bf370a16
Pipeline #17052 passed with stage
in 9 minutes and 29 seconds
...@@ -2,6 +2,13 @@ ...@@ -2,6 +2,13 @@
History History
======= =======
0.9.2 (2020-12-15)
------------------
* Cluster classifiers can now be saved as JSON files.
* Added attributes 'spechomo_version' and 'spechomo_versionalias' to ClusterLearner.
0.9.1 (2020-12-11) 0.9.1 (2020-12-11)
------------------ ------------------
......
...@@ -78,6 +78,10 @@ class Cluster_Learner(object): ...@@ -78,6 +78,10 @@ class Cluster_Learner(object):
self.tgt_wavelengths = sample_MLinst.tgt_wavelengths self.tgt_wavelengths = sample_MLinst.tgt_wavelengths
self.n_clusters = sample_MLinst.n_clusters self.n_clusters = sample_MLinst.n_clusters
self.cluster_centers = np.array([cc.cluster_center for cc in self.MLdict.values()]) self.cluster_centers = np.array([cc.cluster_center for cc in self.MLdict.values()])
self.spechomo_version = \
sample_MLinst.spechomo_version if hasattr(sample_MLinst, 'spechomo_version') else 'NA'
self.spechomo_versionalias = \
sample_MLinst.spechomo_versionalias if hasattr(sample_MLinst, 'spechomo_versionalias') else 'NA'
@classmethod @classmethod
def from_disk(cls, classifier_rootDir, method, n_clusters, def from_disk(cls, classifier_rootDir, method, n_clusters,
...@@ -252,7 +256,7 @@ class Cluster_Learner(object): ...@@ -252,7 +256,7 @@ class Cluster_Learner(object):
NOTE: This version of the prediction function uses the prediction coefficients of multiple spectral clusters NOTE: This version of the prediction function uses the prediction coefficients of multiple spectral clusters
and computes the result as weighted average of them. Therefore, the classification map must assign and computes the result as weighted average of them. Therefore, the classification map must assign
multiple spectral cluster to each input pixel. multiple spectral clusters to each input pixel.
# NOTE: At unclassified pixels (cmap_3D[y,x,z>0] == -1) the prediction result using global coefficients # NOTE: At unclassified pixels (cmap_3D[y,x,z>0] == -1) the prediction result using global coefficients
# is ignored in the weighted average. In that case the prediction result is based on the found valid # is ignored in the weighted average. In that case the prediction result is based on the found valid
...@@ -280,17 +284,22 @@ class Cluster_Learner(object): ...@@ -280,17 +284,22 @@ class Cluster_Learner(object):
for band in range(cmap_3D.shape[2]): for band in range(cmap_3D.shape[2]):
ims_pred_temp.append( ims_pred_temp.append(
self.predict(im_src, cmap_3D[:, :, band], self.predict(im_src,
cmap_3D[:, :, band],
nodataVal=nodataVal, nodataVal=nodataVal,
cmap_nodataVal=cmap_nodataVal, cmap_nodataVal=cmap_nodataVal,
cmap_unclassifiedVal=cmap_unclassifiedVal cmap_unclassifiedVal=cmap_unclassifiedVal
)) ))
# merge classification results by weighted averaging # merge classification results by weighted averaging
nsamp, nbandpred, nbandscmap = np.dot(*weights_3D.shape[:2]), ims_pred_temp[0].shape[2], weights_3D.shape[2] nsamp = np.dot(*weights_3D.shape[:2])
nbandpred = ims_pred_temp[0].shape[2]
nbandscmap = weights_3D.shape[2]
weights = \ weights = \
np.ones((nsamp, nbandpred, nbandscmap)) if weights_3D is None else \ np.ones((nsamp, nbandpred, nbandscmap)) if weights_3D is None else \
np.tile(weights_3D.reshape(nsamp, 1, nbandscmap), (1, nbandpred, 1)) # nclust x n_tgt_bands x n_cmap_bands np.tile(weights_3D.reshape((nsamp, 1, nbandscmap)),
(1, nbandpred, 1)) # nclust x n_tgt_bands x n_cmap_bands
# set weighting of unclassified pixel positions to zero (except from the first cmap band) # set weighting of unclassified pixel positions to zero (except from the first cmap band)
# -> see NOTE #2 in the docstring # -> see NOTE #2 in the docstring
...@@ -298,8 +307,12 @@ class Cluster_Learner(object): ...@@ -298,8 +307,12 @@ class Cluster_Learner(object):
# mask_unclassif[:, :, :1] = False # if all other clusters are invalid, at least the first one is used for prediction # noqa # mask_unclassif[:, :, :1] = False # if all other clusters are invalid, at least the first one is used for prediction # noqa
# weights[mask_unclassif] = 0 # weights[mask_unclassif] = 0
spectra_pred = np.average(np.dstack([im2spectra(im) for im in ims_pred_temp]), weights=weights, axis=2) spectra_pred = np.average(np.dstack([im2spectra(im) for im in ims_pred_temp]),
im_pred = spectra2im(spectra_pred, tgt_rows=im_src.shape[0], tgt_cols=im_src.shape[1]) weights=weights,
axis=2)
im_pred = spectra2im(spectra_pred,
tgt_rows=im_src.shape[0],
tgt_cols=im_src.shape[1])
return im_pred return im_pred
...@@ -396,7 +409,8 @@ class Cluster_Learner(object): ...@@ -396,7 +409,8 @@ class Cluster_Learner(object):
def to_jsonable_dict(self): def to_jsonable_dict(self):
"""Create a dictionary containing a JSONable replicate of the current Cluster_Learner instance.""" """Create a dictionary containing a JSONable replicate of the current Cluster_Learner instance."""
common_meta_keys = ['src_satellite', 'src_sensor', 'tgt_satellite', 'tgt_sensor', 'src_LBA', 'tgt_LBA', common_meta_keys = ['src_satellite', 'src_sensor', 'tgt_satellite', 'tgt_sensor', 'src_LBA', 'tgt_LBA',
'src_n_bands', 'tgt_n_bands', 'src_wavelengths', 'tgt_wavelengths', 'n_clusters'] 'src_n_bands', 'tgt_n_bands', 'src_wavelengths', 'tgt_wavelengths', 'n_clusters',
'spechomo_version', 'spechomo_versionalias']
jsonable_dict = dict() jsonable_dict = dict()
decode_types_dict = dict() decode_types_dict = dict()
...@@ -422,16 +436,13 @@ class Cluster_Learner(object): ...@@ -422,16 +436,13 @@ class Cluster_Learner(object):
return jsonable_dict return jsonable_dict
# def save_to_json(self, filepath): def save_to_json(self, filepath):
# dict2save = dict( jsonable_dict = self.to_jsonable_dict()
# cluster_centers=self.cluster_centers.tolist(),
# # Create json and save to file
# ) json_txt = json.dumps(jsonable_dict, sort_keys=True, indent=4)
# with open(filepath, 'w') as file:
# # Create json and save to file file.write(json_txt)
# json_txt = json.dumps(dict2save, indent=4)
# with open(filepath, 'w') as file:
# file.write(json_txt)
class ClassifierCollection(object): class ClassifierCollection(object):
......
...@@ -521,6 +521,9 @@ class ClusterClassifier_Generator(object): ...@@ -521,6 +521,9 @@ class ClusterClassifier_Generator(object):
ML.rmse_per_band = list(rmse) ML.rmse_per_band = list(rmse)
ML.mae_per_band = list(mae) ML.mae_per_band = list(mae)
ML.mape_per_band = list(mape) ML.mape_per_band = list(mape)
from .version import __version__, __versionalias__
ML.spechomo_version = __version__
ML.spechomo_versionalias = __versionalias__
# convert float64 attributes to float32 to save memory (affects <0,05% of homogenized pixels by 1 DN) # convert float64 attributes to float32 to save memory (affects <0,05% of homogenized pixels by 1 DN)
for attr in ['coef_', 'intercept_', 'singular_', '_residues']: for attr in ['coef_', 'intercept_', 'singular_', '_residues']:
......
...@@ -35,7 +35,7 @@ Tests for spechomo.classifier ...@@ -35,7 +35,7 @@ Tests for spechomo.classifier
import os import os
import json import json
from unittest import TestCase from unittest import TestCase
# from tempfile import TemporaryDirectory from tempfile import TemporaryDirectory
from spechomo.classifier import Cluster_Learner from spechomo.classifier import Cluster_Learner
from spechomo import __path__ from spechomo import __path__
...@@ -72,9 +72,9 @@ class Test_ClusterClassifier(TestCase): ...@@ -72,9 +72,9 @@ class Test_ClusterClassifier(TestCase):
outstr = json.dumps(jsonable_dict, sort_keys=True, indent=4) outstr = json.dumps(jsonable_dict, sort_keys=True, indent=4)
self.assertIsInstance(outstr, str) self.assertIsInstance(outstr, str)
# def test_save_to_json(self): def test_save_to_json(self):
# with TemporaryDirectory() as tmpDir: with TemporaryDirectory() as tmpDir:
# self.clf.save_to_json(os.path.join(tmpDir, 'clf.json')) self.clf.save_to_json(os.path.join(tmpDir, 'clf.json'))
# class Test_ClassifierCollection(TestCase): # class Test_ClassifierCollection(TestCase):
......
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