James O'Neill's Blog

January 22, 2008

The Wow of powershell (again)

Filed under: Photography,Powershell — jamesone111 @ 12:19 am

I’ve recently bought Efficasoft’s GPS utilities  for my phone – I keep thinking about GeoTagging photos. I was toying with writing a GPS logger of my own, but for $17.95 Efficasoft gave me that and a bunch of other things which range from the useful to the clever party trick. For example it has no maps, but you can give it co-ordinates of known points on an image file and it manipulates it accordingly. It will save key points as well as recording a track. Money well spent; it even has a choice of log formats, it’s own compact format or a standard dump of the NMEA 0183 sentences sent back by the GPS device. The problem is that these are not exactly easy to read; they look like this


The ones which begin $GPGSV, and $GPGSA are satellite diagnostics and of no interest to me here. I only want the  lines beginning $GPRMC which are the “Recommended Minimum data”

Translates  as time=13:22:06.42, GPS Status OK, Latitude 52 degrees 07.8403 minutes North, Longitude 0 degrees 59.2248 minutes west. Speed 20.059710 knots, track 146.77 degrees, date 20 Jan 2008,,checksum.

Now what I want to do is to take that data and do something like this

$myPhoto=Get-Picture “picture.jpg”


Get-GPS_co-ordinates_at ($myPhoto.DateTimeTaken)



Easy. But Get-GPS-Coordinates at a given time ? A pipe dream surely ? Here’s how I did it.

Since it’s all comma separated to start with, I wanted to use PowerShell’s built in Import-CSV. But I wanted to strip out the lines that weren’t relevant. That’s easy enough, but here’s a trick, Get-Content returns an array of strings, one for each line, so if I put my header in an array of strings and add the cleaned up file content to it I get a useful CSV file.

@(“HEADERS”) +  ( get-content FILE.log | where {$_ -match “GPRMC” } ) > temp.csv

I’d like to pipe this into Import-CSV, but it insists on a file (Imust check if that has changed in the V2 CTP), so the next bit processes that.  Using Select-object , I can pare the data dow and splice the date and time together forcing the result to a DATE-TIME type – that accounts for most of the next bit

import-csv temp.csv | select-Object -property NS, latitude, EW , longitude , @{Name=”DateTime”; Expression =
{[DateTime]::ParseExact(($_.Date+$_.Time),”ddMMyyHHmmss.fff”,[System.Globalization.CultureInfo]::InvariantCulture)}} |

 So now I’ve got a collection of objects with North/South, Latitude, East/West, Longitude , DateTime. Now to find the one that matches the photo’s date and time.  Part of my brain took this as an idle process and came up with  “| Sort-on (Difference between GPS time and photo time) | select the first one”  it took me an age to realize I needed the absolute (not signed) value to sort successfully, which meant calling up the system.math library

sort -Property @{ Expression={[system.math]::abs(($_.datetime – $MyPhoto.TimeTAKEN).totalMilliseconds)}} | 
select-object -First 1 |

Finally I added a GeoCode routine to the Exif library I published in August, so I can pipe the results into $myPhoto.GeoCode

foreach-object {$MyPhoto.geoTag($_.Latitude, $_.NS, $_.Longitude, $_.EW)}

Granted it is a heck of a long line, but Import | Select | sort | select | geoTag is one of only 4 lines needed: one to get the Photo (which is actually $MyPhoto=new-object oneimage.exifimage “Picture.jpg”), one to make the CSV file and one to save the result at the end. I don’t want to think about how much VB script it would take to parse the file, and find which date was closest

I’ve added the latest version of my EXIF class here, for anyone who wants to play.

Disclaimer . Like any code on my blog, this code is provided as an Example for illustration purposes is only. It comes with No support and No warranty that it is fit for any purpose whatsoever.

Technorati tags: EXIF, Powershell, Windows, Photography

Share this:

This post originally appeared on my technet blog.


Create a free website or blog at WordPress.com.

%d bloggers like this: