Import geospatial data

How to import geospatial data and sample import formats.

Specifications

Supported file formats:

  • Slippy maps: url/zoom-level/x-coordinate/y-coordinate.png
  • Deep zoom servers for pathology use case, such as Openslide and tiffslide
  • GeoTIFF: Standard or Cloud-optimized
  • NITF: 2.0 or 2.1 format

Import methods:

  • Slippy map URL
  • IAM Delegated Access (NITF, GeoTIFF, or COG files only)
  • Signed URLs (https URLs only)

❗️

IAM Delegated Access not supported with slippy maps

IAM Delegated Access is not supported with slippy maps due to the nature of how slippy maps work. We strongly encourage you to use cloud-optimized GeoTIFFs instead of slippy maps.

To use IAM Delegated Access with geospatial/tiled imagery, please use NITF, GeoTIFF, or COG files.

Slippy maps

Definitions

When importing slippy map data, make sure your import file contains this information and follows this format.

ParameterRequiredDescription
row_dataYesA dictionary of
{ "tile_layer_url": str, "min_zoom": int, "max_zoom": int, "bounds": \[[float, float],[float, ffloat]], "epsg": "EPSG3857" ... }

For IAM Delegated Access, this URL must be in virtual-hosted-style format.
row_data['version']NoAdd version to your import to distinguish it from the legacy format.

If version: 2 is present, Labelbox will read all coordinates as [long, lat] or [x, y] depending on the data format.
If version: 1 is present, Labelbox will read all coordinates as [lat, long] or [y, x] depending on the data format.

If no version is provided, the default value for Slippy map files using an espg coordinate system and COG files is version: 1 and the default value for cartesian and simple coordinate system is version: 2
row_data['tile_layer_url']YesURL where map data is hosted. Must be in the following format: <https://URL/{z}/{x}/{y}.png>

Slippy map tiles in JPG or PNG.
row_data['min_zoom']NoMinimum map zoom level down to which this layer will be displayed (inclusive). If not provided, users will potentially be able to zoom beyond where tiles are available.
row_data['max_zoom']NoMaximum map zoom level up to which this layer will be displayed (inclusive). If not provided, users will potentially be able to zoom beyond where tiles are available.
row_data['max_native_zoom']NoMaximum zoom number the tile source has available (maxNativeZoom & maxZoom). If specified, the tiles on all zoom levels higher than maxNativeZoom will be auto-scaled.
row_data['bounds']YesThe bounds where the projection is valid. For the Simple coordinate system, bounds are in x,y. For the EPSG coordinate system, bounds are in lat,long.
row_data['epsg']YesStructured dataset of coordinate reference systems and coordinate transformations. Can be EPSG3857, EPSG3395, EPSG4326, Simple, or Cartesian.

If using Cartesian, you must pass in the parameters for the pixel dimensions in the dimensions field.
row_data['tile_size']NoSpecifies the size of the individual slippy map tiles. Common sizes are 256, 512, 1024. Note: Currently, only square tiles are supported which is why tileSize is a single number that indicates the width and height of the tile.
row_data['alternative_layers']NoAdditional tile layers. Only alternativeLayers.tileLayerUrl and alternativeLayers.name are required. If no values for optional parameters are given, those values will default to the top-level keys.
row_data['dimensions']NoThis is required if using the Cartesian coordinate system. This represents the pixel height and width of the entire image.

The format is: "dimensions": { "width": <Pixel width>, "height": <Pixel height> }
global_keyNoUnique user-generated file name or ID for the file. Global keys are enforced to be unique in your org. Data rows will not be imported if its global keys are duplicated to existing data rows.
media_typeNo"TMS_GEO" (optional media type to provide better validation and error messaging)
metadata_fieldsNoSee Metadata.
attachmentsNoSee Attachments and Asset overlays.

Import format

[
  {
    "row_data":{
      "tile_layer_url": "https://s3-us-west-1.amazonaws.com/lb-tiler-layers/mexico_city/{z}/{x}/{y}.png",
      "bounds": [
        [
          19.405662413477728,
          -99.21052827588443
        ],
        [
          19.400498983095076,
          -99.20534818927473
        ]
      ],
      "min_zoom": 12,
      "max_zoom": 20,
      "epsg": "EPSG4326",
      "alternative_layers": [
        {
          "tile_layer_url": "https://api.mapbox.com/styles/v1/mapbox/satellite-streets-v11/tiles/{z}/{x}/{y}?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw",
          "name": "Satellite"
        },
        {
          "tile_layer_url": "https://api.mapbox.com/styles/v1/mapbox/navigation-guidance-night-v4/tiles/{z}/{x}/{y}?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw",
          "name": "Guidance"
        }
      ]
    },
    "global_key": "https://s3-us-west-1.amazonaws.com/lb-tiler-layers/mexico_city/{z}/{x}/{y}.png",
    "media_type": "TMS_GEO",
    "metadata_fields": [{"name": "<metadata_field_name>", "value": "tag_string"}],
    "attachments": [{"type": "TEXT_URL", "value": "https://storage.googleapis.com/labelbox-sample-datasets/Docs/text_attachment.txt"}]
  }
]
[
  {
    "row_data": {
      "tile_layer_url": "https://labelbox.s3-us-west-2.amazonaws.com/tiler/drone-map/rgb/{z}/{x}/{y}.png",
      "bounds": [
        [17.983835501492813,74.41417694091798],
        [17.996825561127697, 74.44644927978517]
      ],
      "min_zoom": 8,
      "max_zoom": 22,
      "max_native_zoom": 22,
      "epsg": "EPSG3857",
      "version": 2,
      "alternative_layers": [
        {
          "tileLayer_url": "https://labelbox.s3-us-west-2.amazonaws.com/tiler/drone-map/ndvi/{z}/{x}/{y}.png",
          "name": "NDVI"
        },
        {
          "tileLayer_url": "https://labelbox.s3-us-west-2.amazonaws.com/tiler/drone-map/dtm/{z}/{x}/{y}.png",
          "name": "DTM"
        }
      ]
    },
    "global_key": "https://labelbox.s3-us-west-2.amazonaws.com/tiler/drone-map/rgb/{z}/{x}/{y}.png",
    "media_type": "TMS_GEO",
    "metadata_fields": [{"schema_id": "cko8s9r5v0001h2dk9elqdidh", "value": "tag_string"}],
    "attachments": [{"type": "TEXT_URL", "value": "https://storage.googleapis.com/labelbox-sample-datasets/Docs/text_attachment.txt"}]
  }
]
[
  {
    "row_data": {
      "tile_layer_url": "https://public-tiles.dronedeploy.com/1499994155_DANIELOPENPIPELINE_ortho_qfs/{z}/{x}/{y}.png?Policy=eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiaHR0cHM6Ly9wdWJsaWMtdGlsZXMuZHJvbmVkZXBsb3kuY29tLzE0OTk5OTQxNTVfREFOSUVMT1BFTlBJUEVMSU5FX29ydGhvX3Fmcy8qIiwiQ29uZGl0aW9uIjp7IkRhdGVMZXNzVGhhbiI6eyJBV1M6RXBvY2hUaW1lIjoyMTQ1OTE0MTE4fX19XX0_&Signature=O~50rrGXdEC6Hi8jPJ3dbT~UtBd7Cw6iQPTxdJ8LU2IaoxeP22R3JpKPkLN3T3~Lcw3CyX7uft2Baj0MH93qUoCYyN~~jNX3OMkYV2jbrHDezf6zQRHAabXX-L2bL-JEGfFL6z3DWccOFeCH56CuhgC29k5CJx7I34P-LQJdnAUsA-KaqKH1IyYsHStRIfmMzdXNAWU58FTfqVljq9SbKXxfgdr2SZ~7VgLaZ8IhA0WnlKUo-JgqTd~jYa5mGCpR8351IMK0aMuY4Mld4SOXssQ-rOtlZtypvo8FDp474TlGIEGz5PHxGOPsqLPF19hEYTgoPqsUj8QEuiTfg-cmsg__&Key-Pair-Id=APKAJXGC45PGQXCMCXSA",
      "bounds": [
        [
          37.87488726890353,
          -122.32488870620728
        ],
        [
          37.87280390440759,
          -122.32154130935669
        ]
      ],
      "min_zoom": 10,
      "max_zoom": 23,
      "epsg": "EPSG4326",
      "version": 2
    }
  },
  {
    "row_data": {
      "tile_layer_url": "https://public-tiles.dronedeploy.com/1499994155_DANIELOPENPIPELINE_ortho_qfs/{z}/{x}/{y}.png?Policy=eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiaHR0cHM6Ly9wdWJsaWMtdGlsZXMuZHJvbmVkZXBsb3kuY29tLzE0OTk5OTQxNTVfREFOSUVMT1BFTlBJUEVMSU5FX29ydGhvX3Fmcy8qIiwiQ29uZGl0aW9uIjp7IkRhdGVMZXNzVGhhbiI6eyJBV1M6RXBvY2hUaW1lIjoyMTQ1OTE0MTE4fX19XX0_&Signature=O~50rrGXdEC6Hi8jPJ3dbT~UtBd7Cw6iQPTxdJ8LU2IaoxeP22R3JpKPkLN3T3~Lcw3CyX7uft2Baj0MH93qUoCYyN~~jNX3OMkYV2jbrHDezf6zQRHAabXX-L2bL-JEGfFL6z3DWccOFeCH56CuhgC29k5CJx7I34P-LQJdnAUsA-KaqKH1IyYsHStRIfmMzdXNAWU58FTfqVljq9SbKXxfgdr2SZ~7VgLaZ8IhA0WnlKUo-JgqTd~jYa5mGCpR8351IMK0aMuY4Mld4SOXssQ-rOtlZtypvo8FDp474TlGIEGz5PHxGOPsqLPF19hEYTgoPqsUj8QEuiTfg-cmsg__&Key-Pair-Id=APKAJXGC45PGQXCMCXSA",
      "bounds": [
        [
          37.8749042065848,
          -122.32149839401245
        ],
        [
          37.87278696624341,
          -122.31810808181763
        ]
      ],
      "min_zoom": 10,
      "max_zoom": 23,
      "epsg": "EPSG4326",
      "version": 2
    }

  },
  {
    "row_data": {
      "tile_layer_url": "https://public-tiles.dronedeploy.com/1499994155_DANIELOPENPIPELINE_ortho_qfs/{z}/{x}/{y}.png?Policy=eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiaHR0cHM6Ly9wdWJsaWMtdGlsZXMuZHJvbmVkZXBsb3kuY29tLzE0OTk5OTQxNTVfREFOSUVMT1BFTlBJUEVMSU5FX29ydGhvX3Fmcy8qIiwiQ29uZGl0aW9uIjp7IkRhdGVMZXNzVGhhbiI6eyJBV1M6RXBvY2hUaW1lIjoyMTQ1OTE0MTE4fX19XX0_&Signature=O~50rrGXdEC6Hi8jPJ3dbT~UtBd7Cw6iQPTxdJ8LU2IaoxeP22R3JpKPkLN3T3~Lcw3CyX7uft2Baj0MH93qUoCYyN~~jNX3OMkYV2jbrHDezf6zQRHAabXX-L2bL-JEGfFL6z3DWccOFeCH56CuhgC29k5CJx7I34P-LQJdnAUsA-KaqKH1IyYsHStRIfmMzdXNAWU58FTfqVljq9SbKXxfgdr2SZ~7VgLaZ8IhA0WnlKUo-JgqTd~jYa5mGCpR8351IMK0aMuY4Mld4SOXssQ-rOtlZtypvo8FDp474TlGIEGz5PHxGOPsqLPF19hEYTgoPqsUj8QEuiTfg-cmsg__&Key-Pair-Id=APKAJXGC45PGQXCMCXSA",
      "bounds": [
        [
          37.8749042065848,
          -122.31806516647339
        ],
        [
          37.87278696624341,
          -122.31529712677002
        ]
      ],
      "min_zoom": 10,
      "max_zoom": 23,
      "epsg": "EPSG4326",
      "version": 2
    }
  }
]
[
  {
    "row_data": {
      "tile_layer_url": "https://storage.googleapis.com/labelbox-developer-testing-assets/cartesian/sample_5184x2000_maxZoom_3/{z}/{x}/{y}.png",
      "bounds": [[0,0],[500,500]],
      "epsg": "Cartesian",
      "min_zoom": 0,
      "max_zoom": 3,
      "dimensions": {
        "width": 5184,
        "height": 2000
      },
    }
  },
  {
    "row_data":{
      "tile_layer_url": "https://storage.googleapis.com/labelbox-developer-testing-assets/cartesian/sample_5184x2000_maxZoom_3/{z}/{x}/{y}.png",
      "bounds": [[500, 500], [1000,1000]],
      "epsg": "Cartesian",
      "min_zoom": 0,
      "max_zoom": 3,
      "dimensions": {
        "width": 5184,
        "height": 2000
      },
    }   
  },
  {
    "row_data":{
      "tile_layer_url": "https://storage.googleapis.com/labelbox-developer-testing-assets/cartesian/sample_5184x2000_maxZoom_3/{z}/{x}/{y}.png",
      "bounds": [[0, 0],[5184,2000]],
      "epsg": "Cartesian",
      "min_zoom": 0,
      "max_zoom": 3,
      "dimensions": {
        "width": 5184,
        "height": 2000
      },
    }
  }
]

