diff --git a/Common/otb_numpy_proc.py b/Common/otb_numpy_proc.py
index 09122ac60440455608cd317a5b8eef921e8d87d2..b784ce42a0a0b891495e33b2ccc824af43e18114 100644
--- a/Common/otb_numpy_proc.py
+++ b/Common/otb_numpy_proc.py
@@ -194,7 +194,7 @@ def check_function_padding(function, test_tile_size=(100,100)):
 
 def to_otb_pipeline(obj):
     if isinstance(obj, str):
-        ppl = otb.Registry.CreateApplication('ExtractROI')
+        ppl = otb.Registry.CreateApplicationWithoutLogger('ExtractROI')
         ppl.SetParameterString('in',obj)
         ppl.Execute()
     elif isinstance(obj,otb.Application):
diff --git a/Learning/ObjectBased.py b/Learning/ObjectBased.py
index 17c70e3b6e401d9702dcc035532f2c7629b9982f..46c459e8a4dd697f0e7ad827eeff77f79b957382 100644
--- a/Learning/ObjectBased.py
+++ b/Learning/ObjectBased.py
@@ -94,13 +94,41 @@ class ObjectBasedClassifier:
             }
         return models, summary, results
 
+    def classify(self, model):
+        if isinstance(model, list):
+            for t, L, X in self.obia_base.tiled_data(normalize=[self.training_base['perc2'],
+                                                                self.training_base['perc98']]):
+                prob = []
+                for m in model:
+                    prob.append(m.predict_proba(X))
+                prob = np.prod(prob, axis=0)
+                c = model[0].classes_[np.argmax(prob, axis=1)]
+                self.obia_base.populate_map(t, L, c)
+        else:
+            for t,L,X in self.obia_base.tiled_data(normalize=[self.training_base['perc2'],
+                                                              self.training_base['perc98']]):
+                c = model.predict(X)
+                self.obia_base.populate_map(t, L, c)
+        return
+
 #TEST CODE
 def run_test():
+    '''
     obc = ObjectBasedClassifier('/DATA/Moringa_Sample/Parakou/output/segmentation/segmentation.tif',
                                 '/DATA/Moringa_Sample/Parakou/input/REF/ref.shp',
                                 ['/DATA/Moringa_Sample/Parakou/output/S2_processed/T31PDL/*/*FEAT.tif'],
                                 ['/DATA/Moringa_Sample/Parakou/input/THR/THR_SPOT6.tif'])
+    '''
+    print('Initializing the OBIA training base...')
+    obc = ObjectBasedClassifier('/DATA/Benin/OBSYDYA_data/MORINGA/SEGMENTATION/segmentation.tif',
+                                '/DATA/Benin/OBSYDYA_data/MORINGA/reference/BD_OBSYDYA_2022_ParakouNdali_v0.2.shp',
+                                ['/DATA/Benin/OBSYDYA_data/MORINGA/basefolder/FEAT/S2_THEIA_FEAT/S2_THEIA_MOSAIC_*.tif'],
+                                glob.glob('/DATA/Benin/OBSYDYA_data/MORINGA/ext_features'))
     obc.gen_k_folds(5)
-    m,s,r = obc.train_RF(100)
+    print('Performing Training and Cross-Validation...')
+    m,s,r = obc.train_RF(400)
     print(s)
-    return
+    print('Performing Classification...')
+    obc.classify(m)
+    obc.obia_base.export_raster_map('/DATA/Benin/OBSYDYA_data/MORINGAv2/firstmap.tif')
+    return obc
diff --git a/OBIA/OBIABase.py b/OBIA/OBIABase.py
index e900d4aacf14cba9fbd7627ccf8330fcb1f09b21..03e5c6dacdefa2fc49db6f8ae583ea685930f3e1 100644
--- a/OBIA/OBIABase.py
+++ b/OBIA/OBIABase.py
@@ -48,7 +48,11 @@ class OBIABase:
         self.raster_groups = []
         self.n_vars = 0
 
+        # Output raster
+        self.output_map = None
+
     def init_ref_db(self, vector_file, id_field, class_field):
+        print("Enter init")
         ras_id = otb.Registry.CreateApplication('Rasterization')
         ras_id.SetParameterString('in', vector_file)
         ras_id.SetParameterString('im', self.object_layer)
@@ -56,6 +60,7 @@ class OBIABase:
         ras_id.SetParameterString('mode.attribute.field', id_field)
         ras_id.Execute()
         ids = ras_id.GetImageAsNumpyArray('out')
+        print("First raster")
 
         ras_cl = otb.Registry.CreateApplication('Rasterization')
         ras_cl.SetParameterString('in', vector_file)
@@ -64,15 +69,18 @@ class OBIABase:
         ras_cl.SetParameterString('mode.attribute.field', class_field)
         ras_cl.Execute()
         cls = ras_cl.GetImageAsNumpyArray('out')
+        print("Second raster")
 
         in_seg = to_otb_pipeline(self.object_layer)
         obj = in_seg.GetImageAsNumpyArray('out')
+        print("Load segmentation")
 
         mask = ids>0
         # 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)
+        print("Before Regionprops")
         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'],
@@ -80,11 +88,35 @@ class OBIABase:
         return
 
     def generate_tile_info(self, nominal_tile_size, background_label):
+        print('Enter generate_tile')
         in_seg = to_otb_pipeline(self.object_layer)
