GitHub - noahgolmant/label-tiles: Label geospatial data with tile servers

6 min read Original article ↗

Label geospatial data with tile servers

label-tiles is a small open source tool for making geospatial training datasets. You can draw labeled bounding boxes on map images from any tile server. So you can label any raster data that can be served on a map.

You can then download the underlying tile images for ML training and inference, and export labels in COCO annotation format or GeoJSON/GeoParquet.

Exported data is compatible with standard computer vision and ML frameworks like pytorch and ultralytics. See the example in examples/dataloader.py for how to load the COCO annotation output in PyTorch.

For context, a tile server is an API that delivers map images in small square "tiles" based on zoom level and location, letting map applications efficiently load and display only the relevant portions of very large datasets.

This is built with React + FastAPI + MapLibre and developed at Earthscale.

Demo

Features

  • Configure multiple tile server URLs
  • Draw bounding boxes within tiles
  • Hotkey-driven label assignment for custom categories or negative examples
  • Persist labels to GeoParquet, GeoJSON, or COCO JSON for ML training
  • Download tiles over bounding boxes to build training datasets
  • Local GeoTIFF support via optional TiTiler integration

Prerequisites

Quick Start

# If uv not installed:
curl -LsSf https://astral.sh/uv/install.sh | sh

# If pnpm not installed:
curl -fsSL https://get.pnpm.io/install.sh | sh

# Clone repo
git clone https://github.com/noahgolmant/label-tiles
cd label-tiles

# Start web app & backend
make install && make dev

This will install all dependencies and start both the backend and frontend servers. The frontend runs at http://localhost:5173 and the backend API at http://localhost:8000.

Open http://localhost:5173 in your browser to start.

Example tile server

Try it out on Esri's World_Imagery layer. Click Config and add this server:

https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}

Built-in GeoTIFF Support (TiTiler)

You can load a local GeoTIFF file directly from the Config panel to label it. This uses TiTiler to dynamically serve tiles from your computer.

To enable this feature, install the optional TiTiler dependencies:

Then restart the backend. In the Config panel, enter the full path to your GeoTIFF file (.tif, .tiff) and click "Add GeoTIFF". The file is automatically registered and a tile server is created.

You can then label it and export tiled PNGs to 'chip' the TIFF for model training.

Note: This uses a default TiTiler deployment, so it may require additional tuning to handle different file formats and visualization parameters.

Tile Server Backends

If you need custom tile servers for various data formats, here are some options:

Open Source

  • TiTiler: Lightweight XYZ dynamic tiling for Cloud Optimized GeoTIFFs and other raster sources.
  • GeoServer: Supports serving vector and raster data using standard web protocols (WMS, WMTS, WFS, XYZ, etc).
  • xpublish: Built on Xarray for serving scientific (multi-dimensional) datasets. Useful for tiled access to netCDF or Zarr.

Proprietary

  • Earthscale: Managed tile servers for cloud raster mosaics (Tiled COGs, Zarr, STAC).
  • Mapbox: Raster tile hosting, global mapping API with commercial plans.
  • Esri: Offers a variety of servers and tile services for ArcGIS ecosystem users.
  • Google Earth Engine: you can use ee.Image.getMap() to get a temporary tile server URL for any given EE image.

Detailed Makefile Commands

  • make install or make setup - Install all dependencies (backend and frontend)
  • make install-titiler - Install TiTiler for drag-and-drop GeoTIFF support
  • make dev - Start both backend and frontend in development mode
  • make backend - Start backend server only
  • make frontend - Start frontend dev server only
  • make clean - Clean build artifacts and dependencies
  • make sliding-window STRIDE=N [ID=server-id] - Generate sliding window training data
  • make help - Show all available commands

Scope

It is quite minimal in scope. Some benefits of this tool are:

  • Use what you have: If you have an easy way to serve tiles for some data, you don't have to write additional code to label it.
  • Collaboration: pass a config to a colleague and ask them to label another bbox on their local instance.
  • ML/analysis-ready export formats (It's also probably easy to ask Claude to modify this to support more formats if you'd like.)

Things this tool doesn't try to be good at:

  • Advanced QA/QC workflows
  • Complex attribute tagging

Areas where this could be improved (feel free to contribute!):

  • Shared config setup for multiple users to label in parallel from the same deployment
  • More export formats
  • Pixel-level labeling

Comparisons to other tools

QGIS: Supports tile server viz but requires more setup and manual export to ML formats. Better for complex GIS workflows, but complex for simple bounding box labeling. Doesn't support tile export.

Roboflow: Cloud-based labeling platform optimized for ML workflows. Requires uploading data and works best with non-geospatial images. Good for teams needing cloud collaboration and QA features.

label-tiles is good when you have easy access to tile servers and want ML-ready exports without heavy data transfer.

Usage

1. Configure Tile Servers

Click Config to add tile servers. Each server needs:

  • Name: Display name
  • URL template: Tile URL with {z}/{x}/{y} placeholders
  • Tile size: 256 (default) or 512 for Earthscale tile servers

Example URL: https://tile.server.com/tiles/{z}/{x}/{y}.png

2. Set Labeling Parameters

In the Config panel:

  • Set the labeling zoom level (tiles will be shown at this zoom)
  • Set the labeling extent (optional, for download scope)
  • Add/remove label categories (accessible via hotkeys 1-9)

3. Enable Layers

Use the Layers panel (top-left on map) to toggle tile server visibility.

4. Draw Bounding Boxes

  1. Click and drag on the map to draw a bounding box
  2. Press a number key (1-9) to assign a label category
  3. Press N to mark the tile as having no objects (negative example)
  4. Press Esc to cancel

5. Manage Labels

The sidebar shows all labels grouped by tile. Click to select, click × to delete.

Hotkeys:

  • 1-9: Assign label (after drawing bbox)
  • N: Mark tile as negative
  • D: Delete selected label
  • Esc: Cancel drawing

6. Export

Click Export to:

  • Export GeoJSON: Download labels with geographic bboxes and tile indices
  • Export COCO JSON: Download in COCO format for ML training
  • Download Labeled Tiles: Download tile images for labeled tiles only
  • Download All Tiles: Download all tiles in the labeling extent

7. Sliding Window Augmentation (Optional)

After exporting tiles and COCO annotations, you can generate additional training data using the sliding window script. This creates new images by sliding a window across neighboring tiles at a configurable stride, effectively augmenting your dataset with shifted views of the same annotations.

# Generate sliding windows with 128px stride (50% overlap for 256px tiles)
make sliding-window STRIDE=128

# Specify a tile server ID if you have multiple
make sliding-window STRIDE=128 ID=my-tile-server

The script:

  • Copies all original labeled tiles to data/sliding_windows/
  • Creates new composite images by combining portions of neighboring tiles at each offset
  • Translates and clips bounding box annotations to match the new window positions
  • Outputs a combined COCO annotations file with all images (original + augmented)

Windows are only generated when all required neighboring tiles exist and at least one annotation is visible in the window.

Data Storage

  • data/config.json - Tile server configuration
  • data/ui_state.json - UI state (viewport, active layers)
  • data/labels.geoparquet - Labels/annotations
  • data/tiles/ - Downloaded tile images