Deep Zoom Servers (ex. Pathology Slides)

Definitions

When using a Deep Zoom server endpoint (like OpenSlide or tiffslides), please use the following format.

ParameterRequiredDescription
row_dataYesA dictionary of
{ "tile_layer_url": str, "is_deep_zoom": bool, "min_zoom": int, "max_zoom": int, "bounds": [[float, float],[float, float]], "epsg": "EPSG3857" ... }

For IAM Delegated Access, this URL must be in virtual-hosted-style format.
row_data['version']NoAdd version to your import to distinguish it from the legacy format.

If version: 2 is present, Labelbox will read all coordinates as [long, lat] or [x, y] depending on the data format.
If version: 1 is present, Labelbox will read all coordinates as [lat, long] or [y, x] depending on the data format.

If no version is provided, the default value for DeepZoom files is version: 2
row_data['tile_layer_url']YesFor DeepZoom servers, the URL should be the API to return the tile with parameters for {x}, {y}, and {z}. If using a Deep Zoom server, you must set up your coordinate system as 'Cartesian'
row_data['is_deep_zoom']NoThis must be set to "true" if using a Deep Zoom server
row_data['min_zoom']NoMinimum map zoom level down to which this layer will be displayed (inclusive).

If not populated, we will default to 0.
row_data['max_zoom']NoMaximum map zoom level up to which this layer will be displayed (inclusive).

