Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ch/update readme #38

Merged
merged 16 commits into from
Oct 30, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,12 +111,16 @@ The same configuration file can be used for all the commands, as each of them on

* **labels**: geo-referenced polygons surrounding the objects targeted by a given analysis

* **FP labels**: geo-referenced polygons surrounding the False Positive objects detected by a previously trained model and included to the training dataset to improve the model performance
cleherny marked this conversation as resolved.
Show resolved Hide resolved

* **AoI**, abbreviation of "area of interest": geographical area over which the user intend to carry out the analysis. This area encompasses
* regions for which ground-truth data is available, as well as
* regions over which the user intends to detect potentially unknown objects

* **tiles**, or - more explicitly - "geographical map tiles": see [this link](https://wiki.openstreetmap.org/wiki/Tiles). More precisely, "Slippy Map Tiles" are used within this project, see [this link](https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames).

* **empty_tiles**, tiles not intersecting ground truth used in the model training to increase context tiles and improve the model training.

* **COCO data format**: see [this link](https://cocodataset.org/#format-data)

* **trn**, **val**, **tst**, **oth**: abbreviations of "training", "validation", "test" and "other", respectively
Expand All @@ -130,16 +134,18 @@ This `generate_tilesets` command generates the various tilesets concerned by a g

The following relations apply:

* <img src="https://latex.codecogs.com/png.latex?\fn_cm&space;\mbox{AoI&space;tiles}&space;=&space;(\mbox{GT&space;tiles})&space;\cup&space;(\mbox{oth&space;tiles})" title="\mbox{AoI tiles} = (\mbox{GT tiles}) \cup (\mbox{oth tiles})" />
* <img src="https://latex.codecogs.com/png.latex?\fn_cm&space;\mbox{AoI&space;tiles}&space;=&space;(\mbox{GT&space;tiles})&space;\cup&space;(\mbox{oth&space;tiles})&space;\cup&space;(\mbox{FP&space;tiles})&space;\cup&space;(\mbox{empty&space;tiles})" title="\mbox{AoI tiles} = (\mbox{GT tiles}) \cup (\mbox{oth tiles}) \cup (\mbox{FP tiles}) \cup (\mbox{empty tiles})" />

* <img src="https://latex.codecogs.com/png.latex?\fn_cm&space;\mbox{GT&space;tiles}&space;=&space;(\mbox{trn&space;tiles})&space;\cup&space;(\mbox{val&space;tiles})&space;\cup&space;(\mbox{tst&space;tiles})" title="\mbox{GT tiles} = (\mbox{trn tiles}) \cup (\mbox{val tiles}) \cup (\mbox{tst tiles})" />
* <img src="https://latex.codecogs.com/png.latex?\fn_cm&space;(\mbox{GT&space;tiles})\cup&space;(\mbox{FP&space;tiles})\cup&space;(\mbox{empty&space;tiles})&space;=&space;(\mbox{trn&space;tiles})&space;\cup&space;(\mbox{val&space;tiles})&space;\cup&space;(\mbox{tst&space;tiles})" title="\mbox{GT tiles} \cup (\mbox{FP_tiles}= (\mbox{trn tiles}) \cup (\mbox{val tiles}) \cup (\mbox{tst tiles})" />

where "GT tiles" are AoI tiles including GT labels and

<img src="https://latex.codecogs.com/png.latex?\fn_cm&space;A&space;\neq&space;B&space;\Rightarrow&space;A&space;\cap&space;B&space;=&space;\emptyset,&space;\quad&space;\forall&space;A,&space;B&space;\in&space;\{\mbox{trn&space;tiles},&space;\mbox{val&space;tiles},&space;\mbox{tst&space;tiles},&space;\mbox{oth&space;tiles}\}" title="A \neq B \Rightarrow A \cap B = \emptyset, \quad \forall A, B \in \{\mbox{trn tiles}, \mbox{val tiles}, \mbox{tst tiles}, \mbox{oth tiles}\}" />
cleherny marked this conversation as resolved.
Show resolved Hide resolved

In case no GT labels are provided by the user, the script will only generate `oth` tiles, covering the entire AoI.

The user can choose to add empty tiles and/or tiles containing FP detections to improve model performance. Empty tiles can be manually defined or selected randomly in a given AoI.

In order to speed up some of the subsequent computations, each output image is accompanied by a small sidecar file in JSON format, carrying information about the image

* width and height in pixels;
Expand All @@ -158,11 +164,17 @@ generate_tilesets.py:
aoi_tiles: <the path to the file including polygons of the Slippy Mappy Tiles covering the AoI>
ground_truth_labels: <the path to the file including ground-truth labels (optional)>
other_labels: <the path to the file including other (non ground-truth) labels (optional)>
FP_labels: <the path to the file including false positive labels (optional)>
image_source:
type: <"WMS" as Web Map Service or "MIL" as ESRI's Map Image Layer or "XYZ" for xyz link or "FOLDER" for tiles from an existing folder>
location: <the URL of the web service or the path to the initial folder>
layers: <only applies to WMS endpoints>
year: <numeric year if no 'year' in tiles.geojson or "multi-year" if 'year' in tiles.geojson(optional). Use only with "XYZ" and "FOLDER" connectors>
srs: <e.g. "EPSG:3857">
empty_tiles:
tiles_frac: <fraction (relative to the number of tiles intersecting labels) of empty tiles to add>
frac_trn: <fraction of empty tiles to add to the trn dataset, then the remaining tiles will be split in 2 and added to tst and val datasets>
keep_oth_tiles: <True or False, if True keep tiles in oth dataset not intersecting oth labels>
output_folder: <the folder were output files will be written>
tile_size: <the tile/image width and height, in pixels>
overwrite: <True or False (without quotes); if True, the script is allowed to overwrite already existing images>
Expand All @@ -188,7 +200,7 @@ Note that:

1. a field named `id` must exist;
2. the `id` field must not contain any duplicate value;
3. values of the `id` field must follow the following pattern: `(<integer 1>, <integer 2>, <integer 3>)`, e.g. `(135571, 92877, 18)`.
3. values of the `id` field must follow the following pattern: `(<integer 1>, <integer 2>, <integer 3>)`, e.g. `(135571, 92877, 18)` or if a year is specified from the data preparation `(<integer 1>, <integer 2>, <integer 3>, <integer 4>)`, e.g. `(2020, 135571, 92877, 18)`

### Stage 2: model training

Expand Down
22 changes: 17 additions & 5 deletions examples/mineral-extract-sites-detection/config_trne.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ prepare_data.py:
srs: EPSG:2056
datasets:
shapefile: ./data/labels/tlm-hr-trn-topo.shp # GT labels
FP_shapefile: ./data/FP/FP_list.gpkg # FP labels
empty_tiles_aoi: ./data/AoI/AoI_2020.shp # AOI in which additional empty tiles can be selected. Only one 'empty_tiles' option can be selected
# FP_shapefile: ./data/FP/FP_list.gpkg # FP labels
# empty_tiles_aoi: ./data/AoI/AoI_2020.shp # AOI in which additional empty tiles can be selected. Only one 'empty_tiles' option can be selected
# empty_tiles_shp: .data/EPT/<SHPFILE> # Provided shpfile of selected empty tiles. Only one 'empty_tiles' option can be selected
output_folder: ./output/output_trne
zoom_level: 16
Expand All @@ -18,11 +18,23 @@ generate_tilesets.py:
datasets:
aoi_tiles: output_trne/tiles.geojson
ground_truth_labels: output_trne/labels.geojson
FP_labels: output_trne/FP.geojson
# FP_labels: output_trne/FP.geojson
image_source:
type: XYZ # supported values: 1. MIL = Map Image Layer 2. WMS 3. XYZ 4. FOLDER
year: 2020
# #############
# type: FOLDER
# location: data/images/SWISSIMAGE/
# srs: 3857
# #############
# type: WMS # supported values: 1. MIL = Map Image Layer 2. WMS 3. XYZ 4. FOLDER
# location: https://wms.geo.admin.ch/service
# layers: ch.swisstopo.swissimage
# srs: "EPSG:2056"
# # year: 2020
# ############
type: XYZ # supported values: 1. MIL = Map Image Layer 2. WMS 3. XYZ 4. FOLDER
year: multi-year # supported values: 1. multi-year (tiles of different year), 2. <year> (i.e. 2020)
location: https://wmts.geo.admin.ch/1.0.0/ch.swisstopo.swissimage-product/default/{year}/3857/{z}/{x}/{y}.jpeg
# ############
empty_tiles: # add empty tiles to datasets
tiles_frac: 0.5 # fraction (relative to the number of tiles intersecting labels) of empty tiles to add
frac_trn: 0.75 # fraction of empty tiles to add to the trn dataset, then the remaining tiles will be split in 2 and added to tst and val datasets
Expand Down
42 changes: 28 additions & 14 deletions scripts/generate_tilesets.py
cleherny marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -198,21 +198,27 @@ def assert_year(img_src, year, tiles_gdf):
"""

try:
assert year=='multi-year' and 'year_tile' in tiles_gdf.keys() or str(year).isnumeric() and 'year_tile' not in tiles_gdf.keys()
assert (year=='multi-year' and 'year_tile' in tiles_gdf.keys()) or (str(year).isnumeric() and 'year_tile' not in tiles_gdf.keys() and img_src!='WMS' and img_src!='MIL')
except:
if img_src=='XYZ' and year=='multi-year':
logger.error("Option 'multi-year' chosen but the tile geodataframe does not contain a year column. "
"Please add it or set a numeric year in the configuration file.")
elif img_src=='XYZ' and year:
logger.error("Option 'year' chosen but the tile geodataframe contains a year column. "
"Please delete it or set the 'multi-year' option in the configuration file. ")
elif img_src=='XYZ':
logger.error("Please provide a year in the configuration file.")
if year=='multi-year':
logger.error("Option 'multi-year' chosen but the tile geodataframe does not contain a 'year' column."
"Please add it while producing the tile geodtaframe or set a numeric year in the configuration file.")
sys.exit(1)
elif year:
if img_src=='WMS' or img_src=='MIL':
logger.error("The connectors WMS and MIL do not support year information. The input year will be ignored.")
else:
logger.error("Option 'year' chosen but the tile geodataframe contains a 'year' column."
"Please delete it while producing the tile geodtaframe or set the 'multi-year' option in the configuration file.")
sys.exit(1)
elif 'year_tile' in tiles_gdf.keys():
logger.error("Option 'year' not chosen but the tile geodataframe contains a year column. "
"Please set 'year: multi-year' in the configuration file.")
sys.exit(1)

if img_src=='WMS' or img_src=='MIL':
logger.error("The connectors WMS and MIL do not support year information. Please provide a tile geodataframe without it.")
else:
logger.error("Option 'year' not chosen but the tile geodataframe contains a 'year' column. "
"Please delete it while producing the tile geodtaframe or set the 'multi-year' option in the configuration file.")
sys.exit(1)


def main(cfg_file_path):

Expand Down Expand Up @@ -485,7 +491,11 @@ def main(cfg_file_path):
if IM_SOURCE_TYPE == 'MIL':

logger.info("(using the MIL connector)")


assert_year(IM_SOURCE_TYPE, YEAR, aoi_tiles_gdf)
if YEAR:
YEAR = None

job_dict = MIL.get_job_dict(
tiles_gdf=aoi_tiles_gdf.to_crs(IM_SOURCE_SRS), # <- note the reprojection
mil_url=IM_SOURCE_LOCATION,
Expand All @@ -503,6 +513,10 @@ def main(cfg_file_path):

logger.info("(using the WMS connector)")

assert_year(IM_SOURCE_TYPE, YEAR, aoi_tiles_gdf)
if YEAR:
YEAR = None

job_dict = WMS.get_job_dict(
tiles_gdf=aoi_tiles_gdf.to_crs(IM_SOURCE_SRS), # <- note the reprojection
wms_url=IM_SOURCE_LOCATION,
Expand Down
Loading