diff --git a/Learning/ObjectBased.py b/Learning/ObjectBased.py new file mode 100644 index 0000000000000000000000000000000000000000..3000c29af9a0a6100a46a8cab8aa197b90267e08 --- /dev/null +++ b/Learning/ObjectBased.py @@ -0,0 +1,37 @@ +import glob +from OBIA.OBIABase import * +from sklearn.model_selection import StratifiedGroupKFold +from sklearn.ensemble import RandomForestClassifier +from sklearn.metrics import confusion_matrix, accuracy_score, cohen_kappa_score, precision_recall_fscore_support + +class ObjectBasedClassifier: + def __init__(self, object_layer, reference_data, time_series_patterns, user_feature_list): + self.obia_base = OBIABase(object_layer, ref_data = reference_data) + for ptrn in time_series_patterns: + lst = sorted(glob.glob(ptrn)) + self.obia_base.add_raster_time_series_for_stats(lst) + for ras in user_feature_list: + self.obia_base.add_raster_for_stats(ras) + self.obia_base.populate_ref_db() + + def train_RF(self, n_estimators, n_folds): + L, X, Y, G, p2, p98 = self.obia_base.get_reference_db_as_training_base() + sgk = StratifiedGroupKFold(n_splits=n_folds, shuffle=True) + folds_indices = [] + models = [] + results = [] + for tr_i, ts_i in sgk.split(X, Y, G): + folds_indices.append((tr_i, ts_i)) + models.append(RandomForestClassifier(n_estimators=n_estimators)) + models[-1].fit(X[tr_i], Y[tr_i]) + l, c = L[ts_i], models[-1].predict(X[ts_i]) + y_true, y_pred = self.obia_base.true_pred_bypixel(l, c) + results.append( + { + 'conf_matrix': confusion_matrix(y_true, y_pred), + 'accuracy': accuracy_score(y_true, y_pred), + 'kappa' : cohen_kappa_score(y_true, y_pred), + 'p_r_f1': precision_recall_fscore_support(y_true, y_pred) + } + ) + return folds_indices, models, results diff --git a/OBIA/OBIABase.py b/OBIA/OBIABase.py index 1680405b79602fa87d8d1a28560f5ddc424f9335..e900d4aacf14cba9fbd7627ccf8330fcb1f09b21 100644 --- a/OBIA/OBIABase.py +++ b/OBIA/OBIABase.py @@ -69,7 +69,10 @@ class OBIABase: obj = in_seg.GetImageAsNumpyArray('out') mask = ids>0 - self.ref_obj_layer = label(obj * mask, connectivity=1).astype(np.uint32) + # This was to relabel object being disconnected by intersecting the GT + # Re-enable if needed... + # self.ref_obj_layer = label(obj * mask, connectivity=1).astype(np.uint32) + self.ref_obj_layer = (obj * mask).astype(np.uint32) rp = regionprops(self.ref_obj_layer, intensity_image=np.dstack((obj,ids,cls)).astype(np.int)) self.ref_db = pd.DataFrame(data=[np.insert(o.intensity_min,0,o.area) for o in rp], columns=['area','orig_label','polygon_id','class'], @@ -219,6 +222,7 @@ class OBIABase: def get_reference_db_as_training_base(self): assert(self.ref_db is not None and len(self.raster_var_names)>0) vars = [item for sublist in self.raster_var_names for item in sublist] + L = self.ref_db['orig_label'].to_numpy(dtype=int) X = self.ref_db[vars].to_numpy() # compute percentiles and normalize p2 = np.zeros(X.shape[1]) @@ -236,7 +240,7 @@ class OBIABase: X[:,g] = (tmp - m)/(M - m) Y = self.ref_db['class'].to_numpy(dtype=int) G = self.ref_db['polygon_id'].to_numpy(dtype=int) - return X,Y,G,p2,p98 + return L,X,Y,G,p2,p98 def tiled_data(self, normalize=None): vars = [item for sublist in self.raster_var_names for item in sublist] @@ -249,4 +253,14 @@ class OBIABase: yield L,X def populate_map(self, tilenum, labels): - return \ No newline at end of file + return + + def true_pred_bypixel(self, labels, predicted_classes): + pred_c = np.zeros(np.max(self.ref_obj_layer)+1) + pred_c[labels] = predicted_classes + pred = pred_c[self.ref_obj_layer] + true_c = np.zeros(np.max(self.ref_db['orig_label']).astype(int)+1) + # ATTENTION: works if "labels" is sorted (as provided by get_reference_...) + true_c[labels] = self.ref_db.loc[self.ref_db['orig_label'].isin(labels),'class'].to_numpy(dtype=int) + true = true_c[self.ref_obj_layer] + return pred[pred>0], true[pred>0]