Давайте воспользуемся пакетами exif and folium Python

Большинство современных камер и мобильных телефонов с поддержкой GPS записывают информацию о геолокации при съемке фотографии, и эта информация сохраняется вместе со всеми другими метаданными.

Существует также множество веб-приложений, которые позволяют создавать различные визуализации с использованием этих метаданных. Но что, если вы, как и я, не доверяете свои фотографии сторонним сервисам с неизвестным уровнем безопасности данных? К счастью, большинство этих визуализаций относительно просто воспроизвести с помощью Python. В этом руководстве я покажу, как создать карту путешествия, используя фотоданные GPS.

Для этого проекта вам понадобится несколько пакетов, установленных в вашей среде Python. Мы будем использовать два основных пакета: exifпозволит нам извлекать метаданные из фотографий, а folium мы будем использовать для создания карты и добавления маркеров местоположения. Наконец, мы также будем использовать карты цветов из matplotlib, и pandasи numpy для манипуляций с данными.Чтобы установить все необходимые пакеты, просто выполните следующие действия. в вашем терминале:

pip install exif folium pandas numpy matplotlib

Начнем с импорта всех необходимых пакетов. В дополнение к перечисленным выше, мы также импортируем json и Pathclass из pathlib library, оба из которых являются частью стандартной библиотеки.

Извлечение и подготовка метаданных для построения графика

Чтение метаданных с помощью exif очень просто — нам просто нужно открыть файл в двоичном формате и создать из него объект Image. Определим для этого функцию удобства:

В зависимости от устройства фотография может содержать десятки типов метаданных. Чтобы увидеть те, которые конкретно относятся к геолокации, мы можем загрузить одну фотографию и распечатать все категории метаданных, которые начинаются с «gps_».

Если в фотографию встроена информация о геолокации, вы должны увидеть следующий вывод:

gps_latitude_ref 
gps_latitude 
gps_longitude_ref 
gps_longitude 
gps_altitude_ref 
gps_altitude 
gps_timestamp 
gps_processing_method 
gps_datestamp

Некоторые из этих категорий относительно просты для понимания: gps_latitude, gps_longitude и gps_altitude хранят информацию о широте, долготе и высоте соответственно. Высота сохраняется как высота над уровнем моря, обычно в метрах. Широта и долгота хранятся в виде кортежей градусов, минут и угловых секунд.

Категории, оканчивающиеся на "_ref", содержат справочную информацию о том, как следует интерпретировать данные. В случае высоты он просто сообщает, что значение представляет собой высоту над уровнем моря, но для широты и долготы они содержат информацию об опорном полушарии, «E» или «W» для долготы и «N» или «S» для широты. Это важно при преобразовании необработанных данных в десятичный формат, поскольку стандартная запись имеет отрицательные координаты к западу от Гринвича и к югу от экватора.

Поскольку пакет folium, который мы будем использовать для построения графиков,не понимает координаты в градусах/минутах/секундах, нам нужно преобразовать широты и долготы в десятичное представление, и поскольку мы будем делать это довольно много раз, мы можем упростить жизнь и сделать код чище, определив функцию, которая будет принимать кортеж координат и опорное значение и возвращать его двоичное представление. Для этого переводим минуты и секунды в доли градуса путем деления на 60 и 3600 соответственно. Затем знак определяется на основе справочных данных:

Эта функция преобразует широту и долготу в десятичный формат, и нам не нужно ничего делать с высотами. При этом мы можем определить еще одну вспомогательную функцию, которая будет принимать объект exif.Image и возвращать кортеж десятичных координат в формате (широта, долгота, высота).

Наконец, мы добавим еще одну функцию, которая будет рекурсивно проходить по всем подпапкам выбранной папки, считывать пространственную информацию из всех файлов изображений и возвращать словарь имен файлов и координат.

Теперь, когда это сделано, мы можем легко прочитать данные о местоположении из всех файлов в папке изображения:

Печать результирующего словаря должна привести к выводу, аналогичному моему:

print(json.dumps(res, indent=4))
Out:
{     
    "/media/pav/Storage/Photo/Phone/IMAG0036.jpg": {
        "latitude": -37.79912566666666,         
        "longitude": 144.9850463611111,         
        "altitude": 0.0,         
        "timestamp": "2014:04:12 18:14:59"},  
    "/media/pav/Storage/Photo/Phone/IMAG0037.jpg": { 
        "latitude": -37.79912566666666,         
        "longitude": 144.9850463611111,         
        "altitude": 0.0,         
        "timestamp": "2014:04:12 18:15:36"},
    ...
}

График данных

Чтобы упростить будущие операции, мы можем преобразовать полученный словарь в pandas DataFrame. Затем мы также преобразуем столбец меток времени в формат datetime и сортируем значения по дате в порядке возрастания.

Чтобы покрасить наши точки данных, мы можем получить одну из цветовых карт, которые входят в состав пакета matplotlib. В дополнение к этому нам также необходимо создать объект Normalize. Этот объект будет присваивать числовые значения отдельным цветам в colourmap от 0 до 1, и мы сможем вызывать любой цвет в colourspace по его числовому значению. И для этого мы добавим столбец к нашему dataframe, используя numpy.linspace().

Одна небольшая проблема заключается в том, что наши цвета будут в формате RGBA, но он не работает с folium, поэтому нам также нужно будет преобразовать цвет в его шестнадцатеричное представление, что легко сделать:

Теперь давайте, наконец, пришло время визуализировать наши данные!

Основной частью пакета folium является объект Map, и простое создание экземпляра через folium.Map() приведет к созданию карты всего мира.

Это нормально, но я предпочитаю, чтобы карта автоматически масштабировалась до уровня, на котором видны все маркеры. Мы можем добиться этого, используя метод fit_bounds() результирующего объекта и предоставив координаты юго-западного и северо-восточного углов экстентов карты.

Мы можем рассчитать координаты юго-западного угла, взяв максимальную широту и минимальную долготу из наших данных. Точно так же координаты северо-восточного угла являются минимальной широтой и максимальной долготой. В приведенном ниже коде я также скорректировал ограничивающую рамку на 3 градуса в каждом направлении, чтобы данные аккуратно помещались в окне.

Итак, теперь, наконец, мы готовы создать карту, показывающую расположение фотографий, выделенных цветом по дате съемки.

В моем случае результат показывает кучу мест вокруг Виктории, Австралия, с фиолетовыми точками, представляющими более ранние фотографии, и более яркими красными и желтыми точками — более новые фотографии:

Заключение

Здесь мы коснулись лишь крошечной части всех возможностей, которые предлагают метаданные фотографий. С помощью этих данных вы можете создавать свои собственные базы данных фотографий, позволяющие легко классифицировать их и управлять ими. Вы также можете расширить использование данных геолокации, чтобы иметь возможность искать фотографии по местоположению в папках с изображениями, а также доступны многие другие вещи.

Полный код этого проекта можно загрузить с моего GitHub по следующему адресу: