在给定图片上将 long/lat 转换为像素 x/y

IT技术 javascript google-maps coordinates google-static-maps
2021-02-24 16:26:07

我有一张莫斯科的城市地图。我们用一些艺术元素修改了一张谷歌地图图像,但 GPS 坐标和像素之间的关系保持不变。

问题:如何将 GPS 坐标从我们拥有的各种数据点转换为图像中的像素坐标?

理想情况下,我可以在 Javascript 中执行此操作,但是 PHP 就可以了。


我知道在小尺度上(例如在城市尺度上)它可以简单地制作(有必要了解哪些地理坐标具有图片角之一,然后了解轴上图片上地理坐标中一个像素的“价格” OX 和 OY 分开)。

但在大尺度(国家尺度)上,一个像素的“价格”将不是一个常数,而且变化很大,上述方法无法应用。

如何解决国家层面的问题?


更新:

我不使用 API 谷歌地图,我只有:对象的地理坐标(它们来自谷歌地图),我的网站上还有一张简单的图片 *。gif,我必须在其中绘制一个点对应的地理坐标。

6个回答

所有这一切的关键是理解地图投影正如其他人指出的那样,失真的原因是球形(或更准确地说是椭圆体)地球被投影到一个平面上。

为了实现您的目标,您首先必须了解有关数据的两件事:

  1. 您的地图所在的投影。如果它们纯粹来自Google 地图,那么它们很可能使用的是球形墨卡托投影
  2. 您的纬度/经度坐标使用的地理坐标系。这可能会有所不同,因为在地球上定位经纬度有不同的方法。最常见的 GCS 是WGS84,用于大多数网络地图应用程序和 GPS

我假设您的数据在这些坐标系中。

球形墨卡托投影为地球表面定义了一个以米为单位的坐标对。这意味着,对于每个纬度/经度坐标,都有一个匹配的米/米坐标。这使您可以使用以下过程进行转换:

  1. 找到图像角的 WGS84 纬度/经度。
  2. 将 WGS 纬度/经度转换为球形墨卡托投影。那里有转换工具,我最喜欢使用 cs2cs 工具,它是PROJ4 项目的一部分
  3. 您可以安全地进行简单的线性变换,以在图像上的点与球形墨卡托投影中地球上的点之间进行转换,然后再返回。

为了从 WGS84 点到图像上的像素,现在的过程是:

  1. 将经纬度投影到球形墨卡托。这可以使用proj4js 库来完成
  2. 使用上面发现的线性关系将球面墨卡托坐标转换为图像像素坐标。

您可以像这样使用 proj4js 库:

// include the library
<script src="lib/proj4js-combined.js"></script>  //adjust the path for your server
                                                 //or else use the compressed version
// creating source and destination Proj4js objects
// once initialized, these may be re-used as often as needed
var source = new Proj4js.Proj('EPSG:4326');    //source coordinates will be in Longitude/Latitude, WGS84
var dest = new Proj4js.Proj('EPSG:3785');     //destination coordinates in meters, global spherical mercators projection, see http://spatialreference.org/ref/epsg/3785/


// transforming point coordinates
var p = new Proj4js.Point(-76.0,45.0);   //any object will do as long as it has 'x' and 'y' properties
Proj4js.transform(source, dest, p);      //do the transformation.  x and y are modified in place

//p.x and p.y are now EPSG:3785 in meters
@fmark,插入代码,正如你所说,脚本在Proj4js.Proj = OpenLayers.Class({...})它说的那一行给出了一个错误OpenLayers is not defined如何解决问题?
2021-04-20 16:26:07

您必须以您的语言实现 Google Maps API 投影。我有 C# 源代码:

public class GoogleMapsAPIProjection
{
    private readonly double PixelTileSize = 256d;
    private readonly double DegreesToRadiansRatio = 180d / Math.PI;
    private readonly double RadiansToDegreesRatio = Math.PI / 180d;
    private readonly PointF PixelGlobeCenter;
    private readonly double XPixelsToDegreesRatio;
    private readonly double YPixelsToRadiansRatio;

    public GoogleMapsAPIProjection(double zoomLevel)
    {
        var pixelGlobeSize = this.PixelTileSize * Math.Pow(2d, zoomLevel);
        this.XPixelsToDegreesRatio = pixelGlobeSize / 360d;
        this.YPixelsToRadiansRatio = pixelGlobeSize / (2d * Math.PI);
        var halfPixelGlobeSize = Convert.ToSingle(pixelGlobeSize / 2d);
        this.PixelGlobeCenter = new PointF(
            halfPixelGlobeSize, halfPixelGlobeSize);
    }

    public PointF FromCoordinatesToPixel(PointF coordinates)
    {
        var x = Math.Round(this.PixelGlobeCenter.X
            + (coordinates.X * this.XPixelsToDegreesRatio));
        var f = Math.Min(
            Math.Max(
                 Math.Sin(coordinates.Y * RadiansToDegreesRatio),
                -0.9999d),
            0.9999d);
        var y = Math.Round(this.PixelGlobeCenter.Y + .5d * 
            Math.Log((1d + f) / (1d - f)) * -this.YPixelsToRadiansRatio);
        return new PointF(Convert.ToSingle(x), Convert.ToSingle(y));
    }

