前言
之前有小伙伴问想获取多张街景图的元数据,总不能在Mapillary上面自己找图像id号,然后发请求,这种方法太耗时了。所以就有了第二篇Mapillary街景数据获取的博文,旨在解决如何快速获取大量的街景图像这一问题。好在Mapillary提供了获取某个区域内部街景图像id号的接口,只要有id号就能按第一篇博文的方法获取元数据,下面介绍思路。
一、基于矩形边界框坐标获取地图瓦片行列号
根据边界框的WGS84坐标获取14级地图瓦片中与边界框区域相交的瓦片行列号。瓦片层级为何是14级,这是Mapillary官方规定的。此处用到了mercantile库,这是一个有关地图切片的Python库。
代码如下:
import mercantile
# boundingbox,左下角与右上角WGS84坐标--示例坐标为美国佛罗里达州
west, south, east, north = [-80.13423442840576, 25.77376933762778, -80.1264238357544, 25.788608487732198]
tiles = list(mercantile.tiles(west, south, east, north, 14))
print(tiles)
代码运行结果如下图所示:
可知与矩形区域相交的瓦片有两个,它们的行列号xy、层级z将用来构造请求区域街景id的Url
二、构造Url并请求
本节利用第一部分获取的地图瓦片行列号层级构造url,通过GET请求获取数据,并将数据保存json格式。这部分需使用requests库、vt2geojson库和json库,其中vt2geojson库的作用是将地图矢量切片从远程 URL 或本地系统文件转储到 GeoJSON。
代码如下:
import json
import requests
from vt2geojson.tools import vt_bytes_to_geojson
# Mapillary访问令牌,换成你自己的
access_token = 'MLYARDJsQP6BFV3QPg8VIVjqFRZBjDE08XJjP33pZAkjNppgVJjKJP9BLiawEepZCQ7Pbk10lnvEFTWedTAN2fEXtKIz9HTXXLqJ5qy2NTwaLLIUQHgQKB3CsdjmiZBfgZDZD'
num = 1
# 这里的变量tiles是第一部分中得到的
for tile in tiles:
# 构造url
tile_url = 'https://tiles.mapillary.com/maps/vtp/mly1_public/2/{}/{}/{}?access_token={}'.format(tile.z,tile.x,tile.y,access_token)
# 发GET请求
response = requests.get(tile_url)
# response.content是二进制字节
# vt_bytes_to_geojson() 基于矢量瓦片的字节创建GeoJSON
# 参数一:瓦片内容,字节类型
# 参数二:瓦片X坐标,int
# 参数三:瓦片Y坐标,int
# 参数四:瓦片Z坐标,int
# 参数五:瓦片图层的类型
data = vt_bytes_to_geojson(response.content, tile.x, tile.y, tile.z,layer="image")
data = json.dumps(data,indent=4)
# 将数据保存为json格式
with open(f'{num}.json','w') as f:
f.write(data)
print('保存成功!')
num = num+1
保存的json文件内容如下图所示:
可以看到,json文件中每个街景图像是用点要素格式保存的,既有空间几何信息也有属性信息,其中属性信息包括街景id号。下面只需for循环遍历id号就能请求元数据了。
把json文件导入mapshaper网站中可视化,效果如下图所示,可以看到街景点在地图上的位置。共有5459个点要素,说明当前14级地图瓦片内部有5459张街景图像。
三、遍历id获取元数据并下载图像
本节在请求元数据之前还需判断当前id对应的街景位置是否在矩形区域内部,虽然地图瓦片与矩形区域相交,但不能保证整个瓦片都在矩形区域内部,所以判断是必要的。
代码如下:
# 代码与第一第二部分无关
import json
import requests
# 读取第二部分保存的json文件
with open('1.json','r') as f:
data = json.load(f)
#矩形区域坐标
west, south, east, north = [-80.13423442840576,25.77376933762778,-80.1264238357544,25.788608487732198]
# Mapillary访问令牌,换成你自己的
access_token = 'MLYARDJsQP6BFV3QPg8VIVjqFRZBjDE08XJjP33pZAkjNppgVJjKJP9BLiawEepZCQ7Pbk10lnvEFTWedTAN2fEXtKIz9HTXXLqJ5qy2NTwaLLIUQHgQKB3CsdjmiZBfgZDZD'
# 以前5个点要素为例
for feature in data['features'][:5]:
# 获取每个点要素的经纬度坐标
lng = feature['geometry']['coordinates'][0]
lat = feature['geometry']['coordinates'][1]
# 判断要素是否在矩形区域内部
if lng > west and lng < east and lat > south and lat < north:
# 请求图像元数据中原图字段
image_id = feature['properties']['id']
header = {'Authorization': 'OAuth {}'.format(access_token)}
url = 'https://graph.mapillary.com/{}?fields=thumb_original_url'.format(image_id)
r = requests.get(url, headers=header)
data = r.json()
# 拿到原图对应的url
image_url = data['thumb_original_url']
# 保存图像,因为图像是二进制数据,所以用wb模式
with open(f'{image_id}.jpg','wb') as f:
image_data = requests.get(image_url, stream=True).content
f.write(image_data)
print('ok')
下载的街景图如下所示:
总结
以上内容就是快速获取大量Mapillary街景图像的方法,希望可以帮助到更多的人。