forked from hotosm/GDAL_scripts
-
Notifications
You must be signed in to change notification settings - Fork 1
/
extract_location_from_exif.py
executable file
·91 lines (78 loc) · 3.33 KB
/
extract_location_from_exif.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#! /usr/bin/python3
"""
Extracts the GPS locations from EXIF data from a directory full of
Sensefly Ebee camera images. Not sure if it works with other cameras as it's
currently only set up for the specific numerical format of the EXIF data
the Ebee camera creates (degrees, minutes, and seconds as a Ratio datatype).
Creates a CSV file containing the file basenames,
the paths, and the lats and lons in decimal degree
format for all images, suitable for importation
into QGIS as delimited text.
Expects a single argument: a directory. Recursively traverses all
subdirectories, so it'll give you a CSV with info from all .jpg images in the
folder and all subfolders. The CSV file will be in the same parent folder as
the input directory, and will have the same name with a .csv extension.
Requires the exifread library, available on pip
(pip install exifread).
Might be sensible to rewrite using PIL (or pillow)
library to make it a more common dependency. Not urgent.
"""
import sys, os
import csv
import exifread
def scandir(dir):
"""
Walk recursively through a directory and return a list
of all files in it and its subdirectories.
"""
filelist = []
for path, dirs, files in os.walk(dir):
for f in files:
filelist.append(os.path.join(path, f))
return filelist
def exif_GPS_to_decimal_degrees(intag):
"""
Spit out a decimal degree lat or long.
Expects an exifread tag full of exifread.utils.Ratio types
"""
d = float(intag.values[0].num) / float(intag.values[0].den)
m = float(intag.values[1].num) / float(intag.values[1].den)
s = float(intag.values[2].num) / float(intag.values[2].den)
return d + (m / 60.0) + (s / 3600.0)
def extract_location(infile):
"""Return the GPS lat and long of a photo from EXIF in decimal degrees"""
with open(infile, 'rb') as f:
try:
tags = exifread.process_file(f)
lattag = tags.get('GPS GPSLatitude')
latref = tags.get('GPS GPSLatitudeRef')
lontag = tags.get('GPS GPSLongitude')
lonref = tags.get('GPS GPSLongitudeRef')
lat = exif_GPS_to_decimal_degrees(lattag)
lon = exif_GPS_to_decimal_degrees(lontag)
if latref.values == 'S':
lat = -lat
if lonref.values == 'W':
lon = -lon
return(lat, lon)
except Exception as e:
print(e)
print('The photo {} failed for some reason'.format(infile))
def create_geotag_list(indir):
"""Create a CSV file with a list of photos and their lat & long"""
outfile = indir + '.csv'
image_files = scandir(indir)
writer = csv.writer(open(outfile, 'w'), delimiter = ',')
writer.writerow(['file', 'path', 'directory', 'lat', 'lon'])
for image_file in image_files:
(image_path, image_ext) = os.path.splitext(image_file)
image_filename = os.path.basename(image_file)
image_dirname = os.path.dirname(image_file)
if(image_ext == '.JPG' or image_ext == '.jpg'):
crds = extract_location(image_file)
if(crds):
writer.writerow([image_filename, image_file, image_dirname,
crds[0], crds[1]])
if __name__ == "__main__":
"""Expects a directory as the sole argument"""
create_geotag_list(sys.argv[1])