1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
|
import os
import random
import json
import sqlite3
from contextlib import closing # with close sqlite
import flask
from PIL import Image as PIL_Image # Image file exif data for GPS coordinate extraction
import PIL.ExifTags as PIL_ExifTags
import geopy.distance
app = flask.Flask(__name__)
def decimal_coords(coords, ref):
decimal_degrees = coords[0] + coords[1] / 60 + coords[2] / 3600
if ref == "S" or ref =='W' :
decimal_degrees = -decimal_degrees
return decimal_degrees
def get_exif(image_path: os.PathLike) -> dict:
# Extract EXIF metadata as a dictionary with readable tags
image = PIL_Image.open(image_path) # Load the image from the specified path
exif = {
PIL_ExifTags.TAGS[k]: v
for k, v in image._getexif().items()
if k in PIL_ExifTags.TAGS
}
return exif
def image_coordinates(exif: dict) -> (float, float):
# Extract raw GPS data for latitude (north) and longitude (east)
north = exif['GPSInfo'][2] # Latitude data in degrees, minutes, and seconds
east = exif['GPSInfo'][4] # Longitude data in degrees, minutes, and seconds
# Convert latitude and longitude from degrees-minutes-seconds to decimal format
lat = ((((north[0]*60) + north[1])*60) + north[2]) / 60 / 60
lng = ((((east[0]*60) + east[1])*60) + east[2]) / 60 / 60
return float(lat),float(lng)
@app.route('/favicon.ico')
def favicon():
return flask.send_from_directory(os.path.join(app.root_path, 'static'),
'favicon.ico', mimetype='image/vnd.microsoft.icon')
@app.route('/get_random_image.json')
def get_random_image():
return random.choice(pics)
@app.route("/guess.json", methods=['POST'])
def guess():
data = json.loads(flask.request.data)
exif = get_exif(os.path.join(pic_root_path, data['image_name']))
correct_coordinates = image_coordinates(exif)
guess_coordinates = (data['coordinates']['lat'], data['coordinates']['lng'])
distance = geopy.distance.geodesic(correct_coordinates, guess_coordinates)
distance_meters = round(distance.meters)
image_unique_id = exif['ImageUniqueID']
with closing(sqlite3.connect("guess_where.db")) as connection:
with closing(connection.cursor()) as cursor:
cursor.execute("""INSERT INTO guesses(
picture_name,
image_unique_id,
correct_coordinates,
guess_coordinates,
distance_meters
)
VALUES (?, ?, ?, ?, ?)
""", (
data['image_name'],
image_unique_id,
f"{correct_coordinates[0]}, {correct_coordinates[1]}",
f"{data['coordinates']['lat']}, {data['coordinates']['lng']}",
distance_meters
))
connection.commit()
return {'correct_coordinates': correct_coordinates, 'distance_meters': distance_meters}
@app.route("/")
def game():
return flask.render_template('game.html')
pic_root_path = 'src/static/pics/mine'
pics_original = os.listdir(pic_root_path)
pics = []
# Check if all images have GPS coordinates on application start
for pic in pics_original:
img_path = os.path.join(pic_root_path, pic)
try:
exif = get_exif(img_path)
correct_coordinates = image_coordinates(exif)
pics.append(pic)
except Exception as ex:
print(f'Error loading GPS coordinates for: {img_path}')
raise ex
with closing(sqlite3.connect("guess_where.db")) as connection:
with closing(connection.cursor()) as cursor:
rows = cursor.execute("""
CREATE TABLE IF NOT EXISTS guesses (
picture_name TEXT,
image_unique_id TEXT,
correct_coordinates TEXT,
guess_coordinates TEXT,
distance_meters INT,
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
)
""").fetchall()
|