web-dev-qa-db-de.com

Konvertieren Sie long/lat in Pixel x/y in einem bestimmten Bild

Ich habe einen Stadtplan von Moskau. Wir haben ein Google Maps-Bild mit einigen künstlerischen Elementen geändert, die Beziehung zwischen GPS-Koordinaten und Pixeln bleibt jedoch gleich.

Problem: Wie konvertiere ich GPS-Koordinaten von verschiedenen Datenpunkten in Pixelkoordinaten im Bild?

Idealerweise kann ich dies in Javascript tun, aber PHP wäre in Ordnung.


Ich weiß, dass es auf kleinen Maßstäben (zum Beispiel auf Stadtskalen) einfach genug ist (es ist notwendig zu lernen, welche geographischen Koordinaten eine der Bildecken hat), um dann den "Preis" eines Pixels in geographischen Koordinaten auf einem Bild auf Achsen zu lernen OX und OY getrennt).

Auf der großen Skala (Länderskala) ist der "Preis" eines Pixels jedoch nicht konstant und variiert stark genug, und das oben beschriebene Verfahren kann nicht angewendet werden.

Wie löse ich ein Problem auf Länderskalen?


Update:

Ich verwende keine API von Google Maps, ich habe nur: Geographische Koordinaten des Objekts (sie stammen von Google Maps), ich habe immer noch auf meiner Website ein einfaches Bild *. gif, in dem ich einen Punkt entsprechend geografischer Koordinaten zeichnen muss.

61
Kalinin

Der Schlüssel zu all dem ist das Verständnis von Kartenprojektionen . Wie andere darauf hingewiesen haben, ist die Ursache der Verzerrung die Tatsache, dass die kugelförmige (oder genauer ellipsoide) Erde auf eine Ebene projiziert wird. 

Um Ihr Ziel zu erreichen, müssen Sie zunächst zwei Dinge über Ihre Daten wissen:

  1. Die Projektion, in der sich Ihre Karten befinden. Wenn sie nur von Google Maps stammen, verwenden Sie wahrscheinlich eine sphärische Mercator-Projektion
  2. Das geografische Koordinatensystem, das Ihre Breiten-/Längenkoordinaten verwenden. Dies kann variieren, da es verschiedene Möglichkeiten gibt, Lat/Longs auf dem Globus zu lokalisieren. Das am häufigsten verwendete GCS, das in den meisten Web-Mapping-Anwendungen und für GPS verwendet wird, ist WGS84 .

Ich gehe davon aus, dass sich Ihre Daten in diesen Koordinatensystemen befinden.

Die sphärische Mercator-Projektion definiert ein Koordinatenpaar in Metern für die Erdoberfläche. Das heißt, für jede Breiten-/Längenkoordinate gibt es eine übereinstimmende Meter-/Meterkoordinate. Auf diese Weise können Sie die Konvertierung folgendermaßen durchführen:

  1. Suchen Sie die WGS84-Lat/Long der Ecken des Bildes.
  2. Konvertieren Sie die WGS-Lat/Longs in die sphärische Mercator-Projektion. Dort gibt es Konvertierungswerkzeuge. Mein Favorit ist das cs2cs-Tool, das Teil des PROJ4-Projekts ist
  3. Sie können sicher eine einfache lineare Transformation durchführen, um zwischen Punkten im Bild und Punkten auf der Erde in der sphärischen Mercator-Projektion und wieder zurück zu konvertieren.

Um von einem WGS84-Punkt zu einem Pixel im Bild zu gelangen, ist das Verfahren nun wie folgt: 

  1. Projektieren Sie lat/lon auf sphärischen Mercator. Dies kann mit der Bibliothek proj4js durchgeführt werden.
  2. Wandeln Sie die sphärische Mercator-Koordinate in die Bildpixelkoordinate um.

Sie können die Bibliothek proj4js wie folgt verwenden:

// 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
66
fmark

Sie müssen die Google Maps API-Projektion in Ihrer Sprache implementieren. Ich habe den C # -Quellcode dafür: 

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));
    }
}

Quelle:

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

16
Jader Dias

Sie möchten also Breiten-/Längenkoordinaten nehmen und die Pixelkoordinaten auf Ihrem Bild dieser Position ermitteln?

Die GMap2-Hauptklasse bietet Transformationen von/zu einem Pixel auf der angezeigten Karte und eine Lat/Long-Koordinate:

Gmap2.fromLatLngToContainerPixel(latlng)

Zum Beispiel:

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." );
    }
);

Wenn Sie also davon ausgehen, dass Ihr Kartenbild eine Bildschirmdarstellung der Google Map-Anzeige ist, erhalten Sie auf diesem Bild die korrekte Pixelkoordinate einer Lat/Long-Koordinate.

Die Sache ist schwieriger, wenn Sie sich Kachelbilder schnappen und sie selbst zusammennähen, da der Bereich des gesamten Kachelsatzes außerhalb des Bereichs der angezeigten Karte liegt.

