[GIS] How to georeference a tile downloaded from Google Maps

georeferencinggoogle mapstilesweb-mercatorworld-file

I'm trying to georeference a set of image tiles downloaded from a Google Maps site. Based only on each image's Google Maps grid reference and zoom level, how can I calculate the real-world coordinates?

The page at http://www.maptiler.org/google-maps-coordinates-tile-bounds-projection shows the coordinates and Google Maps grid reference for web mercator tiles.

For example, the centre tile is x=49, y=30, z=6 and has the corner coordinates 10644926.307106785, 626172.1357121654, 11271098.44281895, 1252344.27142432:

enter image description here

Is it possible to calculate the corner coordinates based solely on the grid reference and zoom level (49, 30, 6)?

This is similar to How to georeference a web mercator tile correctly using gdal? but I need a completely programmatic solution, without needing to look anything up online. (Or, if I do need to look up values online it needs to be programmatic).

Edit: this screenshot shows the location of a sample tile (zoom level 11, x = 1593, y = 933). How would I georeference that tile?

enter image description here

Best Answer

This page http://www.maptiler.org/google-maps-coordinates-tile-bounds-projection provides algorithms, written in python, to compute tile bounds in EPSG:900913 coordinates and in latutude/longitude using WGS84 datum.

The class GlobalMercator in this script http://www.maptiler.org/google-maps-coordinates-tile-bounds-projection/globalmaptiles.py contains two methods, TileBounds() and TileLatLonBounds() to do this.

A modified version of the script to show tile bounds coordinates:

#!/usr/bin/env python
###############################################################################
# $Id$
#
# Project:  GDAL2Tiles, Google Summer of Code 2007 & 2008
#           Global Map Tiles Classes
# Purpose:  Convert a raster into TMS tiles, create KML SuperOverlay EPSG:4326,
#           generate a simple HTML viewers based on Google Maps and OpenLayers
# Author:   Klokan Petr Pridal, klokan at klokan dot cz
# Web:      http://www.klokan.cz/projects/gdal2tiles/
#
###############################################################################
# Copyright (c) 2008 Klokan Petr Pridal. All rights reserved.
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
###############################################################################

"""
tilebounds.py

Adapted from: 
http://www.maptiler.org/google-maps-coordinates-tile-bounds-projection/globalmaptiles.py

Global Map Tiles as defined in Tile Map Service (TMS) Profiles
==============================================================

Functions necessary for generation of global tiles used on the web.
It contains classes implementing coordinate conversions for:

  - GlobalMercator (based on EPSG:900913 = EPSG:3785)
       for Google Maps, Yahoo Maps, Microsoft Maps compatible tiles
  - GlobalGeodetic (based on EPSG:4326)
       for OpenLayers Base Map and Google Earth compatible tiles

More info at:

http://wiki.osgeo.org/wiki/Tile_Map_Service_Specification
http://wiki.osgeo.org/wiki/WMS_Tiling_Client_Recommendation
http://msdn.microsoft.com/en-us/library/bb259689.aspx
http://code.google.com/apis/maps/documentation/overlays.html#Google_Maps_Coordinates

Created by Klokan Petr Pridal on 2008-07-03.
Google Summer of Code 2008, project GDAL2Tiles for OSGEO.

In case you use this class in your product, translate it to another language
or find it usefull for your project please let me know.
My email: klokan at klokan dot cz.
I would like to know where it was used.

Class is available under the open-source GDAL license (www.gdal.org).
"""

import math

