Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
init
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- README.md +4 -4
- app.py +262 -0
- requirements.txt +4 -0
- select.csv +51 -0
- select/104642768529339.jpg +0 -0
- select/1093560081172659.jpg +0 -0
- select/1132165610543859.jpg +0 -0
- select/1234836596948376.jpg +0 -0
- select/1389710078031039.jpg +0 -0
- select/1394764281000584.jpg +0 -0
- select/141905757860376.jpg +0 -0
- select/1441534879556156.jpg +0 -0
- select/152454737707008.jpg +0 -0
- select/160540152679305.jpg +0 -0
- select/1632995353756681.jpg +0 -0
- select/169961348374774.jpg +0 -0
- select/174371825084733.jpg +0 -0
- select/184068376916582.jpg +0 -0
- select/189829202981952.jpg +0 -0
- select/213668066965052.jpg +0 -0
- select/228333062384255.jpg +0 -0
- select/2295166667284628.jpg +0 -0
- select/2521081868187418.jpg +0 -0
- select/299535091653682.jpg +0 -0
- select/303007251265953.jpg +0 -0
- select/304682731408847.jpg +0 -0
- select/308415407537837.jpg +0 -0
- select/311028890545710.jpg +0 -0
- select/317939186591897.jpg +0 -0
- select/320105042867850.jpg +0 -0
- select/339675071071472.jpg +0 -0
- select/364473748335727.jpg +0 -0
- select/383548139454148.jpg +0 -0
- select/393732468965312.jpg +0 -0
- select/4000903146675702.jpg +0 -0
- select/4169751473085624.jpg +0 -0
- select/4304508472933745.jpg +0 -0
- select/468632131073831.jpg +0 -0
- select/477063033350685.jpg +0 -0
- select/491911438726571.jpg +0 -0
- select/492211698793885.jpg +0 -0
- select/503560481463361.jpg +0 -0
- select/520441642700354.jpg +0 -0
- select/5265020933627697.jpg +0 -0
- select/612686053145014.jpg +0 -0
- select/769547813760817.jpg +0 -0
- select/813929882849515.jpg +0 -0
- select/826435791283265.jpg +0 -0
- select/838797057047031.jpg +0 -0
- select/859387714930005.jpg +0 -0
README.md
CHANGED
@@ -1,10 +1,10 @@
|
|
1 |
---
|
2 |
title: Plonk
|
3 |
-
emoji:
|
4 |
-
colorFrom:
|
5 |
-
colorTo:
|
6 |
sdk: gradio
|
7 |
-
sdk_version:
|
8 |
app_file: app.py
|
9 |
pinned: false
|
10 |
license: mit
|
|
|
1 |
---
|
2 |
title: Plonk
|
3 |
+
emoji: 👀
|
4 |
+
colorFrom: yellow
|
5 |
+
colorTo: purple
|
6 |
sdk: gradio
|
7 |
+
sdk_version: 3.44.0
|
8 |
app_file: app.py
|
9 |
pinned: false
|
10 |
license: mit
|
app.py
ADDED
@@ -0,0 +1,262 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""Requires gradio==3.44.0"""
|
2 |
+
import io
|
3 |
+
import os
|
4 |
+
import uuid
|
5 |
+
import matplotlib
|
6 |
+
import time
|
7 |
+
matplotlib.use('Agg')
|
8 |
+
from os.path import join
|
9 |
+
from PIL import Image
|
10 |
+
import pandas as pd
|
11 |
+
import reverse_geocoder as rg
|
12 |
+
import cartopy.crs as ccrs
|
13 |
+
import cartopy.feature as cfeature
|
14 |
+
import matplotlib.pyplot as plt
|
15 |
+
from math import radians, sin, cos, sqrt, asin, exp
|
16 |
+
from collections import defaultdict
|
17 |
+
|
18 |
+
IMAGE_FOLDER = './select'
|
19 |
+
CSV_FILE = './select.csv'
|
20 |
+
RESULTS_DIR = './results'
|
21 |
+
RULES = """# Plonk 🌍 🌎 🌏
|
22 |
+
## Total time: 50 pictures ~ 5min
|
23 |
+
### How it works:
|
24 |
+
- Click on the map 🗺️ (left) to indicate where do you think the image 🖼️ (right) was captured!
|
25 |
+
- Click next to move to the next image.
|
26 |
+
⚠️ Your selection is final!
|
27 |
+
### Click "start" to begin...
|
28 |
+
"""
|
29 |
+
|
30 |
+
def haversine(lat1, lon1, lat2, lon2):
|
31 |
+
if (lat1 is None) or (lon1 is None) or (lat2 is None) or (lon2 is None):
|
32 |
+
return 0
|
33 |
+
R = 6371 # radius of the earth in km
|
34 |
+
dLat = radians(lat2 - lat1)
|
35 |
+
dLon = radians(lon2 - lon1)
|
36 |
+
a = (
|
37 |
+
sin(dLat / 2.0) ** 2
|
38 |
+
+ cos(radians(lat1)) * cos(radians(lat2)) * sin(dLon / 2.0) ** 2
|
39 |
+
)
|
40 |
+
c = 2 * asin(sqrt(a))
|
41 |
+
distance = R * c
|
42 |
+
return distance
|
43 |
+
|
44 |
+
def geoscore(d):
|
45 |
+
return 5000 * exp(-d / 1492.7)
|
46 |
+
|
47 |
+
|
48 |
+
class Engine(object):
|
49 |
+
def __init__(self, image_folder, csv_file, cache_path):
|
50 |
+
self.image_folder = image_folder
|
51 |
+
self.load_images_and_coordinates(csv_file)
|
52 |
+
self.cache_path = cache_path
|
53 |
+
|
54 |
+
# Initialize the score and distance lists
|
55 |
+
self.index = 0
|
56 |
+
self.stats = defaultdict(list)
|
57 |
+
|
58 |
+
# Create the figure and canvas only once
|
59 |
+
self.fig = plt.Figure(figsize=(10, 6))
|
60 |
+
self.ax = self.fig.add_subplot(1, 1, 1, projection=ccrs.PlateCarree())
|
61 |
+
self.MIN_LON, self.MAX_LON, self.MIN_LAT, self.MAX_LAT = self.ax.get_extent()
|
62 |
+
|
63 |
+
def load_images_and_coordinates(self, csv_file):
|
64 |
+
# Load the CSV
|
65 |
+
df = pd.read_csv(csv_file)
|
66 |
+
|
67 |
+
# Get the image filenames and their coordinates
|
68 |
+
self.images = df['image_id'].tolist()[:]
|
69 |
+
self.coordinates = df[['longitude', 'latitude']].values.tolist()[:]
|
70 |
+
self.admins = df[['city', 'area', 'region', 'country']].values.tolist()[:]
|
71 |
+
|
72 |
+
|
73 |
+
def isfinal(self):
|
74 |
+
return self.index == len(self.images)-1
|
75 |
+
|
76 |
+
def load_image(self):
|
77 |
+
if self.index > len(self.images)-1:
|
78 |
+
self.master.update_idletasks()
|
79 |
+
self.finish()
|
80 |
+
|
81 |
+
self.ax.clear()
|
82 |
+
self.ax.set_global()
|
83 |
+
self.ax.stock_img()
|
84 |
+
self.ax.add_feature(cfeature.COASTLINE)
|
85 |
+
self.ax.add_feature(cfeature.BORDERS, linestyle=':')
|
86 |
+
self.fig.canvas.draw()
|
87 |
+
pil = self.get_figure()
|
88 |
+
self.set_clock()
|
89 |
+
return pil, os.path.join(self.image_folder, f"{self.images[self.index]}.jpg"), '### ' + str(self.index + 1) + '/' + str(len(self.images))
|
90 |
+
|
91 |
+
def get_figure(self):
|
92 |
+
img_buf = io.BytesIO()
|
93 |
+
self.fig.savefig(img_buf, format='png', bbox_inches='tight', pad_inches=0, dpi=300)
|
94 |
+
pil = Image.open(img_buf)
|
95 |
+
self.width, self.height = pil.size
|
96 |
+
return pil
|
97 |
+
|
98 |
+
def normalize_pixels(self, click_lon, click_lat):
|
99 |
+
return self.MIN_LON + click_lon * (self.MAX_LON-self.MIN_LON) / self.width, self.MIN_LAT + (self.height - click_lat+1) * (self.MAX_LAT-self.MIN_LAT) / self.height
|
100 |
+
|
101 |
+
def set_clock(self):
|
102 |
+
self.time = time.time()
|
103 |
+
|
104 |
+
def get_clock(self):
|
105 |
+
return time.time() - self.time
|
106 |
+
|
107 |
+
def click(self, click_lon, click_lat):
|
108 |
+
time_elapsed = self.get_clock()
|
109 |
+
self.stats['times'].append(time_elapsed)
|
110 |
+
|
111 |
+
# convert click_lon, click_lat to lat, lon (given that you have the borders of the image)
|
112 |
+
# click_lon and click_lat is in pixels
|
113 |
+
# lon and lat is in degrees
|
114 |
+
click_lon, click_lat = self.normalize_pixels(click_lon, click_lat)
|
115 |
+
self.stats['clicked_locations'].append((click_lat, click_lon))
|
116 |
+
true_lon, true_lat = self.coordinates[self.index]
|
117 |
+
|
118 |
+
self.ax.plot(click_lon, click_lat, 'bo', transform=ccrs.Geodetic())
|
119 |
+
self.ax.plot([true_lon, click_lon], [true_lat, click_lat], color='blue', linewidth=1, transform=ccrs.Geodetic())
|
120 |
+
self.ax.plot(true_lon, true_lat, 'rx', transform=ccrs.Geodetic())
|
121 |
+
|
122 |
+
distance = haversine(true_lat, true_lon, click_lat, click_lon)
|
123 |
+
score = geoscore(distance)
|
124 |
+
self.stats['scores'].append(score)
|
125 |
+
self.stats['distances'].append(distance)
|
126 |
+
|
127 |
+
average_text = self.update_average_display()
|
128 |
+
result_text = (f"### GeoScore: {score:.0f}, distance: {distance:.0f} km\n ")
|
129 |
+
|
130 |
+
self.cache(self.index+1, score, distance, (click_lat, click_lon), time_elapsed)
|
131 |
+
return self.get_figure(), result_text + average_text
|
132 |
+
|
133 |
+
def next_image(self):
|
134 |
+
# Go to the next image
|
135 |
+
self.index += 1
|
136 |
+
return self.load_image()
|
137 |
+
|
138 |
+
def update_average_display(self):
|
139 |
+
# Calculate the average values
|
140 |
+
avg_score = sum(self.stats['scores']) / len(self.stats['scores']) if self.stats['scores'] else 0
|
141 |
+
avg_distance = sum(self.stats['distances']) / len(self.stats['distances']) if self.stats['distances'] else 0
|
142 |
+
|
143 |
+
# Update the text box
|
144 |
+
return f"### Average GeoScore: {avg_score:.0f}, Average distance: {avg_distance:.0f} km"
|
145 |
+
|
146 |
+
def finish(self):
|
147 |
+
clicks = rg.search(self.stats['clicked_locations'])
|
148 |
+
clicked_admins = [[click['name'], click['admin2'], click['admin1'], click['cc']] for click in clicks]
|
149 |
+
|
150 |
+
correct = [0,0,0,0]
|
151 |
+
valid = [0,0,0,0]
|
152 |
+
|
153 |
+
for clicked_admin, true_admin in zip(clicked_admins, self.admins):
|
154 |
+
for i in range(4):
|
155 |
+
if true_admin[i]!= 'nan':
|
156 |
+
valid[i] += 1
|
157 |
+
if true_admin[i] == clicked_admin[i]:
|
158 |
+
correct[i] += 1
|
159 |
+
|
160 |
+
avg_city_accuracy = correct[0] / valid[0]
|
161 |
+
avg_area_accuracy = correct[1] / valid[1]
|
162 |
+
avg_region_accuracy = correct[2] / valid[2]
|
163 |
+
avg_country_accuracy = correct[3] / valid[3]
|
164 |
+
|
165 |
+
avg_score = sum(self.stats['scores']) / len(self.stats['scores']) if self.stats['scores'] else 0
|
166 |
+
avg_distance = sum(self.stats['distances']) / len(self.stats['distances']) if self.stats['distances'] else 0
|
167 |
+
|
168 |
+
final_results = (
|
169 |
+
f"Average GeoScore: {avg_score:.0f} \n" +
|
170 |
+
f"Average distance: {avg_distance:.0f} km \n" +
|
171 |
+
f"Country Acc: {100*avg_country_accuracy:.1f} \n" +
|
172 |
+
f"Region Acc: {100*avg_region_accuracy:.1f} \n" +
|
173 |
+
f"Area Acc: {100*avg_area_accuracy:.1f} \n" +
|
174 |
+
f"City Acc: {100*avg_city_accuracy:.1f}"
|
175 |
+
)
|
176 |
+
|
177 |
+
self.cache_final(final_results)
|
178 |
+
|
179 |
+
# Update the text box
|
180 |
+
return f"# Your stats 🌍\n" + final_results + f" \n# Thanks for playing ❤️"
|
181 |
+
|
182 |
+
# Function to save the game state
|
183 |
+
def cache(self, index, score, distance, location, time_elapsed):
|
184 |
+
if not os.path.exists(self.cache_path):
|
185 |
+
os.makedirs(self.cache_path)
|
186 |
+
|
187 |
+
with open(join(self.cache_path, str(index).zfill(2) + '.txt'), 'w') as f:
|
188 |
+
print(f"{score}, {distance}, {location[0]}, {location[1]}, {time_elapsed}", file=f)
|
189 |
+
|
190 |
+
# Function to save the game state
|
191 |
+
def cache_final(self, final_results):
|
192 |
+
times = ', '.join(map(str, self.stats['times']))
|
193 |
+
with open(join(self.cache_path, 'full.txt'), 'w') as f:
|
194 |
+
print(f"{final_results}" + '\n Times: ' + times, file=f)
|
195 |
+
|
196 |
+
|
197 |
+
|
198 |
+
if __name__ == "__main__":
|
199 |
+
import gradio as gr
|
200 |
+
def click(state, evt: gr.SelectData):
|
201 |
+
if state['clicked']:
|
202 |
+
return gr.update(), gr.update()
|
203 |
+
x, y = evt.index
|
204 |
+
state['clicked'] = True
|
205 |
+
image, text = state['engine'].click(x, y)
|
206 |
+
return gr.update(value=image), gr.update(value=text)
|
207 |
+
|
208 |
+
def next_(state):
|
209 |
+
if state['clicked']:
|
210 |
+
if state['engine'].isfinal():
|
211 |
+
text = state['engine'].finish()
|
212 |
+
return gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(value=text), gr.update(visible=False)
|
213 |
+
else:
|
214 |
+
fig, image, text = state['engine'].next_image()
|
215 |
+
state['clicked'] = False
|
216 |
+
return gr.update(value=fig), gr.update(value=image), gr.update(value=text), gr.update(), gr.update()
|
217 |
+
else:
|
218 |
+
return gr.update(), gr.update(), gr.update(), gr.update(), gr.update()
|
219 |
+
|
220 |
+
def start(state):
|
221 |
+
# create a unique random temporary name under CACHE_DIR
|
222 |
+
# generate random hex and make sure it doesn't exist under CACHE_DIR
|
223 |
+
while True:
|
224 |
+
path = str(uuid.uuid4().hex)
|
225 |
+
name = os.path.join(RESULTS_DIR, path)
|
226 |
+
if not os.path.exists(name):
|
227 |
+
break
|
228 |
+
|
229 |
+
state['engine'] = Engine(IMAGE_FOLDER, CSV_FILE, name)
|
230 |
+
state['clicked'] = False
|
231 |
+
fig, image, text = state['engine'].load_image()
|
232 |
+
|
233 |
+
return (
|
234 |
+
gr.update(value=fig, visible=True),
|
235 |
+
gr.update(value=image, visible=True),
|
236 |
+
gr.update(value=text, visible=True),
|
237 |
+
gr.update(visible=True),
|
238 |
+
gr.update(visible=True),
|
239 |
+
gr.update(visible=False),
|
240 |
+
gr.update(visible=False),
|
241 |
+
gr.update(visible=False),
|
242 |
+
gr.update(visible=False),
|
243 |
+
)
|
244 |
+
|
245 |
+
with gr.Blocks() as demo:
|
246 |
+
state = gr.State({})
|
247 |
+
rules = gr.Markdown(RULES, visible=True)
|
248 |
+
|
249 |
+
start_button = gr.Button("Start", visible=True)
|
250 |
+
with gr.Row():
|
251 |
+
map_ = gr.Image(label='Map', visible=False)
|
252 |
+
image_ = gr.Image(label='Image', visible=False)
|
253 |
+
with gr.Row():
|
254 |
+
text = gr.Markdown("", visible=False)
|
255 |
+
text_count = gr.Markdown("", visible=False)
|
256 |
+
|
257 |
+
next_button = gr.Button("Next", visible=False)
|
258 |
+
start_button.click(start, inputs=[state], outputs=[map_, image_, text_count, text, next_button, rules, state, start_button])
|
259 |
+
map_.select(click, inputs=[state], outputs=[map_, text])
|
260 |
+
next_button.click(next_, inputs=[state], outputs=[map_, image_, text_count, text, next_button])
|
261 |
+
|
262 |
+
demo.launch(share=True, debug=True)
|
requirements.txt
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
matplotlib==3.7.1
|
2 |
+
pandas==2.0.1
|
3 |
+
reverse_geocoder==1.5.1
|
4 |
+
cartopy==0.22.0
|
select.csv
ADDED
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
image_id,longitude,latitude,city,area,region,country
|
2 |
+
860133474581133,117.73186795368,-31.94982838928,Cunderdin,Cunderdin,Western Australia,AU
|
3 |
+
152454737707008,-115.46546196759182,51.171538690221375,Banff,,Alberta,CA
|
4 |
+
393732468965312,18.97688915808808,69.11780259850913,Storsteinnes,Balsfjord,Troms,NO
|
5 |
+
1132165610543859,-58.849666972752,-35.554807349705,San Miguel del Monte,,Buenos Aires,AR
|
6 |
+
1394764281000584,147.03644442101,-43.241833344957,Cygnet,Huon Valley,Tasmania,AU
|
7 |
+
4304508472933745,111.71332546557,2.1383249963969,Sibu,,Sarawak,MY
|
8 |
+
184068376916582,99.957131581331,9.4777282094183,Ko Samui,,Surat Thani,TH
|
9 |
+
311028890545710,118.28358048575,29.724935841625,Xintan,,Anhui Sheng,CN
|
10 |
+
813929882849515,35.055043425688,-15.0184741953,Balaka,Balaka District,Southern Region,MW
|
11 |
+
1093560081172659,-6.2240662119428,56.725251766279,Isle Of Mull,Argyll and Bute,Scotland,GB
|
12 |
+
612686053145014,-96.16942670000188,18.993103300001184,Paso del Toro,,Veracruz,MX
|
13 |
+
1632995353756681,-66.11192506887,18.135853801397,G. L. Garcia,,Cayey,PR
|
14 |
+
317939186591897,55.555796187621,25.533114073286,Umm al Qaywayn,,Umm al Qaywayn,AE
|
15 |
+
520441642700354,-119.31753516877,50.249882799029,Vernon,Regional District of North Okanagan,British Columbia,CA
|
16 |
+
189829202981952,44.005405251222,41.599785003198,Tsalka,Tsalka,Kvemo Kartli,GE
|
17 |
+
4000903146675702,50.579197062107,36.973620940803,Ramsar,,Mazandaran,IR
|
18 |
+
1389710078031039,13.71181614806,47.399453831847,Schladming,Politischer Bezirk Liezen,Styria,AT
|
19 |
+
949517792450129,9.7177091797716,4.046983959221,Douala,,Littoral,CM
|
20 |
+
769547813760817,34.087808245679,1.0808757622682,Mbale,Mbale District,Eastern Region,UG
|
21 |
+
104642768529339,16.450404476788645,68.31075667561743,Kjopsvik,Tysfjord,Nordland,NO
|
22 |
+
303007251265953,-71.578509002669,-36.390450225908,Coihueco,Provincia de Nuble,Biobio,CL
|
23 |
+
320105042867850,71.468575775224,51.122642222111,Astana,,Astana Qalasy,KZ
|
24 |
+
468632131073831,29.218865526259,65.777072925388,Kuusamo,Koillismaa,Northern Ostrobothnia,FI
|
25 |
+
503560481463361,67.86856499056314,47.49971675692054,Zhezqazghan,,Qaraghandy,KZ
|
26 |
+
304682731408847,-104.84187971601,38.921916584821,Air Force Academy,El Paso County,Colorado,US
|
27 |
+
492211698793885,15.243938905249,11.731445568385,Kousseri,,Far North,CM
|
28 |
+
169961348374774,-66.338308918774,-17.444761411827,Sipe Sipe,,Cochabamba,BO
|
29 |
+
141905757860376,-74.780652186738,10.934612493587,Soledad,,Atlantico,CO
|
30 |
+
957589118406370,-48.46767735367,-8.0935339973733,Conceicao do Araguaia,Conceicao Do Araguaia,Para,BR
|
31 |
+
2521081868187418,-0.40230996669347,32.614639189097,Ain Sefra,,Wilaya de Naama,DZ
|
32 |
+
917445892443616,-1.1248279177789,52.937541598214,West Bridgford,Nottinghamshire,England,GB
|
33 |
+
383548139454148,-1.7849243363171,48.039562839713,Chavagne,Departement d'Ille-et-Vilaine,Brittany,FR
|
34 |
+
859387714930005,147.10522055011,-42.977124432213,Huonville,Huon Valley,Tasmania,AU
|
35 |
+
2295166667284628,7.1359534780749,51.190279172602,Solingen,Regierungsbezirk Dusseldorf,North Rhine-Westphalia,DE
|
36 |
+
826435791283265,-102.14648195121,31.99819818952,Midland,Midland County,Texas,US
|
37 |
+
160540152679305,32.640044964906,54.194653471895,Stodolishche,,Smolensk,RU
|
38 |
+
1441534879556156,131.9022521,43.093777400038,Vladivostok,,Primorskiy,RU
|
39 |
+
213668066965052,-7.7833356565566,41.298426689978,Vila Real,Vila Real,Vila Real,PT
|
40 |
+
491911438726571,62.642283844441,35.982936156486,Serhetabat,,Mary,TM
|
41 |
+
228333062384255,20.03622352221,42.173352559956,Iballe,Rrethi i Pukes,Shkoder,AL
|
42 |
+
339675071071472,18.935150981289,53.3141942187,Wabrzezno,Powiat wabrzeski,Kujawsko-Pomorskie,PL
|
43 |
+
174371825084733,-54.40021860075962,-15.844177431680396,Poxoreo,Poxoreo,Mato Grosso,BR
|
44 |
+
5265020933627697,81.92179231998388,41.36342468712621,Baicheng,,Xinjiang Uygur Zizhiqu,CN
|
45 |
+
364473748335727,-55.731720607751,-27.91313764655,Apostoles,Departamento de Apostoles,Misiones,AR
|
46 |
+
477063033350685,97.735136849091,16.797879002023,Hpa-an,,Kayin,MM
|
47 |
+
1234836596948376,118.2591368156,29.761870407333,Xintan,,Anhui Sheng,CN
|
48 |
+
308415407537837,-6.8798972749875,10.960432369588,Kolondieba,,Sikasso,ML
|
49 |
+
4169751473085624,136.87180806629,50.250143059295,Amursk,,Khabarovsk Krai,RU
|
50 |
+
838797057047031,1.4928102327598,43.618538732481,Balma,Departement de la Haute-Garonne,Midi-Pyrenees,FR
|
51 |
+
299535091653682,171.22063076773,-44.390911705397,Timaru,Timaru District,Canterbury,NZ
|
select/104642768529339.jpg
ADDED
![]() |
select/1093560081172659.jpg
ADDED
![]() |
select/1132165610543859.jpg
ADDED
![]() |
select/1234836596948376.jpg
ADDED
![]() |
select/1389710078031039.jpg
ADDED
![]() |
select/1394764281000584.jpg
ADDED
![]() |
select/141905757860376.jpg
ADDED
![]() |
select/1441534879556156.jpg
ADDED
![]() |
select/152454737707008.jpg
ADDED
![]() |
select/160540152679305.jpg
ADDED
![]() |
select/1632995353756681.jpg
ADDED
![]() |
select/169961348374774.jpg
ADDED
![]() |
select/174371825084733.jpg
ADDED
![]() |
select/184068376916582.jpg
ADDED
![]() |
select/189829202981952.jpg
ADDED
![]() |
select/213668066965052.jpg
ADDED
![]() |
select/228333062384255.jpg
ADDED
![]() |
select/2295166667284628.jpg
ADDED
![]() |
select/2521081868187418.jpg
ADDED
![]() |
select/299535091653682.jpg
ADDED
![]() |
select/303007251265953.jpg
ADDED
![]() |
select/304682731408847.jpg
ADDED
![]() |
select/308415407537837.jpg
ADDED
![]() |
select/311028890545710.jpg
ADDED
![]() |
select/317939186591897.jpg
ADDED
![]() |
select/320105042867850.jpg
ADDED
![]() |
select/339675071071472.jpg
ADDED
![]() |
select/364473748335727.jpg
ADDED
![]() |
select/383548139454148.jpg
ADDED
![]() |
select/393732468965312.jpg
ADDED
![]() |
select/4000903146675702.jpg
ADDED
![]() |
select/4169751473085624.jpg
ADDED
![]() |
select/4304508472933745.jpg
ADDED
![]() |
select/468632131073831.jpg
ADDED
![]() |
select/477063033350685.jpg
ADDED
![]() |
select/491911438726571.jpg
ADDED
![]() |
select/492211698793885.jpg
ADDED
![]() |
select/503560481463361.jpg
ADDED
![]() |
select/520441642700354.jpg
ADDED
![]() |
select/5265020933627697.jpg
ADDED
![]() |
select/612686053145014.jpg
ADDED
![]() |
select/769547813760817.jpg
ADDED
![]() |
select/813929882849515.jpg
ADDED
![]() |
select/826435791283265.jpg
ADDED
![]() |
select/838797057047031.jpg
ADDED
![]() |
select/859387714930005.jpg
ADDED
![]() |