Janvier 2009
Objectif
Ce tutoriel vous explique comment utiliser des photos géolocalisées pour créer un fichier KML PhotoOverlays
. Bien que l'exemple de code soit écrit en Python, de nombreuses bibliothèques similaires existent dans d'autres langages de programmation. Vous ne devriez donc pas avoir de problème à traduire ce code dans un autre langage. Le code de cet article s'appuie sur une bibliothèque Python Open Source, EXIF.py.
Introduction
Les appareils photo numériques sont des outils incroyables. De nombreux utilisateurs ne s'en rendent pas compte, mais ils font bien plus que prendre des photos et des vidéos. Ils taguent également ces vidéos et photos avec des métadonnées sur la caméra et ses paramètres. Ces dernières années, les utilisateurs ont trouvé des moyens d'ajouter des données géographiques à ces informations, soit intégrées par les fabricants d'appareils photo, comme certains appareils Ricoh et Nikon, soit par le biais d'appareils tels que les enregistreurs GPS et EyeFi Explore. Les téléphones équipés d'un appareil photo, comme l'iPhone et les téléphones utilisant le système d'exploitation Android, comme le G1 de T-Mobile, intègrent automatiquement ces données. Certains sites d'importation de photos, tels que Panoramio, Picasa Albums Web et Flickr, analysent automatiquement les données GPS et les utilisent pour géolocaliser une photo. Vous pouvez ensuite récupérer ces données dans les flux. Mais où est le plaisir ? Cet article vous explique comment accéder vous-même à ces données.
En-têtes Exif
La méthode la plus courante pour intégrer des données dans un fichier image consiste à utiliser le format de fichier image échangeable (EXIF). Les données sont stockées au format binaire dans les en-têtes EXIF de manière standard. Si vous connaissez la spécification des en-têtes EXIF, vous pouvez les analyser vous-même. Heureusement, quelqu'un a déjà fait le gros du travail et écrit un module Python pour vous. La bibliothèque Open Source EXIF.py est un excellent outil pour lire les en-têtes des fichiers JPEG.
Le code
L'exemple de code de cet article se trouve dans le fichier exif2kml.py. Si vous souhaitez passer directement à l'utilisation de ce module, téléchargez-le, ainsi que EXIF.py, et placez-les dans le même répertoire. Exécutez python exif2kml.py foo.jpg
en remplaçant foo.jpg par le chemin d'accès à une photo géolocalisée. Un fichier nommé test.kml
sera créé.
Analyse des en-têtes Exif
EXIF.py fournit une interface simple pour extraire les en-têtes Exif. Il vous suffit d'exécuter la fonction process_file()
pour qu'elle renvoie les en-têtes sous forme d'objet 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
Une fois que vous avez les en-têtes Exif, vous devez extraire les coordonnées GPS. EXIF.py les traite comme des objets Ratio
, c'est-à-dire des objets permettant de stocker le numérateur et le dénominateur des valeurs. Cela permet de définir un ratio précis au lieu de s'appuyer sur un nombre à virgule flottante. Toutefois, le format KML attend des nombres décimaux, et non des ratios. Vous devez donc extraire chacune des coordonnées, puis convertir le numérateur et le dénominateur en un seul nombre à virgule flottante pour les degrés décimaux :
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
Une fois que vous avez les coordonnées, il est facile de créer un PhotoOverlay
simple pour chaque photo :
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)
Comme vous pouvez le voir, nous utilisons simplement les méthodes W3C DOM standards, car ce sont celles qui sont disponibles dans la plupart des langages de programmation. Pour voir comment tout cela s'articule, téléchargez le code sur cette page.
Cet exemple n'exploite pas tout le potentiel de PhotoOverlays
, qui vous permet de créer des explorations approfondies de photos haute résolution. Toutefois, il montre comment accrocher une photo à la manière d'un panneau publicitaire sur Google Earth. Voici un exemple de fichier KML créé à l'aide de ce code :
<?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>
Voici à quoi cela ressemble dans Google Earth :

Mises en garde
Le géotagging des photos n'en est qu'à ses débuts.
Voici quelques points à prendre en compte :
- Les appareils GPS ne sont pas toujours précis à 100 %, en particulier ceux intégrés aux caméras. Vous devez donc vérifier la position de vos photos.
- De nombreux appareils ne suivent pas l'altitude et la définissent sur 0. Si l'altitude est importante pour vous, vous devez trouver un autre moyen de capturer ces données.
- La position GPS correspond à celle de l'appareil photo, et non à celle du sujet de la photo. C'est pourquoi cet exemple positionne l'élément Camera à la position GPS et la photo réelle loin de cette position.
- Les données Exif ne capturent pas d'informations sur la direction dans laquelle votre caméra est orientée. Vous devrez peut-être ajuster votre
PhotoOverlays
en conséquence. La bonne nouvelle, c'est que certains appareils, comme les téléphones fonctionnant sous le système d'exploitation Android, vous permettent de capturer directement des données telles que la direction de la boussole et l'inclinaison, mais pas dans les en-têtes Exif.
Cela dit, il s'agit toujours d'un moyen efficace de visualiser vos photos. Nous espérons que le géotagging des photos deviendra de plus en plus précis dans un avenir proche.
Étapes suivantes
Maintenant que vous avez commencé à utiliser les en-têtes EXIF, vous pouvez explorer la spécification EXIF. De nombreuses autres données y sont stockées. Vous pouvez les capturer et les placer dans une bulle de description. Vous pouvez également envisager de créer des PhotoOverlays
plus riches à l'aide de ImagePyramids
. L'article du guide du développeur sur PhotoOverlays
offre une bonne vue d'ensemble de leur utilisation.