    public PointF FromPixelToCoordinates(PointF pixel)
    {
        var longitude = (pixel.X - this.PixelGlobeCenter.X) /
            this.XPixelsToDegreesRatio;
        var latitude = (2 * Math.Atan(Math.Exp(
            (pixel.Y - this.PixelGlobeCenter.Y) / -this.YPixelsToRadiansRatio))
            - Math.PI / 2) * DegreesToRadiansRatio;
        return new PointF(
            Convert.ToSingle(latitude),
            Convert.ToSingle(longitude));
    }
}

来源:

http://code.google.com/p/geographical-dot-net/source/browse/trunk/GeographicalDotNet/GeographicalDotNet/Projection/GoogleMapsAPIProjection.cs

谢谢@Jader Dias。你的代码对我有用。我采用了大小为 256*256 的静态谷歌地图。
2021-05-02 16:26:07
我仔细检查过,这与上面提到的 gheat 代码相匹配,该代码是从 Google 地图服务器提供的实际 JS 中提取的。所以我想我们可以说:问题解决了。
2021-05-10 16:26:07
FromPixelToCoordinates方法不应该返回PointF(Convert.ToSingle(longitude), Convert.ToSingle(latitude))吗?[+1]
2021-05-11 16:26:07

因此,您想获取纬度/经度坐标并找出该位置图像上的像素坐标吗?

主要的 GMap2 类提供到/从显示地图上的像素和纬度/经度坐标的转换:

Gmap2.fromLatLngToContainerPixel(latlng)

例如:

var gmap2 = new GMap2(document.getElementById("map_canvas"));
var geocoder = new GClientGeocoder();

geocoder.getLatLng( "1600 Pennsylvania Avenue NW Washington, D.C. 20500",
    function( latlng ) {
        var pixel_coords = gmap2.fromLatLngToContainerPixel(latlng);

        window.alert( "The White House is at pixel coordinates (" + 
            pixel_coodrs.x + ", " + pixel_coords.y + ") on the " +
            "map image shown on this page." );
    }
);

因此,假设您的地图图像是 Google 地图显示的屏幕抓取,那么这将为您提供经纬度坐标图像上的正确像素坐标。

如果您自己抓取图块图像并将它们拼接在一起,事情会更棘手,因为完整图块集的区域将位于显示地图的区域之外。

在这种情况下,您需要使用左上角图像图块的左值和上值作为 fromLatLngToContainerPixel(latlng:GLatLng) 为您提供的坐标的偏移量,从 x 坐标中减去左坐标,从y 坐标。因此,如果左上角的图像位于 (-50, -122) (左,上),并且 fromLatLngToContainerPixel() 告诉您纬度/经度位于像素坐标 (150, 320),那么在从瓷砖,坐标的真实位置在 (150 - (-50), 320 - (-122)) 即 (200, 442)。

也有可能是类似的 GMap2 坐标平移函数:

GMap2.fromLatLngToDivPixel(latlng:GLatLng)

将为您提供拼接瓷砖案例的正确纬度/经度到像素的转换 - 我没有测试过这个,也不是 100% 从 API 文档中清楚。

请参阅此处了解更多信息:http : //code.google.com/apis/maps/documentation/reference.html#GMap2.Methods.Coordinate-Transformations

您可能会查看在gheat 上使用的代码,它是从 js 移植到 python 的。

链接已下线
2021-05-17 16:26:07

您要解决的转换与Map Projection 相关,这就是我们世界的球面如何转换为 2 维渲染。有多种方式(投影)可以在二维表面上渲染世界。

如果您的地图仅使用特定的投影(墨卡托很受欢迎),您应该能够找到方程、一些示例代码和/或一些库(例如一个墨卡托解决方案 -将纬度/经度转换为 X/Y 坐标. 如果那不行,我相信你可以找到其他示例 - https://stackoverflow.com/search?q=mercator。如果你的图像不是使用墨卡托投影的地图,你需要确定它使用什么投影来找到正确的平移方程。

如果您尝试支持多个地图投影(您想支持许多使用不同投影的不同地图),那么您肯定想使用像PROJ.4这样的库,但我再次不确定您会为 Javascript 找到什么或 PHP。

@Donnelly - 很棒的一点 - 她确实说过她的地图图片与谷歌的地图图片相匹配。GMercatorProjection 本身应该是一个答案 - 您应该将其添加为单独的答案 [或者,我将更新此答案以包含它]。我确实阅读了她问题的第二部分(行下方的部分),以便更一般地了解如何将纬度/经度坐标匹配到一般的地图图像(不一定是谷歌),所以我试图给出一个更一般的答案。我可能对她的问题读了很多。
2021-04-29 16:26:07
PROJ.4 很棒,但是当您已经在处理从 Google Maps 获得的地图时,使用它已经提供的坐标转换 API 会更容易。这处理投影翻译(谷歌地图似乎使用墨卡托http://code.google.com/apis/maps/documentation/reference.html#GMercatorProjection)并且可以轻松地从纬度/经度转换为像素。
2021-05-20 16:26:07