Mapillary API: FAQs

Popular questions about the Mapillary API v4 are answered here. Examples are given using Python.

How do I retrieve all object detections from a single sequence?

If you have a known sequence key, such as kx7r2uYeFwT6XCfvqh30VZ, you can send an API request to get a list of images in the sequence, then make a dictionary of all the detections for each image:

import requests, json
# Mapillary access token -- provide your own, replace this example
mly_key = 'MLY|0000000000000000000|9856ad9cc629a15337480e7344792d78'

seq = 'kx7r2uYeFwT6XCfvqh30VZ'

url = f'{mly_key}&sequence_id={seq}'
response = requests.get(url)

image_ids = None

if response.status_code == 200:
   json = response.json()
   image_ids = [obj['id'] for obj in json['data']]
   # make a dictionary to store each detection by image ID
   detections = {}
   for image_id in image_ids:
      dets_url = f'{image_id}/detections?access_token={mly_key}&fields=geometry,value'
      response = requests.get(dets_url)
      json = response.json()
      detections[image_id] = json['data']

How do I paginate or retrieve more than the limit of 2000 map features if I search by bounding box?

If you have a large bounding box, a good strategy is to break it into smaller boxes that will request less than 2000 objects each. You can use Bbox Finder to get a set of bounds, and Mercantile Python library:

import requests, json, mercantile

east, south, west, north = [-79.546171,8.948970,-79.528040,8.956771]

# Mapillary access token -- provide your own, replace this example
mly_key = 'MLY|0000000000000000000|9856ad9cc629a15337480e7344792d78'

# use zoom 18 size map tiles, which are quite small -- see to understand the sizes
tiles = list(mercantile.tiles(east, south, west, north, 18))
bbox_list = [mercantile.bounds(tile.x, tile.y, tile.z) for tile in tiles]

features = []

# loop through each smaller bbox to request data
for bbox in bbox_list:
    bbox_features = []
    bbox_str = str(f'{bbox.west},{bbox.south},{bbox.east},{bbox.north}')
    url = f'{mly_key}&fields=id,object_value,geometry&bbox={bbox_str}'
    response = requests.get(url)
    if response.status_code == 200:
        json = response.json()
        # check if the response is empty or not
        if len(json['data']):
            for obj in json['data']:
                # build a GeoJSON object for each feature
                feature = {}
                feature['type'] = 'Feature'
                feature['properties"] = {}
                feature['geometry'] = obj['geometry']
                feature['properties']['id'] = obj['id']
                feature['properties']['object_value'] = obj['object_value']
        # merge into the list of all feature objects
        features += bbox_features

How do I get the image segmentation (pixel coordinates) data for detections?

An API request for detections will return an encoded geometry (based64 encoding of a vector tile), which contains the pixel polygon coordinates--where the detection exists in the image. Remember that image coordinates, unlike Cartesian coordinates, start at the top left corner of an image.

You can decode the base64 string returned by the Mapillary API, then decode the vector tile that the encoded string contains, using Mapbox Vector Tile Python library. You can send an image ID or a map feature ID to the API to get back associated detections.

The detection geometry, once decoded, has coordinates based on the vector tile size of 4096 pixels. To normalize this, divide each x and y coordinate by the extent (4096). To get exact pixel coordinates, multiply the normalized x by the width of the image containing the detection, and the normalized y coordinate by the height. The image detections are overall highly compressed to reduce data size, which can be enormous for a single request if not compressed.

A sample detections request for image ID 315219450124680 withfetching the JPEG URL and decoding detection geometry follows:

import base64, requests, json, mapbox_vector_tile

image_id = '315219450124680'

image_url = f'{image_id}?access_token={mly_key}&fields=height,width,thumb_original_url'

detections_url = f'{image_id}/detections?access_token={mly_key}&fields=geometry'

# request the image: get the height, width, and a URL to the original resolution blurred image
response = requests.get(image_url)
image_data = response.json()
height = image_data['height']
width = image_data['width']
jpeg_url = image_data['thumb_original_url']


# request the detection
response = requests.get(detections_url)
json = response.json()
detection = json['data'][0]
base64_string = detection['geometry']

# decode from base64
vector_data = base64.decodebytes(base64_string.encode('utf-8'))

# decode the vector tile into detection geometry
decoded_geometry = mapbox_vector_tile.decode(vector_data)

# select just the coordinate xy pairs from this detection
detection_coordinates = decoded_geometry['mpy-or']['features'][0]['geometry']['coordinates']

# normalize by the 4096 extent, then multiply by image height and width to get true coordinate location
pixel_coords = [[[x/4096 * width, y/4096 * height] for x,y in tuple(coord_pair)] for coord_pair in detection_coordinates]

How do I retrieve the images in which a specific map feature is visible?

If you have a map feature know ID, for example this speed limit traffic sign with ID 241757724395351 then you can query it and its images:

import requests, json
mly_key = 'MLY|0000000000000000000|9856ad9cc629a15337480e7344792d78'
map_feature_id = '241757724395351'
url = f'{map_feature_id}?access_token={mly_key}&fields=images'
image_ids = []

response = requests.get(url)

if response.status_code == 200: 
    json = response.json()
    image_ids = [obj['id'] for obj in json['images']['data']]

# get and print the URL of each image, to access the JPEG
for image_id in image_ids:
    image_url = f'{image_id}?access_token={mly_key}&fields=thumb_original_url'
    response = requests.get(image_url)
    image_data = response.json()
    jpeg_url = image_data['thumb_original_url']