use*_*624 4 python google-maps geolocation google-maps-api-3
我正在从谷歌静态地图API加载图像,加载的卫星图像是一个数百米宽和长度的地方.
https://maps.googleapis.com/maps/api/staticmap?center=53.4055429,-2.9976502&zoom=16&size=400x400&maptype=satellite&key=YOUR_API_KEY
Run Code Online (Sandbox Code Playgroud)
此外,图像分辨率显示为10米,如下所示
我的问题是
因为我知道(53.4055429,-2.9976502)这个静态图像的居中地理位置和分辨率,我怎么能够扩展它来计算图像中左上或右下的地理位置,最后计算图像的每个像素
它是什么样的解决方案
看起来你不需要javascript解决方案,但python不能在浏览器中使用它,而是在服务器上使用它.我已经创建了一个python示例,但它是我将要站立的数学,数学就是计算坐标所需的全部内容.让我用js来做它以使代码片段在浏览器中工作.你可以看到,python和js给出了相同的结果.
跳到答案
如果您只需要每像素度数的公式,那么您就是这样.它们很简单,你不需要任何外部库,只需要一个python math.可以进一步解释.
#!/usr/bin/python
import math
w = 400
h = 400
zoom = 16
lat = 53.4055429
lng = -2.9976502
def getPointLatLng(x, y):
parallelMultiplier = math.cos(lat * math.pi / 180)
degreesPerPixelX = 360 / math.pow(2, zoom + 8)
degreesPerPixelY = 360 / math.pow(2, zoom + 8) * parallelMultiplier
pointLat = lat - degreesPerPixelY * ( y - h / 2)
pointLng = lng + degreesPerPixelX * ( x - w / 2)
return (pointLat, pointLng)
print 'NE: ', getPointLatLng(w, 0)
print 'SW: ', getPointLatLng(0, h)
print 'NW: ', getPointLatLng(0, 0)
print 'SE: ', getPointLatLng(w, h)
Run Code Online (Sandbox Code Playgroud)
脚本的输出是
$ python getcoords.py
NE: (53.40810128625675, -2.9933586655761717)
SW: (53.40298451374325, -3.001941734423828)
NW: (53.40810128625675, -3.001941734423828)
SE: (53.40298451374325, -2.9933586655761717)
Run Code Online (Sandbox Code Playgroud)
我们必须从什么开始
我们在url中需要一些参数https://maps.googleapis.com/maps/api/staticmap?center=53.4055429,-2.9976502&zoom=16&size=400x400&maptype=satellite&key=YOUR_API_KEY- 坐标,缩放,大小(以像素为单位).
我们来介绍一些初始变量:
var config = {
lat: 53.4055429,
lng: -2.9976502,
zoom: 16,
size: {
x: 400,
y: 400,
}
};
Run Code Online (Sandbox Code Playgroud)
512像素的地球数学
数学如下.使用图像尺寸时1,缩放代表地球赤道的全景(请参阅文档了解尺寸和缩放).请参阅缩放1处的示例.这是非常重要的一点.比例(每像素度数)不依赖于图像大小.当一个人改变图像大小时,会看到相同的比例:比较1和2 - 第二个图像是较大图像的裁剪版本.为最大图像尺寸为.360°512googleapis640
每次放大都会使分辨率提高两倍.因此,经度方面的图像宽度是
lngDegrees = 360 / 2**(zoom - 1); // full image width in degrees, ** for power
Run Code Online (Sandbox Code Playgroud)
然后使用线性函数查找图像任意点的坐标.应该提到的是,线性仅适用于高变焦图像,不能用于5或更低的低变焦.低变焦具有稍微复杂的数学.
lngDegreesPerPixel = lngDegrees / 512 = 360 / 2**(zoom - 1) / 2**9 = 360 / 2**(zoom + 8);
lngX = config.lng + lngDegreesPerPixel * ( point.x - config.size.x / 2);
Run Code Online (Sandbox Code Playgroud)
纬度是不同的
赤道上的纬度和经度具有相同的大小,但如果我们向北或向南,经度会变小,因为地球上的平行环具有较小的半径 - r = R * cos(lat) < R因此图像高度以度为单位变小(见PS).
latDegrees = 360 / 2**(zoom - 1) * cos(lat); // full image height in degrees, ** for power
Run Code Online (Sandbox Code Playgroud)
分别
latDegreesPerPixel = latDegrees / 512 = 360 / 2**(zoom - 1) * cos(lat) / 2**9 = 360 / 2**(zoom + 8) * cos(lat);
latY = config.lat - latDegreesPerPixel * ( point.y - config.size.y / 2)
Run Code Online (Sandbox Code Playgroud)
由于地球经度方向与图像方向一致,因此符号config.lat与符号不同,但是纬度方向lngX与图像x上的方向相反y.
所以我们现在可以创建一个简单的函数来使用它x和y图片上的坐标找到像素的坐标.
var config = {
lat: 53.4055429,
lng: -2.9976502,
zoom: 16,
size: {
x: 400,
y: 400,
}
};
function getCoordinates(x, y) {
var degreesPerPixelX = 360 / Math.pow(2, config.zoom + 8);
var degreesPerPixelY = 360 / Math.pow(2, config.zoom + 8) * Math.cos(config.lat * Math.PI / 180);
return {
lat: config.lat - degreesPerPixelY * ( y - config.size.y / 2),
lng: config.lng + degreesPerPixelX * ( x - config.size.x / 2),
};
}
console.log('SW', getCoordinates(0, config.size.y));
console.log('NE', getCoordinates(config.size.x, 0));
console.log('SE', getCoordinates(config.size.x, config.size.y));
console.log('NW', getCoordinates(0, 0));
console.log('Something at 300,128', getCoordinates(300, 128));Run Code Online (Sandbox Code Playgroud)
PS你可能会问我,为什么我把cos(lat)乘数放在纬度上,而不是作为经度公式的除法器.我发现,谷歌选择在不同的纬度上每个像素具有恒定的经度比例,因此,cos作为乘数进入纬度.
我相信您可以使用 Maps JavaScript API 计算边界框。
您有一个中心位置,并且知道从中心到东北和西南的距离是 200 像素,因为示例中的尺寸是 400x400。
看一下下面计算 NE 和 SW 点的代码
var map;
function initMap() {
var latLng = new google.maps.LatLng(53.4055429,-2.9976502);
map = new google.maps.Map(document.getElementById('map'), {
center: latLng,
zoom: 16,
mapTypeId: google.maps.MapTypeId.SATELLITE
});
var marker = new google.maps.Marker({
position: latLng,
map: map
});
google.maps.event.addListener(map, "idle", function() {
//Verical and horizontal distance from center in pixels
var h = 200;
var w = 200;
var centerPixel = map.getProjection().fromLatLngToPoint(latLng);
var pixelSize = Math.pow(2, -map.getZoom());
var nePoint = new google.maps.Point(centerPixel.x + w*pixelSize, centerPixel.y - h*pixelSize);
var swPoint = new google.maps.Point(centerPixel.x - w*pixelSize, centerPixel.y + h*pixelSize);
var ne = map.getProjection().fromPointToLatLng(nePoint);
var sw = map.getProjection().fromPointToLatLng(swPoint);
var neMarker = new google.maps.Marker({
position: ne,
map: map,
title: "NE: " + ne.toString()
});
var swMarker = new google.maps.Marker({
position: sw,
map: map,
title: "SW: " + sw.toString()
});
var polygon = new google.maps.Polygon({
paths: [ne, new google.maps.LatLng(ne.lat(),sw.lng()), sw, new google.maps.LatLng(sw.lat(),ne.lng())],
map: map,
strokeColor: "green"
});
console.log("NE: " + ne.toString());
console.log("SW: " + sw.toString());
});
}Run Code Online (Sandbox Code Playgroud)
#map {
height: 100%;
}
/* Optional: Makes the sample page fill the window. */
html, body {
height: 100%;
margin: 0;
padding: 0;
}Run Code Online (Sandbox Code Playgroud)
<div id="map"></div>
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyDztlrk_3CnzGHo7CFvLFqE_2bUKEq1JEU&libraries=geometry&callback=initMap"
async defer></script>Run Code Online (Sandbox Code Playgroud)
我希望这有帮助!
更新
为了在 python 中解决这个问题,您应该了解Google Maps JavaScript API 使用的地图和图块坐标原理,并在 python 中实现类似于 Google Maps API 的投影逻辑。
map.getProjection().fromLatLngToPoint()幸运的是,有人已经完成了这项任务,您可以找到实现与map.getProjection().fromPointToLatLng()我的 python 示例类似的方法的项目。在github上看一下这个项目:
https://github.com/hrldcpr/mercator.py
因此,您可以下载 Mercator.py 并在您的项目中使用它。我的 JavaScript API 示例转换为以下 python 代码
#!/usr/bin/python
from mercator import *
w = 200
h = 200
zoom = 16
lat = 53.4055429
lng = -2.9976502
centerPixel = get_lat_lng_tile(lat, lng, zoom)
pixelSize = pow(2, -zoom)
nePoint = (centerPixel[0] + w*pixelSize, centerPixel[1] - h*pixelSize)
swPoint = (centerPixel[0] - w*pixelSize, centerPixel[1] + h*pixelSize)
ne = get_tile_lat_lng(zoom, nePoint[0], nePoint[1]);
sw = get_tile_lat_lng(zoom, swPoint[0], swPoint[1]);
print 'NorthEast: ', ne
print 'SouthWest: ', sw
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3745 次 |
| 最近记录: |