Source code for geococo.cli

import typer
import pathlib
from datetime import datetime
import geopandas as gpd
import rasterio
from geococo.coco_processing import append_dataset
from geococo.coco_manager import save_dataset, load_dataset, create_dataset
from typing_extensions import Annotated
from typing import Optional

app = typer.Typer(add_completion=False, help="Transform your GIS annotations into COCO datasets.")


[docs] @app.command() def new( json_path: Annotated[ pathlib.Path, typer.Argument( help="Output path for new CocoDataset", exists=False, file_okay=True, writable=True, resolve_path=True, ), ], ) -> None: """Initialize a new CocoDataset with user-prompted metadata""" print("Creating new dataset..") description = input("Dataset description: ") contributor = input("Dataset contributor: ") dataset = create_dataset( description=description, contributor=contributor, ) # Encode CocoDataset instance as JSON and save to json_path save_dataset(dataset=dataset, json_path=json_path) print(f"Created new CocoDataset as {json_path}")
[docs] @app.command() def copy( source_json: Annotated[ pathlib.Path, typer.Argument( help="Path to source CocoDataset", exists=True, readable=True, resolve_path=True, ), ], dest_json: Annotated[ pathlib.Path, typer.Argument( help="Output path for copied CocoDataset", exists=True, readable=True, resolve_path=True, ), ], update_meta: Annotated[ bool, typer.Option(help="Whether to prompt the user for new metadata"), ] = True, ) -> None: """Copy and (optionally) update the metadata of an existing CocoDataset""" # Loading CocoDataset model from json_path dataset = load_dataset(json_path=source_json) if update_meta: print("Updating metadata..") dataset.info.version = ( input(f"Dataset version ({dataset.info.version}): ") or dataset.info.version ) dataset.info.description = input( f"Dataset description ({dataset.info.description}): " or dataset.info.description ) dataset.info.contributor = input( f"Dataset contributor ({dataset.info.contributor}): " or dataset.info.contributor ) dataset.info.date_created = datetime.now() print(f"Dataset date: {dataset.info.date_created}") dataset.info.year = dataset.info.date_created.year # Encode CocoDataset instance as JSON and save to json_path save_dataset(dataset=dataset, json_path=dest_json) print(f"Copied CocoDataset to {dest_json}")
[docs] @app.command() def add( image_path: Annotated[ pathlib.Path, typer.Argument( help="Path to geospatial image containing image objects", exists=True, readable=True, resolve_path=True, ), ], labels_path: Annotated[ pathlib.Path, typer.Argument( help="Path to vector file containing annotated image objects", exists=True, readable=True, resolve_path=True, ), ], json_path: Annotated[ pathlib.Path, typer.Argument( help="Path to json file containing the COCO dataset", exists=True, readable=True, resolve_path=True, ), ], output_dir: Annotated[ pathlib.Path, typer.Argument( help="Path to output directory for image subsets", exists=True, readable=True, resolve_path=True, ), ], width: Annotated[int, typer.Argument(help="Width of image subsets")], height: Annotated[int, typer.Argument(help="Height of image subsets")], id_attribute: Annotated[ Optional[str], typer.Option( help="Name of column containing category_id values " "(optional if --name_attribute is given)" ), ] = None, name_attribute: Annotated[ Optional[str], typer.Option( help="Name of column containing category_name values " "(optional if --id_attribute is given)" ), ] = None, super_attribute: Annotated[ Optional[str], typer.Option(help="Name of column containing supercategory values"), ] = None, ) -> None: """Transform and add GIS annotations to an existing CocoDataset This method generates a COCO dataset by moving across the given image (image_path) with a moving window (image_size), constantly checking for intersecting annotations (labels_path) that represent image objects in said image (e.g. buildings in satellite imagery; denoted by (super)category name and/or id). Each valid intersection will add n Annotations entries to the dataset (json_path) and save a subset of the input image that contained these entries (output_dir). The output data size depends on your input labels, as the moving window adjusts its step size to accommodate the average annotation size, optimizing dataset representation and minimizing tool configuration. Each addition will also increment the dataset version: patch if using the same image_path, minor if using a new image_path, and major if using a new output_dir. """ # Loading CocoDataset model from json_path dataset = load_dataset(json_path=json_path) # Loading GIS data labels = gpd.read_file(labels_path) with rasterio.open(image_path) as src: # Find and save all Annotation instances dataset = append_dataset( dataset=dataset, images_dir=output_dir, src=src, labels=labels, window_bounds=[(width, height)], id_attribute=id_attribute, name_attribute=name_attribute, super_attribute=super_attribute, ) # Encode CocoDataset instance as JSON and save to json_path save_dataset(dataset=dataset, json_path=json_path)
if __name__ == "__main__": app()