Commit 9429243a authored by Daniel Scheffler's avatar Daniel Scheffler
Browse files

No-data value of input/output image of spectral homogenization and no-data...

No-data value of input/output image of spectral homogenization and no-data value of intermediate classification maps are now separately handled to solve nodata issue during spectral homogenization.
parent d25fd7ea
Pipeline #3182 passed with stage
in 18 minutes and 13 seconds
......@@ -291,9 +291,9 @@ class SpectralHomogenizer(object):
if cls:
self.logger.info('Performing spectral homogenization using %s. Target is %s %s %s.'
% (method, tgt_satellite, tgt_sensor, tgt_LBA))
im_homo = PR.predict(arrcube, classifier=cls, nodataVal=nodataVal)
im_homo = PR.predict(arrcube, classifier=cls, nodataVal=nodataVal, cmap_nodataVal=nodataVal)
if compute_errors:
errors = PR.compute_prediction_errors(im_homo, cls, nodataVal=nodataVal)
errors = PR.compute_prediction_errors(im_homo, cls, nodataVal=nodataVal, cmap_nodataVal=nodataVal)
if not bandwise_errors:
errors = np.median(errors, axis=2).astype(errors.dtype)
......@@ -1489,7 +1489,7 @@ class RSImage_ClusterPredictor(object):
"""Predictor class applying the predict() function of a machine learning classifier described by the given args."""
def __init__(self, method='LR', n_clusters=50, classif_alg='MinDist', kNN_n_neighbors=10, classifier_rootDir='',
CPUs=1):
# type: (str, int, str, int, str, int) -> None
# type: (str, int, str, int, str, Union[None, int]) -> None
"""Get an instance of RSImage_ClusterPredictor.
:param method: machine learning approach to be used for spectral bands prediction
......@@ -1510,6 +1510,7 @@ class RSImage_ClusterPredictor(object):
:param kNN_n_neighbors: The number of neighbors to be considered in case 'classif_alg' is set to
'kNN'. Otherwise, this parameter is ignored.
:param classifier_rootDir: root directory where machine learning classifiers are stored.
:param CPUs: number of CPUs to use
"""
self.method = method
self.n_clusters = n_clusters
......@@ -1562,28 +1563,31 @@ class RSImage_ClusterPredictor(object):
return Cluster_Learner(dict_clust_MLinstances)
def predict(self, image, classifier, nodataVal=None, CPUs=1):
# type: (Union[np.ndarray, GeoArray], Cluster_Learner, float, int) -> GeoArray
def predict(self, image, classifier, nodataVal=None, cmap_nodataVal=None, CPUs=1):
# type: (Union[np.ndarray, GeoArray], Cluster_Learner, Union[None, float], Union[None, float], int) -> GeoArray
"""Apply the prediction function of the given specifier to the given remote sensing image.
:param image: 3D array representing the input image
:param classifier: the classifier instance
:param nodataVal: no data value of the input image (ignored if image is a GeoArray with existing nodata value)
:param CPUs: CPUs to use (default: 1)
:return: 3D array representing the predicted spectral image cube
# NOTE: The 'nodataVal' is written
:param image: 3D array representing the input image
:param classifier: the classifier instance
:param nodataVal: no data value of the input image
(auto-computed if not given or contained in image GeoArray)
:param cmap_nodataVal: no data value for the classification map
in case more than one sub-classes are used for prediction
:param CPUs: CPUs to use (default: 1)
:return: 3D array representing the predicted spectral image cube
FIXME:
Wichtig, dass hier der richtige nodata value in image.nodata drin steht.
Beachten:
- image.nodata = image.nodata if image._nodata is not None else nodataVal:
soll nodata value NUR dann benutzt werden, wenn sich der nodata value nicht automatisch berechnen lässt?
- classify_image schreibt nodataVal dort in den output wo image.nodata drin steht
- classify_image schreibt nodataVal dort in den output wo image.nodata drin steht -> darf nicht None sein!
- predict überspringt sp#ter die postionen, wo nodataval in classif_map steht
-
"""
image = image if isinstance(image, GeoArray) else GeoArray(image, nodata=nodataVal)
image.nodata = image.nodata if image.nodata is not None else nodataVal # TODO: validate that
image.nodata = nodataVal if nodataVal is not None else image.nodata # might be auto-computed here
# assign each input pixel to a cluster (compute classfication with cluster centers as endmembers)
if not self.classif_map:
......@@ -1594,7 +1598,7 @@ class RSImage_ClusterPredictor(object):
classifier.cluster_pixVals,
classif_alg=self.classif_alg,
kNN_n_neighbors=self.kNN_n_neighbors,
nodataVal=nodataVal, # written into classif_map at nodata pixels
nodataVal=cmap_nodataVal, # written into classif_map at nodata pixels
CPUs=self.CPUs)
print('Total classification time: %s' % time.strftime("%H:%M:%S", time.gmtime(time.time() - t0)))
else:
......@@ -1619,7 +1623,8 @@ class RSImage_ClusterPredictor(object):
classif_map_tile = self.classif_map[rS: rE+1, cS: cE+1] # integer array
# predict!
im_tile_pred = classifier.predict(im_tile, classif_map_tile, nodataVal=nodataVal).astype(image.dtype)
im_tile_pred = classifier.predict(im_tile, classif_map_tile,
nodataVal=nodataVal, cmap_nodataVal=cmap_nodataVal).astype(image.dtype)
image_predicted[rS:rE + 1, cS:cE + 1] = im_tile_pred
print('Total prediction time: %s' % time.strftime("%H:%M:%S", time.gmtime(time.time()-t0)))
......@@ -1641,18 +1646,20 @@ class RSImage_ClusterPredictor(object):
return image_predicted
def compute_prediction_errors(self, im_predicted, cluster_classifier, nodataVal=None):
# type: (Union[np.ndarray, GeoArray], Cluster_Learner, float) -> np.ndarray
def compute_prediction_errors(self, im_predicted, cluster_classifier, nodataVal=None, cmap_nodataVal=None):
# type: (Union[np.ndarray, GeoArray], Cluster_Learner, float, float) -> np.ndarray
"""Compute errors that quantify prediction inaccurracy per band and per pixel.
:param im_predicted: 3D array representing the predicted image
:param cluster_classifier: instance of Cluster_Learner
:param nodataVal: no data value of the input image
(ignored if image is a GeoArray with existing nodata value)
(auto-computed if not given or contained in im_predicted GeoArray)
:param cmap_nodataVal: no data value for the classification map
in case more than one sub-classes are used for prediction
:return: 3D array (int16) representing prediction errors per band and pixel
"""
im_predicted = im_predicted if isinstance(im_predicted, GeoArray) else GeoArray(im_predicted, nodata=nodataVal)
im_predicted.nodata = im_predicted.nodata if im_predicted.nodata is not None else nodataVal
im_predicted.nodata = nodataVal if nodataVal is not None else im_predicted.nodata # might be auto-computed here
for cls in cluster_classifier:
if not len(cls.rmse_per_band) == GeoArray(im_predicted).bands:
......@@ -1665,7 +1672,7 @@ class RSImage_ClusterPredictor(object):
# iterate over all cluster labels and copy rmse values
for pixVal in sorted(list(np.unique(self.classif_map))):
if pixVal == nodataVal:
if pixVal == cmap_nodataVal:
continue
print('Inpainting error values for cluster #%s...' % pixVal)
......@@ -1713,13 +1720,14 @@ class Cluster_Learner(object):
for cluster in self.cluster_pixVals:
yield self.MLdict[cluster]
def predict(self, im_src, cmap, nodataVal=None):
def predict(self, im_src, cmap, nodataVal=None, cmap_nodataVal=None):
"""
:param im_src:
:param cmap: classification map that assigns each image spectrum to its corresponding cluster
-> must be a 1D np.ndarray with the same Y-dimension like src_spectra
:param nodataVal:
:param cmap: classification map that assigns each image spectrum to its corresponding cluster
-> must be a 1D np.ndarray with the same Y-dimension like src_spectra
:param nodataVal: nodata value to be used to fill into the predicted image
:param cmap_nodataVal: nodata class value of the nodata class of the classification map
:return:
"""
cluster_labels = sorted(list(np.unique(cmap)))
......@@ -1733,7 +1741,7 @@ class Cluster_Learner(object):
# to predict target spectra
for pixVal in cluster_labels:
if pixVal == nodataVal:
if pixVal == cmap_nodataVal:
continue
classifier = self.MLdict[pixVal]
......@@ -1744,7 +1752,7 @@ class Cluster_Learner(object):
# predict target spectra directly (much faster than the above algorithm)
pixVal = cluster_labels[0]
if pixVal != nodataVal:
if pixVal != cmap_nodataVal:
spectra = im2spectra(im_src)
classifier = self.MLdict[pixVal]
spectra_pred = classifier.predict(spectra).astype(im_src.dtype)
......
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