Friday 29 August 2014

Geotagging and Picasa Web Albums API, or was it Google+ Photos?

In my last blog post, I presented a new plugin, Leaflet.Photo, that allows you to display geotagged photos from any source. Among them was Google+ Photos and Picasa Web Albums API. My plan is to use this API for my travel map, and this is why.

Does Picasa Web Albums still exist? 
It's a bit messy these days. Google is trying to transition from Picasa Web Albums to Google+ Photos, as photos are the number one things that people want to share on social networks. When you use Picasa to share your albums (Sync to Web), the album URL is now on your Google+ profile, and not on Picasa Web Albums (which is just redirecting me to Google+). This is the URL to the public album from my trip to the Trollfjord:

https://plus.google.com/photos/+BjørnSandvik/albums/6052628080819524545

It also works with your Google+ user id:

https://plus.google.com/photos/118196887774002693676/albums/6052628080819524545

My public Google+ web album. The album contains both photos and videos. 

The thing is, there is no Google+ API for photos and videos yet (apparently they were working on it back in 2011). But the Google Web Albums API still works on your Google+ albums.

Google Web Albums API is not the easiest API I've worked with, but it's flexible and quite fast. This is an XML feed of my public album from Trollfjord:

https://picasaweb.google.com/data/feed/api/user/118196887774002693676/albumid/6052628080819524545

The user number and album id is the same as above. Or better for your JavaScript apps, a JSON feed:

https://picasaweb.google.com/data/feed/api/user/118196887774002693676/albumid/6052628080819524545?alt=json

And if you're still using JSONP:

https://picasaweb.google.com/data/feed/api/user/118196887774002693676/albumid/6052628080819524545?alt=json-in-script

If you click on any of these links, you'll see that it's not a very compact format. There is a lot of data that you don't need. Although complicated, you can select the fields you want to include in the feed. This is how I selected the following elements:
  • Photo URL: entry/media:group/media:content
  • Photo caption: entry/media:group/media:description
  • Photo thumbnail URL: entry/media:group/media:thumbnail
  • Photo timestamp: entry/gphoto:timestamp
  • Photo location: entry/georss:where

This is the new URL:

https://picasaweb.google.com/data/feed/api/user/118196887774002693676/albumid/6052628080819524545?alt=json&fields=entry/media:group/media:content,entry/media:group/media:description,entry/media:group/media:thumbnail,entry/gphoto:timestamp,entry/georss:where

While researching, I also learnt that I could use the imgmax attribute to specify the size of the photos referenced in the photo URL. Neat!

So why should I use this (relatively) old API?
Compared to other popular social media sites, Google don't strip off the meta information of your photos. Instead it uses the build in support for image metadata extensively. Hopefully Google will continue to do this, although social media sites have reasons not doing so.

This means that Google don't lock you in. I can change the location of my photos using my GPS tracks, and it's reflected where I embed my photos. I can edit the image captions in Picasa and it's stored within the image file, allowing me to write the caption once and use it everywhere.

So what is my album workflow for my travel map. Before starting my journey, I'm creating a new Google+ album. The feed from this album is attached to my map, by simply passing on the album id. While on journey, I use the Google Photos app to add photos to the album, that will automagically show up on the map as well. Back from trip, I can add and edit photos from my digital camera in Picasa and sync them to the web album.

Update 12 September 2015: I'm having trouble uploading images with the Google photos app. The images are geotagged and the location data shows in the Google+ album, but unfortunately the location data is not included in the API feed. Please notify me if you're able to get this to work. 

Photos from Google+ shown on my travel map. 

PS! This blog post is not sponsored by Google :-) 

Showing geotagged photos on a Leaflet map

Using Instagram for my real-time travel map had too many limitations, so I decided to use Google+ photos or Picasa Web Albums instead. I've create a new plugin, Leaflet.Photo, that allows you to add geotagged photos to your map, from any source.

The plugin plays well with the great Leaflet.markercluster plugin, showing your photos in clusters. To make the plugin more versatile, it doesn't deal with AJAX loading or image presentation except the thumbnails on the map. Use your AJAX loader of choice, and simply pass on an array of photo objects to the plugin. 

The photo objects can include the properties you like, but the following are required:
  • lat: latitude of photo
  • lng: longitude og photo
  • thumbnail: url to thumbnail photo
