Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Python: get GPS latitude and longitude coordinates from JPEG EXIF using exifread
import exifread
# based on https://gist.github.com/erans/983821
def _get_if_exist(data, key):
if key in data:
return data[key]
return None
def _convert_to_degress(value):
"""
Helper function to convert the GPS coordinates stored in the EXIF to degress in float format
:param value:
:type value: exifread.utils.Ratio
:rtype: float
"""
d = float(value.values[0].num) / float(value.values[0].den)
m = float(value.values[1].num) / float(value.values[1].den)
s = float(value.values[2].num) / float(value.values[2].den)
return d + (m / 60.0) + (s / 3600.0)
def get_exif_location(exif_data):
"""
Returns the latitude and longitude, if available, from the provided exif_data (obtained through get_exif_data above)
"""
lat = None
lon = None
gps_latitude = _get_if_exist(exif_data, 'GPS GPSLatitude')
gps_latitude_ref = _get_if_exist(exif_data, 'GPS GPSLatitudeRef')
gps_longitude = _get_if_exist(exif_data, 'GPS GPSLongitude')
gps_longitude_ref = _get_if_exist(exif_data, 'GPS GPSLongitudeRef')
if gps_latitude and gps_latitude_ref and gps_longitude and gps_longitude_ref:
lat = _convert_to_degress(gps_latitude)
if gps_latitude_ref.values[0] != 'N':
lat = 0 - lat
lon = _convert_to_degress(gps_longitude)
if gps_longitude_ref.values[0] != 'E':
lon = 0 - lon
return lat, lon
@rudyvogt
Copy link

rudyvogt commented Jan 23, 2017

very helpful code

@JoeDevlin
Copy link

JoeDevlin commented Jul 14, 2017

Thanks for this! I cant seem to actually return or print the coordinates to terminal, how can I do that?

@ryanmeasel
Copy link

ryanmeasel commented Nov 1, 2018

There is no get_exif_data in this gist.

@bcjarrett
Copy link

bcjarrett commented Dec 27, 2018

@ryanmeasel

def get_exif_data(image_file):
    with open(image_file, 'rb') as f:
        exif_tags = exifread.process_file(f)
    return exif_tags 

lat, long = get_exif_location(get_exif_data(image_file))

@bcjarrett
Copy link

bcjarrett commented Dec 27, 2018

I also added altitude:

gps_altitude_ref = _get_if_exist(exif_data, 'GPS GPSAltitudeRef')
gps_altitude = _get_if_exist(exif_data, 'GPS GPSAltitude')

if gps_altitude and gps_altitude_ref:
     alt = gps_altitude.values[0]
     altitude = alt.num / alt.den
     if gps_altitude_ref.values[0] == 1: altitude *= -1

return lat, lon, altitude

@Olegt0rr
Copy link

Olegt0rr commented Dec 2, 2021

Thanks for code!

Some improvements

  1. More accuracy with Decimal calculations (instead of float)
from decimal import Decimal

d, m, s = coord_value
decimal_degrees = (
    Decimal(d.numerator) / Decimal(d.denominator)
    + Decimal(m.numerator) / Decimal(m.denominator) / Decimal(60)
    + Decimal(s.numerator) / Decimal(s.denominator) / Decimal(3600)
)
  1. Shorter ref usage
if coord_ref in {"S", "W"}:
    decimal_degrees *= -1
  1. Shorter result
#  GoogleMaps ngigits=7, but 6 == 0.1 meter distance - a lot :)
return round(float(decimal_degrees), ndigits=7)

Sorry for var naming, got it from my solution, based on Pillow
https://gitlab.com/-/snippets/2215069

@snakeye
Copy link
Author

snakeye commented Dec 13, 2021

@Olegt0rr one question - do we really need to use Decimals if we do not care about precision less than 10e6?

@Olegt0rr
Copy link

Olegt0rr commented Dec 16, 2021

@snakeye just in case )))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment