Skip to content
Merged
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -232,8 +232,11 @@ train_model.py:
tst: <the COCO JSON file related to the test dataset>
detectron2_config_file: <the detectron2 configuration file (relative path w/ respect to the working_folder>
model_weights:
model_zoo_checkpoint_url: <e.g. "COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_1x.yaml">
pth_file: <path to the model if training is resumed. Defaults to "<log directory>/model_final.pth">
model_zoo_checkpoint_url: <zoo model to start training from, e.g. "COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_1x.yaml">
init_model_weights: <True or False; if True, the model weights will be initialized to 0 (optional, defaults to False)>
resume_training: <True or False; if True, the training is resumed from the final weights saved in the log folder. Defaults to False>
data_augmentation: <True or False; if True, apply random adjustment of brightness, contrast, saturation, lightning, and size, plus flip the image horizontally. Defaults to False>
```

Detectron2's configuration files are provided in the example folders mentioned here-below. We warn the end-user about the fact that, **for the time being, no hyperparameters tuning is automatically performed**.
Expand Down Expand Up @@ -324,7 +327,7 @@ A few examples are provided within the `examples` folder. For further details, w
* [Segmentation of Border Points based on Analog Cadastral Plans](examples/borderpoints/README.md): multi-class instance segmentation with images from another folder based on a custom grid,
* [Evolution of Mineral Extraction Sites over the Entire Switzerland](examples/mineral-extrac-sites-detection/README.md): object monitoring with images from an XYZ service,
* [Swimming Pool Detection over the Canton of Geneva](examples/swimming-pool-detection/GE/README.md): instance segmentation with images from a MIL service,
* [Swimming Pool Detection over the Canton of Neuchâtel](examples/swimming-pool-detection/NE/README.md): instance segmentation with images from a WMS service.service,
* [Swimming Pool Detection over the Canton of Neuchâtel](examples/swimming-pool-detection/NE/README.md): instance segmentation with images from a WMS service.

It is brought to the reader attention that the examples are provided with a debug parameter that can be set to `True` for quick tests.

Expand Down
2 changes: 1 addition & 1 deletion examples/anthropogenic-activities/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Example: detection of anthropic soils potentially suitable for rehabilitation
# Example: segmentation of anthropic soils on historic images

A working setup is provided here to test the multi-class classification and the use of empty tiles, as well as false positive ones.
It consists of the following elements:
Expand Down
11 changes: 0 additions & 11 deletions examples/anthropogenic-activities/config_trne.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -94,21 +94,10 @@ assess_detections.py:
metrics_method: micro-average # 1: macro-average ; 2: macro-weighted-average ; 3: micro-average
# confidence_threshold: 0.05

# Plots (optional)
result_analysis.py:
working_directory: output/trne
output_directory: plots
detections: tagged_detections.gpkg
min_year: 1950
max_year: 2023
class_dict: {'Activité non agricole': 'Non-agricultural activity', # Provide a customed legend
'Mouvement de terrain': 'Land movement'}

# Merge detections across tiles
merge_detections.py:
working_directory: output/trne
output_dir: post_processed
labels: labels.geojson
detections:
trn: trn_detections_at_0dot05_threshold.gpkg
val: val_detections_at_0dot05_threshold.gpkg
Expand Down
1 change: 0 additions & 1 deletion examples/anthropogenic-activities/detectron2_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,6 @@ MODEL:
NAME: SemSegFPNHead
NORM: GN
NUM_CLASSES: 54
WEIGHTS: https://dl.fbaipublicfiles.com/detectron2/COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_1x/137260431/model_final_a54504.pkl
OUTPUT_DIR: logs
SEED: 42
SOLVER:
Expand Down
3 changes: 1 addition & 2 deletions examples/anthropogenic-activities/merge_detections.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
# Load input parameters
WORKING_DIR = cfg['working_directory']
OUTPUT_DIR = cfg['output_dir']
LABELS = cfg['labels'] if 'labels' in cfg.keys() else None
DETECTION_FILES = cfg['detections']

DISTANCE = cfg['distance']
Expand Down Expand Up @@ -100,8 +99,8 @@
detections_tiles_join_gdf = gpd.sjoin(tiles_gdf, detections_buffer_gdf, how='left', predicate='contains')
remove_det_list = detections_tiles_join_gdf.det_id.unique().tolist()

detections_overlap_tiles_gdf = detections_by_year_gdf[~detections_by_year_gdf.det_id.isin(remove_det_list)].drop_duplicates(subset=['det_id'], ignore_index=True)
detections_within_tiles_gdf = detections_by_year_gdf[detections_by_year_gdf.det_id.isin(remove_det_list)].drop_duplicates(subset=['det_id'], ignore_index=True)
detections_overlap_tiles_gdf = detections_by_year_gdf[~detections_by_year_gdf.det_id.isin(remove_det_list)].drop_duplicates(subset=['det_id'], ignore_index=True)

# Merge polygons within the thd distance
detections_overlap_tiles_gdf.loc[:, 'geometry'] = detections_overlap_tiles_gdf.buffer(DISTANCE, resolution=2)
Expand Down
2 changes: 1 addition & 1 deletion examples/anthropogenic-activities/prepare_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@

written_files = []

gt_labels_4326_gdf = ffe.preapre_labels(SHPFILE, CATEGORY, supercategory=SUPERCATEGORY)
gt_labels_4326_gdf = ffe.prepare_labels(SHPFILE, CATEGORY, supercategory=SUPERCATEGORY)

label_filepath = os.path.join(OUTPUT_DIR, 'labels.geojson')
gt_labels_4326_gdf.to_file(label_filepath, driver='GeoJSON')
Expand Down
2 changes: 0 additions & 2 deletions examples/borderpoints/config/detectron2_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -258,8 +258,6 @@ MODEL:
LOSS_WEIGHT: 1.0
NAME: SemSegFPNHead
NORM: GN
NUM_CLASSES: 54
WEIGHTS: https://dl.fbaipublicfiles.com/detectron2/COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_1x/137260431/model_final_a54504.pkl
OUTPUT_DIR: logs
SEED: 42
SOLVER:
Expand Down
2 changes: 1 addition & 1 deletion examples/mineral-extract-sites-detection/config_trne.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ train_model.py:
detectron2_config_file: ../../detectron2_config_dqry.yaml # path relative to the working_folder
model_weights:
model_zoo_checkpoint_url: COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_1x.yaml

# Object detection with the optimised trained model
make_detections.py:
working_directory: ./output/trne/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,8 +261,6 @@ MODEL:
LOSS_WEIGHT: 1.0
NAME: SemSegFPNHead
NORM: GN
NUM_CLASSES: 54
WEIGHTS: https://dl.fbaipublicfiles.com/detectron2/COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_1x/137260431/model_final_a54504.pkl
OUTPUT_DIR: logs
SEED: 42
SOLVER:
Expand Down
4 changes: 2 additions & 2 deletions examples/mineral-extract-sites-detection/prepare_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import geopandas as gpd

sys.path.insert(0, '../..')
from helpers.functions_for_examples import format_all_tiles, preapre_labels
from helpers.functions_for_examples import format_all_tiles, prepare_labels
from helpers.misc import format_logger
from helpers.constants import DONE_MSG

Expand Down Expand Up @@ -60,7 +60,7 @@
os.makedirs(OUTPUT_DIR)
written_files = []

gt_labels_4326_gdf = preapre_labels(SHPFILE, CATEGORY, supercategory=SUPERCATEGORY)
gt_labels_4326_gdf = prepare_labels(SHPFILE, CATEGORY, supercategory=SUPERCATEGORY)

label_filepath = os.path.join(OUTPUT_DIR, 'labels.geojson')
gt_labels_4326_gdf.to_file(label_filepath, driver='GeoJSON')
Expand Down
2 changes: 1 addition & 1 deletion examples/swimming-pool-detection/GE/config_GE.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ train_model.py:
detectron2_config_file: '../detectron2_config_GE.yaml' # path relative to the working_folder
model_weights:
model_zoo_checkpoint_url: "COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_1x.yaml"

make_detections.py:
working_directory: output_GE
log_subfolder: logs
Expand Down
2 changes: 0 additions & 2 deletions examples/swimming-pool-detection/GE/detectron2_config_GE.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -260,8 +260,6 @@ MODEL:
LOSS_WEIGHT: 1.0
NAME: SemSegFPNHead
NORM: GN
NUM_CLASSES: 54
WEIGHTS: https://dl.fbaipublicfiles.com/detectron2/COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_1x/137260431/model_final_a54504.pkl
OUTPUT_DIR: logs
SEED: -1
SOLVER:
Expand Down
4 changes: 2 additions & 2 deletions examples/swimming-pool-detection/NE/config_NE.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ train_model.py:
tst: COCO_tst.json
detectron2_config_file: '../detectron2_config_NE.yaml' # path relative to the working_folder
model_weights:
model_zoo_checkpoint_url: "COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_1x.yaml"

model_zoo_checkpoint_url: COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_1x.yaml
make_detections.py:
working_directory: output_NE
log_subfolder: logs
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,12 +261,10 @@ MODEL:
LOSS_WEIGHT: 1.0
NAME: SemSegFPNHead
NORM: GN
NUM_CLASSES: 54
WEIGHTS: https://dl.fbaipublicfiles.com/detectron2/COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_1x/137260431/model_final_a54504.pkl
OUTPUT_DIR: logs
SEED: -1
SOLVER:
BASE_LR: 0.005
BASE_LR: 0.00005
BIAS_LR_FACTOR: 1.0
CHECKPOINT_PERIOD: 1000
CLIP_GRADIENTS:
Expand Down
20 changes: 16 additions & 4 deletions helpers/detectron2.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@

from detectron2.engine.hooks import HookBase
from detectron2.engine import DefaultTrainer
from detectron2.data import build_detection_test_loader, DatasetMapper
from detectron2.data import build_detection_test_loader, build_detection_train_loader, DatasetMapper
from detectron2.data import transforms as T
from detectron2.evaluation import COCOEvaluator
from detectron2.utils import comm
from detectron2.utils.logger import log_every_n_seconds
Expand Down Expand Up @@ -97,11 +98,8 @@ def build_evaluator(cls, cfg, dataset_name, output_folder=None):

if output_folder is None:
output_folder = os.path.join(cfg.OUTPUT_DIR, "inference")

os.makedirs("COCO_eval", exist_ok=True)

return COCOEvaluator(dataset_name, None, False, output_folder)


def build_hooks(self):

Expand All @@ -117,6 +115,20 @@ def build_hooks(self):

return hooks


class AugmentedCocoTrainer(CocoTrainer):

@classmethod
def build_train_loader(cls, cfg):
mapper = DatasetMapper(cfg, is_train=True, augmentations=[
T.RandomBrightness(0.5, 1.5),
T.RandomContrast(0.5, 1.5),
T.RandomSaturation(0.5, 1.5),
T.RandomLighting(0.5),
T.RandomFlip(),
T.ResizeShortestEdge(short_edge_length=[128, 1024], max_size=1333, sample_style='range')
])
return build_detection_train_loader(cfg, mapper=mapper)


# HELPER FUNCTIONS
Expand Down
2 changes: 1 addition & 1 deletion helpers/functions_for_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ def get_tile_name(path, geom):
return new_name


def preapre_labels(labels_shp, category, supercategory):
def prepare_labels(labels_shp, category, supercategory):

## Convert datasets shapefiles into geojson format
logger.info('Convert labels shapefile into GeoJSON format (EPSG:4326)...')
Expand Down
19 changes: 19 additions & 0 deletions helpers/misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,16 @@ def clip_row(row, fact=fact):


def format_logger(logger):
"""
Configures the logger to format log messages with specific styles and colors based on their severity level.

Args:
logger (loguru.logger): The logger instance to be formatted.

Returns:
loguru.logger: The configured logger instance with custom formatting.

"""

logger.remove()
logger.add(sys.stdout, format="{time:YYYY-MM-DD HH:mm:ss} - {level} - {message}",
Expand All @@ -166,6 +176,15 @@ def format_logger(logger):


def find_category(df):
"""
Ensures that the CATEGORY and SUPERCATEGORY columns are present in the input DataFrame.

Args:
df (pandas.DataFrame): DataFrame containing the GT labels.

Returns:
pandas.DataFrame: The input DataFrame with the CATEGORY and SUPERCATEGORY columns properly renamed.
"""

if 'category' in df.columns:
df.rename(columns={'category': 'CATEGORY'}, inplace = True)
Expand Down
1 change: 0 additions & 1 deletion scripts/make_detections.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
from tqdm import tqdm

import geopandas as gpd
import pandas as pd

from detectron2.utils.logger import setup_logger
setup_logger()
Expand Down
Loading