Hoy en día casi todo el mundo utiliza un smartphone. Estos teléfonos implementan muchas funcionalidades y una de las más comunes es la de tomar fotos y grabar vídeos. Gracias a que también poseen GPS, puedes habilitar la opción de localización para cada foto que tomes, capturando y guardando sus coordenadas geográficas con los metadatos que acompañan a la foto. Dichos metadatos son almacenados en formato de imagen Exchangeable Image File (Exif).

Código del ejemplo completo y las fotos

Python posee una librería  llamada “Python Imaging Library” (PIL) con la que puedes extraer las coordenadas geográficas de latitud y longitud.

Usando esta información, puedes aplicar a cada coordenada el proceso de geocodificación inversa (proceso que consiste en encontrar la dirección más cercana a una ubicación geográfica, lo contrario que la geocodificación, que es el proceso de buscar una ubicación geográfica a partir de una dirección) para determinar la dirección más cercana a la foto.

Es fácil entender que este tipo de servicio es utilísimo para multitud de usuarios

Imaginemos a un grupo de usuarios mapeando con fotos la ciudad para detectar algún tipo de problemas urbanos. Los usuarios capturan las fotos y estas tienen la ubicación embebida.

Posteriormente podríamos extraer las coordenadas de cada foto tomada y realizar un proceso de geocodificación inversa con el fin de atribuir la dirección, guardar esta información en una geodatabase. Desde aquí podríamos usar esta información , guardarlas en servidores como Amazon o Dropbox y cargarla en visores Web vía, por ejemplo, CartoDB.

En este post te enseñaré como extraer las coordenadas a partir de unas fotos tomadas con un iPhone, y aplicar el proceso de geocodificación inversa para obtener la dirección más cercana.

El código para realizar este proceso lo vamos a implementar  mediante una Toolbox Python de ArcGIS, como vemos en este ejemplo: 

ToolBox Iphone

Hacer las fotos

Para este ejemplo, el código utilizado requiere que uses un iPhone o iPad .Si tienes Android u otro sistema operativo de móvil, los metadatos creados de las fotos son diferentes y debes modificar el código.

Las fotos tomadas con la cámara del iPhone almacenan las coordenadas geográficas en los metadatos asociados de cada foto. Sin embargo necesitarás activar los Servicios de Localización para que se almacenen las coordenadas geográficas. Los pasos para hacerlo se explican a continuación:

 

1.  Accede a “Settings” en tu iPhone.

2.  Accede a “Privacy”.

3.  Deberías ver “Location Services” en la parte superior del cuadro de diálogo de “Privacy”, tal como se ve en la imagen de abajo.

4.  Click en “Location Services”, busca la aplicación de cámara de tu móvil y selecciona “While Using”.

 

El código: Obtener los Metadatos de las Fotos, Localización con Geocodificación Inversa, Escribir en Dropbox y Escribir a Feature Class.

En este paso vamos a crear una herramienta que procese las fotos tomadas desde el iPhone. La herramienta recupera la latitud y longitud de cada foto y guarda la información como puntos en una capa de una geodatabase. La información de coordenadas para las fotos se puede obtener usando el módulo PIL de Python antes descrito.Más adelante actualizaremos el script realizado para poder copiar las fotos a Dropbox.

Nota: No voy a escribir en el post todo el código usado para crear esta herramienta. Lo que estoy obviando es parte del código utilizado para crear la Toolbox Python de  ArcGIS, así como una función que crea la geodatabase de archivos para almacenar los datos.Estas tareas son relativamente simples y comunes pero debes tenerlo en cuenta al leer el código. El objetivo principal aquí es enfocarnos en las partes del código que tratan sobre obtención de metadatos, geocodificación inversa y copia de fotos a Dropbox. El código también asume que tienes instalado el PIL, las librerías de ArcGIS y los módulos de Dropbox. Estas acciones se pueden hacer a través del sistema de gestión de paquetes (pip).

Puedes pulsar cualquiera de los ejemplos de código siguientes para ampliarlos, por si te es difícil leerlos y comprenderlos.

1.  Importa los diferentes módulos de Python que serán usados para nuestra aplicación.

