diff --git a/README.md b/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..571e3c8f14e6aabd37633749c290ad610e91229e
--- /dev/null
+++ b/README.md
@@ -0,0 +1,42 @@
+---
+title: Plonk
+emoji: ๐
+colorFrom: yellow
+colorTo: purple
+sdk: gradio
+sdk_version: 3.44.0
+app_file: app.py
+pinned: false
+license: mit
+---
+
+Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
+
+# OpenStreetView-5M
The Many Roads to Global Visual Geolocation ๐๐
+
+OpenStreetView-5M is hosted at [huggingface/datasets/osv5m/osv5m](https://huggingface.co/datasets/osv5m/osv5m)
+Demo for [OpenStreetView-5M: The Many Roads to Global Visual Geolocation](https://imagine.enpc.fr/~guillaume-astruc/osv-5m).
+
+**First authors:** [Guillaume Astruc](https://gastruc.github.io/), [Nicolas Dufour](https://nicolas-dufour.github.io/), [Ioannis Siglidis](https://imagine.enpc.fr/~siglidii/)
+**Second authors:** [Constantin Aronssohn](), Nacim Bouia, [Stephanie Fu](https://stephanie-fu.github.io/), [Romain Loiseau](https://romainloiseau.fr/), [Van Nguyen Nguyen](https://nv-nguyen.github.io/), [Charles Raude](https://imagine.enpc.fr/~raudec/), [Elliot Vincent](https://imagine.enpc.fr/~vincente/), Lintao XU, Hongyu Zhou
+**Last author:** [Loic Landrieu](https://loiclandrieu.com/)
+**Research Institute:** [Imagine](https://imagine.enpc.fr/), _LIGM, Ecole des Ponts, Univ Gustave Eiffel, CNRS, Marne-la-Vallรฉe, France_
+
+OpenStreetView-5M is the first large-scale open geolocation benchmark of streetview images.
+To get a sense of the difficulty of the benchmark, you can play our [demo](https://huggingface.co/spaces/osv5m/plonk).
+Our dataset was used in an extensive benchmark of which we provide the best model.
+For more details and results, please check out our [paper](arxiv) and [project page](https://imagine.enpc.fr/~guillaume-astruc/osv-5m).
+
+### Citing ๐ซ
+
+```bibtex
+@article{osv5m,
+ title = {{OpenStreetView-5M}: {T}he Many Roads to Global Visual Geolocation},
+ author = {Astruc, Guillaume and Dufour, Nicolas and Siglidis, Ioannis
+ and Aronssohn, Constantin and Bouia, Nacim and Fu, Stephanie and Loiseau, Romain
+ and Nguyen, Van Nguyen and Raude, Charles and Vincent, Elliot and Xu, Lintao
+ and Zhou, Hongyu and Landrieu, Loic},
+ journal = {CVPR},
+ year = {2024},
+ }
+```
diff --git a/app.py b/app.py
new file mode 100644
index 0000000000000000000000000000000000000000..c322019371940952e2ef64e9fc1376097ba3ec34
--- /dev/null
+++ b/app.py
@@ -0,0 +1,545 @@
+"""Requires gradio==4.27.0"""
+import io
+import shutil
+import os
+import json
+import uuid
+import time
+import math
+import datetime
+import numpy as np
+
+from uuid import uuid4
+from PIL import Image
+from math import radians, sin, cos, sqrt, asin, exp
+from os.path import join
+from collections import defaultdict
+from itertools import tee
+
+import matplotlib.style as mplstyle
+mplstyle.use(['fast'])
+import pandas as pd
+
+import gradio as gr
+import reverse_geocoder as rg
+import cartopy.crs as ccrs
+import cartopy.feature as cfeature
+import matplotlib.pyplot as plt
+
+from gradio_folium import Folium
+from geographiclib.geodesic import Geodesic
+from folium import Map, Element, LatLngPopup, Marker, Icon, PolyLine, FeatureGroup
+from folium.map import LayerControl
+from folium.plugins import BeautifyIcon
+from huggingface_hub import CommitScheduler
+
+MPL = False
+IMAGE_FOLDER = './images'
+CSV_FILE = './select.csv'
+BASE_LOCATION = [0, 23]
+RULES = """
OSV-5M (plonk)
+
+ Instructions
+ Click on the map ๐บ๏ธ (left) to the location at which you think the image ๐ผ๏ธ (right) was captured!
+ Click "Select" to finalize your selection and then "Next" to move to the next image.
+"""
+css = """
+@font-face {
+ font-family: custom;
+ src: url("/file=custom.ttf");
+}
+
+h1 {
+ text-align: center;
+ display:block;
+ font-family: custom;
+}
+img {
+ text-align: center;
+ display:block;
+}
+h2 {
+ text-align: center;
+ display:block;
+ font-family: custom;
+}
+h3 {
+ text-align: center;
+ display:block;
+ font-family: custom;
+ font-weight: normal;
+}
+"""
+
+space_js = """
+
+
+"""
+
+def sample_points_along_geodesic(start_lat, start_lon, end_lat, end_lon, min_length_km=2000, segment_length_km=5000, num_samples=None):
+ geod = Geodesic.WGS84
+ distance = geod.Inverse(start_lat, start_lon, end_lat, end_lon)['s12']
+ if distance < min_length_km:
+ return [(start_lat, start_lon), (end_lat, end_lon)]
+
+ if num_samples is None:
+ num_samples = min(int(distance / segment_length_km) + 1, 1000)
+ point_distance = np.linspace(0, distance, num_samples)
+ points = []
+ for pd in point_distance:
+ line = geod.InverseLine(start_lat, start_lon, end_lat, end_lon)
+ g_point = line.Position(pd, Geodesic.STANDARD | Geodesic.LONG_UNROLL)
+ points.append((g_point['lat2'], g_point['lon2']))
+ return points
+
+class GeodesicPolyLine(PolyLine):
+ def __init__(self, locations, min_length_km=2000, segment_length_km=1000, num_samples=None, **kwargs):
+ kwargs1 = dict(min_length_km=min_length_km, segment_length_km=segment_length_km, num_samples=num_samples)
+ assert len(locations) == 2, "A polyline must have at least two locations"
+ start, end = locations
+ geodesic_locs = sample_points_along_geodesic(start[0], start[1], end[0], end[1], **kwargs1)
+ super().__init__(geodesic_locs, **kwargs)
+
+def inject_javascript(folium_map):
+ js = """
+ document.addEventListener('DOMContentLoaded', function() {
+ map_name_1.on('click', function(e) {
+ window.state_data = e.latlng
+ });
+ });
+ """
+ folium_map.get_root().html.add_child(Element(f''))
+
+def make_map_(name="map_name", id="1"):
+ map = Map(location=BASE_LOCATION, zoom_start=1)
+ map._name, map._id = name, id
+
+ LatLngPopup().add_to(map)
+ inject_javascript(map)
+ return map
+
+def make_map(name="map_name", id="1", height=500):
+ map = make_map_(name, id)
+ fol = Folium(value=map, height=height, visible=False, elem_id='map-fol')
+ return fol
+
+def map_js():
+ return """
+ (a, textBox) => {
+ const iframeMap = document.getElementById('map-fol').getElementsByTagName('iframe')[0];
+ const latlng = iframeMap.contentWindow.state_data;
+ if (!latlng) { return; }
+ textBox = `${latlng.lat},${latlng.lng}`;
+ document.getElementById('coords-tbox').getElementsByTagName('textarea')[0].value = textBox;
+ var a = countryCoder.iso1A2Code([latlng.lng, latlng.lat]);
+ if (!a) { a = 'nan'; }
+ return [a, `${latlng.lat},${latlng.lng},${a}`];
+ }
+ """
+
+def haversine(lat1, lon1, lat2, lon2):
+ if (lat1 is None) or (lon1 is None) or (lat2 is None) or (lon2 is None):
+ return 0
+ R = 6371 # radius of the earth in km
+ dLat = radians(lat2 - lat1)
+ dLon = radians(lon2 - lon1)
+ a = (
+ sin(dLat / 2.0) ** 2
+ + cos(radians(lat1)) * cos(radians(lat2)) * sin(dLon / 2.0) ** 2
+ )
+ c = 2 * asin(sqrt(a))
+ distance = R * c
+ return distance
+
+def geoscore(d):
+ return 5000 * exp(-d / 1492.7)
+
+def compute_scores(csv_file):
+ df = pd.read_csv(csv_file)
+ if 'accuracy_country' not in df.columns:
+ print('Computing scores... (this may take a while)')
+ geocoders = rg.search([(row.true_lat, row.true_lon) for row in df.itertuples(name='Pandas')])
+ df['city'] = [geocoder['name'] for geocoder in geocoders]
+ df['area'] = [geocoder['admin2'] for geocoder in geocoders]
+ df['region'] = [geocoder['admin1'] for geocoder in geocoders]
+ df['country'] = [geocoder['cc'] for geocoder in geocoders]
+
+ df['city_val'] = df['city'].apply(lambda x: 0 if pd.isna(x) or x == 'nan' else 1)
+ df['area_val'] = df['area'].apply(lambda x: 0 if pd.isna(x) or x == 'nan' else 1)
+ df['region_val'] = df['region'].apply(lambda x: 0 if pd.isna(x) or x == 'nan' else 1)
+ df['country_val'] = df['country'].apply(lambda x: 0 if pd.isna(x) or x == 'nan' else 1)
+
+ df['distance'] = df.apply(lambda row: haversine(row['true_lat'], row['true_lon'], row['pred_lat'], row['pred_lon']), axis=1)
+ df['score'] = df.apply(lambda row: geoscore(row['distance']), axis=1)
+ df['distance_base'] = df.apply(lambda row: haversine(row['true_lat'], row['true_lon'], row['pred_lat_base'], row['pred_lon_base']), axis=1)
+ df['score_base'] = df.apply(lambda row: geoscore(row['distance_base']), axis=1)
+
+ print('Computing geocoding accuracy (base)...')
+ geocoders_base = rg.search([(row.pred_lat_base, row.pred_lon_base) for row in df.itertuples(name='Pandas')])
+ df['pred_city_base'] = [geocoder['name'] for geocoder in geocoders_base]
+ df['pred_area_base'] = [geocoder['admin2'] for geocoder in geocoders_base]
+ df['pred_region_base'] = [geocoder['admin1'] for geocoder in geocoders_base]
+ df['pred_country_base'] = [geocoder['cc'] for geocoder in geocoders_base]
+
+ df['city_hit_base'] = [df['city'].iloc[i] != 'nan' and df['pred_city_base'].iloc[i] == df['city'].iloc[i] for i in range(len(df))]
+ df['area_hit_base'] = [df['area'].iloc[i] != 'nan' and df['pred_area_base'].iloc[i] == df['area'].iloc[i] for i in range(len(df))]
+ df['region_hit_base'] = [df['region'].iloc[i] != 'nan' and df['pred_region_base'].iloc[i] == df['region'].iloc[i] for i in range(len(df))]
+ df['country_hit_base'] = [df['country'].iloc[i] != 'nan' and df['pred_country_base'].iloc[i] == df['country'].iloc[i] for i in range(len(df))]
+
+ df['accuracy_city_base'] = [(0 if df['city_val'].iloc[:i].sum() == 0 else df['city_hit_base'].iloc[:i].sum()/df['city_val'].iloc[:i].sum())*100 for i in range(len(df))]
+ df['accuracy_area_base'] = [(0 if df['area_val'].iloc[:i].sum() == 0 else df['area_hit_base'].iloc[:i].sum()/df['area_val'].iloc[:i].sum())*100 for i in range(len(df))]
+ df['accuracy_region_base'] = [(0 if df['region_val'].iloc[:i].sum() == 0 else df['region_hit_base'].iloc[:i].sum()/df['region_val'].iloc[:i].sum())*100 for i in range(len(df))]
+ df['accuracy_country_base'] = [(0 if df['country_val'].iloc[:i].sum() == 0 else df['country_hit_base'].iloc[:i].sum()/df['country_val'].iloc[:i].sum())*100 for i in range(len(df))]
+
+ print('Computing geocoding accuracy (best)...')
+ geocoders = rg.search([(row.pred_lat, row.pred_lon) for row in df.itertuples()])
+ df['pred_city'] = [geocoder['name'] for geocoder in geocoders]
+ df['pred_area'] = [geocoder['admin2'] for geocoder in geocoders]
+ df['pred_region'] = [geocoder['admin1'] for geocoder in geocoders]
+ df['pred_country'] = [geocoder['cc'] for geocoder in geocoders]
+
+ df['city_hit'] = [df['city'].iloc[i] != 'nan' and df['pred_city'].iloc[i] == df['city'].iloc[i] for i in range(len(df))]
+ df['area_hit'] = [df['area'].iloc[i] != 'nan' and df['pred_area'].iloc[i] == df['area'].iloc[i] for i in range(len(df))]
+ df['region_hit'] = [df['region'].iloc[i] != 'nan' and df['pred_region'].iloc[i] == df['region'].iloc[i] for i in range(len(df))]
+ df['country_hit'] = [df['country'].iloc[i] != 'nan' and df['pred_country'].iloc[i] == df['country'].iloc[i] for i in range(len(df))]
+
+ df['accuracy_city'] = [(0 if df['city_val'].iloc[:i].sum() == 0 else df['city_hit'].iloc[:i].sum()/df['city_val'].iloc[:i].sum())*100 for i in range(len(df))]
+ df['accuracy_area'] = [(0 if df['area_val'].iloc[:i].sum() == 0 else df['area_hit'].iloc[:i].sum()/df['area_val'].iloc[:i].sum())*100 for i in range(len(df))]
+ df['accuracy_region'] = [(0 if df['region_val'].iloc[:i].sum() == 0 else df['region_hit'].iloc[:i].sum()/df['region_val'].iloc[:i].sum())*100 for i in range(len(df))]
+ df['accuracy_country'] = [(0 if df['country_val'].iloc[:i].sum() == 0 else df['country_hit'].iloc[:i].sum()/df['country_val'].iloc[:i].sum())*100 for i in range(len(df))]
+ df.to_csv(csv_file, index=False)
+
+
+if __name__ == "__main__":
+ JSON_DATASET_DIR = 'results'
+ scheduler = CommitScheduler(
+ repo_id="osv5m/humeval",
+ repo_type="dataset",
+ folder_path=JSON_DATASET_DIR,
+ path_in_repo=f"raw_data",
+ every=2
+ )
+
+
+class Engine(object):
+ def __init__(self, image_folder, csv_file, mpl=True):
+ self.image_folder = image_folder
+ self.csv_file = csv_file
+ self.load_images_and_coordinates(csv_file)
+
+ # Initialize the score and distance lists
+ self.index = 0
+ self.stats = defaultdict(list)
+
+ # Create the figure and canvas only once
+ self.fig = plt.Figure(figsize=(10, 6))
+ self.mpl = mpl
+ if mpl:
+ self.ax = self.fig.add_subplot(1, 1, 1, projection=ccrs.PlateCarree())
+
+ self.tag = str(uuid4()) + datetime.datetime.now().strftime("__%Y_%m_%d_%H_%M_%S")
+
+ def load_images_and_coordinates(self, csv_file):
+ # Load the CSV
+ df = pd.read_csv(csv_file)
+
+ # Get the image filenames and their coordinates
+ self.images = [os.path.join(self.image_folder, f"{img_path}.jpg") for img_path in df['id'].tolist()[:]]
+ self.coordinates = df[['true_lon', 'true_lat']].values.tolist()[:]
+
+ # compute the admins
+ self.df = df
+ self.admins = self.df[['city', 'area', 'region', 'country']].values.tolist()[:]
+ self.preds = self.df[['pred_lon', 'pred_lat']].values.tolist()[:]
+
+ def isfinal(self):
+ return self.index == len(self.images)-1
+
+ def load_image(self):
+ if self.index > len(self.images)-1:
+ self.master.update_idletasks()
+ self.finish()
+
+ self.set_clock()
+ return self.images[self.index], '### ' + str(self.index + 1) + '/' + str(len(self.images))
+
+ def get_figure(self):
+ if self.mpl:
+ img_buf = io.BytesIO()
+ self.fig.savefig(img_buf, format='png', bbox_inches='tight', pad_inches=0, dpi=300)
+ pil = Image.open(img_buf)
+ self.width, self.height = pil.size
+ return pil
+ else:
+ pred_lon, pred_lat, true_lon, true_lat, click_lon, click_lat = self.info
+ map = Map(location=BASE_LOCATION, zoom_start=1)
+ map._name, map._id = 'visu', '1'
+
+ icon_star = BeautifyIcon(
+ icon='star',
+ inner_icon_style='color:red;font-size:30px;',
+ background_color='transparent',
+ border_color='transparent',
+ )
+ feature_group = FeatureGroup(name='Ground Truth')
+ Marker(
+ location=[true_lat, true_lon],
+ popup="True location",
+ icon=icon_star,
+ ).add_to(feature_group)
+ map.add_child(feature_group)
+
+ icon_square = BeautifyIcon(
+ icon_shape='rectangle-dot',
+ border_color='green',
+ border_width=10,
+ )
+ feature_group_best = FeatureGroup(name='Best Model')
+ Marker(
+ location=[pred_lat, pred_lon],
+ popup="Best Model",
+ icon=icon_square,
+ ).add_to(feature_group_best)
+ GeodesicPolyLine([[true_lat, true_lon], [pred_lat, pred_lon]], color='green').add_to(feature_group_best)
+ map.add_child(feature_group_best)
+
+ icon_circle = BeautifyIcon(
+ icon_shape='circle-dot',
+ border_color='blue',
+ border_width=10,
+ )
+ feature_group_user = FeatureGroup(name='User')
+ Marker(
+ location=[click_lat, click_lon],
+ popup="Human",
+ icon=icon_circle,
+ ).add_to(feature_group_user)
+ GeodesicPolyLine([[true_lat, true_lon], [click_lat, click_lon]], color='blue').add_to(feature_group_user)
+ map.add_child(feature_group_user)
+
+ map.add_child(LayerControl())
+
+ return map
+
+ def set_clock(self):
+ self.time = time.time()
+
+ def get_clock(self):
+ return time.time() - self.time
+
+ def mpl_style(self, pred_lon, pred_lat, true_lon, true_lat, click_lon, click_lat):
+ if self.mpl:
+ self.ax.clear()
+ self.ax.set_global()
+ self.ax.stock_img()
+ self.ax.add_feature(cfeature.COASTLINE)
+ self.ax.add_feature(cfeature.BORDERS, linestyle=':')
+
+ self.ax.plot(pred_lon, pred_lat, 'gv', transform=ccrs.Geodetic(), label='model')
+ self.ax.plot([true_lon, pred_lon], [true_lat, pred_lat], color='green', linewidth=1, transform=ccrs.Geodetic())
+ self.ax.plot(click_lon, click_lat, 'bo', transform=ccrs.Geodetic(), label='user')
+ self.ax.plot([true_lon, click_lon], [true_lat, click_lat], color='blue', linewidth=1, transform=ccrs.Geodetic())
+ self.ax.plot(true_lon, true_lat, 'rx', transform=ccrs.Geodetic(), label='g.t.')
+ legend = self.ax.legend(ncol=3, loc='lower center') #, bbox_to_anchor=(0.5, -0.15), borderaxespad=0.
+ legend.get_frame().set_alpha(None)
+ self.fig.canvas.draw()
+ else:
+ self.info = [pred_lon, pred_lat, true_lon, true_lat, click_lon, click_lat]
+
+
+ def click(self, click_lon, click_lat, country):
+ time_elapsed = self.get_clock()
+ self.stats['times'].append(time_elapsed)
+
+ # convert click_lon, click_lat to lat, lon (given that you have the borders of the image)
+ # click_lon and click_lat is in pixels
+ # lon and lat is in degrees
+ self.stats['clicked_locations'].append((click_lat, click_lon))
+ true_lon, true_lat = self.coordinates[self.index]
+ pred_lon, pred_lat = self.preds[self.index]
+ self.mpl_style(pred_lon, pred_lat, true_lon, true_lat, click_lon, click_lat)
+
+ distance = haversine(true_lat, true_lon, click_lat, click_lon)
+ score = geoscore(distance)
+ self.stats['scores'].append(score)
+ self.stats['distances'].append(distance)
+ self.stats['country'].append(int(self.admins[self.index][3] != 'nan' and country == self.admins[self.index][3]))
+
+ df = pd.DataFrame([self.get_model_average(who) for who in ['user', 'best', 'base']], columns=['who', 'GeoScore', 'Distance', 'Accuracy (country)']).round(2)
+ result_text = (f"### GeoScore: {score:.0f}, distance: {distance:.0f} km")
+
+ self.cache(self.index+1, score, distance, (click_lat, click_lon), time_elapsed)
+ return self.get_figure(), result_text, df
+
+ def next_image(self):
+ # Go to the next image
+ self.index += 1
+ return self.load_image()
+
+ def get_model_average(self, which, all=False):
+ aux, i = [], self.index+1
+ if which == 'user':
+ avg_score = sum(self.stats['scores']) / len(self.stats['scores']) if self.stats['scores'] else 0
+ avg_distance = sum(self.stats['distances']) / len(self.stats['distances']) if self.stats['distances'] else 0
+ avg_country_accuracy = (0 if self.df['country_val'].iloc[:i].sum() == 0 else sum(self.stats['country'])/self.df['country_val'].iloc[:i].sum())*100
+ if all:
+ avg_city_accuracy = (0 if self.df['city_val'].iloc[:i].sum() == 0 else sum(self.stats['city'])/self.df['city_val'].iloc[:i].sum())*100
+ avg_area_accuracy = (0 if self.df['area_val'].iloc[:i].sum() == 0 else sum(self.stats['area'])/self.df['area_val'].iloc[:i].sum())*100
+ avg_region_accuracy = (0 if self.df['region_val'].iloc[:i].sum() == 0 else sum(self.stats['region'])/self.df['region_val'].iloc[:i].sum())*100
+ aux = [avg_city_accuracy, avg_area_accuracy, avg_region_accuracy]
+ elif which == 'base':
+ avg_score = np.mean(self.df[['score_base']].iloc[:i])
+ avg_distance = np.mean(self.df[['distance_base']].iloc[:i])
+ avg_country_accuracy = self.df['accuracy_country_base'].iloc[i]
+ if all:
+ aux = [self.df['accuracy_city_base'].iloc[i], self.df['accuracy_area_base'].iloc[i], self.df['accuracy_region_base'].iloc[i]]
+ elif which == 'best':
+ avg_score = np.mean(self.df[['score']].iloc[:i])
+ avg_distance = np.mean(self.df[['distance']].iloc[:i])
+ avg_country_accuracy = self.df['accuracy_country'].iloc[i]
+ if all:
+ aux = [self.df['accuracy_city_base'].iloc[i], self.df['accuracy_area_base'].iloc[i], self.df['accuracy_region_base'].iloc[i]]
+ return [which, avg_score, avg_distance, avg_country_accuracy] + aux
+
+ def update_average_display(self):
+ # Calculate the average values
+ avg_score = sum(self.stats['scores']) / len(self.stats['scores']) if self.stats['scores'] else 0
+ avg_distance = sum(self.stats['distances']) / len(self.stats['distances']) if self.stats['distances'] else 0
+
+ # Update the text box
+ return f"GeoScore: {avg_score:.0f}, Distance: {avg_distance:.0f} km"
+
+ def finish(self):
+ clicks = rg.search(self.stats['clicked_locations'])
+ self.stats['city'] = [(int(self.admins[self.index][0] != 'nan' and click['name'] == self.admins[self.index][0])) for click in clicks]
+ self.stats['area'] = [(int(self.admins[self.index][1] != 'nan' and click['admin2'] == self.admins[self.index][1])) for click in clicks]
+ self.stats['region'] = [(int(self.admins[self.index][2] != 'nan' and click['admin1'] == self.admins[self.index][2])) for click in clicks]
+
+ df = pd.DataFrame([self.get_model_average(who, True) for who in ['user', 'best', 'base']], columns=['who', 'GeoScore', 'Distance', 'Accuracy (country)', 'Accuracy (city)', 'Accuracy (area)', 'Accuracy (region)'])
+ return df
+
+ # Function to save the game state
+ def cache(self, index, score, distance, location, time_elapsed):
+ with scheduler.lock:
+ os.makedirs(join(JSON_DATASET_DIR, self.tag), exist_ok=True)
+ with open(join(JSON_DATASET_DIR, self.tag, f'{index}.json'), 'w') as f:
+ json.dump({"lat": location[0], "lon": location[1], "time": time_elapsed, "user": self.tag}, f)
+ f.write('\n')
+
+
+if __name__ == "__main__":
+ # login with the key from secret
+ if 'csv' in os.environ:
+ csv_str = os.environ['csv']
+ with open(CSV_FILE, 'w') as f:
+ f.write(csv_str)
+
+ compute_scores(CSV_FILE)
+ import gradio as gr
+ def click(state, coords):
+ if coords == '-1' or state['clicked']:
+ return gr.update(), gr.update(), gr.update(), gr.update()
+ lat, lon, country = coords.split(',')
+ state['clicked'] = True
+ image, text, df = state['engine'].click(float(lon), float(lat), country)
+ df = df.sort_values(by='GeoScore', ascending=False)
+ return gr.update(visible=False), gr.update(value=image, visible=True), gr.update(value=text, visible=True), gr.update(value=df, visible=True)
+
+ def exit_(state):
+ if state['engine'].index > 0:
+ df = state['engine'].finish()
+ return gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(value='', visible=True), gr.update(visible=False), gr.update(visible=False), gr.update(value=df, visible=True), gr.update(value="-1", visible=False), gr.update(value=" Your stats on OSV-5M๐
", visible=True), gr.update(value="Thanks for playing โค๏ธ
", visible=True), gr.update(visible=False)
+ else:
+ return gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update()
+
+ def next_(state):
+ if state['clicked']:
+ if state['engine'].isfinal():
+ return exit_(state)
+ else:
+ image, text = state['engine'].next_image()
+ state['clicked'] = False
+ return gr.update(value=make_map_(), visible=True), gr.update(visible=False), gr.update(value=image), gr.update(value=text), gr.update(visible=False), gr.update(), gr.update(visible=False), gr.update(value="-1"), gr.update(), gr.update(), gr.update()
+ else:
+ return gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update()
+
+ def start(state):
+ # create a unique random temporary name under CACHE_DIR
+ # generate random hex and make sure it doesn't exist under CACHE_DIR
+ state['engine'] = Engine(IMAGE_FOLDER, CSV_FILE, MPL)
+ state['clicked'] = False
+ image, text = state['engine'].load_image()
+
+ return (
+ gr.update(visible=True),
+ gr.update(visible=False),
+ gr.update(value=image, visible=True),
+ gr.update(value=text, visible=True),
+ gr.update(visible=True),
+ gr.update(visible=True),
+ gr.update(value="OSV-5M (plonk)
"),
+ gr.update(visible=False),
+ gr.update(visible=False),
+ gr.update(value="-1"),
+ gr.update(visible=True),
+ )
+
+ with gr.Blocks(css=css, head=space_js) as demo:
+ state = gr.State({})
+ rules = gr.Markdown(RULES, visible=True)
+
+ exit_button = gr.Button("Exit", visible=False, elem_id='exit_btn')
+ start_button = gr.Button("Start", visible=True)
+ with gr.Row():
+ map_ = make_map(height=512)
+ if MPL:
+ results = gr.Image(label='Results', visible=False)
+ else:
+ results = Folium(height=512, visible=False)
+ image_ = gr.Image(label='Image', visible=False, height=512)
+
+ with gr.Row():
+ text = gr.Markdown("", visible=False)
+ text_count = gr.Markdown("", visible=False)
+
+ with gr.Row():
+ select_button = gr.Button("Select", elem_id='latlon_btn', visible=False)
+ next_button = gr.Button("Next", visible=False, elem_id='next')
+ perf = gr.Dataframe(value=None, visible=False)
+ text_end = gr.Markdown("", visible=False)
+
+ coords = gr.Textbox(value="-1", label="Latitude, Longitude", visible=False, elem_id='coords-tbox')
+ start_button.click(start, inputs=[state], outputs=[map_, results, image_, text_count, text, next_button, rules, state, start_button, coords, select_button])
+ select_button.click(click, inputs=[state, coords], outputs=[map_, results, text, perf], js=map_js())
+ next_button.click(next_, inputs=[state], outputs=[map_, results, image_, text_count, text, next_button, perf, coords, rules, text_end, select_button])
+ exit_button.click(exit_, inputs=[state], outputs=[map_, results, image_, text_count, text, next_button, perf, coords, rules, text_end, select_button])
+
+ demo.launch(allowed_paths=["custom.ttf"], debug=True)
diff --git a/custom.ttf b/custom.ttf
new file mode 100644
index 0000000000000000000000000000000000000000..af7c13cb4792b24b96bb4537c2e625d04c6e6fad
Binary files /dev/null and b/custom.ttf differ
diff --git a/images/1117948158689819.jpg b/images/1117948158689819.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..734962e409d8e75e2985bc7fce126834ffbf0aee
Binary files /dev/null and b/images/1117948158689819.jpg differ
diff --git a/images/1131929937219152.jpg b/images/1131929937219152.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..8b30daae3c56b11414c3038b58b2a01a2ed01f57
Binary files /dev/null and b/images/1131929937219152.jpg differ
diff --git a/images/132981045530287.jpg b/images/132981045530287.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..5b5378d263da5dbe93c4509730bbb029b7c16a29
Binary files /dev/null and b/images/132981045530287.jpg differ
diff --git a/images/1373307973052511.jpg b/images/1373307973052511.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..5be613af695aff2deb287a6c0228d8f24464b62e
Binary files /dev/null and b/images/1373307973052511.jpg differ
diff --git a/images/175745731085288.jpg b/images/175745731085288.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..835712d91b36264f77ed217317cecfb33c351ca0
Binary files /dev/null and b/images/175745731085288.jpg differ
diff --git a/images/1906611242827635.jpg b/images/1906611242827635.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..bd16abb50510f868274fa6d95bd7ef3307f3663f
Binary files /dev/null and b/images/1906611242827635.jpg differ
diff --git a/images/2569566893353047.jpg b/images/2569566893353047.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..7d209050f24d1ed89df8bc06062aa0c4c4c30aab
Binary files /dev/null and b/images/2569566893353047.jpg differ
diff --git a/images/262995582382853.jpg b/images/262995582382853.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..97069be879c030a2dfb0345ddafe20cde02d5a68
Binary files /dev/null and b/images/262995582382853.jpg differ
diff --git a/images/2688573051442365.jpg b/images/2688573051442365.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..cb00dc221091684419a4ede3e6f168935a5b180c
Binary files /dev/null and b/images/2688573051442365.jpg differ
diff --git a/images/2815113128739763.jpg b/images/2815113128739763.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..40a6b07e65ef2b4bc4a371e7f3f6f13790ee3b73
Binary files /dev/null and b/images/2815113128739763.jpg differ
diff --git a/images/2926954904217999.jpg b/images/2926954904217999.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..6e6f3184bb10eb517bcddb6c768eb57243dbb4e8
Binary files /dev/null and b/images/2926954904217999.jpg differ
diff --git a/images/296619375337754.jpg b/images/296619375337754.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..9ec1a217a08a896e81e6c42c7e63024aefc85568
Binary files /dev/null and b/images/296619375337754.jpg differ
diff --git a/images/2967574993525954.jpg b/images/2967574993525954.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..346ee0601ca0e7511cda63545af97a3ebe78417a
Binary files /dev/null and b/images/2967574993525954.jpg differ
diff --git a/images/297765091851450.jpg b/images/297765091851450.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..32648b62ca0d05ec32734add3f76a7cae5a62311
Binary files /dev/null and b/images/297765091851450.jpg differ
diff --git a/images/298997258922815.jpg b/images/298997258922815.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..983cd348f672cc3c745082719f170d692115eec2
Binary files /dev/null and b/images/298997258922815.jpg differ
diff --git a/images/312137333614311.jpg b/images/312137333614311.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..1306213ccd0e7f11632807e2016a32ee440b5c65
Binary files /dev/null and b/images/312137333614311.jpg differ
diff --git a/images/314603156759488.jpg b/images/314603156759488.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..5718cfbbbcb1db8c640a428930ceb3fa6babe204
Binary files /dev/null and b/images/314603156759488.jpg differ
diff --git a/images/316183296688571.jpg b/images/316183296688571.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..faa28f036fa55345eb244a353b0363e859f067f9
Binary files /dev/null and b/images/316183296688571.jpg differ
diff --git a/images/320045362820818.jpg b/images/320045362820818.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..c1a89bc7cd0ebddeee3bdbfd7b44b817af7cf956
Binary files /dev/null and b/images/320045362820818.jpg differ
diff --git a/images/3295650104022182.jpg b/images/3295650104022182.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..6665fc25e8aef6ccfb97af63b0bab3192a7f7df1
Binary files /dev/null and b/images/3295650104022182.jpg differ
diff --git a/images/3741052562672207.jpg b/images/3741052562672207.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..2c46073b9e7dab0c04e14b00fdac16b2924811a1
Binary files /dev/null and b/images/3741052562672207.jpg differ
diff --git a/images/374123653951353.jpg b/images/374123653951353.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..ec6498deead405d13f9998ba18d32a2927629821
Binary files /dev/null and b/images/374123653951353.jpg differ
diff --git a/images/393835759099320.jpg b/images/393835759099320.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..c74fa58bb135d2af61fdc48bcf01529b476518f7
Binary files /dev/null and b/images/393835759099320.jpg differ
diff --git a/images/4065883540137904.jpg b/images/4065883540137904.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..359651c2658a225f6d7370d137118fc74ac78022
Binary files /dev/null and b/images/4065883540137904.jpg differ
diff --git a/images/474703873606185.jpg b/images/474703873606185.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..4dc0822d4e0d3a4e5ebd5674fdcf19419b7e43c2
Binary files /dev/null and b/images/474703873606185.jpg differ
diff --git a/images/477541399978996.jpg b/images/477541399978996.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..ad8ddce1ed580e6f09bbdbb18f925633c5952afa
Binary files /dev/null and b/images/477541399978996.jpg differ
diff --git a/images/479790613361193.jpg b/images/479790613361193.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..eb860a1bb48e23aa774f67a02d4f7f1238479ee5
Binary files /dev/null and b/images/479790613361193.jpg differ
diff --git a/images/4887875507910938.jpg b/images/4887875507910938.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..ad3f6b3d0c4efc3847d5cf88f7920e04e0eb2fa8
Binary files /dev/null and b/images/4887875507910938.jpg differ
diff --git a/images/4898606693529789.jpg b/images/4898606693529789.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..d2791389c81a660444d477b570952773b48d5d76
Binary files /dev/null and b/images/4898606693529789.jpg differ
diff --git a/images/495204901603170.jpg b/images/495204901603170.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..379bfdf2a85195c8297831ad7d683bd6164e11aa
Binary files /dev/null and b/images/495204901603170.jpg differ
diff --git a/images/503058357484613.jpg b/images/503058357484613.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..2fa18d466e54acbe980e12299af0c8187f0714d1
Binary files /dev/null and b/images/503058357484613.jpg differ
diff --git a/images/509010086792207.jpg b/images/509010086792207.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..7f056483de48fea66a76f36b27f2d64586b20d01
Binary files /dev/null and b/images/509010086792207.jpg differ
diff --git a/images/517681129360654.jpg b/images/517681129360654.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..e4f0367ea894a13ce651ed7c4b8a3205e4eefe0a
Binary files /dev/null and b/images/517681129360654.jpg differ
diff --git a/images/521919388810193.jpg b/images/521919388810193.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..d73c9e15988472f0a85d352784372dca9c9db06f
Binary files /dev/null and b/images/521919388810193.jpg differ
diff --git a/images/524652062251031.jpg b/images/524652062251031.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..f9d27336688e036a211b60b44483f7f24a52222d
Binary files /dev/null and b/images/524652062251031.jpg differ
diff --git a/images/529442031384910.jpg b/images/529442031384910.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..1bfd72730bb56b59187bb6d36582d8cef94d24c1
Binary files /dev/null and b/images/529442031384910.jpg differ
diff --git a/images/537681453897872.jpg b/images/537681453897872.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..f6f817fd805d626b5b62a4f4266175073130d1c3
Binary files /dev/null and b/images/537681453897872.jpg differ
diff --git a/images/546314506564628.jpg b/images/546314506564628.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..1ddeb58229e09f510d42cf699c486f9da05164bd
Binary files /dev/null and b/images/546314506564628.jpg differ
diff --git a/images/688692811847809.jpg b/images/688692811847809.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..3fc3ecc2f52795114dfe9f69ab7aca20e56ea0e5
Binary files /dev/null and b/images/688692811847809.jpg differ
diff --git a/images/732681614433401.jpg b/images/732681614433401.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..08672f5c6bc7572ff23766b628751b4d99626490
Binary files /dev/null and b/images/732681614433401.jpg differ
diff --git a/images/743171673023530.jpg b/images/743171673023530.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..1d8fde5764ab1127c0b0c95c2c553a068b58b4e6
Binary files /dev/null and b/images/743171673023530.jpg differ
diff --git a/images/744683329529751.jpg b/images/744683329529751.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..ef60e63fcfe266c41578c48d3327da5535aefd39
Binary files /dev/null and b/images/744683329529751.jpg differ
diff --git a/images/797108350987275.jpg b/images/797108350987275.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..41c9d516c484052d3ed225a4e14ade2e18228795
Binary files /dev/null and b/images/797108350987275.jpg differ
diff --git a/images/803654143860113.jpg b/images/803654143860113.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..b71760973d1028e498416bd6dd5d57e07074a85b
Binary files /dev/null and b/images/803654143860113.jpg differ
diff --git a/images/810457353224255.jpg b/images/810457353224255.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..3b20a8da55c44c556cca8202d73789f9e1f9655b
Binary files /dev/null and b/images/810457353224255.jpg differ
diff --git a/images/827026111505364.jpg b/images/827026111505364.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..c75fb15db31792f7db761991dff3f572d6573ee0
Binary files /dev/null and b/images/827026111505364.jpg differ
diff --git a/images/900447860688305.jpg b/images/900447860688305.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..949d66fffc5ff1daca1db6992d3f1b1b675d8c47
Binary files /dev/null and b/images/900447860688305.jpg differ
diff --git a/images/920935432029696.jpg b/images/920935432029696.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..e7166615761a1904e6372dfbb548ee6e25aa0be0
Binary files /dev/null and b/images/920935432029696.jpg differ
diff --git a/images/930880641087774.jpg b/images/930880641087774.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..27faa5d59fcf73fce36f5d78308fa6c63a2637d2
Binary files /dev/null and b/images/930880641087774.jpg differ
diff --git a/images/986770098793816.jpg b/images/986770098793816.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..8d63050a04f27790647b40bc03ed72386f1b3284
Binary files /dev/null and b/images/986770098793816.jpg differ
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c49208f979467e5c39e6beb27078c2a6ea653d2f
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,7 @@
+matplotlib==3.7.1
+pandas==2.0.1
+reverse_geocoder==1.5.1
+cartopy==0.22.0
+gradio-folium=0.0.6
+folium==0.16.0
+geographiclib==2.0
\ No newline at end of file
diff --git a/teaser.png b/teaser.png
new file mode 100644
index 0000000000000000000000000000000000000000..05f62d7a2488b9616889ace8d50b84de1f5f2895
Binary files /dev/null and b/teaser.png differ