Easy OpenStreetMap tile displaying for Python

后端 未结 7 708
野的像风
野的像风 2020-12-08 12:21

I want to include the open street map (OSM) in my python code.

I have read through lots of webpages regarding to OSM. But unfortunately I\'m a bit lost, regarding wh

7条回答
  •  借酒劲吻你
    2020-12-08 12:37

    Edit: OpenStreetMap states that their tile servers are not free to use and are under a usage policy:
    https://operations.osmfoundation.org/policies/tiles/
    Please read this before using the example.

    As I had problems implementing the code in Python 3.8, I merged a few of the answers together and modified the code. Now it works for me and I don't get any errors.
    When I tried to run the original code from BerndGit in Python 3, I had to make the same changes as Joining Dots described in his answer. I replaced

     import urllib2
     import StringIO
    

    with

    import requests
    from io import BytesIO
    

    because the urllib2 library doesn't work with Python 3 anymore. You have to use urllib.request or requests.
    Then I had to change these two lines from the getImageCluster function

    imgstr = urllib2.urlopen(imgurl).read()
    tile = Image.open(StringIO.StringIO(imgstr))
    

    to

    imgstr = requests.get(imgurl)
    tile = Image.open(BytesIO(imgstr.content))
    

    After that I could run the code without errors but it still couldn't download the images. I always got a black tile as a result. Through some research I learned, that it is important to fake a user agent while using requests, as the website could tell that the request is coming from Python and may block it. The following website describes this:
    https://www.scrapehero.com/how-to-fake-and-rotate-user-agents-using-python-3/
    So I followed the suggestions from the website which resulted in adding this line right at the beginning of the getImageCluster function:

    headers = {"User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36"}
    

    Now we need to include these headers into the requests call:

    imgstr = requests.get(imgurl, headers=headers)
    

    The whole code looks like this now:

    import matplotlib.pyplot as plt
    import numpy as np
    import math
    import requests
    from io import BytesIO
    from PIL import Image
       
        
        
    def deg2num(lat_deg, lon_deg, zoom):
      lat_rad = math.radians(lat_deg)
      n = 2.0 ** zoom
      xtile = int((lon_deg + 180.0) / 360.0 * n)
      ytile = int((1.0 - math.log(math.tan(lat_rad) + (1 / math.cos(lat_rad))) / math.pi) / 2.0 * n)
      return (xtile, ytile)
        
    def num2deg(xtile, ytile, zoom):
      n = 2.0 ** zoom
      lon_deg = xtile / n * 360.0 - 180.0
      lat_rad = math.atan(math.sinh(math.pi * (1 - 2 * ytile / n)))
      lat_deg = math.degrees(lat_rad)
      return (lat_deg, lon_deg)
       
    def getImageCluster(lat_deg, lon_deg, delta_lat,  delta_long, zoom):
        headers = {"User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36"}
        smurl = r"http://a.tile.openstreetmap.org/{0}/{1}/{2}.png"
        xmin, ymax =deg2num(lat_deg, lon_deg, zoom)
        xmax, ymin =deg2num(lat_deg + delta_lat, lon_deg + delta_long, zoom)
       
        Cluster = Image.new('RGB',((xmax-xmin+1)*256-1,(ymax-ymin+1)*256-1) ) 
        for xtile in range(xmin, xmax+1):
            for ytile in range(ymin,  ymax+1):
                try:
                    imgurl = smurl.format(zoom, xtile, ytile)
                    print("Opening: " + imgurl)
                    imgstr = requests.get(imgurl, headers=headers)
                    tile = Image.open(BytesIO(imgstr.content))
                    Cluster.paste(tile, box = ((xtile-xmin)*256 ,  (ytile-ymin)*255))
                except: 
                    print("Couldn't download image")
                    tile = None
       
        return Cluster
        
        
        
    if __name__ == '__main__':
        
        a = getImageCluster(38.5, -77.04, 0.02,  0.05, 13)
        fig = plt.figure()
        fig.patch.set_facecolor('white')
        plt.imshow(np.asarray(a))
        plt.show()
    

    The result is the following:

提交回复
热议问题