If not populated, we will calculate this from your data.
row_data['max_native_zoom']NoMaximum zoom number the tile source has available (maxNativeZoom & maxZoom). If specified, the tiles on all zoom levels higher than maxNativeZoom will be auto-scaled.
row_data['bounds']YesThe bounds where the projection is valid. For the Simple coordinate system, bounds are in x,y. For the EPSG coordinate system, bounds are in lat,long.

To annotate the entire asset, the bounds should match up with your values in dimensions
row_data['epsg']YesThis should be set to Cartesian for Deep Zoom use cases.
row_data['alternative_layers']NoAdditional tile layers. Only alternativeLayers.tileLayerUrl and alternativeLayers.name are required. If no values for optional parameters are given, those values will default to the top-level keys.
row_data['dimensions']NoThis is required if using the Cartesian coordinate system. This represents the pixel height and width of the entire image.

The format is: "dimensions": { "width": <Pixel width>, "height": <Pixel height> }
global_keyNoUnique user-generated file name or ID for the file. Global keys are enforced to be unique in your org. Data rows will not be imported if its global keys are duplicated to existing data rows.
media_typeNo"TMS_GEO" (optional media type to provide better validation and error messaging)
metadata_fieldsNoSee Metadata.
attachmentsNoSee Attachments and Asset overlays.

Import format

[
    {
        "row_data":{
            "tile_layer_url": "https://storage.googleapis.com/labelbox-datasets/openslides/CMU-1/slide_files/{z}/{x}_{y}.png",
            "is_deep_zoom": true,
            "epsg": "Cartesian",
            "min_zoom": 8,
            "max_xoom": 16,
            "dimensions": {
                "height": 32914,
                "width": 46000
            },
            "bounds": [[0,0], [46000,32914]]
        },
        "global_key": "https://storage.googleapis.com/labelbox-datasets/openslides/CMU-1/slide_files/{z}/{x}_{y}.png",
        "media_type": "TMS_GEO",
        "metadata_fields": [{"name": "<metadata_field_name>", "value": "tag_string"}],
        "attachments": [{"type": "TEXT_URL", "value": "https://storage.googleapis.com/labelbox-sample-datasets/Docs/text_attachment.txt"}]
    }
]

GeoTIFF (standard or cloud-optimized) and NITF specifications

Definitions

When you upload a NITF file, Labelbox will convert it to a COG file and upload the asset. If it is already a COG file, Labelbox will skip the conversion and upload the asset natively. Since COG files can have many extension names, Labelbox will check the header of the file to verify that it is a COG file.

