I am writing a small program to get the GPS info of a iphone jpg photo.
The library I am using is the PIL in python. Now I am able to get the GPSInfo, which is something like:
{1: 'N',
2: ((1, 1), (20, 1), (5365, 100)),
3: 'E',
4: ((103, 1), (41, 1), (1052, 100)),
5: 0,
6: (43, 1),
7: ((15, 1), (32, 1), (7, 1)),
16: 'T',
17: (77473, 452),
29: '2013:10:25'}
How can I interpret this? And I notice the tag is not continuous, so is there any cheating sheet which I can refer to in order to get a better understanding of all the number tags and what they mean? Thank you!
UPDATES
Sorry, I have figured it out. In the PIL lib, there is a GPSTAGS.get() function which can help me decode the key in gps info. Thank you guys!
gpsinfo = {}
for key in exif['GPSInfo'].keys():
decode = ExifTags.GPSTAGS.get(key,key)
gpsinfo[decode] = exif['GPSInfo'][key]
print gpsinfo
and here is the result
{'GPSTimeStamp': ((15, 1), (32, 1), (7, 1)),
'GPSImgDirectionRef': 'T',
'GPSImgDirection': (77473, 452),
'GPSLongitude': ((103, 1), (41, 1), (1052, 100)),
'GPSLatitudeRef': 'N', 29: '2013:10:25',
'GPSAltitude': (43, 1),
'GPSLatitude': ((1, 1), (20, 1), (5365, 100)),
'GPSLongitudeRef': 'E',
'GPSAltitudeRef': 0}
Use exifread module.
Here is a very helpful gist
import exifread as ef
# barrowed from
# https://gist.github.com/snakeye/fdc372dbf11370fe29eb
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 getGPS(filepath):
'''
returns gps data if present other wise returns empty dictionary
'''
with open(filepath, 'rb') as f:
tags = ef.process_file(f)
latitude = tags.get('GPS GPSLatitude')
latitude_ref = tags.get('GPS GPSLatitudeRef')
longitude = tags.get('GPS GPSLongitude')
longitude_ref = tags.get('GPS GPSLongitudeRef')
if latitude:
lat_value = _convert_to_degress(latitude)
if latitude_ref.values != 'N':
lat_value = -lat_value
else:
return {}
if longitude:
lon_value = _convert_to_degress(longitude)
if longitude_ref.values != 'E':
lon_value = -lon_value
else:
return {}
return {'latitude': lat_value, 'longitude': lon_value}
return {}
file_path = 'file path of the file'
gps = getGPS(file_path)
print gps
Late answer, but as of 2022 you can use GPSPhoto, i.e.:
from GPSPhoto import gpsphoto
# Get the data from image file and return a dictionary
data = gpsphoto.getGPSData('IMG_20181224_201933.jpg')
print(data['Latitude'], data['Longitude'])
Output:
38.71615498471598 -9.148730635643007
Installation:
pip3 install piexif
pip3 install gpsphoto
OP, has already posted a solution using PIL. If you wants to just get GPS info from Python, you can get it by using exifread
Install package using pip
$ pip install exifread
and get GPS data
In [10]: import exifread
In [11]: tags = exifread.process_file(open('./tests/demo-project/content/test.jpg', 'rb'))
In [12]: geo = {i:tags[i] for i in tags.keys() if i.startswith('GPS')}
In [13]: geo
Out[13]:
{'GPS GPSAltitude': (0x0006) Ratio=186188/239 # 898,
'GPS GPSAltitudeRef': (0x0005) Byte=0 # 722,
'GPS GPSDate': (0x001D) ASCII=2015:12:06 # 954,
'GPS GPSDestBearing': (0x0018) Ratio=43771/526 # 946,
'GPS GPSDestBearingRef': (0x0017) ASCII=T # 806,
'GPS GPSImgDirection': (0x0011) Ratio=43771/526 # 938,
'GPS GPSImgDirectionRef': (0x0010) ASCII=T # 782,
'GPS GPSLatitude': (0x0002) Ratio=[46, 3803/100, 0] # 850,
'GPS GPSLatitudeRef': (0x0001) ASCII=N # 674,
'GPS GPSLongitude': (0x0004) Ratio=[13, 2429/100, 0] # 874,
'GPS GPSLongitudeRef': (0x0003) ASCII=E # 698,
'GPS GPSSpeed': (0x000D) Ratio=139/50 # 930,
'GPS GPSSpeedRef': (0x000C) ASCII=K # 758,
'GPS GPSTimeStamp': (0x0007) Ratio=[10, 37, 33] # 906,
'GPS Tag 0x001F': (0x001F) Ratio=30 # 966}
Related
I'm a university student and we were tasked to implement Dijkstra's algorithm on the given graph below.
Graph to implement Dijkstra's algorithm on
We were given a code to use and/or modify and help answer the question given.
import heapq
import math
def dijkstra(G, S):
pq = []
entry_finder = {}
costs = {}
pred = {S: None}
REMOVED = 'removed'
def add_entry(label, priority):
if label in entry_finder:
remove_entry(label)
entry = [priority, label]
entry_finder[label] = entry
heapq.heappush(pq, entry)
def remove_entry(label):
entry = entry_finder.pop(label)
entry[-1] = REMOVED
def pop_entry():
while pq:
priority, label = heapq.heappop(pq)
if label != REMOVED:
del entry_finder[label]
return priority, label
return None, None
for v in G:
if v == S:
add_entry(S, 0)
else:
add_entry(v, math.inf)
while pq:
d_u, u = pop_entry()
if u is not None and u != REMOVED:
costs[u] = d_u
for e in G[u]:
v, w = e
entry_v = entry_finder[v]
d_v = entry_v[0]
if d_v > d_u + w:
add_entry(v, d_u + w)
pred[v] = u
return costs, pred
This code was shown to work for a separate graph that was used in an example from our lectures. The graph was converted into code as such.
G = {
'0': [('1', 2), ('2', 6), ('3', 7)],
'1': [('3', 3), ('4', 6)],
'2': [('4', 1)],
'3': [('4', 5)],
'4': []
}
costs, pred = dijkstra(G, '0')
print(costs, pred)
So I know for a fact that the given code works. The problem arose when I tried to implement the graph into code and it gave me a KeyError: 'D'. My implementation of the graph is as follows.
G = {
'A': [('B', 56), ('C', 96), ('D', 78)],
'B': [('D', 18), ('F', 208), ('E', 110)],
'C': [('D', 20), ('F', 90)],
'D': [('F', 112)],
'E': [('F', 16), ('G', 46), ('I', 108)],
'F': [('G', 20), ('H', 62)],
'G': [('H', 40)],
'H': [('I', 29), ('J', 56)],
'I': [('J', 21)],
'J': []
}
costs, pred = dijkstra(G, 'A')
print(costs, pred)
The error also comes with:
line 41, in dijkstra
entry_v = entry_finder[v]. I'd like to know if the error came from my wrong implementation of the graph or if the given sample code itself had errors.
I am trying to save all function arguments as it is ran, to a container. Container is common for all funcs ran in the script. How to ensure all container's content is NOT saved every time I save function arguments?
Below decorator saves function arguments:
import inspect
from datetime import datetime
import time
def func_logger(method):
def wrapper(*args, **kw):
method_args = inspect.signature(method).bind(*args, **kw).arguments
runtime = str( datetime.now() )
name = method.__name__
module = method.__module__
signature = runtime + ': ' + '.'.join([module, name])
ts = time.time()
result = method(*args, **kw)
te = time.time()
kw['log'][signature] = {}
kw['log'][signature]['time'] = round(te - ts, 2)
kw['log'][signature]['args'] = method_args
return result
return wrapper
And an example function:
#func_logger
def test(a, b=4, c='blah-blah', *args, **kwargs):
return 4**4**8
When I am running the following snippet:
log = {}
output = test(1,4,2,4,1,par=1, log=log)
output = test(1,4,2,4,1,par=1, log=log)
log
I receive this output:
{'2019-05-17 13:48:25.214094: __main__.test': {'time': 0.0,
'args': OrderedDict([('a', 1),
('b', 4),
('c', 2),
('args', (4, 1)),
('kwargs', {'par': 1, 'log': {...}})])},
'2019-05-17 13:48:25.215092: __main__.test': {'time': 0.0,
'args': OrderedDict([('a', 1),
('b', 4),
('c', 2),
('args', (4, 1)),
('kwargs', {'par': 1, 'log': {...}})])}}
I already tried a workaround - a function that removes 'log' entry from the dictionary. However, every next item in this log stores of the log's current content. So when I try this:
list( log.items() )[-1][-1]['args']
The output is this:
OrderedDict([('a', 1),
('b', 4),
('c', 2),
('args', (4, 1)),
('kwargs',
{'par': 1,
'log': {'2019-05-17 13:45:45.748722: __main__.test': {'time': 0.0,
'args': OrderedDict([('a', 1),
('b', 4),
('c', 2),
('args', (4, 1)),
('kwargs', {'par': 1, 'log': {...}})])},
'2019-05-17 13:45:45.749221: __main__.test': {'time': 0.0,
'args': OrderedDict([('a', 1),
('b', 4),
('c', 2),
('args', (4, 1)),
('kwargs', {'par': 1, 'log': {...}})])},
'2019-05-17 13:45:45.750218: __main__.test': {'time': 0.0,
'args': OrderedDict(...)}}})])
So essentially, such a workaround won't work because with time, the memory would get clogged quickly.
Is there any way decorator would not save log entry every time I save function arguments? What I would rather like to avoid is to create a new 'log = {}' container every time I want to dump arguments from a new function.
You could simply store the log parameter if present and remove it from **kw:
def func_logger(method):
def wrapper(*args, **kw):
try:
log = kw['log']
del kw['log']
except KeyError:
log = None
method_args = inspect.signature(method).bind(*args, **kw).arguments
runtime = str( datetime.now() )
name = method.__name__
module = method.__module__
signature = runtime + ': ' + '.'.join([module, name])
ts = time.time()
result = method(*args, **kw)
te = time.time()
if log is not None:
log[signature] = {}
log[signature]['time'] = round(te - ts, 2)
log[signature]['args'] = method_args
return result
return wrapper
use global log in func_logger
log = {}
def func_logger(method):
def wrapper(*args, **kw):
# pass
log[signature] = {...}
return result
return wrapper
then, use output = test(1,4,2,4,1,par=1)
I am trying to modify the fuzzywuzzy library. The module process returns the score and the array element. But I want it to return the index of the element along with the group of score,item,index.
Here is what I tried:
#!/usr/bin/env python
# encoding: utf-8
from fuzzywuzzy import fuzz
from fuzzywuzzy import utils
import heapq
import logging
from functools import partial
default_scorer = fuzz.WRatio
default_processor = utils.full_process
def extractWithoutOrder(query, choices, processor=default_processor, scorer=default_scorer, score_cutoff=0):
def no_process(x):
return x
try:
if choices is None or len(choices) == 0:
raise StopIteration
except TypeError:
pass
if processor is None:
processor = no_process
processed_query = processor(query)
if len(processed_query) == 0:
logging.warning(u"Applied processor reduces input query to empty string, "
"all comparisons will have score 0. "
"[Query: \'{0}\']".format(query))
# Don't run full_process twice
if scorer in [fuzz.WRatio, fuzz.QRatio,
fuzz.token_set_ratio, fuzz.token_sort_ratio,
fuzz.partial_token_set_ratio, fuzz.partial_token_sort_ratio,
fuzz.UWRatio, fuzz.UQRatio] \
and processor == utils.full_process:
processor = no_process
# Only process the query once instead of for every choice
if scorer in [fuzz.UWRatio, fuzz.UQRatio]:
pre_processor = partial(utils.full_process, force_ascii=False)
scorer = partial(scorer, full_process=False)
elif scorer in [fuzz.WRatio, fuzz.QRatio,
fuzz.token_set_ratio, fuzz.token_sort_ratio,
fuzz.partial_token_set_ratio, fuzz.partial_token_sort_ratio]:
pre_processor = partial(utils.full_process, force_ascii=True)
scorer = partial(scorer, full_process=False)
else:
pre_processor = no_process
processed_query = pre_processor(processed_query)
count = -1
try:
# See if choices is a dictionary-like object.
for key, choice in choices.items():
count = count + 1
processed = pre_processor(processor(choice))
score = scorer(processed_query, processed)
if score >= score_cutoff:
yield (choice, score, key,count)
except AttributeError:
# It's a list; just iterate over it.
for choice in choices:
count = count + 1
processed = pre_processor(processor(choice))
score = scorer(processed_query, processed)
if score >= score_cutoff:
yield (choice, score,count)
def extract(query, choices, processor=default_processor, scorer=default_scorer, limit=5):
sl = extractWithoutOrder(query, choices, processor, scorer)
return heapq.nlargest(limit, sl, key=lambda i: i[1]) if limit is not None else \
sorted(sl, key=lambda i: i[1], reverse=True)
When I tried to implement it, the result was what it was previously showing by fuzzywuzzy.
import process as p
box=['ness', 'apple','banana','carrot','duck','eagle','fish','gate','hitler']
p.extract('b',box)
[('banana', 90), ('apple', 0), ('carrot', 0), ('duck', 0), ('eagle', 0)]
But what I am expecting it to return is:
[('banana', 90, 2), ('apple', 0, 1), ('carrot', 0, 3), ('duck', 0, 4), ('eagle', 0, 5)]
Kindly let me know the suggestion.
As an alternative to FuzzyWuzzy you could use RapidFuzz (I am the author) which will return the index as well:
from rapidfuzz import process
box=['ness', 'apple','banana','carrot','duck','eagle','fish','gate','hitler']
p.extract('b',box)
which returns
[('banana', 90, 2), ('apple', 0, 1), ('carrot', 0, 3), ('duck', 0, 4), ('eagle', 0, 5)]
For those looking for the answer, can pass a dictionary to the process.
from fuzzywuzzy import fuzz
from fuzzywuzzy import process
box = ['apple','banana','carrot','duck','eagle']
box_dict = {i: val for i, val in enumerate(box)}
process.extract("b", box_dict, scorer=fuzz.WRatio)
# O/P -> [("banana", 90, 1), ('apple', 0, 0), ('carrot', 0, 2), ('duck', 0, 3), ('eagle', 0, 4)]
I need to enter data in to csv using headers and put a value if the flag is available in the event else zero it. Required output is:
I am currently getting:
This is my current code, I would like to know how to generate my desired output:
inputs for code is counter1-4 shown below :
OrderedDict([('flags=40', 3971), ('flags=10004', 6244), ('flags=10100', 236), ('flags=90002', 2), ('flags=80', 2009), ('flags=10080', 5421), ('flags=4', 2886), ('flags=100', 227), ('flags=80002', 58), ('flags=10040', 8990), ('flags=0', 5)])
OrderedDict([('flags=40', 16), ('flags=10004', 6244), ('flags=10100', 236), ('flags=90002', 2), ('flags=10080', 5421), ('flags=4', 16), ('flags=80002', 11), ('flags=10040', 8990), ('flags=0', 4), ('Total', 20940)])
OrderedDict([('flags=4', 1332), ('flags=40', 1839), ('flags=80002', 3), ('flags=100', 197), ('flags=80', 935), ('Total', 4306)])
OrderedDict([('Total', 0)])
OrderedDict([('flags=40', 2116), ('flags=80', 1074), ('flags=4', 1538), ('flags=100', 30), ('flags=80002', 44), ('flags=0', 1), ('Total', 4803)])
dat = 1
with open(outputcsv,'wb') as outcsv:
writer = csv.writer(outcsv,delimiter=',')
appname = inputfile[:-3]
writer.writerow(appname.split(','))
for x in threads:
writer.writerows([x.split(',')])
#w.writeheader([x.split(',')])
if dat == 1:
w = csv.DictWriter(outcsv,counter1.keys())
w.writeheader()
w.writerow(counter1)
elif dat == 2:
w = csv.DictWriter(outcsv,counter2.keys())
w.writeheader()
w.writerow(counter2)
elif dat == 3:
w = csv.DictWriter(outcsv,counter3.keys())
w.writeheader()
w.writerow(counter3)
elif dat == 4:
w = csv.DictWriter(outcsv,counter4.keys())
w.writeheader()
w.writerow(counter4)
dat = dat +1
writer.writerows('\n')
code for how threads are being read:
exampleFile = open('top_tasks.csv')
exampleReader = csv.reader(exampleFile)
exampleData = list(exampleReader)
thread1 = exampleData[11][0]
thread2 = exampleData[12][0]
thread3 = exampleData[13][0]
thread4 = exampleData[14][0]
threads = [thread1,thread2,thread3,thread4]
I think this code meets your requirements:
from collections import OrderedDict
import csv
# build an OrderedDict of all keys
all_keys = OrderedDict()
# first column gets name of data set
all_keys[data_set_name] = data_set_name
# collect all of the known keys, and insert the thread name
for counter, thread in zip(counters, threads):
all_keys.update(counter)
counter[data_set_name] = thread
with open(outputcsv, 'wb') as outcsv:
# using all known keys, create a csv writer
w = csv.DictWriter(outcsv, fieldnames=all_keys.keys())
# output the header and data rows
w.writeheader()
w.writerows(counters)
Data Used:
outputcsv = 'output.csv'
counters = [
OrderedDict(
[('flags=40', 3971), ('flags=10004', 6244), ('flags=10100', 236),
('flags=90002', 2), ('flags=80', 2009), ('flags=10080', 5421),
('flags=4', 2886), ('flags=100', 227), ('flags=80002', 58),
('flags=10040', 8990), ('flags=0', 5)]),
OrderedDict(
[('flags=40', 16), ('flags=10004', 6244), ('flags=10100', 236),
('flags=90002', 2), ('flags=10080', 5421), ('flags=4', 16),
('flags=80002', 11), ('flags=10040', 8990), ('flags=0', 4),
('Total', 20940)]),
OrderedDict([('flags=4', 1332), ('flags=40', 1839), ('flags=80002', 3),
('flags=100', 197), ('flags=80', 935), ('Total', 4306)]),
OrderedDict([('Total', 0)]),
OrderedDict([('flags=40', 2116), ('flags=80', 1074), ('flags=4', 1538),
('flags=100', 30), ('flags=80002', 44), ('flags=0', 1),
('Total', 4803)]),
]
# code assumes thread names are in a list, make some sample names
threads = ['thread%d' % (i+1) for i in range(len(counters))]
# first column header if the name of the data set
data_set_name = 'CandyCrush 1'
I am using the following code to extract the geolocation of an image taken with an iPhone:
from PIL import Image
from PIL.ExifTags import TAGS
def get_exif(fn):
ret = {}
i = Image.open(fn)
info = i._getexif()
for tag, value in info.items():
decoded = TAGS.get(tag, tag)
ret[decoded] = value
return ret
a = get_exif('photo2.jpg')
print a
This is the result that I am returned:
{
'YResolution': (4718592, 65536),
41986: 0,
41987: 0,
41990: 0,
'Make': 'Apple',
'Flash': 32,
'ResolutionUnit': 2,
'GPSInfo': {
1: 'N',
2: ((32, 1), (4571, 100), (0, 1)),
3: 'W',
4: ((117, 1), (878, 100), (0, 1)),
7: ((21, 1), (47, 1), (3712, 100))
},
'MeteringMode': 1,
'XResolution': (4718592, 65536),
'ExposureProgram': 2,
'ColorSpace': 1,
'ExifImageWidth': 1600,
'DateTimeDigitized': '2011:03:01 13:47:39',
'ApertureValue': (4281, 1441),
316: 'Mac OS X 10.6.6',
'SensingMethod': 2,
'FNumber': (14, 5),
'DateTimeOriginal': '2011:03:01 13:47:39',
'ComponentsConfiguration': '\x01\x02\x03\x00',
'ExifOffset': 254,
'ExifImageHeight': 1200,
'Model': 'iPhone 3G',
'DateTime': '2011:03:03 10:37:32',
'Software': 'QuickTime 7.6.6',
'Orientation': 1,
'FlashPixVersion': '0100',
'YCbCrPositioning': 1,
'ExifVersion': '0220'
}
So, I am wondering how I convert the GPSInfo values (DMS) to Decimal Degrees for actual coordinates? Also, there seems to be two Wests listed . . . ?
Here's a way to do it, adapted for a script I wrote some months ago using pyexiv2:
a = get_exif('photo2.jpg')
lat = [float(x)/float(y) for x, y in a['GPSInfo'][2]]
latref = a['GPSInfo'][1]
lon = [float(x)/float(y) for x, y in a['GPSInfo'][4]]
lonref = a['GPSInfo'][3]
lat = lat[0] + lat[1]/60 + lat[2]/3600
lon = lon[0] + lon[1]/60 + lon[2]/3600
if latref == 'S':
lat = -lat
if lonref == 'W':
lon = -lon
This gives me the following latitude and longitude for your picture: 32.7618333, -117.146333 (same results as Lance Lee).
The last entry of GPSInfo may be the heading of the picture. You could check this using a tool that gives proper names to the different EXIF values such as exiv2 or exiftools.
http://www.exiv2.org/tags.html
find the string 'Exif.GPSInfo.GPSLatitude' in that page.
It appears that you get 3 pairs (representing rationals) and the second number in the pair is the denominator.
I would expect the thing after Longitude to be altitude, however it is a better fit for GPS timestamp.
In this example:
32/1 + (4571 / 100)/60 + (0 / 1)/3600 = 32.761833 N
117/1 + (878 / 100)/60 + (0 / 1)/3600 = 117.146333 W
Was this picture taken near 4646 Park Blvd, San Diego, CA 92116? If not then ignore this answer.