Los metadatos EXIF de una fotografía contienen mucha información relativa a la misma, generalmente no somos conscientes de dicha información y no la utilizamos correctamente o la distribuimos de forma inconsciente al ir incluidos junto a la imagen en un único archivo.

Al realizar una foto, el dispositivo guarda información entre otros del tiempo de exposición, flash utilizado, modelo de cámara o teléfono movil, lugar exacto donde se realiza o fecha y hora.

Con dichos datos es posible ubicar nuestro domicilio, trazar un mapa de nuestras vacaciones, lugares más visitados, dispositivos móviles y cámaras, etc.

De cara a nuestra privacidad es importante conocer la existencia de esta información y cómo tratarla, por ejemplo eliminar estos datos antes de subir la foto a una red social.

{272: 'E6653', 305: '32.2.A.0.224_0_f500', 274: 6, 306: '2016:06:21 20:12:51', 'Flash': 16, 'FocalLength': (423, 100), 'ColorSpace': 1, 'ExifImageWidth': 3840, 'ExifInteroperabilityOffset': 20960, 'SceneCaptureType': 0, 'SubjectDistanceRange': 0, 'SubsecTime': '251832', 'SubsecTimeOriginal': '251832', 'SubsecTimeDigitized': '251832', 'ExifImageHeight': 2160, 'ExposureTime': (10, 200), 'FNumber': (20, 10), 'CustomRendered': 0, 'ISOSpeedRatings': 800, 'ExposureMode': 0, 'WhiteBalance': 0, 'DigitalZoomRatio': (100, 100), 'MakerNote': b'SONY MOBILE\x00\t\x...

Aunque cada metadato tiene su importancia, sin duda uno de los más utilizados y delicados de cara a nuestra privacidad es la ubicación, guardada con los datos GPS:

'GPSInfo': {'GPSVersionID': b'\x02\x02\x00\x00', 'GPSLatitudeRef': 'N', 'GPSLatitude': ((37, 1), (22, 1), (47866, 1000)), 'GPSLongitudeRef': 'W', 'GPSLongitude': ((6, 1), (2, 1), (9997, 1000)), 'GPSAltitudeRef': b'\x00', 'GPSAltitude': (94000, 1000), 'GPSTimeStamp': ((18, 1), (12, 1), (47000, 1000)), 'GPSStatus': 'A', 'GPSMapDatum': 'WGS-84', 'GPSDateStamp': '2016:06:21', 'Latitude': 37.37986277777778, 'Longitude': -6.0361152777777775}

Librerías

Las librerias utilizadas son viejas conocidas:

from PIL import Image
from PIL.ExifTags import TAGS, GPSTAGS

Código Python listar metadatos

Comencemos con un ejemplo simple, mostrar los metadatos EXIF por Terminal.

La siguiente función abre la imagen e imprime por pantalla los tags que va encontrando:

def exif_print(filename):
	try:
		image = Image.open(filename)
		exif = image._getexif().items()
		if exif is not None:
			for key, value in exif:
				svalue=str(value)[0:200]
				print("%s: %s" % (TAGS.get(key, key), svalue))
	except:
		debug.print_exception()
		return None

Para llamar a la función:

exif_print(<tu_archivo_de_imagen>)

En caso de error, para obtener mas información llamamos a print_exception(), puedes ver el detalle de esta función para tratar excepciones en esta entrada:

Si ejecutas desde Terminal obtendrás por pantalla algo parecido a esto:

GPSInfo: {0: b'\x02\x02\x00\x00', 1: 'N', 2: ((37, 1), (22, 1), (47816, 1000)), 3: 'W', 4: ((6, 1), (2, 1), (
ResolutionUnit: 2
ExifOffset: 214
Make: Sony
Model: E6653
Software: 32.2.A.0.224_0_f500
Orientation: 6
DateTime: 2016:06:21 20:10:35
YCbCrPositioning: 1
XResolution: (72, 1)
YResolution: (72, 1)
ExifVersion: b'0220'
ComponentsConfiguration: b'\x01\x02\x03\x00'
ShutterSpeedValue: (500, 100)
DateTimeOriginal: 2016:06:21 20:10:35
DateTimeDigitized: 2016:06:21 20:10:35
ExposureBiasValue: (0, 3)
FlashPixVersion: b'0100'
MeteringMode: 5
LightSource: 0
Flash: 16
FocalLength: (423, 100)
ColorSpace: 1
ExifImageWidth: 3840
ExifInteroperabilityOffset: 20960
SceneCaptureType: 0
SubjectDistanceRange: 0
SubsecTime: 056145
SubsecTimeOriginal: 056145
SubsecTimeDigitized: 056145
ExifImageHeight: 2160
ExposureTime: (10, 320)
FNumber: (20, 10)
CustomRendered: 0
ISOSpeedRatings: 125
ExposureMode: 0
WhiteBalance: 0
DigitalZoomRatio: (100, 100)
MakerNote: b'SONY MOBILE\x00\t\x00\x0f \x04\x00\x01\x00\x00\x00\x00

¿Interesante verdad?

Habrás visto la etiqueta GPSInfo, esta es la que nos interesa por ahora ya que contiene información relativa a las coordenadas GPS del momento de la captura.

Código Python extraer coordenadas GPS desde EXIF

El siguiente código recupera los datos EXIF y una vez obtenidos localiza coordenadas GPS para su tratamiento.

Declaramos dos funciones:

  • get_exif(archivo): recupera los metadatos EXIF en bruto
  • get_decimal_coordinates(info): devuelve coordenadas GPS: latitud y longitud
def get_decimal_coordinates(info):
	try:
		for key in ['Latitude', 'Longitude']:
			if 'GPS'+key in info and 'GPS'+key+'Ref' in info:
				e = info['GPS'+key]
				ref = info['GPS'+key+'Ref']
				info[key] = ( e[0][0]/e[0][1] + e[1][0]/e[1][1] / 60 + e[2][0]/e[2][1] / 3600) * (-1 if ref in ['S','W'] else 1)
		if 'Latitude' in info and 'Longitude' in info:
			return [float(info['Latitude']), float(info['Longitude'])]
		else:
			return [0.0, 0.0]
	except:		
		debug.print_exception()
		return None

def get_exif(filename):
	try:
		exif = Image.open(filename)._getexif()	
		if exif is not None:
			for key, value in exif.items():
				name = TAGS.get(key, key)
				exif[name] = exif.pop(key)
	
			if 'GPSInfo' in exif:
				for key in exif['GPSInfo'].keys():
					name = GPSTAGS.get(key,key)
					exif['GPSInfo'][name] = exif['GPSInfo'].pop(key)

		return exif
	    
	except:		
		debug.print_exception()
		return None

Para recuperar las coordenadas simplemente obtenemos los metadatos EXIF y posteriormente llamamos a la función get_decimal_coordinates() para las coordenadas:

sfilepath="/media/lubuntu/4A5B-42E5/cmrep/201606/20160621201251_efbbd74f15d4d1b8f3ca081f8af7b7f4.jpg"		
exif=get_exif(sfilepath)		
lat,lon=get_decimal_coordinates(exif['GPSInfo'])
print("%s %s" % (lat,lon))

Y listo! sencillo y práctico.

Si además de coordenadas, quieres ver como obtener la dirección en formato calle + ciudad + pais, te puede interesar esta entrada:

Dudas y comentarios donde siempre.

Saludos!