The problem
You want to extract GPS coordinates from image or video
metadata (Exif data) and turn the coordinates into useful location
information like addresses
Background
Digital cameras typically record all sorts of data
about the image in a format known as
Exchangeable image file format,
(commonly known as "Exif").
This data includes things like what type of camera was used to make the
image. If the camera is able to it, for example a camera on
a mobile phone, it may also include information about the location
the image was taken.
The location information is recorded as GPS coordinates: longitude and
latitude.
Converting geocoordinates (longitude, latitude) into location information
is the process know as reverse geocoding.
You can pass coordinates to the OpenCage geocoding API to reverse
geocode the coordinates and return information about the location.
The solution
The process of geocoding images follows a few basic steps.
-
Load an Exif library
You will need a way to extract the raw coordinates from the image. There are many open source libraries available, search for "Exif" in the relevant library collection for your language (CPAN, pypi, rubygems, etc). -
Use the library to extract the coordinates from the image
Note that the image may no have coordinates. Make sure you check for this case. -
Convert the coordinates to decimal format
Exif data stores coordinates in degree/minutes/seconds format. Most software however, including our geocoding API, expects decimal degrees. Luckily conversion is not particularly difficult. -
Send the decimal coordinates to the OpenCage geocoding API
We have SDKs for calling the OpenCage geocoding API for over 30 other programming languages. - Examine the response, extract the information you need
Code Example
Here is a detailed javascript example.
The logic will be the same in other languages.
To extract the Exif data from an image we use the open source library
exif.js
library from a CDN via
<script src="https://cdn.jsdelivr.net/npm/exif-js"></script>
<script>
// we need to turn degree, min, sec format into decimal
function DMS2DD(degrees, minutes, seconds, direction) {
var dd = degrees + (minutes/60) + (seconds/3600);
if (direction == "S" || direction == "W") {
dd = dd * -1;
}
return dd;
}
// extract the coordinates from the image
function getCoords() {
var img1 = document.getElementById("img1");
return EXIF.getData(img1, function() {
myData = this;
// the image may not have coordinates
if (myData.exifdata.GPSLatitude != null){
// latitude in decimal
var latDeg = myData.exifdata.GPSLatitude[0].numerator;
var latMin = myData.exifdata.GPSLatitude[1].numerator;
var latSec = myData.exifdata.GPSLatitude[2].numerator;
var latDir = myData.exifdata.GPSLatitudeRef;
var lat = DMS2DD(latDeg, latMin, latSec, latDir);
// longitude in decimal
var lngDeg = myData.exifdata.GPSLongitude[0].numerator;
var lngMin = myData.exifdata.GPSLongitude[1].numerator;
var lngSec = myData.exifdata.GPSLongitude[2].numerator;
var lngDir = myData.exifdata.GPSLongitudeRef;
var lng = DMS2DD(lngDeg, lngMin, lngSec, lngDir);
return lat + ',' + lng;
}
});
}
function Geocode(coords){
// do the geocoding via OpenCage
var apikey = 'YOUR-API-KEY';
var api_url = 'https://api.opencagedata.com/geocode/v1/json'
var request_url = api_url
+ '?'
+ 'key=' + apikey
+ '&q=' + encodeURIComponent(coords)
+ '&pretty=1'
+ '&no_annotations=1';
// see full list of required and optional parameters:
// https://opencagedata.com/api#required-params
var request = new XMLHttpRequest();
request.open('GET', request_url, true);
request.onload = function() {
// see full list of possible response codes:
// https://opencagedata.com/api#codes
if (request.status === 200){ // Success!
var data = JSON.parse(request.responseText);
console.log(data.results[0].formatted); // print the location
} else {
console.log("unable to geocode! Response code: " + request.status);
var data = JSON.parse(request.responseText);
console.log('error msg: ' + data.status.message);
}
};
request.onerror = function() {
// There was a connection error of some sort
console.log("unable to connect to server");
};
request.send(); // make the request
}
var coords = getCoords();
console.log('coords from image: ' + coords);
if (coords != null){
Geocode(coords);
}
</script>