2.  En la parte de ConvertPhotosToGeodatabase has de prestar mucha atención para varias partes del código.

El método getParameterInfo() se usa para capturar los parámetros de entrada. Con este método estamos obteniendo el path a las fotos, el path al archivo geodatabase que se creará, el nombre del archivo geodatabase y el nombre de salida de la feature class.

3.  El método execute() también recopila estos parámetros de entrada después de que el usuario haya corrido el script, para posteriormente enviar estos parámetros a la función makeGISpointsFromPics().

4.  Ahora examinamos la función   makeGISpointsFromPics() que se ve a continuación.

5.  La línea de código _createFGDB(path,fgdb,fc) llama a la función para crear una nueva geodatabase y una feature class, en base al parámetro de entrada recibido mediante la herramienta.

No voy a entrar en detalles con esta función. Es bastante sencilla y simple, y si quieres puedes revisarla por tu cuenta.

6.  El código siguiente almacena, desde la carpeta de imágenes de entrada, una lista de fotos con la extensión de archivo .jpg o .JPG.

7.  Ahora en este paso creamos un bucle (for loop) que circule a través de todas las imágenes, extrayendo las coordenadas geográficas desde los metadatos de las fotos y escribiendo esta información en una feature class.

La siguiente línea de código recupera los datos exif de cada imagen recorrida por el bucle.

8.  Aquí debajo se muestra la función get_exif_data(). Esta función usa el módulo PIL para abrir la foto y extraer la información exif, incluyendo las etiquetas proporcionadas por el GPS.

Posteriormente esta información es devuelta de nuevo a la función get_exif_data().

9.  Las siguientes líneas de código nos devuelven, desde los metadatos, la latitud y longitud usando la función get_lat_lon(). Este código nos proporciona una lista de objetos, de la que podemos recuperar los valores de latitud y longitud.

10.  Aquí debajo puedes observar el bloque de código de la función get_lat_lon(). Esta función devuelve la latitud, longitud y la información referencial de los metadatos exif, y luego convierte de grados, minutos y segundos a grados decimales, mediante la función _convert_to_degrees().

No me explayaré con esta función, aunque su código está disponible si quieres repasarlo y verlo con más detalle.

 

11.  Estas dos líneas de código de la función makeGISpointsFromPics() sirven para geocodificar inversamente los puntos dados  y enviar las fotos a Dropbox. Examinaremos cada línea de código con más detalle.

12.  Cuando llamamos a la función getAddress(), ésta recorre los valores de latitud y longitud obtenidos desde los metadatos de la fotos. La función getAddress() usa el módulo de peticiones de Python para enviar la información de coordenadas al Servicio Mundial de Geocodificación de Esri. El valor de distancia y el formato de salida también son transferidos al Servicio de Geocodificación.

El valor de distancia especifíca la distancia máxima (en metros) a utilizar cuando buscas la dirección más cercana.

El servicio de geocodificación inversa buscará la dirección más cercana al punto a buscar. Esri te permite ejecutar la geocodificación inversa con este servicio, siempre y cuando no guardes tus resultados. Si intentas guardar los resultados necesitarás adquirir los créditos de ArcGIS Online.

Observa también que hemos pasado a un formato de respuesta de pjson (mejor que json). El dato devuelto por la operación de geocodificación inversa será un formato json similar al que se ve en el ejemplo de debajo.

 

 

13.  El bloque de código que aparece debajo de la función getAddress() se usa para obtener la información de dirección devuelta por la operación de geocodificación inversa.

14.  Lo siguiente será comentar la función sendPhotoDropbox(), que se llama desde la función makeGISpointFromPics(). La llamada de esta función recorre el path de la foto para guardarla junto con el nombre de la foto.

15.  La función sendPhotoDropbox(), crea una conexión a la cuenta de Dropbox usando el módulo Dropbox de Python para despuès cargar el archivo.

16.  Ahora regresamos otra vez a la función makeGISpointsFromPics(). El bloque de código de debajo usa ArcPy para crear un nuevo objeto de punto desde las coordenadas de longitud y latitud extraídas,  e inserta este objeto de punto en una feature class usando un objeto InsertCursor. También son insertados varios atributos en la fila, incluida la dirección de los puntos.