ItemSupported OptionsComments
Coordinate SystemsEPSG3857, EPSG3395, or EPSG4326If your COG files are not one of these supported coordinates systems, it must be converted prior to upload into Labelbox.

We require that the the files are geo-referenced in order to render on our map
Coordinate System TypeProjected CRSOur editor only supports a Projected CRS (coordinate reference system). If you are using a geographic coordinate reference system, please convert it.
BandsWe support up to 4 bands:
- Red
- Green
- Blue
- Alpha

Internal color-interpretation must be set on NITF files.
If your COG files have a band outside of these four support bands, the tiles will not be able to render in our editor.

The alpha band must also be an "explicit alpha" meaning that the fourth band must be grouped under the alpha band and not in the "unknown" band
Alternative layersAdditional GeoTIFF/NITF layer, specified as a URL/path to the file.
NITF VersionIf you are using NITF files, they must be in NITF 2.0 or 2.1 format.
File Sizeup to 1 GB recommendedIf you require larger files - please convert the files to cloud-optimized GeoTIFF and upload

Import format

[
    {
        "tileLayerUrl": "https://storage.googleapis.com/jakub-test/pre_DSM_hill_camera_4326.cog.tif",
        "alternativeLayers": [
          {
            "tileLayerUrl": "https://storage.googleapis.com/jakub-test/pre_DSM_hill_camera_4326_red.cog.tif",
            "name": "Red Lee Hill"
          }
        ],
        "bounds": [
          [40.05578109295705, -105.32837712340128],
          [40.06485226245013, -105.2813925407782]
        ]
    },
    {
        "tileLayerUrl": "https://storage.googleapis.com/jakub-test/pre_DSM_hill_camera_4326.cog.tif",
        "alternativeLayers": [
          {
            "tileLayerUrl": "https://storage.googleapis.com/jakub-test/pre_DSM_hill_camera_4326_red.cog.tif",
            "name": "Red Lee Hill"
          }
        ],
        "bounds": [
          [40.06485226245013, -105.32837712340128],
          [40.07392343194322, -105.2813925407782]
        ]
    }
]
[
  {
    "global_key": "https://lb-test-data.s3.us-west-1.amazonaws.com/geospatial-samples/sample-geotiff.tif",
    "row_data": {
      "tile_layer_url": "https://lb-test-data.s3.us-west-1.amazonaws.com/geospatial-samples/sample-geotiff.tif",
    },
    "media_type": "TMS_GEO",
    "metadata_fields": [{"schema_id": "cko8s9r5v0001h2dk9elqdidh", "value": "tag_string"}],
    "attachments": [{"type": "TEXT_URL", "value": "https://storage.googleapis.com/labelbox-sample-datasets/Docs/text_attachment.txt"}]
  }
]

Verify files are processed

🚧

File processing can take up to 20 mins

Since GeoTIFF or NITF files can be very large, the conversion can sometimes take up to 20 minutes to perform a data upload.

You can verify whether a file conversion is complete by checking the Media Attributes section.

If the Mime type shows as application/x-tms-geo, the file was successfully processed.

If the Mime type still shows as application/json, the file pre-processing has not yet been completed.

Python example

For geospatial and custom-defined Data Rows, you have to specify the Data Row in a JSON format. Here's an example with alternative layers, bounds, attachments (text, image, and google maps widget).

from labelbox import Client
from uuid import uuid4 ## to generate unique IDs
import datetime 

client = Client(api_key="<YOUR_API_KEY>")

dataset = client.create_dataset(name="Bulk import example - Geospatial")

assets = [
  {
    "global_key": "https://lb-test-data.s3.us-west-1.amazonaws.com/geospatial-samples/sample-geotiff.tif",
    "row_data": {
      "tile_layer_url": "https://lb-test-data.s3.us-west-1.amazonaws.com/geospatial-samples/sample-geotiff.tif",
    },
    "media_type": "TMS_GEO",
    "metadata_fields": [{"name": "<metadata_field_name>", "value": "tag_string"}],
    "attachments": [{"type": "TEXT_URL", "value": "https://storage.googleapis.com/labelbox-sample-datasets/Docs/text_attachment.txt"}]
  }
]

task = dataset.create_data_rows(assets)
task.wait_till_done()
print(task.errors)
1200 1200