67

モスクワの都市地図を持っています。いくつかの芸術的な要素でGoogleマップの画像を変更しましたが、GPS座標とピクセルの関係は同じままです。

問題: GPS座標をさまざまなデータポイントから画像のピクセル座標に変換するにはどうすればよいですか?

理想的にはJavascriptでこれを行うことができますが、PHPでも問題ありません。


小規模(たとえば都市規模)では、十分に簡単に作成できることを知っています(どの地理座標が画像の角の1つを持っているかを学習し、次に軸上の画像の地理座標の1ピクセルの「価格」を学習する必要があります) OXとOYは別々に)。

しかし、大規模(国規模)では、1ピクセルの「価格」は一定ではなく、十分に大きく変動するため、上記の方法を適用することはできません。

国の規模で問題を解決する方法は?


アップデート:

私はAPIGoogleマップを使用していません、私は持っています:オブジェクトの地理座標(それらはグーグルマップからのものです)、私はまだ私のサイトに簡単な写真を持っています*。gif、地理座標に対応する点を描画する必要があります。

4

10 に答える 10

71

これらすべての鍵は、地図投影法を理解することです。他の人が指摘しているように、歪みの原因は、球形(またはより正確には楕円体)の地球が平面に投影されているという事実です。

目標を達成するには、まずデータについて2つのことを知っておく必要があります。

  1. マップが含まれている投影法。純粋にGoogleマップから派生している場合は、球形のメルカトル図法を使用している可能性があります。
  2. 緯度/経度座標が使用している地理座標系。地球上で緯度/経度を特定する方法はさまざまであるため、これはさまざまです。ほとんどのWebマッピングアプリケーションおよびGPSで使用される最も一般的なGCSは、WGS84です。

私はあなたのデータがこれらの座標系にあると仮定しています。

球形のメルカトル図法は、地球の表面の座標ペアをメートル単位で定義します。これは、すべての緯度/経度座標に対して、一致するメートル/メートル座標があることを意味します。これにより、次の手順を使用して変換を実行できます。

  1. 画像の角のWGS84緯度/経度を見つけます。
  2. WGS lat/longsを球形のメルカトル図法に変換します。そこに変換ツールがあります。私のお気に入りは、PROJ4プロジェクトの一部であるcs2csツールを使用することです。
  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
于 2010-04-22T08:31:20.637 に答える
17

ご使用の言語でGoogleMapsAPIプロジェクションを実装する必要があります。私はこれのための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

于 2010-04-25T01:45:52.113 に答える
8

それで、緯度/経度の座標を取り、その場所の画像のピクセル座標を見つけたいですか?

メインの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)

ステッチタイルの場合の正しい緯度/経度からピクセルへの変換が得られます-これはテストしていません。また、APIドキュメントから100%明確ではありません。

詳細については、こちらをご覧ください: http ://code.google.com/apis/maps/documentation/reference.html#GMap2.Methods.Coordinate-Transformations

于 2010-04-22T11:02:09.067 に答える
7

あなたはgheatで使用されたコードを見るかもしれません、それはjsからpythonに移植されています。

于 2010-04-17T17:01:29.070 に答える
5

あなたが取り組んでいる翻訳は、地図投影法と関係があります。これは、私たちの世界の球面が2次元レンダリングに変換される方法です。2Dサーフェス上に世界をレンダリングするには、複数の方法(投影)があります。

マップが特定の投影法のみを使用している場合(メルカトル図法が一般的)、方程式、サンプルコード、および/またはライブラリ(たとえば、1つのメルカトル図法-緯度/経度をX /Y座標に変換)を見つけることができるはずです。それでもうまくいかない場合は、他のサンプルを見つけることができると確信しています -https://stackoverflow.com/search?q =mercator 。画像がメルカトル図法を使用してマップされていない場合は、正しい変換方程式を見つけるために使用する投影法を決定する必要があります。

複数の地図投影法をサポートしようとしている場合(異なる投影法を使用する多くの異なる地図をサポートしたい場合)、間違いなくPROJ.4のようなライブラリを使用したいと思いますが、Javascriptで何が見つかるかわかりません。またはPHP。

于 2010-04-21T23:18:52.250 に答える
3

緯度と経度を長方形の座標に変換する式が必要です。選択できる数は非常に多く、それぞれが異なる方法でマップを歪めます。WolframMathWorldには優れたコレクションがあります。

http://mathworld.wolfram.com/MapProjection.html

「関連項目」リンクをたどります。

于 2010-04-16T11:18:36.220 に答える
3

各ピクセルが同じ領域にあると想定される場合、距離を経度/緯度座標に変換することに関する次の記事が役立つ場合があります。

http://www.johndcook.com/blog/2009/04/27/converting-miles-to-degrees-longitude-or-latitude/

于 2010-04-16T07:21:04.610 に答える
3

考慮すべき重要なことの1つは、投影の「ズーム」レベルです(特にGoogleマップの場合)。

グーグルがそれを説明するように:

ズームレベル1では、マップは4つの256x256ピクセルのタイルで構成され、512x512のピクセルスペースになります。ズームレベル19では、マップ上の各xおよびyピクセルは、0〜256 * 2^19の値を使用して参照できます。

https://developers.google.com/maps/documentation/javascript/maptypes?hl=en#MapCoordinatesを参照してください)

「ズーム」値を考慮に入れるには、以下のシンプルで効果的なdeltaLonPerDeltaXおよびdeltaLatPerDeltaY関数をお勧めします。xピクセルと経度は厳密に比例しますが、これはyピクセルと緯度には当てはまりません。この場合、式には初期緯度が必要です。

// Adapted from : http://blog.cppse.nl/x-y-to-lat-lon-for-google-maps


window.geo = {

    glOffset: Math.pow(2,28), //268435456,
    glRadius:  Math.pow(2,28) / Math.PI,
    a: Math.pow(2,28),
    b: 85445659.4471,
    c: 0.017453292519943,
    d: 0.0000006705522537,
    e: Math.E, //2.7182818284590452353602875,
    p: Math.PI / 180,

    lonToX: function(lon) {
        return Math.round(this.glOffset + this.glRadius * lon * this.p);
    },

    XtoLon: function(x) {
        return -180 + this.d * x;
    },

    latToY: function(lat) {
        return Math.round(this.glOffset - this.glRadius *
                          Math.log((1 + Math.sin(lat * this.p)) /
                          (1 - Math.sin(lat * this.p))) / 2);
    },

    YtoLat: function(y) {
        return Math.asin(Math.pow(this.e,(2*this.a/this.b - 2*y/this.b)) /
                                 (Math.pow(this.e, (2*this.a/this.b - 2*y/this.b))+1) -
                                 1/(Math.pow(this.e, (2*this.a/this.b - 2*y/this.b))+1)
                        ) / this.c;
    },

    deltaLonPerDeltaX: function(deltaX, zoom) {
        // 2^(7+zoom) pixels <---> 180 degrees
        return deltaX * 180 / Math.pow(2, 7+zoom);
    },

    deltaLatPerDeltaY: function(deltaY, zoom, startLat) {
        // more complex because of the curvature, we calculte it by difference
        var startY = this.latToY(startLat),
            endY = startY + deltaY * Math.pow(2, 28-7-zoom),
            endLat = this.YtoLat(endY);

        return ( endLat - startLat ); // = deltaLat
    }
}
于 2014-08-07T21:00:05.923 に答える
2

私のアプローチは、ライブラリがなくても、トリミングされたマップで機能します。メルカトル図法の一部だけで機能することを意味します。多分それは誰かを助けます:https ://stackoverflow.com/a/10401734/730823

于 2012-05-02T05:51:06.763 に答える
0

これに苦労している-オープンストリートマップとグーグルストリートマップの両方を持っていて、外部のグラフィック画像を投影したかった

var map = new OpenLayers.Map({
            div:"map-id",
            allOverlays: true
    });
    var osm = new OpenLayers.Layer.OSM("OpenStreeMao");
    var gmap = new OpenLayers.Layer.Google("Google Streets", {visibility: false});

    map.addLayers([osm,gmap]);

    var vectorLayer = new OpenLayers.Layer.Vector("IconLayer");


    var lonlatObject = new OpenLayers.LonLat(24.938622,60.170421).transform(
            new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject()
    );
    console.log(lonlatObject);

    var point = new OpenLayers.Geometry.Point(lonlatObject.lon, lonlatObject.lat);
    console.log(point);

    var point2 = new OpenLayers.Geometry.Point(lonlatObject.x, lonlatObject.y);
    console.log(point2);

    var feature = new OpenLayers.Feature.Vector(point, null, {
        externalGraphic:  "http://cdn1.iconfinder.com/data/icons/SUPERVISTA/networking/png/72/antenna.png",
        graphicWidth: 72,
        graphicHeight: 72,
        fillOpacity: 1
    });


    vectorLayer.addFeatures(feature);

    map.addLayer(vectorLayer);


    map.setCenter(
            new OpenLayers.LonLat(24.938622,60.170421).transform(
            new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject()
            ),
            12);

     map.addControl(new OpenLayers.Control.LayerSwitcher());

http://jsfiddle.net/alexcpn/N9dLN/8/

于 2013-01-22T07:16:34.127 に答える