我正在开发一个函数,该函数给出以下参数并返回纬度和经度。该图像来自谷歌地图静态 api。谷歌地图使用墨卡托投影。我试图弄清楚如何从图像上的 x,y 像素准确获取纬度和经度。我进行了多种形式的计算,它们似乎略有偏差。
:param x, y: Pixel coordinates.
:param zoom: Zoom level of the image.
:param scale: Scale factor of the image.
:param image_center_lat_lon: Tuple of latitude and longitude at the image center.
:param image_size: Size of the image in pixels.
以下是我使用过的两个函数示例,结果接近但不准确
def pixel_to_lat_lon(x, y, zoom, scale, image_center_lat_lon, image_size):
C = 640 * scale * (2 ** zoom) # Total number of pixels in the map's width or height
lat_center, lon_center = image_center_lat_lon
image_size_scaled = (image_size[0] * scale, image_size[1] * scale)
# Calculate pixel coordinates of the center of the image
center_x = (lon_center + 180) / 360 * C
center_y = (1 - math.log(math.tan(math.radians(lat_center)) + 1 / math.cos(math.radians(lat_center))) / math.pi) / 2 * C
# Calculate the latitude and longitude from the pixel coordinates
pixel_x = center_x - image_size_scaled[0] / 2 + x
pixel_y = center_y - image_size_scaled[1] / 2 + y
lon = pixel_x / C * 360 - 180
lat_rad = math.atan(math.sinh(math.pi * (1 - 2 * pixel_y / C)))
lat = math.degrees(lat_rad)
return lat, lon
示例2:
def project(lat_lng, zoom, scale, tile_size):
"""Project latitude, longitude to world coordinates."""
lat, lng = lat_lng
siny = math.sin(lat * math.pi / 180.0)
siny = min(max(siny, -0.9999), 0.9999)
x = tile_size * (0.5 + lng / 360.0) * scale * (2 ** zoom)
y = tile_size * (0.5 - math.log((1 + siny) / (1 - siny)) / (4 * math.pi)) * scale * (2 ** zoom)
return x, y
def unproject(world_coordinate, zoom, scale, tile_size):
"""Unproject world coordinates to latitude, longitude."""
x, y = world_coordinate
lng = (x / (tile_size * scale * (2 ** zoom)) - 0.5) * 360.0
n = math.pi - 2.0 * math.pi * y / (tile_size * scale * (2 ** zoom))
lat = (180.0 / math.pi) * math.atan(0.5 * (math.exp(n) - math.exp(-n)))
return lat, lng
def pixel_to_lat_lon(x, y, zoom, scale, image_center_lat_lon, image_size):
tile_size = 640
center_x, center_y = project(image_center_lat_lon, zoom, scale, tile_size)
# Calculate the center pixel of the image
image_center_x = image_size[0] / 2
image_center_y = image_size[1] / 2
# Adjust x and y to be absolute pixel coordinates on the map
abs_x = center_x + (x - image_center_x)
abs_y = center_y + (y - image_center_y)
# Convert absolute pixel coordinates back to latitude and longitude
return unproject((abs_x, abs_y), zoom, scale, tile_size)
以下是谷歌地图 API 图像支持文档的一些参考链接:
Google Maps 静态 API 参数用法,有助于理解缩放和缩放
测试案例1:
{
"latitude": 25.64208985300285,
"longitude": -80.37262545716628,
"zoom": 18,
"scale": 2,
"size": 640,
"pixelX": 767.4027099609375,
"pixelY": 700.3953857421875
}
测试案例2:
{
"latitude": 25.63934327097157,
"longitude": -80.35101258254728,
"zoom": 18,
"scale": 2,
"size": 640,
"pixelX": 247.67588806152344,
"pixelY": 239.9282989501953
}
测试用例的结果是粗略的估计。但根据Google Maps UI应该反映泳池的中心,纬度和经度应该大致在:
测试用例1:25.641942181931114,-80.37228858417026
测试用例2:25.640310082174018,-80.3520713140406
使用 pyproj 库和 Transformer 解决了在 WGS84 和 Google Maps Mercator 之间移动的问题
google_maps_proj = Proj('epsg:3857')
wgs84 = Proj('epsg:4326')
transformer = Transformer.from_proj(wgs84, google_maps_proj, always_xy=True)