-        full = in_seg.GetImageAsNumpyArray('out')
-        rp = regionprops(full.astype(np.uint32))
-
         W, H = in_seg.GetImageSize('out')
+        r = otb.itkRegion()
+        obj_bbox = {}
+        for i in range(0, W, nominal_tile_size[0]):
+            for j in range(0, H, nominal_tile_size[1]):
+                r['index'][0], r['index'][1] = i, j
+                r['size'][0], r['size'][1] = min(nominal_tile_size[0], W-i), min(nominal_tile_size[1], H-j)
+                in_seg.PropagateRequestedRegion('out', r)
+                tile = in_seg.GetImageAsNumpyArray('out')
+                rp = regionprops(tile.astype(np.uint32))
+                for o in rp:
+                    bbox = np.array([o.bbox[0]+j, o.bbox[1]+i, o.bbox[2]+j, o.bbox[3]+i])
+                    if o.label in obj_bbox.keys():
+                        obj_bbox[o.label].append(bbox)
+                    else:
+                        obj_bbox[o.label] = [bbox]
+
+        for o in obj_bbox.keys():
+            obj_bbox[o] = np.array(obj_bbox[o])
+            mn, mx = np.min(obj_bbox[o], axis=0), np.max(obj_bbox[o], axis=0)
+            obj_bbox[o] = [mn[0], mn[1], mx[2], mx[3]]
+
+        print("Finished BBOX.")
+        print("BBOX:")
+        print(obj_bbox)
+        input("Pippo...")
+
         tx, ty = int(W / nominal_tile_size[0]) + 1, int(H / nominal_tile_size[1]) + 1
 
         obj_to_tile = {}
@@ -104,6 +136,8 @@ class OBIABase:
 
         tiles = {k: [v[0],v[1],v[2]-v[0],v[3]-v[1]] for k,v in tiles.items() if not np.isinf(v[0])}
 
+        self.W, self.H = W, H
+
         return tiles, obj_to_tile
 
     def compute_stats_on_tile(self, tile_num, input_image, stats=[OStats.MEAN], on_ref=False):
@@ -246,15 +280,41 @@ class OBIABase:
         vars = [item for sublist in self.raster_var_names for item in sublist]
         for tilenum in self.tiles.keys():
             tile_data = self.get_full_stats_on_tile(tilenum)
-            L = tile_data.index.to_numpy(dtype=np.int)
+            L = tile_data.index.to_numpy(dtype=np.int32)
             X = tile_data[vars].to_numpy()
             if normalize is not None:
                 X = (X - normalize[0]) / (normalize[1] - normalize[0])
-            yield L,X
+            yield tilenum,L,X
 
-    def populate_map(self, tilenum, labels):
+    def populate_map(self, tilenum, obj_id, classes):
+        if self.output_map is None:
+            self.output_map = np.zeros((self.H,self.W), dtype=np.int)
+        r = otb.itkRegion()
+        r['index'][0], r['index'][1], r['size'][0], r['size'][1] = self.tiles[tilenum]
+        obj = to_otb_pipeline(self.object_layer)
+        obj.PropagateRequestedRegion('out', r)
+        clip_obj = obj.ExportImage('out')
+        tile_obj = np.squeeze(clip_obj['array']).astype(np.uint32)
+        tmp = np.zeros(np.max(tile_obj) + 1, dtype=int)
+        tmp[obj_id] = classes
+        self.output_map[self.tiles[tilenum][1]:self.tiles[tilenum][1]+self.tiles[tilenum][3],
+        self.tiles[tilenum][0]:self.tiles[tilenum][0]+self.tiles[tilenum][2]] += tmp[tile_obj]
         return
 
+    def export_raster_map(self, output_file, compress=False):
+        assert (self.output_map is not None)
+        if not os.path.exists(os.path.dirname(output_file)):
+            os.makedirs(os.path.dirname(output_file))
+        obj = to_otb_pipeline(self.object_layer)
+        arr = obj.ExportImage('out')
+        arr['array'] = self.output_map.astype(np.float32)
+        obj.ImportImage('in', arr)
+        if compress:
+            output_file = output_file + "?gdal:co:compress=deflate"
+        obj.SetParameterString('out', output_file)
+        obj.SetParameterOutputImagePixelType('out', otb.ImagePixelType_uint16)
+        obj.ExecuteAndWriteOutput()
+
     def true_pred_bypixel(self, labels, predicted_classes):
         pred_c = np.zeros(np.max(self.ref_obj_layer)+1)
         pred_c[labels] = predicted_classes
diff --git a/moringa.py b/moringa.py
index de7a3d60256e3490877f9192b61bc0b4104a0bfb..840250ff03f0cdfb52a91cb5a1aba1f7b774ab0f 100755
--- a/moringa.py
+++ b/moringa.py
@@ -91,7 +91,7 @@ def main(args):
     vhrprep.add_argument("--align_to_band", type=int, default=3, help="Band of reference image used for alignment.")
     vhrprep.add_argument("--align_using_band", type=int, default=1, help="Band of current image used for alignment.")
     vhrprep.add_argument("--skip_ps", help="Skip pansharpening step.", action='store_true')
-    vhrprep.add_argument("--compress", help="Use lossless compresion on outputs.", action='store_true')
+    vhrprep.add_argument("--compress", help="Use lossless compression on outputs.", action='store_true')