I've kept the squared thumbnails of Instagram, as I think it look nicer than variable size thumbnails. Since the photos can have any dimensions, I'm using a CSS technique to crop and center the thumbnails. 

I've created three examples using Picasa Web Albums Data API, CartoDB (synced with Instagram) and Norvegiana API. With CartoDB you can easily get the required photo properties by manipulating the SQL query. Other APIs will require some data parsing before you pass on the photo objects to the plugin. All examples show the photos in a popup when you click/tap on them, but do whatever you like! On my travel map (click on "Bilder"), I'm using my own lightbox showing all photos in a cluster.

Google+ photos


Photos and videos from Google+. See the small animated GIF video thumbnails. 


Instagram / CartoDB


Instagram photos synced with CartoDB. 


Norvegiana 


Historic photos of Oslo from Norvegiana API. 



Enjoy! :-)

Thursday 28 August 2014

Geotagging photos using GPS tracks, ExifTool and Picasa

I take a lot of photos while trekking, and most of the time I'm also carrying a GPS with me. As my camera don't have a built-in GPS, my photos are not geotagged while shooting. Luckily, this is an easy task if you've kept your GPS logs from the trip. 

I'm still very happy with my Garmin GPSmap 60CSx that I bought 7 years ago. By changing the setup, the GPS allows me to automatically save the tracks to the memory card. I get one GPX file for each day trekking named with the date. I can easily transfer these tracks to my computer or smartphone with a cable or a card reader. 

Before I converted to Mac, I used GeoSetter to geotag my photos on Windows. Now, I want to do it on the command line using the great ExifTool by Phil Harvey. I installed it on my MacBook using Homebrew:

brew install exiftool

After copying my GPX file to the image folder, I'm simply running:

exiftool -geotag=my.gpx ./

If you forgot to sync the camera and GPS time before your trip, you can use the geosync-option to fix it: (60:00 = 60 minutes):

exiftool -geotag=20140329.gpx -geosync=-60:00 ./

You have a lot of options, so make sure to read the "Geotagging with ExifTool" documentation. ExifTool is modifying the Exif headers of your image files, storing the location data in the same file. 

To see the result on a map, I'm using Picasa.  


Click the map pin button (bottom right) to see the map. If the positions are not shown on the map, try to right-click the image folder and select "Refresh Thumbnails". 

If you don't have a GPS track you can always use Picasa to manually geotag your photos. 

Be aware! I just learnt that social media sites like Facebook, Twitter and Instagram removes the Exif data from your images. Google+ don't. 

Now, how can you display the photos on your own map? It will be the topic of my next blog post. 

Wednesday 27 August 2014

Live tracking in Lofoten and Vesterålen

Last weekend, I had a great trip to scenic Lofoten and Vesterålen in Northern Norway. I brought my tracking gear to test my new real time travel map. How did it go?

Our first trip was to Trollfjord, a 2 km long fjord with a narrow entrance and steep-sided mountains. It's a famous tourist spot in the Lofoten archipelago, but not many leave the boat at the fjord's end to hike up to the Trollfjord hut.

The small Trollfjord hut.

Trollfjord goes in an east-west direction, and I expected to be in the "satellite shadow" being far north and having steep mountains blocking the sky towards the south. My good old Garmin GPSmap 60CSx did well in the rugged landscape, while my satellite SPOT messenger had some difficulties finding and sending positions. 

Live track from my SPOT messenger (interactive map).

GPS track from my Garmin GPS.

The great thing of using CartoDB to sync my SPOT-data, is that you can edit your positions with ease after the trip. 

Tip! The default basemaps in CartoDB are not very detailed for Norwegian mountains, but you can easily add a basemap (Topo2) from the Norwegian Mapping Authority ("Kartverket") with this URL: 

http://opencache.statkart.no/gatekeeper/gk/gk.open_gmaps?layers=topo2&zoom={z}&x={x}&y={y}

Changing the basemap of CartoDB.  


It's then easy to edit or delete the wrong positions:


Be aware! I was struggling editing my CartoDB-tables from my smartphone, but it was not possible to edit the content of table cells. Hopefully, the CartoDB team will make their editor more mobile friendly in the future. 


Another issue was to get the correct time and position of Instagram photos on the map. Trollfjord is an area with poor mobile coverage. When I took photos with the Instagram app it was struggling placing the photos on the map. It worked better if I took the photos the the built-in camera app of my phone (with geotagging activated) and then posting the photo with the Instagram app. 


