I’ve previously written about grabbing Google Streetview images given a particular address. For a different project I sampled images running along an entire street, so figured I would share that code. It is a bit more complicated though, because when you base it off an address you do not need to worry about drawing the same image twice. So I will walk through an example.
So first we will import the necessary libraries we are using, then will globally define your user key and the download folder you want to save the streetview images into.
#Upfront stuff you need
import urllib, os, json
key = "&key=" + "!!!!!!!!!!!!!YourAPIHere!!!!!!!!!!!!!!!!"
DownLoc = r'!!!!!!!!!!!YourFileLocationHere!!!!!!!!!!!!!!'
Second are a few functions. The first, MetaParse
, grabs the date
(Month and Year) and pano_id
from a particular street view image. Because if you submit just a slightly different set of lat-lon, google will just download the same image again. To prevent that, we do a sort of memoization, where we grab the meta-data first, stuff it in a global list PrevImage
. Then if you have already downloaded that image once, the second GetStreetLL
function will not download it again, as it checks the PrevImage
list. If you are doing a ton of images you may limit the size of PrevImage
to a certain amount, but it is no problem doing a few thousand images as is. (With a free account you can IIRC get 25,000 images in a day, but the meta-queries count against that as well.)
def MetaParse(MetaUrl):
response = urllib.urlopen(MetaUrl)
jsonRaw = response.read()
jsonData = json.loads(jsonRaw)
#return jsonData
if jsonData['status'] == "OK":
if 'date' in jsonData:
return (jsonData['date'],jsonData['pano_id']) #sometimes it does not have a date!
else:
return (None,jsonData['pano_id'])
else:
return (None,None)
PrevImage = [] #Global list that has previous images sampled, memoization kindof
def GetStreetLL(Lat,Lon,Head,File,SaveLoc):
base = r"https://maps.googleapis.com/maps/api/streetview"
size = r"?size=1200x800&fov=60&location="
end = str(Lat) + "," + str(Lon) + "&heading=" + str(Head) + key
MyUrl = base + size + end
fi = File + ".jpg"
MetaUrl = base + r"/metadata" + size + end
#print MyUrl, MetaUrl #can check out image in browser to adjust size, fov to needs
met_lis = list(MetaParse(MetaUrl)) #does not grab image if no date
if (met_lis[1],Head) not in PrevImage and met_lis[0] is not None: #PrevImage is global list
urllib.urlretrieve(MyUrl, os.path.join(SaveLoc,fi))
met_lis.append(fi)
PrevImage.append((met_lis[1],Head)) #append new Pano ID to list of images
else:
met_lis.append(None)
return met_lis
Now we are ready to download images running along an entire street. To get the necessary coordinates and header information I worked it out in a GIS. Using a street centerline file I regularly sampled along the streets. Based on those sample points then you can calculate a local trajectory of the street, and then based on that trajectory turn the camera how you want it. Most social science folks I imagine want it to look at the sidewalk, so then you will calculate 90 degrees to the orientation of the street.
Using trial and error I found that spacing the samples around 40 feet apart tended to get a new image. I have the pixel size and fov parameters to the streetview api hard set in the function, but you could easily amend the function to take those as arguments as well.
So next I have an example list of tuples with lat-lon’s and orientation. Then I just loop over those sample locations and draw the images. Here I also have another list image_list
, that contains what I save the images too, as well as saves the pano-id and the date meta data.
DataList = [(40.7036043470179800,-74.0143908501053400,97.00),
(40.7037139540670900,-74.0143727485309500,97.00),
(40.7038235569946140,-74.0143546472568100,97.00),
(40.7039329592712600,-74.0143365794219800,97.00),
(40.7040422704154500,-74.0143185262956300,97.00),
(40.7041517813782500,-74.0143004403322000,97.00),
(40.7042611636045350,-74.0142823755611700,97.00),
(40.7043707615693800,-74.0142642750708300,97.00)]
image_list = [] #to stuff the resulting meta-data for images
ct = 0
for i in DataList:
ct += 1
fi = "Image_" + str(ct)
temp = GetStreetLL(Lat=i[0],Lon=i[1],Head=i[2],File=fi,SaveLoc=DownLoc)
if temp[2] is not None:
image_list.append(temp)
I have posted the entire python code snippet here. If you want to see the end result, you can check out the photo album. Below is one example image out of the 8 in that street segment, but when viewing the whole album you can see how it runs along the entire street.
Still one of the limitations of this is that there is no easy way to draw older images that I can tell — doing this approach you just get the most recent image. You need to know the pano-id to query older images. Preferably the meta data json should contain multiple entries, but that is not the case. Let me know if there is a way to amend this to grab older imagery or imagery over time. Here is a great example from Kyle Walker showing changes over time in Detroit.
