Convert long/lat to pixel x/y on a given picture Convert long/lat to pixel x/y on a given picture javascript javascript

Convert long/lat to pixel x/y on a given picture


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

In order to achieve your goal, you first must know two things about your data:

  1. The projection your maps are in. If they are purely derived from Google Maps, then chances are they are using a spherical Mercator projection.
  2. The geographic coordinate system your latitude/longitude coordinates are using. This can vary, because there are different ways of locating lat/longs on the globe. The most common GCS, used in most web-mapping applications and for GPS's, is WGS84.

I'm assuming your data is in these coordinate systems.

The spherical Mercator projection defines a coordinate pair in meters, for the surface of the earth. This means, for every lat/long coordinate there is a matching meter/meter coordinate. This enables you to do the conversion using the following procedure:

  1. Find the WGS84 lat/long of the corners of the image.
  2. Convert the WGS lat/longs to the spherical Mercator projection. There conversion tools out there, my favorite is to use the cs2cs tool that is part of the PROJ4 project.
  3. You can safely do a simple linear transform to convert between points on the image, and points on the earth in the spherical Mercator projection, and back again.

In order to go from a WGS84 point to a pixel on the image, the procedure is now:

  1. Project lat/lon to spherical Mercator. This can be done using the proj4js library.
  2. Transform spherical Mercator coordinate into image pixel coordinate using the linear relationship discovered above.

You can use the proj4js library like this:

// 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 neededvar source = new Proj4js.Proj('EPSG:4326');    //source coordinates will be in Longitude/Latitude, WGS84var dest = new Proj4js.Proj('EPSG:3785');     //destination coordinates in meters, global spherical mercators projection, see http://spatialreference.org/ref/epsg/3785/// transforming point coordinatesvar p = new Proj4js.Point(-76.0,45.0);   //any object will do as long as it has 'x' and 'y' propertiesProj4js.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


You will have to implement the Google Maps API projection in your language. I have the 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


So you want to take latitude/longitude coordinates and find out the pixel coordinates on your image of that location?

The main GMap2 class provides transformation to/from a pixel on the displayed map and a 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, 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." );    });

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

Things are trickier if you're grabbing tile images and stitching them together yourself since the area of the complete tile set will lie outside the area of the displayed map.

In this case, you'll need to use the left and top values of the top-left image tile as an offset from the coordinates that fromLatLngToContainerPixel(latlng:GLatLng) gives you, subtracting the left coordinate from the x coordinate and top from the y coordinate. So if the top-left image is positioned at (-50, -122) (left, top), and fromLatLngToContainerPixel() tells you a lat/long is at pixel coordinate (150, 320), then on the image stitched together from tiles, the true position of the coordinate is at (150 - (-50), 320 - (-122)) which is (200, 442).

It's also possible that a similar GMap2 coordinate translation function:

GMap2.fromLatLngToDivPixel(latlng:GLatLng)

will give you the correct lat/long to pixel translation for the stitched-tiles case - I've not tested this, nor is it 100% clear from the API docs.

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