If I didn't have mobile coverage, I would just retry posting the photo when back to civilisation. The time associated with the image is when it was sent and not taken. I'm going to check if I can extract the shooting time from the Exif headers of the image.

Our second trip went through Møysalen national park, one of very few national parks in Norway that goes all the way down to sea level. 

Møysalen national park

Here we went in a south-north direction, and my SPOT messenger did better as there was less mountains blocking the satellites. 

Map and elevation profile of a 2-day hike through Møysalen national park (interactive map).  

The web service from the Norwegian Mapping Authority ("Kartverket") seemed to have some technical troubles this weekend, so the altitude values and place names was not updated instantly. When the web service was failing my script stopped and the weather report from yr.no was not fetched either. I'm going to improve the error handling before my next trip. 

I also took a lot of photos with my compact camera while trekking, and I would like to show these on the map as well. My camera don't have a GPS receiver, but I should be able to geotag my photos by using my GPS track. It will be the topic of my next blog post. In the meanwhile, here are some of the photos: 

Hurtigruta in Trollfjord

Trollfjord by night

Cloudberries

Trollfjordtindan.

Seagull

Seagulls

Sea eagle in Raftsundet.

Durmålstindan

Tverrelvtindan

Cold and fresh bath at Snytindhytta.

Monday 18 August 2014

Making a real time travel map

I had to quit my trip form Oslo to Bergen already on day three - and I have to wait until August 2015 for a second try. I still got time to gain some experience in real time tracking - and mapping. Based on this experience I've made a new version of my live travel map: turban.no



This is a private project to learn new skills - where I care more about new standards and less about old browsers. I'm using CSS3 and HTML5 extensively, the the map will probably not show in Internet Explorer < 10, but it should work well on your tablet or smartphone.


My previous map was about 1 MB to load on my mobile, as I really took off mixing Leaflet, Highcharts, Ext JS, jQuery and Fancybox. I'm now left with only Leaflet and D3.js and only 72 kB gzipped JavaScript. It was a bit more work to create an elevation chart width D3.js, but it's very flexible when you get the grasp of it. I also used D3.js to create a lightbox gallery to show my Intagram photos, as it can easily replace jQuery for selectors and animations.

This is a single page application running in your browser with a CartoDB-backend. The only thing I've changed on my server is the .htaccess file to point all request to the same index.html file. Then I'm using the HTML5 History API to create nice looking URLs to different trips. I've also extended the application to support different users, but I have no plans to create a public web service.

The full application code is not available, but the different bits and pieces are and will. It's still work in progress. The next steps will be to improve the experience on touch screens, add a 3D display and maybe create a mobile app with PhoneGap.

I want to share some experiences I had when creating this map - and I would very much like your feedback!

When you visit the site, you can select between different trips. I'm creating new trips by simply adding new rows to a CartoDB-table. The track and images for each trip are fetched based on time attributes.


You can also link directly to a trip, like: http://turban.no/bjorn/oslo-gaastjern

You can mouseover or click the track to se place names and altitudes. To improve the performance, I'm only drawing the line and not the individual points. To find the nearest point to a mouse/tap position, I'm doing a nearest neighbour search.


Actually I'm drawing two track lines; the stippled line, and a thicker invisible line to make it easier to catch mouseover and click events, especially on touch devices. This is the line shown with less transparency:


The image above show the popup, with terrain type and a weather forecast for this specific location at the time I was there. The track interactions are also linked to the elevation chart:


If you mouseover the track, the same position will show on the elevation chart, and vice versa. Both the track and the chart show the live position with a pulsing marker. I'm also marking the overnight stays, as my SPOT device allows me to send custom messages. The elevation chart reads right to left, as this was the direction of my trip. The direction can be changed for each trip.

If you navigate around in the map, you'll see that the elevation chart is changing to reflect the view:


This is done using Crossfilter to quickly select the points within the map view, although my iPad gets a bit sluggish with instant updates while dragging.

Instagram photos are displayed on the map using the great Leaflet.markercluster plugin:



The photos are shown in a lightbox where you can click/tap through the photos in a cluster (no swipe support yet):



All elements are responsive and should adapt to different screen sizes. I've also made a build process with Grunt to concatenate and compress all the CSS and JavaScript into single files. LESS are used to get rid of all the browser prefixes in CSS. I also made a custom build of D3.js to only include the bits I used, reducing the size to one third.

Continuing the work when there are new trips coming up!