Skip to content

Instantly share code, notes, and snippets.

@cbeddow
Last active March 18, 2024 06:08
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save cbeddow/79d68aa6ed0f028d8dbfdad2a4142cf5 to your computer and use it in GitHub Desktop.
Save cbeddow/79d68aa6ed0f028d8dbfdad2a4142cf5 to your computer and use it in GitHub Desktop.
Download Mapillary images a JPGs
import mercantile, mapbox_vector_tile, requests, json, os
from vt2geojson.tools import vt_bytes_to_geojson
# define an empty geojson as output
output= { "type": "FeatureCollection", "features": [] }
# vector tile endpoints -- change this in the API request to reference the correct endpoint
tile_coverage = 'mly1_public'
# tile layer depends which vector tile endpoints:
# 1. if map features or traffic signs, it will be "point" always
# 2. if looking for coverage, it will be "image" for points, "sequence" for lines, or "overview" for far zoom
tile_layer = "image"
# Mapillary access token -- user should provide their own
access_token = 'MLY|XXX'
# a bounding box in [east_lng,_south_lat,west_lng,north_lat] format
west, south, east, north = [-80.13423442840576,25.77376933762778,-80.1264238357544,25.788608487732198]
# get the list of tiles with x and y coordinates which intersect our bounding box
# MUST be at zoom level 14 where the data is available, other zooms currently not supported
tiles = list(mercantile.tiles(west, south, east, north, 14))
# loop through list of tiles to get tile z/x/y to plug in to Mapillary endpoints and make request
for tile in tiles:
tile_url = 'https://tiles.mapillary.com/maps/vtp/{}/2/{}/{}/{}?access_token={}'.format(tile_coverage,tile.z,tile.x,tile.y,access_token)
response = requests.get(tile_url)
data = vt_bytes_to_geojson(response.content, tile.x, tile.y, tile.z,layer=tile_layer)
# push to output geojson object if yes
for feature in data['features']:
# get lng,lat of each feature
lng = feature['geometry']['coordinates'][0]
lat = feature['geometry']['coordinates'][1]
# ensure feature falls inside bounding box since tiles can extend beyond
if lng > west and lng < east and lat > south and lat < north:
# create a folder for each unique sequence ID to group images by sequence
sequence_id = feature['properties']['sequence_id']
if not os.path.exists(sequence_id):
os.makedirs(sequence_id)
# request the URL of each image
image_id = feature['properties']['id']
header = {'Authorization' : 'OAuth {}'.format(access_token)}
url = 'https://graph.mapillary.com/{}?fields=thumb_2048_url'.format(image_id)
r = requests.get(url, headers=header)
data = r.json()
image_url = data['thumb_2048_url']
# save each image with ID as filename to directory by sequence ID
with open('{}/{}.jpg'.format(sequence_id, image_id), 'wb') as handler:
image_data = requests.get(image_url, stream=True).content
handler.write(image_data)
@Rubix982
Copy link

Rubix982 commented Aug 9, 2021

Well done!

@gSingh-maker
Copy link

gSingh-maker commented May 3, 2023

@cbeddow Are you able to download and view the point cloud supplied as sfm_cluster, among the "fields" associated with an individual image ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment