MapillaryClient#
- class rapidtools.data_sources.MapillaryClient(access_token: str | None = None, save_dir: str | Path = 'mapillary_images', *, api_key: str | None = None, save_directory: str | Path | None = None)[source]#
Bases:
objectFetch and store Mapillary images by ID or geographic bounding box.
The client resolves image metadata through the Mapillary Graph API, discovers images inside an area through Mapillary vector tiles, and optionally downloads image files and rasterizes segmentation detections into masks. A Mapillary API access token is required.
- Variables:
access_token (str) – The Mapillary API token sent with every request.
save_dir (Path) – Directory where downloaded images and masks are written.
session (requests.Session) – A pre-configured session with retry logic and default headers used for image downloads.
AVAILABLE_IMAGE_FIELDS (frozenset[str]) – The set of metadata fields that may be requested from the Graph API
imageendpoint.
Example
>>> from rapidtools.data_sources.mapillary_client import MapillaryClient >>> >>> client = MapillaryClient('MLY|123|abc', save_dir='panos') >>> asset = client.fetch_image( ... '1234567890', ... fields=['captured_at', 'compass_angle'], ... save_to_disk=False, ... ) >>> asset.properties['compass_angle'] 182.4
Methods
Decode a detection's vector-tile geometry into normalised polygons.
Fetch Mapillary's segmentation detections for one image as metadata.
Fetch image metadata using its Mapillary ID and optionally download it.
Get multiple images by ID and return them as a collection.
Download and parse Mapillary vector tiles covering a bbox in parallel.
Fetch Mapillary's pre-triangulated point features inside a bounding box.
Read the survey sequences drawn in one Mapillary coverage tile.
Return a (time-limited) download URL for an image at a given size.
- fetch_image(image_id: str, fields: list[str] | None = None, save_to_disk: bool = True, process_masks: list[Literal['semantic', 'instance']] | None = None) ImageAsset | None[source]#
Fetch image metadata using its Mapillary ID and optionally download it.
- This method:
Validates the requested metadata fields.
Fetches image metadata from the API.
Extracts the download URL from the metadata.
Downloads the image file to the configured save directory.
Optionally generates and saves segmentation masks.
Returns an ImageAsset containing the file path, ID, and metadata.
- Parameters:
image_id (str) – The identifier of the image to fetch from the API.
fields (list[str] | None) – Optional list of metadata fields to request. If
None, all fields defined inAVAILABLE_IMAGE_FIELDSare requested. Invalid fields are ignored with a warning.save_to_disk (bool) – If
True, downloads the image to the configured save directory. Defaults toTrue.process_masks (list[str] | None) – A list of mask types to generate. Options are
'semantic'and'instance'. PassNoneor[]to skip segmentation. Example:['semantic']or['semantic', 'instance'].
- Returns:
ImageAsset | None – An ImageAsset whose
pathis the local path of the downloaded file, whoseidis the APIidif present (otherwise the requestedimage_id), and whosepropertieshold the remaining metadata fields returned by the API (excluding theid). ReturnsNoneif validation fails, metadata retrieval fails, no download URL is present, or the download itself fails.
Example
>>> client = MapillaryClient('MLY|123|abc') >>> asset = client.fetch_image( ... '1234567890', ... fields=['width', 'height'], ... save_to_disk=False, ... process_masks=['semantic'], ... ) >>> asset.semantic_map {0: 'void--unlabeled', 1: 'nature--sky', 2: 'construction--flat--road'}
- fetch_detections(image_id: str, values: Iterable[str] | None = None) list[dict[str, Any]][source]#
Fetch Mapillary’s segmentation detections for one image as metadata.
No pixels are downloaded: each detection is a label and a base64-encoded vector-tile polygon, decodable with
decode_detection_polygons(). This is what makes region-scale object discovery cheap.- Parameters:
- Returns:
list[dict[str, Any]] –
{'value': label, 'geometry': base64_mvt}entries, or an empty list when the request fails or nothing matches.
Example
>>> client = MapillaryClient('MLY|123|abc') >>> cars = client.fetch_detections( ... '1234567890', values=['object--vehicle--car'] ... ) >>> cars[0]['value'] 'object--vehicle--car'
- static decode_detection_polygons(b64_geometry: str) list[list[tuple[float, float]]][source]#
Decode a detection’s vector-tile geometry into normalised polygons.
- Parameters:
b64_geometry (str) – The base64-encoded Mapbox Vector Tile carried by a detection.
- Returns:
list[list[tuple[float, float]]] – Exterior rings with
xandyin[0, 1],ygrowing downwards like image pixels. Multi-polygons yield one ring per part; malformed geometry yields an empty list.
Example
>>> import base64, mapbox_vector_tile >>> tile = mapbox_vector_tile.encode([{ ... 'name': 'mpy-or', ... 'features': [{ ... 'geometry': 'POLYGON((0 0, 2048 0, 2048 2048, 0 2048, 0 0))', ... 'properties': {}, ... }], ... }]) >>> rings = MapillaryClient.decode_detection_polygons( ... base64.encodebytes(tile).decode() ... ) >>> sorted(rings[0])[:2] [(0.0, 0.5), (0.0, 1.0)]
- fetch_sequence_lines(z: int, x: int, y: int, filter_rapid_only: bool = True, start_date: str = '', end_date: str = '') dict[str, Any][source]#
Read the survey sequences drawn in one Mapillary coverage tile.
Mapillary’s coverage tiles carry a
sequencelayer at zoom 6 to 14 (the routes driven, as polylines) so a map can show where street-level imagery exists without listing images. Coordinates are returned in the tile’s own pixel space,ygrowing downwards, so a client can draw them straight onto the tile.- Parameters:
z (int) – Tile zoom, 6 to 14.
x (int) – Tile column.
y (int) – Tile row.
filter_rapid_only (bool) – Keep only sequences uploaded by the RAPID Facility. Defaults to
True.start_date (str) – Inclusive lower bound on the capture date (
YYYY-MM-DD); empty for none.end_date (str) – Inclusive upper bound; empty for none.
- Returns:
dict[str, Any] –
extent(tile size in local units, normally4096),
linesas flat[x0, y0, x1, y1, ...]lists,countof sequences kept,first/lastcapture dates andok. A tile that cannot be read after three attempts returnsok=Falsewith anerrormessage and no lines, so callers can tell a failure from an empty tile.
Example
>>> client = MapillaryClient('MLY|123|abc') >>> tile = client.fetch_sequence_lines(10, 178, 365) >>> tile['count'], tile['lines'][0][:4] (12, [2048, 102, 2051, 130])
- fetch_map_features(bbox: BoundingBox, object_values: Sequence[str], start_date: str = '', end_date: str = '', fields: Sequence[str] | None = None, limit: int = 2000, max_depth: int = 6) list[dict[str, Any]][source]#
Fetch Mapillary’s pre-triangulated point features inside a bounding box.
Map features are objects Mapillary has already located on the map by triangulating detections across several images: utility poles, fire hydrants, street lights, traffic signs, benches, trash cans, manholes, catch basins and so on (see
MAP_FEATURE_VALUES). Each comes back as a single WGS84 point, so no imagery has to be downloaded or segmented to inventory them.The endpoint caps the number of features per response at
limitand offers no pagination for bounding-box queries, so whenever a response is full the box is split into four quadrants that are queried recursively (down tomax_depthlevels) and the results are merged by feature id.- Parameters:
bbox (BoundingBox) – The area of interest in WGS84 coordinates.
object_values (Sequence[str]) – Mapillary feature values to request, e.g.
['object--support--utility-pole', 'object--fire-hydrant'].start_date (str) – Inclusive lower bound (
YYYY-MM-DD) of the observation window. A feature is kept when its[first_seen_at, last_seen_at]span overlaps[start_date, end_date]; a missing date on either side counts as overlapping. Empty for no bound.end_date (str) – Inclusive upper bound of the observation window; empty for no bound.
fields (Sequence[str] | None) – Graph API fields to request. Defaults to
('id', 'object_value', 'geometry', 'aligned_direction', 'first_seen_at', 'last_seen_at'). Add'images'to also receive the ids of the images that saw each feature.limit (int) – Maximum features per request. Mapillary documents 2000 as the maximum for this endpoint. Defaults to
2000.max_depth (int) – Maximum number of quadrant splits applied to a saturated box. Defaults to
6(4096 sub-boxes at most).
- Returns:
list[dict[str, Any]] – One dict per feature with the keys
id,object_value,lon,lat,aligned_direction(degrees orNone),first_seen_atandlast_seen_at(ISO strings orNone) andimage_ids(populated only when'images'is requested, otherwise[]), plus any other requested field copied verbatim. HTTP errors on a (sub-)box are logged as warnings and that box is skipped, so a partial result is returned rather than an exception raised.
Example
>>> from rapidtools.core import BoundingBox >>> client = MapillaryClient('MLY|123|abc') >>> bbox = BoundingBox(-117.50, 47.71, -117.49, 47.72) >>> poles = client.fetch_map_features( ... bbox, ['object--support--utility-pole'] ... ) >>> poles[0]['object_value'], poles[0]['lon'] ('object--support--utility-pole', -117.49456)
- get_image_url(image_id: str, size: str = '2048') str | None[source]#
Return a (time-limited) download URL for an image at a given size.
- Parameters:
- Returns:
str | None – The URL, or
Nonewhen the request fails.
Example
>>> client = MapillaryClient('MLY|123|abc') >>> client.get_image_url('1234567890', size='1024') 'https://scontent.../1234567890_1024.jpg'
- fetch_images_by_ids(image_ids: list[str], fields: list[str] | None, save_to_disk: bool = True, process_masks: list[Literal['semantic', 'instance']] | None = None, max_workers: int = 10, show_progress: bool = True) ImageCollection[source]#
Get multiple images by ID and return them as a collection.
- This method:
Submits one fetch task per image ID to a thread pool.
Fetches metadata and downloads each image (via
fetch_image).Aggregates successfully fetched ImageAsset objects into a list.
Logs any exceptions that occur per image without aborting the entire batch.
- Parameters:
image_ids (list[str]) – A list of image IDs to fetch and download.
fields (list[str] | None) – Optional list of metadata fields to request for each image. If
None, all available fields are requested.save_to_disk (bool) – If
True, downloads image files toself.save_dir. IfFalse, only metadata is retrieved. Defaults toTrue.process_masks (list[str] | None) – A list of mask types to generate. Options are
'semantic'and'instance'. PassNoneor[]to skip segmentation. Example:['semantic']or['semantic', 'instance'].max_workers (int) – Maximum number of parallel worker threads used for fetching images. Defaults to
10.show_progress (bool) – Show a progress bar. Callers that fetch in batches pass
Falseto keep their own bar. Defaults toTrue.
- Returns:
ImageCollection – An
ImageCollectioncontaining all successfully fetchedImageAssetinstances. Any images that fail to download or process are excluded; errors are logged per image ID.
Example
>>> client = MapillaryClient('MLY|123|abc') >>> collection = client.fetch_images_by_ids( ... ['111', '222'], fields=['captured_at'], save_to_disk=False ... ) >>> collection.get_ids() ['111', '222']
- fetch_images_in_bbox(bbox: BoundingBox, fields: list[str] | None = None, save_to_disk: bool = False, process_masks: list[Literal['semantic', 'instance']] | None = None, start_date: str = '', end_date: str = '', filter_rapid_only: bool = True, max_workers: int = 10) ImageCollection[source]#
Download and parse Mapillary vector tiles covering a bbox in parallel.
The bounding box is first converted into the set of zoom-14 XYZ tiles that cover it. Each tile is downloaded and decoded to discover image locations. If richer metadata or file downloads are requested, the Graph API is then queried for every discovered image ID and the results are merged back into the tile-derived collection.
- Parameters:
bbox (BoundingBox) – The geographic rectangular area to search. Must be an instance of
rapidtools.core.BoundingBox.fields (list[str] | None) – A list of specific metadata fields to fetch (e.g.,
['captured_at', 'compass_angle']). IfNoneandsave_to_diskisFalse, only the lightweight tile metadata (location, date) is returned and the Graph API is not queried.save_to_disk (bool) – If
True, downloads the images to the configured save directory. Defaults toFalse.process_masks (list[str] | None) – A list of mask types to generate. Options are
'semantic'and'instance'. PassNoneor[]to skip segmentation.start_date (str) – Inclusive lower bound on capture date in
YYYY-MM-DDformat. An empty string disables the lower bound.end_date (str) – Inclusive upper bound on capture date in
YYYY-MM-DDformat. An empty string disables the upper bound.filter_rapid_only (bool) – If
True, only images uploaded by the RAPID facility account are returned. Defaults toTrue.max_workers (int) – Number of parallel download threads. Defaults to
10.
- Returns:
ImageCollection – A new
ImageCollectionpopulated with assets from all tiles. Empty if the bounding box yields no tiles or no matching images.
Example
>>> from rapidtools.core import BoundingBox >>> >>> client = MapillaryClient('MLY|123|abc') >>> bbox = BoundingBox(-118.15, 34.18, -118.14, 34.19) >>> images = client.fetch_images_in_bbox( ... bbox, start_date='2025-01-01', filter_rapid_only=False ... ) >>> images[0].properties['capture_date'] '2025-02-14'