In diesem Fall müssen Sie den linken und oberen Wert der oberen linken Bildkachel als Abstand von den Koordinaten verwenden, die fromLatLngToContainerPixel (latlng: GLatLng) angibt, indem Sie die linke Koordinate von der x-Koordinate und top von der x-Koordinate abziehen y-Koordinate Wenn also das obere linke Bild bei (-50, -122) (links, oben) positioniert ist und fromLatLngToContainerPixel () Ihnen mitteilt, dass lat/long bei Pixelkoordinate (150, 320) ist, dann wird das Bild zusammengenäht Kacheln liegt die wahre Position der Koordinate bei (150 - (-50), 320 - (-122)), was (200, 442) ist.

Es ist auch möglich, dass eine ähnliche GMap2-Koordinatenübersetzungsfunktion:

GMap2.fromLatLngToDivPixel(latlng:GLatLng)

gibt Ihnen die korrekte Lat/Long-zu-Pixel-Übersetzung für die zusammengefügten Kacheln - Ich habe dies nicht getestet und ist auch nicht zu 100% aus den API-Dokumenten ersichtlich.

Weitere Informationen finden Sie hier: http://code.google.com/apis/maps/documentation/reference.html#GMap2.Methods.Coordinate-Transformations

8
Alan Donnelly

Sie können einen Blick auf code werfen, der für gheat verwendet wurde.

7
Ahmet AYGÜN

Die Übersetzung, die Sie ansprechen, hat mit Map Projection zu tun. So wird die Kugeloberfläche unserer Welt in ein zweidimensionales Rendering übersetzt. Es gibt mehrere Möglichkeiten (Projektionen), um die Welt auf einer 2-D-Oberfläche darzustellen.

Wenn Ihre Karten nur eine bestimmte Projektion verwenden ( Mercator , die beliebt ist), sollten Sie die Gleichungen, einen Beispielcode und/oder eine Bibliothek (z. B. eine Mercator-Lösung - Konvertieren von Lat/Longs nach) finden können X/Y-Koordinaten . Wenn dies nicht der Fall ist, bin ich sicher, dass Sie andere Beispiele finden können - https://stackoverflow.com/search?q=mercator . Wenn Ihre Bilder nicht 'sind Um Karten mit einer Mercator-Projektion zu erstellen, müssen Sie bestimmen, mit welcher Projektion die richtigen Übersetzungsgleichungen gefunden werden.

Wenn Sie versuchen, mehrere Kartenprojektionen zu unterstützen (Sie möchten viele verschiedene Karten unterstützen, die unterschiedliche Projektionen verwenden), möchten Sie auf jeden Fall eine Bibliothek wie PROJ.4 verwenden, aber ich bin mir nicht sicher, was Sie tun ' werde für Javascript oder PHP finden.

5
Bert F

Sie benötigen Formeln, um Breiten- und Längengrade in rechteckige Koordinaten umzuwandeln. Sie können aus einer großen Anzahl auswählen und die Karte wird auf unterschiedliche Weise verzerrt. Wolfram MathWorld hat eine gute Sammlung:

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

Folgen Sie den Links "Siehe auch".

3
Amos Newcombe

Wenn angenommen wird, dass sich jedes Pixel im selben Bereich befindet, kann Ihnen der folgende Artikel zum Konvertieren von Entfernungen in Längen-/Breitengrad-Koordinaten hilfreich sein:

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

3
zaf

Ein wichtiger Aspekt ist die "Zoomstufe" Ihrer Projektion (insbesondere für Google Maps).

Wie Google es erklärt: 

Bei der Zoomstufe 1 besteht die Karte aus 4 256 x 256 Pixel großen Kacheln. in einem Pixelbereich von 512x512. Bei der Zoomstufe 19 ist jedes x- und y-Pixel auf Die Karte kann mit einem Wert zwischen 0 und 256 * 2 ^ 19 referenziert werden

(Siehe https://developers.google.com/maps/documentation/javascript/maptypes?hl=de#MapCoordinates )

Um den "Zoom" -Wert zu berücksichtigen, empfehle ich die einfachen und effektiven Funktionen deltaLonPerDeltaX und deltaLatPerDeltaY. Während x-Pixel und Längen streng proportional sind, gilt dies nicht für y-Pixel und Breiten, für die die Formel den anfänglichen Breitengrad benötigt.

// 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
    }
}
3
Louis LC

mein Ansatz funktioniert ohne Bibliothek und mit zugeschnittenen Karten. Bedeutet, dass es nur mit Teilen eines Mercator-Bildes funktioniert. Vielleicht hilft es jemandem: https://stackoverflow.com/a/10401734/730823

2
Raphael

Kämpfte damit - Habe sowohl eine Openstreet-Karte als auch eine Google-Straßenkarte und wollte ein externes Grafikbild projizieren

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/

0
Alex Punnen