class GlobalMercatorLight(object):

    def __init__(self, tileSize=256):
        "Initialize the TMS Global Mercator pyramid"
        self.tileSize = tileSize
        self.initialResolution = 2 * math.pi * 6378137 / self.tileSize
        # 156543.03392804062 for tileSize 256 pixels
        self.originShift = 2 * math.pi * 6378137 / 2.0
        # 20037508.342789244

    def MetersToLatLon(self, mx, my ):
        "Converts XY point from Spherical Mercator EPSG:900913 to lat/lon in WGS84 Datum"

        lon = (mx / self.originShift) * 180.0
        lat = (my / self.originShift) * 180.0

        lat = 180 / math.pi * (2 * math.atan( math.exp( lat * math.pi / 180.0)) - math.pi / 2.0)
        return lat, lon

    def PixelsToMeters(self, px, py, zoom):
        "Converts pixel coordinates in given zoom level of pyramid to EPSG:900913"

        res = self.Resolution( zoom )
        mx = px * res - self.originShift
        my = py * res - self.originShift
        return mx, my

    def TileBounds(self, tx, ty, zoom):
        "Returns bounds of the given tile in EPSG:900913 coordinates"

        minx, miny = self.PixelsToMeters( tx*self.tileSize, ty*self.tileSize, zoom )
        maxx, maxy = self.PixelsToMeters( (tx+1)*self.tileSize, (ty+1)*self.tileSize, zoom )
        return ( minx, miny, maxx, maxy )

    def TileLatLonBounds(self, tx, ty, zoom ):
        "Returns bounds of the given tile in latutude/longitude using WGS84 datum"

        bounds = self.TileBounds( tx, ty, zoom)
        minLat, minLon = self.MetersToLatLon(bounds[0], bounds[1])
        maxLat, maxLon = self.MetersToLatLon(bounds[2], bounds[3])

        return ( minLat, minLon, maxLat, maxLon )

    def Resolution(self, zoom ):
        "Resolution (meters/pixel) for given zoom level (measured at Equator)"

        # return (2 * math.pi * 6378137) / (self.tileSize * 2**zoom)
        return self.initialResolution / (2**zoom)


#---------------------


if __name__ == "__main__":
    import sys, os

    def Usage(s = ""):
        print "Usage: tilebounds.py tx ty zoomlevel"
        print
        sys.exit(1)

    profile = 'mercator'
    zoomlevel = None
    tx, ty = None, None

    argv = sys.argv
    i = 1
    while i < len(argv):
        arg = argv[i]
        if tx is None:
            tx = float(argv[i])
        elif ty is None:
            ty = float(argv[i])
        elif zoomlevel is None:
            zoomlevel = int(argv[i])
        else:
            Usage("ERROR: Too many parameters")

        i = i + 1

    if profile != 'mercator':
        Usage("ERROR: Sorry, given profile is not implemented yet.")

    if zoomlevel == None or tx == None or ty == None:
        Usage("ERROR: Specify at least 'lat', 'lon' and 'zoomlevel'.")

    tz = zoomlevel
    mercator = GlobalMercatorLight()

    minx, miny, maxx, maxy = mercator.TileBounds( tx, ty, tz )
    print "Bounds of the given tile in EPSG:900913 coordinates: "
    print "  upper-left corner: "
    print (minx, miny)
    print "  bottom-right corner: "
    print (maxx, maxy)
    print 

    minLat, minLon, maxLat, maxLon = mercator.TileLatLonBounds( tx, ty, tz )
    print "Bounds of the given tile in latitude/longitude using WGS84 datum: "
    print "  upper-left corner: "
    print (minLat, minLon)
    print "  bottom-right corner: "
    print (maxLat, maxLon)
    print 

Usage: tilebounds xTile yTile zoom.

For example, the output for the tile x=49, y=30, z=6 is as follows:

$./tilebounds.py 49 30 6
Bounds of the given tile in EPSG:900913 coordinates: 
  upper-left corner: 
(10644926.307106785, -1252344.271424327)
  bottom-right corner: 
(11271098.44281895, -626172.1357121654)

Bounds of the given tile in latitude/longitude using WGS84 datum: 
  upper-left corner: 
(-11.178401873711772, 95.625)
  bottom-right corner: 
(-5.61598581915534, 101.25000000000001)

A tile can be downloaded with the url http://mt.google.com/vt?x=xTile&y=yTile&z=zoom, but this is forbidden to access it directly.

The software was originally written by Klokan Petr Přidal.

I hope this could help!