Convert long / lats to x / y pixel on a given snapshot

I have a map of the city of Moscow. We changed the image of Google Maps with some elements of art, but the connection between GPS coordinates and pixels remained the same.

Problem: How to convert GPS coordinates from different data points that we have to pixel coordinates in the image?

Ideally, I can do this in Javascript, but PHP will be fine.




I know that on a small scale (for example, on a city scale) it is quite simple (you need to find out what geographical coordinates have one of the corners of the image, and then find out the "price" of one pixel in geographical coordinates for the image along the OX and OY axes separately) .

But on a large scale (country scale), the "price" of one pixel will not be constant and will vary greatly, and the method described above cannot be applied.

How to solve the problem on country scales?




Update:

I don’t use the Google Maps API, I only have: the geographical coordinates of the object (they are from Google maps), I still have a simple photo * on my site. gif, in which I have to draw a point corresponding to geographic coordinates.

+57
javascript google-maps google-static-maps coordinates
Apr 16 '10 at 6:39
source share
10 answers

The key to all this is understanding map forecasts . As others have pointed out, the cause of the distortion is the fact that spherical (or more precisely ellipsoidal) earth is projected onto a plane.

To achieve your goal, you first need to know two things about your data:

  • Projecting your maps. If they are obtained exclusively from Google Maps , then most likely they use the spherical projection of the Mercator .
  • A geographic coordinate system is used, which your latitude / longitude coordinates use. This may vary because there are different ways of finding lat / longs on the globe. The most common GCS used in most web mapping and GPS applications, WGS84 .

I assume your data is in these coordinate systems.

The spherical projection of the Mercator defines a coordinate pair in meters for the surface of the earth. This means that for each lat / long coordinate there is a corresponding meter / meter coordinate. This allows the conversion using the following procedure:

  • Find the WGS84 lat / long image corners.
  • Convert WGS lat / longs to the spherical projection of the Mercator. There are conversion tools, my favorite is to use the cs2cs tool, which is part of the PROJ4 project.
  • You can safely make a simple linear translation to convert between image points and points on the ground in the spherical projection of the Mercator and vice versa.

To move from the WGS84 point to a pixel in the image, the procedure now:

  • Lat / lon project for the spherical Mercator. This can be done using the proj4js library .
  • Convert the spherical coordinate of the Mercator to the coordinate of the image pixel using the linear relationship found above.

You can use the proj4js library as follows:

// 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 //px and py are now EPSG:3785 in meters 
+60
Apr 22 2018-10-22T00:
source share

You will need to implement the Google Maps API projection in your language. I have C # source code for this:

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

Source:

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

+14
Apr 25 '10 at 1:45
source share

So, you want to get the latitude / longitude coordinates and find out the coordinates of the pixels in your image of this location?

The main class GMap2 provides conversion to / from a pixel on the displayed map and the lat / long coordinate:

 Gmap2.fromLatLngToContainerPixel(latlng) 

For example:

 var gmap2 = new GMap2(document.getElementById("map_canvas")); var geocoder = new GClientGeocoder(); geocoder.getLatLng( "1600 Pennsylvania Avenue NW Washington, DC 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." ); } ); 

So, assuming your map image is a screen capture on the Google Map screen, then this will give you the correct pixel coordinate in that image lat / long coordinate.

It’s more difficult if you capture tile images and stitch them together, since the full tile set area will be outside the area of ​​the displayed map.

In this case, you will need to use the left and top values ​​of the top of the image as the offset from the coordinates that gives fromLatLngToContainerPixel (latlng: GLatLng), subtracting the left coordinate from the x coordinate and above the y coordinate. Therefore, if the upper left image is located at (-50, -122) (left, top), and fromLatLngToContainerPixel () indicates that lat / long has a pixel coordinate (150, 320), then on the image stitched together (150 - ( -50), 320 - (-122)), which is (200, 442).

It is also possible that a similar coordinate transformation function GMap2:

 GMap2.fromLatLngToDivPixel(latlng:GLatLng) 

will provide you with the correct lat / long to pixel translation for the case of stitched tiles - I have not tested this and am not 100% removed from the API documents.

See here: http://code.google.com/apis/maps/documentation/reference.html#GMap2.Methods.Coordinate-Transformations

+7
Apr 22 '10 at 11:02
source share

You can see the code used on gheat , it is ported from js to python.

+6
Apr 17 '10 at 17:01
source share

The translation you are referring to refers to Map Projection , as a result of which the spherical surface of our world is transformed into two-dimensional rendering. There are several ways (projections) to display the world on a two-dimensional surface.

If your cards use only a certain projection ( Mercator , popularity), you should be able to find equations, some sample code and / or some library (for example, one Mercator solution - Convert Lat / Longs to X / Y coordinates. If not, m Of course, you can find other samples - https://stackoverflow.com/search?q=mercator.If your images are not maps using the Mercator projection, you need to determine which projection is used to find the correct transfer equations.

If you are trying to support multiple map projections (you want to support many different maps that use different projections), then you definitely want to use a library like PROJ.4 , but again I'm not sure what you will find for Javascript or PHP.

+4
Apr. 21 '10 at 23:18
source share

You need formulas to convert latitude and longitude to rectangular coordinates. There are a huge number to choose from, and each of them will distort the map in a different way. Wolfram MathWorld has a good collection:

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

Follow the "See also" links.

+3
Apr 16 '10 at 11:18
source share

If each pixel is considered the same area, then the following article on converting distances to longitude / latitude coordinates can help you:

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

+2
Apr 16 '10 at 7:21
source share

One of the important things to consider is “scaling” your projection level (in particular for Google Maps).

As Google explains:

At a zoom level of 1, the map consists of 4,256x256 pixels, resulting in a pixel space of 512x512. At zoom level 19, each x and y pixel on the map can be referenced using a value from 0 to 256 * 2 ^ 19

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

To influence the meaning of “scaling”, I recommend the simple and effective functions deltaLonPerDeltaX and deltaLatPerDeltaY below. Although x-pixels and longitudes are strictly proportional, this does not apply to y-pixels and latitudes, for which the formula requires an initial latitude.

 // Adapted from : http://blog.cppse.nl/xy-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 } } 
+2
Aug 07 '14 at 21:00
source share

my approach works without a library and with cropped maps. This means that it only works with portions of the Mercator image. Maybe this helps someone: stack overflow

+1
May 2 '12 at 5:51
source share

The fight against this is to have both an open map and a google street map and wanted to project an external graphic image

 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
Jan 22 '13 at 7:16
source share



All Articles