Go program finds photos with nearby GPS coordinates
In the Hood
Every photo you take with your mobile phone stores the GPS location in the Exif data. A Go program was let loose on Mike Schilli's photo collection to locate shots taken within an area around a reference image.
Just recently, my favorite restaurant in San Francisco, Chow, shut down unexpectedly. On top of the traumatic experience of having to find a new eatery, I was overcome by the desire to find old photos of the place from the good old days on my mobile phone. But how? I sure didn't tag them, but who does, anyway? Having said that, every cell phone photo contains GPS information, and the phone's photo app can group the photos as dots on a map.
Of course, over the years, I had outsourced the photos to other media. Not to worry, my new favorite programming language, Go, comes with image processing routines, prompting me to browse my photo collection for photos taken in or near the restaurant.
To-Do
The Unix exiftool
tool finds the metadata of a JPG file in a flash, leaving social media users wondering what juicy bites of data they are giving to Facebook and company when they post them. In addition to the date and time, the altitude, and the direction of the camera, there are also GPS coordinates that record the exact location on the earth's surface where the picture was taken (Figure 1). Online guru Kevin Mitnick even reports that the authorities once tracked down a Bolivian drug lord, because he had published a vacation photo that still contained the metadata of his secret whereabouts [1].
Verbose Photos
Quite surprisingly, in the Exif section of the image file, metadata such as the latitude and longitude of a shot's location are by no means stored in a computer-friendly format. Instead, the mobile phone might put the string 122 deg 25' 46.82'' W
there under the GPS Longitude
tag and the letter W
for western longitude under the GPS Longitude Ref
tag.
To convert this string into something that can be used later to calculate distance from a reference point, you need to use a library function that converts 122 degrees, 25 angular minutes, and 46.82 angular seconds into floating-point format and negates the numerical value for the W
in western longitude, because only eastern longitudes are positive. The result is a value of -122.429672
for the longitude; based on this, along with the latitude, which is determined in a similar way, another library can then determine the geographical offset to the longitude and latitude of another image.
Now the distance between two points on the earth's surface, given as latitude and longitude, cannot be calculated quite as trivially as within a two-dimensional coordinate system. But if you quickly put on your old trigonometry hat from your school days, you can still work it out. The technical term for the curved distance is "orthodrome" ([2], Figure 2); it's a segment of the great circle on the (approximated) spherical surface of the earth, which is why the whole thing is also known as the "great circle distance." Thanks to the Internet, you don't even have to type this by hand, but can turn to a Go library like golang-geo
[3].
With these tools, whipping up an algorithm in the script shown today (Listing 1, [4]) is easy as pie. It accepts a reference image and a search path for the photo collection. It extracts the reference GPS coordinates from the former and then rummages through all the images in the photo collection one after another, comparing their GPS coordinates with the reference and reporting a hit if the distance to the reference image is below a preset minimum.
Listing 1
geosearch.go
Deep Sea Diver
The filepath.Walk
function from Go's core treasure trove plumbs into the depths of the files in the photo collection referenced as a directory no matter how deeply nested. The call in line 45 accepts a callback function (Visit()
defined in line 51). To ensure that this function has the GPS data of the reference image ready for comparisons, a structure of the type Walker
(defined as of line 14) gets created as its receiver, which is how Go ties functions to structs as objects.
First, lines 40 to 43 initialize a Walker
instance in w
by setting the refLat
and refLong
attributes of the GPS data to the values of the reference image, and then Walk()
in line 45 receives w.Visit
as a callback function. Since Visit()
in line 51 is defined with a receiver of the *Walker
type, as a result, the file system walker calls the Visit()
callback function for each file found, but passes the Walker
structure filled with the reference data to it each time, which means that Visit()
can conveniently pick up the location of the reference image in line 63 and use it to compute the offset distance.
The callback also uses a regular expression in line 53 to check whether the file just found also has a .jpg
suffix in its name; thanks to the "(?i)"
expression in the regex string, this also matches uppercase letters as in .JPG
. The somewhat strange MustCompile()
call for compiling the regular expression in line 53 is attributable to Go's strict error management. Every time a function gets called that could possibly go wrong, the program has to check if all systems are go, or an error has occurred, in which case it has to initiate rescue actions. Now, in theory, compiling a regular expression could go wrong (for example, if it contains illegal syntax), but with a static (and hopefully tested) string, this is impossible.
In this way, functions with a "must" in the name, like MustCompile()
for regular expressions, save the programmer from handling errors by internally aborting the program with a Panic()
if something goes wrong. By definition, the function itself does not return an error, because it only returns if everything actually works out.
Buy this article as PDF
(incl. VAT)
Buy Linux Magazine
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs
Subscribe to our ADMIN Newsletters
Support Our Work
Linux Magazine content is made possible with support from readers like you. Please consider contributing when you’ve found an article to be beneficial.
News
-
Linux Servers Targeted by Akira Ransomware
A group of bad actors who have already extorted $42 million have their sights set on the Linux platform.
-
TUXEDO Computers Unveils Linux Laptop Featuring AMD Ryzen CPU
This latest release is the first laptop to include the new CPU from Ryzen and Linux preinstalled.
-
XZ Gets the All-Clear
The back door xz vulnerability has been officially reverted for Fedora 40 and versions 38 and 39 were never affected.
-
Canonical Collaborates with Qualcomm on New Venture
This new joint effort is geared toward bringing Ubuntu and Ubuntu Core to Qualcomm-powered devices.
-
Kodi 21.0 Open-Source Entertainment Hub Released
After a year of development, the award-winning Kodi cross-platform, media center software is now available with many new additions and improvements.
-
Linux Usage Increases in Two Key Areas
If market share is your thing, you'll be happy to know that Linux is on the rise in two areas that, if they keep climbing, could have serious meaning for Linux's future.
-
Vulnerability Discovered in xz Libraries
An urgent alert for Fedora 40 has been posted and users should pay attention.
-
Canonical Bumps LTS Support to 12 years
If you're worried that your Ubuntu LTS release won't be supported long enough to last, Canonical has a surprise for you in the form of 12 years of security coverage.
-
Fedora 40 Beta Released Soon
With the official release of Fedora 40 coming in April, it's almost time to download the beta and see what's new.
-
New Pentesting Distribution to Compete with Kali Linux
SnoopGod is now available for your testing needs