When I was finished last week with creating my video location map in Python, I thought “shame I can’t plot photo locations”. That’s because my Fuji X-T30 camera doesn’t store GPS info. When I bought the camera I assumed every modern camera had GPS tagging, so I didn’t even checked that feature. Too bad. But I also made some photo’s during my vacations with my humble iPhone 8. And it does have GPS tags. So let’s plot some photo locations.
Reading GPS tags from JPGs
GPS tag data is stored in the JPG file itself, in the EXIF metadata. There can be stored a good amount of metadata in that EXIF part of your JPG: GPS location, the direction that you were aiming, your speed at the moment, lighting, lenses, camera type, app used etc.. (This is also the reason why I use the EXIF remover app before I post photos on social media.) To get an impression of metadata stored, upload a JPG to exifdata.com. The GPS tags will look like this:
If you want to read EXIF data with Python there are a LOT of sites with info on how to do that. And they all seem to use different libraries. Not all of them brought me success. The code from this blog by Jayson DeLancey did work and I’ve integrated it into my code. You can best read Jayson’s blog to learn how it works.
I made some minor changes to Jayson DeLancey’s version of the code. For example, I didn’t want to exit if no EXIF data or geodata was found. Like with my video GPS data, the code now creates a dataframe called photodf with a filename, creation date, latitude, longitude and altitude.
Different Folium markers
I wanted the video and photo markers to be clearly different on the map. You’d think changing the marker colour would do the trick. But it did not. It’s the icon colour you want to change.
for index, georow in photodf.iterrows(): folium.Marker([georow['latitude'], georow['longitude']] , popup=f"filename: {georow['filename']}</br>creationdate: {georow['creationdate']}" , icon=folium.Icon(color='red')).add_to(my_map)
But there’s more you can do with marker icons. You can actually make it into an icon of a camera. Here I have a red icon marker, with a white icon of a camera.
for index, georow in photodf.iterrows(): folium.Marker([georow['latitude'], georow['longitude']] , popup=f"filename: {georow['filename']}</br>creationdate: {georow['creationdate']}" , icon=folium.Icon(color='red', icon_color='white', icon='camera')).add_to(my_map)
So what icon to choose for the video? These icons are so called glypicons. And there 250 to choose from. There are ways to load extra icons though. I haven’t checked that out yet. The closest I got to a video camera icon from this icon set, was the facetime-video. Here we have a blue marker with a white facetime-video icon:
for index, georow in videodf.iterrows(): folium.Marker([georow['latitude'], georow['longitude']], popup=f"filename: {georow['filename']}</br>creationdate: {georow['creationdate']}" , icon=folium.Icon(color='blue', icon_color='white', icon='facetime-video')).add_to(my_map)
And when all data is loaded and all markers are projected on the map, it looks something like this:
I was so happy when I saw this. And I got to this part with relative ease.
Can we do something with the image direction?
I noticed the iPhone GPS data also has an image direction. I was wondering: is there a way to show on the map which way I shot the image? For example, Folium icons have an angle property. A quick experiment shows that this works:
for index, georow in photodf.iterrows(): folium.Marker([georow['latitude'], georow['longitude']] , popup=f"filename: {georow['filename']}</br>creationdate: {georow['creationdate']}" , icon=folium.Icon(color='red', icon_color='white', icon='camera', angle=30)).add_to(my_map)
This is the result:
Nice, but it would be confusing for the user (being me). The facetime-video icon shows a clear direction, but the camera icon does not.
Projecting photos on the map?
If my wishes are fulfilled this easily, how about taking it to the next step? How about projecting thumbnails of photo’s on the map, rather than just a marker? Believe it or not, but that is also possible.
It’s possible, which doesn’t mean you want this. We’re talking about reading all my images of 3088 by 2320 pixels here. Even if I downsize them with HTML to fit on the screen, it reads all the images at full resolution.
Still, I can show you the result of just one photo. It will display the photo as a tooltip of a marker. First I have a function to create an img HTML tag. I read the full JPG, and resize it in HTML:
def make_popup_imgtag(popup_image): encoded = base64.b64encode(open(popup_image, 'rb').read()) html = '<img src="data:image/png;base64,{}" width="400" height="300">'.format iframe = IFrame(html(encoded.decode('UTF-8')), width=400, height=300) popup = folium.Popup(iframe, max_width=400) return html, iframe, popup
Then I take one JPG file, and create the marker for it. You can see I chose a gray marker, so I was able to distinguish it from the other photo markers:
popup_image = "Y:\\2021\\Vercors en Drome 2021\\iPhone\\IMG_3474.JPG" popup_html, popup_iframe, popup_text = make_popup_imgtag(popup_image) folium.Marker(location=[44.69158611111111, 5.986177777777778], tooltip=popup_html, popup=popup_text, icon=folium.Icon(color='gray', icon_color='white', icon='camera')).add_to(my_map)
And here is the result:
To make this really work, I’ll probably need to create thumbnail versions of all my photos (and videos, why not?) that I store somewhere for this purpose. But I’m not working on that now. I’m a bit hesistant of having subdirectories with massive lists of tiny files in every photo directory. But I can see a future version where you can click on a marker of any photo or video and get to see a thumbnail or a tiny animated gif of the video.
Going object oriented
With all the extra code for reading EXIF data, getting GPS tags, new dataframe and new Folium markers, my code became rather unwieldy. I dediced it was time to clean it up. So I decided making my code object oriented would probably be a good exercise. I never had a lot of training in object oriented programming.
I assumed a Video and a Photo object would be good to program attributes and methods for. At first it was a very frustrating exercise that took me as much time as writing the whole program in the first place. But gradually I was getting the hang of it and I got my code to do the stuff it did before the operation.
You can find the end result here:
https://github.com/Marcel-Jan/media_gpsplot/blob/main/media_gpsplot.py
A sample result can be found here:
https://github.com/Marcel-Jan/media_gpsplot/blob/main/media_gpsplot.html
I had to rename my Github repo to media_gpsplot, rather than video_gpsplot. So that changed as well.
Other blogposts I wrote about geo data in Python:
Adding the track of my bike ride in Folium (Antpaths and Polylines)