You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

140 lines
3.9 KiB
Python

"""Add geotagged images to a kml for viewing in Google Earth.
This script takes a folder of images, and creates a placemark with a thumbnail
of each image, based on the GPS coordinates in the EXIF tags.
Examples:
Create a kml for a folder of photos, named 'images'.
> python photo_to_kml.py images
"""
__author__ = "D. Howe"
__version__ = "0.1.0"
__email__ = "d.howe@wrl.unsw.edu.au"
import os
import argparse
from PIL import Image
from PIL.ExifTags import TAGS, GPSTAGS
import simplekml
def get_exif_data(image):
"""
Return a dictionary from the exif data of an PIL Image object, and convert
the GPS uags.
https://gist.github.com/valgur/2fbed04680864fab1bfc
"""
info = image._getexif()
if not info:
return {}
exif_data = {TAGS.get(tag, tag): value for tag, value in info.items()}
def is_fraction(val):
return isinstance(val, tuple) and len(val) == 2 and isinstance(
val[0], int) and isinstance(val[1], int)
def frac_to_dec(frac):
return float(frac[0]) / float(frac[1])
if 'GPSInfo' in exif_data:
gpsinfo = {
GPSTAGS.get(t, t): v
for t, v in exif_data['GPSInfo'].items()
}
for tag, value in gpsinfo.items():
if is_fraction(value):
gpsinfo[tag] = frac_to_dec(value)
elif all(is_fraction(x) for x in value):
gpsinfo[tag] = tuple(map(frac_to_dec, value))
exif_data['GPSInfo'] = gpsinfo
return exif_data
def get_lat_lon(exif_data):
"""
Return the latitude and longitude (if available) from exif_data.
https://gist.github.com/valgur/2fbed04680864fab1bfc
"""
lat = None
lon = None
gps_info = exif_data.get('GPSInfo')
def convert_to_degrees(value):
d, m, s = value
return d + (m / 60.0) + (s / 3600.0)
if gps_info:
gps_latitude = gps_info.get('GPSLatitude')
gps_latitude_ref = gps_info.get('GPSLatitudeRef')
gps_longitude = gps_info.get('GPSLongitude')
gps_longitude_ref = gps_info.get('GPSLongitudeRef')
if (gps_latitude and gps_latitude_ref and gps_longitude
and gps_longitude_ref):
lat = convert_to_degrees(gps_latitude)
if gps_latitude_ref == 'S':
lat = -lat
lon = convert_to_degrees(gps_longitude)
if gps_longitude_ref == 'W':
lon = -lon
return lat, lon
def export_kml_file(dirname, fnames, kml_name):
"""
Create the kml document
"""
kml = simplekml.Kml()
for fname in fnames:
print('Reading {}...'.format(fname))
with Image.open(os.path.join(dirname, fname)) as image:
exif_data = get_exif_data(image)
lat, lon = get_lat_lon(exif_data)
pnt = kml.newpoint(name=fname)
pnt.coords = [(lon, lat)]
# Add content to popup window
pnt.description = ('<![CDATA[ <img src={} height="500px" />]]>'.format(
os.path.join(dirname, fname)))
pnt.stylemap.normalstyle.iconstyle.scale = 1
pnt.stylemap.normalstyle.iconstyle.icon.href = (
'http://maps.google.com/'
'mapfiles/kml/shapes/camera.png')
pnt.stylemap.highlightstyle.iconstyle.scale = 2
pnt.stylemap.highlightstyle.iconstyle.icon.href = os.path.join(
dirname, fname)
kml.save(kml_name)
def main():
parser = argparse.ArgumentParser(usage=__doc__)
parser.add_argument(
'folder', nargs='?', help='name of input folder', default=None)
args = parser.parse_args()
# Get files in image directory
ext = ['.jpg', '.jpeg', '.tif', '.tiff']
dirname = args.folder
fnames = [
f for f in os.listdir(dirname)
if os.path.splitext(f)[-1].lower() in ext
]
# Create kml file
kml_name = dirname + '.kml'
export_kml_file(dirname, fnames, kml_name)
if __name__ == '__main__':
main()