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 +![teaser.png](teaser.png) +# 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)

+
Rotating globe
+

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