Gennaio 2009
Obiettivo
Questo tutorial ti insegna a utilizzare le foto georeferenziate per creare file KML PhotoOverlays
. Sebbene il codice di esempio sia scritto in Python, esistono molte librerie simili in altri linguaggi di programmazione, quindi non dovrebbe essere un problema tradurlo in un'altra lingua. Il codice di questo articolo si basa su una libreria Python open source, EXIF.py.
Introduzione
Le fotocamere digitali sono dispositivi straordinari. Molti utenti non se ne rendono conto, ma fanno molto di più che scattare foto e girare video. Inoltre, taggano questi video e queste foto con metadati sulla videocamera e sulle relative impostazioni. Negli ultimi anni, le persone hanno trovato il modo di aggiungere dati geografici a queste informazioni, incorporati dai produttori di fotocamere, come alcune fotocamere Ricoh e Nikon, o tramite dispositivi come i registratori GPS e EyeFi Explore. I fotocamere smartphone come l'iPhone e gli smartphone con sistema operativo Android, come il G1 di T-Mobile, incorporano automaticamente questi dati. Alcuni siti di caricamento di foto, come Panoramio, Picasa Web Albums e Flickr, analizzano automaticamente i dati GPS e li utilizzano per georeferenziare una foto. Potrai quindi recuperare questi dati nei feed. Ma dov'è il divertimento? Questo articolo spiega come accedere autonomamente a questi dati.
Intestazioni EXIF
Il modo più comune per incorporare i dati in un file immagine è utilizzare il formato EXIF (Exchangeable Image File Format). I dati vengono archiviati in formato binario nelle intestazioni EXIF in modo standard. Se conosci la specifica per le intestazioni EXIF, puoi analizzarle autonomamente. Fortunatamente, qualcuno ha già fatto il lavoro più difficile e ha scritto un modulo Python per te. La libreria open source EXIF.py è un ottimo strumento per leggere le intestazioni di un file JPEG.
The Code
Il codice di esempio per questo articolo si trova in questo file: exif2kml.py. Se vuoi passare direttamente all'utilizzo, scarica il modulo e EXIF.py e inseriscili nella stessa directory. Esegui python exif2kml.py foo.jpg
sostituendo foo.jpg con il percorso di una foto georeferenziata. Verrà generato un file denominato test.kml
.
Analisi delle intestazioni Exif
EXIF.py fornisce un'interfaccia semplice per estrarre le intestazioni Exif. Basta eseguire la funzione process_file()
per restituire le intestazioni come oggetto dict
.
def GetHeaders(the_file): """Handles getting the Exif headers and returns them as a dict. Args: the_file: A file object Returns: a dict mapping keys corresponding to the Exif headers of a file. """ data = EXIF.process_file(the_file, 'UNDEF', False, False, False) return data
Una volta ottenute le intestazioni Exif, devi estrarre le coordinate GPS. EXIF.py li considera oggetti Ratio
, oggetti per memorizzare il numeratore e il denominatore dei valori. In questo modo viene impostato un rapporto preciso anziché basarsi su un numero in virgola mobile. Tuttavia, KML prevede numeri decimali, non rapporti. Estrai quindi ciascuna delle coordinate e converti il numeratore e il denominatore in un unico numero in virgola mobile per i gradi decimali:
def DmsToDecimal(degree_num, degree_den, minute_num, minute_den, second_num, second_den): """Converts the Degree/Minute/Second formatted GPS data to decimal degrees. Args: degree_num: The numerator of the degree object. degree_den: The denominator of the degree object. minute_num: The numerator of the minute object. minute_den: The denominator of the minute object. second_num: The numerator of the second object. second_den: The denominator of the second object. Returns: A deciminal degree. """ degree = float(degree_num)/float(degree_den) minute = float(minute_num)/float(minute_den)/60 second = float(second_num)/float(second_den)/3600 return degree + minute + second def GetGps(data): """Parses out the GPS coordinates from the file. Args: data: A dict object representing the Exif headers of the photo. Returns: A tuple representing the latitude, longitude, and altitude of the photo. """ lat_dms = data['GPS GPSLatitude'].values long_dms = data['GPS GPSLongitude'].values latitude = DmsToDecimal(lat_dms[0].num, lat_dms[0].den, lat_dms[1].num, lat_dms[1].den, lat_dms[2].num, lat_dms[2].den) longitude = DmsToDecimal(long_dms[0].num, long_dms[0].den, long_dms[1].num, long_dms[1].den, long_dms[2].num, long_dms[2].den) if data['GPS GPSLatitudeRef'].printable == 'S': latitude *= -1 if data['GPS GPSLongitudeRef'].printable == 'W': longitude *= -1 altitude = None try: alt = data['GPS GPSAltitude'].values[0] altitude = alt.num/alt.den if data['GPS GPSAltitudeRef'] == 1: altitude *= -1 except KeyError: altitude = 0 return latitude, longitude, altitude
Una volta ottenute le coordinate, è facile creare un semplice PhotoOverlay
per ogni foto:
def CreatePhotoOverlay(kml_doc, file_name, the_file, file_iterator): """Creates a PhotoOverlay element in the kml_doc element. Args: kml_doc: An XML document object. file_name: The name of the file. the_file: The file object. file_iterator: The file iterator, used to create the id. Returns: An XML element representing the PhotoOverlay. """ photo_id = 'photo%s' % file_iterator data = GetHeaders(the_file) coords = GetGps(data) po = kml_doc.createElement('PhotoOverlay') po.setAttribute('id', photo_id) name = kml_doc.createElement('name') name.appendChild(kml_doc.createTextNode(file_name)) description = kml_doc.createElement('description') description.appendChild(kml_doc.createCDATASection('<a href="#%s">' 'Click here to fly into ' 'photo</a>' % photo_id)) po.appendChild(name) po.appendChild(description) icon = kml_doc.createElement('icon') href = kml_doc.createElement('href') href.appendChild(kml_doc.createTextNode(file_name)) camera = kml_doc.createElement('Camera') longitude = kml_doc.createElement('longitude') latitude = kml_doc.createElement('latitude') altitude = kml_doc.createElement('altitude') tilt = kml_doc.createElement('tilt') # Determines the proportions of the image and uses them to set FOV. width = float(data['EXIF ExifImageWidth'].printable) length = float(data['EXIF ExifImageLength'].printable) lf = str(width/length * -20.0) rf = str(width/length * 20.0) longitude.appendChild(kml_doc.createTextNode(str(coords[1]))) latitude.appendChild(kml_doc.createTextNode(str(coords[0]))) altitude.appendChild(kml_doc.createTextNode('10')) tilt.appendChild(kml_doc.createTextNode('90')) camera.appendChild(longitude) camera.appendChild(latitude) camera.appendChild(altitude) camera.appendChild(tilt) icon.appendChild(href) viewvolume = kml_doc.createElement('ViewVolume') leftfov = kml_doc.createElement('leftFov') rightfov = kml_doc.createElement('rightFov') bottomfov = kml_doc.createElement('bottomFov') topfov = kml_doc.createElement('topFov') near = kml_doc.createElement('near') leftfov.appendChild(kml_doc.createTextNode(lf)) rightfov.appendChild(kml_doc.createTextNode(rf)) bottomfov.appendChild(kml_doc.createTextNode('-20')) topfov.appendChild(kml_doc.createTextNode('20')) near.appendChild(kml_doc.createTextNode('10')) viewvolume.appendChild(leftfov) viewvolume.appendChild(rightfov) viewvolume.appendChild(bottomfov) viewvolume.appendChild(topfov) viewvolume.appendChild(near) po.appendChild(camera) po.appendChild(icon) po.appendChild(viewvolume) point = kml_doc.createElement('point') coordinates = kml_doc.createElement('coordinates') coordinates.appendChild(kml_doc.createTextNode('%s,%s,%s' %(coords[1], coords[0], coords[2]))) point.appendChild(coordinates) po.appendChild(point) document = kml_doc.getElementsByTagName('Document')[0] document.appendChild(po)
Come puoi vedere, utilizziamo solo metodi W3C DOM standard, perché sono quelli disponibili nella maggior parte dei linguaggi di programmazione. Per vedere come funziona il tutto, scarica il codice da qui.
Questo esempio non sfrutta tutta la potenza di PhotoOverlays
, che ti consente di creare esplorazioni approfondite di foto ad alta risoluzione. Tuttavia, mostra come appendere una foto in stile cartellone pubblicitario su Google Earth. Ecco un esempio di file KML creato utilizzando questo codice:
<?xml version="1.0" encoding="utf-8"?> <kml xmlns="http://www.opengis.net/kml/2.2"> <Document> <PhotoOverlay id="photo0"> <name> 1228258523134.jpg </name> <description> <![CDATA[<a href="#photo0">Click here to fly into photo</a>]]> </description> <Camera> <longitude> -122.3902159196034 </longitude> <latitude> 37.78961266330473 </latitude> <altitude> 10 </altitude> <tilt> 90 </tilt> </Camera> <Icon> <href> 1228258523134.jpg </href> </Icon> <ViewVolume> <leftFov> -26.6666666667 </leftFov> <rightFov> 26.6666666667 </rightFov> <bottomFov> -20 </bottomFov> <topFov> 20 </topFov> <near> 10 </near> </ViewVolume> <Point> <coordinates> -122.3902159196034,37.78961266330473,0 </coordinates> </Point> </PhotoOverlay> </Document> </kml>
Ecco come appare in Google Earth:

Avvertenze
Il geotagging delle foto è ancora agli inizi.
Ecco alcuni aspetti da tenere presente:
- I dispositivi GPS non sono sempre precisi al 100%, in particolare quelli integrati nelle fotocamere, quindi devi controllare le posizioni delle tue foto.
- Molti dispositivi non monitorano l'altitudine, impostandola invece su 0. Se l'altitudine è importante per te, devi trovare un altro modo per acquisire questi dati.
- La posizione GPS è quella della videocamera, non del soggetto della foto. Per questo motivo, questo esempio posiziona l'elemento Fotocamera nella posizione GPS e la foto effettiva lontano da questa posizione.
- Exif non acquisisce informazioni sulla direzione in cui è puntata la videocamera, quindi potresti dover regolare
PhotoOverlays
per questo motivo. La buona notizia è che alcuni dispositivi, come gli smartphone basati sul sistema operativo Android, consentono di acquisire direttamente dati come la direzione della bussola e l'inclinazione, ma non nelle intestazioni Exif.
Detto questo, è comunque un modo efficace per visualizzare le tue foto. Ci auguriamo di vedere un numero sempre maggiore di foto geotaggate con precisione nel prossimo futuro.
Passaggi successivi
Ora che hai iniziato a utilizzare le intestazioni EXIF, puoi esplorare la specifica EXIF. Sono memorizzati molti altri dati che potrebbero interessarti e che potresti inserire in un fumetto descrittivo. Potresti anche prendere in considerazione la creazione di PhotoOverlays
più ricchi utilizzando ImagePyramids
. L'articolo della Guida per gli sviluppatori su PhotoOverlays
offre una buona panoramica del loro utilizzo.