Jonas Rheiner commited on
Commit
8b18a0c
Β·
1 Parent(s): 4b77aea
Files changed (41) hide show
  1. .gitignore +3 -2
  2. README.md +2 -2
  3. app.py +265 -91
  4. countries_per_continent.json +134 -0
  5. kerger-test-images/{Africa_Botswana_-24.358520377382_23.5184910801.jpg β†’ Africa_Botswana_-24.358520377382_23.5184910801_kerger.jpg} +0 -0
  6. kerger-test-images/{Africa_Kenya_-0.21870999999999_37.023791.jpg β†’ Africa_Kenya_-0.21870999999999_37.023791_kerger.jpg} +0 -0
  7. kerger-test-images/{Africa_Madagascar_-16.078452454738_46.73369803641.jpg β†’ Africa_Madagascar_-16.078452454738_46.73369803641_kerger.jpg} +0 -0
  8. kerger-test-images/{Africa_South Africa_-23.590135077274_28.785944164821.jpg β†’ Africa_South Africa_-23.590135077274_28.785944164821_kerger.jpg} +0 -0
  9. kerger-test-images/{Africa_Tanzania_-3.3676537025657_36.716512872377.jpg β†’ Africa_Tanzania_-3.3676537025657_36.716512872377_kerger.jpg} +0 -0
  10. kerger-test-images/{Africa_Uganda_1.1212866787272_33.915204986261.jpg β†’ Africa_Uganda_1.1212866787272_33.915204986261_kerger.jpg} +0 -0
  11. kerger-test-images/{Asia_Israel_31.708865303742_34.94966916063.jpg β†’ Asia_Israel_31.708865303742_34.94966916063_kerger.jpg} +0 -0
  12. kerger-test-images/{Asia_Japan_35.381304970616_134.65860211972.jpg β†’ Asia_Japan_35.381304970616_134.65860211972_kerger.jpg} +0 -0
  13. kerger-test-images/{Asia_Pakistan_24.910493840503_69.506229024537.jpg β†’ Asia_Pakistan_24.910493840503_69.506229024537_kerger.jpg} +0 -0
  14. kerger-test-images/{Asia_Russia_54.597757883015_48.163689656865.jpg β†’ Asia_Russia_54.597757883015_48.163689656865_kerger.jpg} +0 -0
  15. kerger-test-images/{Asia_Russia_56.018311493214_38.359778952407.jpg β†’ Asia_Russia_56.018311493214_38.359778952407_kerger.jpg} +0 -0
  16. kerger-test-images/{Asia_Russia_60.27835356798_29.754665851696.jpg β†’ Asia_Russia_60.27835356798_29.754665851696_kerger.jpg} +0 -0
  17. kerger-test-images/{Asia_Thailand_19.824843951089_99.694080339609.jpg β†’ Asia_Thailand_19.824843951089_99.694080339609_kerger.jpg} +0 -0
  18. kerger-test-images/{Europe_Belgium_51.458478978514_5.0658042197252.jpg β†’ Europe_Belgium_51.458478978514_5.0658042197252_kerger.jpg} +0 -0
  19. kerger-test-images/{Europe_France_46.924166211593_4.8275962064792.jpg β†’ Europe_France_46.924166211593_4.8275962064792_kerger.jpg} +0 -0
  20. kerger-test-images/{Europe_Poland_53.481455371945_14.609283831884.jpg β†’ Europe_Poland_53.481455371945_14.609283831884_kerger.jpg} +0 -0
  21. kerger-test-images/{Europe_United Kingdom_55.876583292802_-3.3883270020737.jpg β†’ Europe_United Kingdom_55.876583292802_-3.3883270020737_kerger.jpg} +0 -0
  22. kerger-test-images/{North America_United States_37.477059817448_-76.614518600673.jpg β†’ North America_United States_37.477059817448_-76.614518600673_kerger.jpg} +0 -0
  23. kerger-test-images/{North America_United States_45.624602778152_-94.568541667454.jpg β†’ North America_United States_45.624602778152_-94.568541667454_kerger.jpg} +0 -0
  24. kerger-test-images/{Oceania_Australia_-30.713709784045_151.4584204031.jpg β†’ Oceania_Australia_-30.713709784045_151.4584204031_kerger.jpg} +0 -0
  25. kerger-test-images/{Oceania_Australia_-32.947127313081_151.47903359833.jpg β†’ Oceania_Australia_-32.947127313081_151.47903359833_kerger.jpg} +0 -0
  26. kerger-test-images/{South America_Brazil_-21.715605849876_-50.736049416477.jpg β†’ South America_Brazil_-21.715605849876_-50.736049416477_kerger.jpg} +0 -0
  27. kerger-test-images/{South America_Colombia_6.7532199340218_-72.975276747858.jpg β†’ South America_Colombia_6.7532199340218_-72.975276747858_kerger.jpg} +0 -0
  28. requirements.txt +2 -2
  29. versus_images/Africa_Somaliland_9.562326_44.067363_im2gps3k.jpg +0 -0
  30. versus_images/Asia_China_22.185338_113.537693_im2gps3k.jpg +0 -0
  31. versus_images/{Asia_China_22.199246_114.1331_im2gps3k.jpg β†’ Asia_Hong Kong_22.199246_114.1331_im2gps3k.jpg} +0 -0
  32. versus_images/{Asia_China_22.220224_114.115591_im2gps3k.jpg β†’ Asia_Hong Kong_22.220224_114.115591_im2gps3k.jpg} +0 -0
  33. versus_images/{Asia_China_22.271782_114.148979_im2gps3k.jpg β†’ Asia_Hong Kong_22.271782_114.148979_im2gps3k.jpg} +0 -0
  34. versus_images/{Asia_China_22.2824_114.1464_im2gps.jpg β†’ Asia_Hong Kong_22.2824_114.1464_im2gps.jpg} +0 -0
  35. versus_images/{Asia_China_22.283457_114.170136_im2gps3k.jpg β†’ Asia_Hong Kong_22.283457_114.170136_im2gps3k.jpg} +0 -0
  36. versus_images/{Asia_China_22.2867_114.1526_im2gps.jpg β†’ Asia_Hong Kong_22.2867_114.1526_im2gps.jpg} +0 -0
  37. versus_images/{Asia_China_22.2885_114.23747_im2gps3k.jpg β†’ Asia_Hong Kong_22.2885_114.23747_im2gps3k.jpg} +0 -0
  38. versus_images/{Asia_China_22.297454_114.172539_im2gps3k.jpg β†’ Asia_Hong Kong_22.297454_114.172539_im2gps3k.jpg} +0 -0
  39. versus_images/{Asia_China_22.310061_114.252147_im2gps3k.jpg β†’ Asia_Hong Kong_22.310061_114.252147_im2gps3k.jpg} +0 -0
  40. versus_images/{Asia_China_22.319539_114.169996_im2gps3k.jpg β†’ Asia_Hong Kong_22.319539_114.169996_im2gps3k.jpg} +0 -0
  41. versus_images/{North America_United States_18.4695_-66.1198_im2gps.jpg β†’ North America_Puerto Rico_18.4695_-66.1198_im2gps.jpg} +0 -0
.gitignore CHANGED
@@ -1,3 +1,4 @@
1
  .venv/
2
- model-checkpoint/
3
- __pycache__/
 
 
1
  .venv/
2
+ model-checkpoints/**
3
+ __pycache__/
4
+ *.ipynb
README.md CHANGED
@@ -1,6 +1,6 @@
1
  ---
2
- title: Thesis Demo
3
- emoji: ⚑
4
  colorFrom: yellow
5
  colorTo: indigo
6
  sdk: gradio
 
1
  ---
2
+ title: Image Gelocation Thesis Demo
3
+ emoji: 🌍
4
  colorFrom: yellow
5
  colorTo: indigo
6
  sdk: gradio
app.py CHANGED
@@ -5,6 +5,11 @@ import torch
5
  import itertools
6
  import os
7
  import plotly.graph_objects as go
 
 
 
 
 
8
 
9
 
10
  CUDA_AVAILABLE = torch.cuda.is_available()
@@ -13,9 +18,9 @@ device = "cuda" if CUDA_AVAILABLE else "cpu"
13
  print(f"count={torch.cuda.device_count()}")
14
  print(f"current={torch.cuda.get_device_name(torch.cuda.current_device())}")
15
 
16
- continent_model = CLIPModel.from_pretrained("model-checkpoints/continent")
17
- country_model = CLIPModel.from_pretrained("model-checkpoints/country")
18
- processor = CLIPProcessor.from_pretrained("openai/clip-vit-large-patch14-336")
19
  continent_model = continent_model.to(device)
20
  country_model = country_model.to(device)
21
 
@@ -24,51 +29,161 @@ continents = ["Africa", "Asia", "Europe",
24
  "North America", "Oceania", "South America"]
25
  countries_per_continent = {
26
  "Africa": [
27
- "Algeria", "Angola", "Benin", "Botswana", "Burkina Faso", "Burundi", "Cabo Verde", "Cameroon",
28
- "Central African Republic", "Congo", "Democratic Republic of the Congo",
29
- "Djibouti", "Egypt", "Equatorial Guinea", "Eritrea", "Eswatini", "Ethiopia", "Gabon",
30
- "Gambia", "Ghana", "Guinea", "Guinea-Bissau", "Ivory Coast", "Kenya", "Lesotho", "Liberia",
31
- "Libya", "Madagascar", "Malawi", "Mali", "Mauritania", "Mauritius", "Morocco", "Mozambique",
32
- "Namibia", "Niger", "Nigeria", "Rwanda", "Sao Tome and Principe", "Senegal", "Seychelles",
33
- "Sierra Leone", "Somalia", "South Africa", "Sudan", "Tanzania", "Togo",
34
- "Tunisia", "Uganda", "Zambia", "Zimbabwe"
35
  ],
36
  "Asia": [
37
- "Afghanistan", "Armenia", "Azerbaijan", "Bahrain", "Bangladesh", "Bhutan", "Brunei",
38
- "Cambodia", "China", "Cyprus", "Georgia", "India", "Indonesia", "Iran", "Iraq",
39
- "Israel", "Japan", "Jordan", "Kazakhstan", "Kuwait", "Kyrgyzstan", "Laos", "Lebanon",
40
- "Malaysia", "Maldives", "Mongolia", "Myanmar", "Nepal", "North Korea", "Oman", "Pakistan",
41
- "Palestine", "Philippines", "Qatar", "Russia", "Saudi Arabia", "Singapore", "South Korea",
42
- "Sri Lanka", "Syria", "Taiwan", "Tajikistan", "Thailand", "Timor-Leste", "Turkey",
43
- "Turkmenistan", "United Arab Emirates", "Uzbekistan", "Vietnam", "Yemen"
44
  ],
45
  "Europe": [
46
- "Albania", "Armenia", "Austria", "Azerbaijan", "Belarus", "Belgium", "Bosnia and Herzegovina",
47
- "Bulgaria", "Croatia", "Cyprus", "Czech Republic", "Denmark", "Estonia", "Finland", "France",
48
- "Georgia", "Germany", "Greece", "Hungary", "Iceland", "Ireland", "Italy", "Kazakhstan",
49
- "Kosovo", "Latvia", "Liechtenstein", "Lithuania", "Luxembourg", "Malta", "Moldova", "Monaco",
50
- "Montenegro", "Netherlands", "North Macedonia", "Norway", "Poland", "Portugal", "Romania",
51
- "Russia", "San Marino", "Serbia", "Slovakia", "Slovenia", "Spain", "Sweden", "Switzerland",
52
- "Turkey", "Ukraine", "United Kingdom"
53
  ],
54
  "North America": [
55
- "Antigua and Barbuda", "Bahamas", "Barbados", "Belize", "Canada", "Costa Rica", "Cuba",
56
- "Dominica", "Dominican Republic", "El Salvador", "Grenada", "Guatemala", "Haiti", "Honduras",
57
- "Jamaica", "Mexico", "Nicaragua", "Panama", "Saint Kitts and Nevis", "Saint Lucia",
58
- "Saint Vincent and the Grenadines", "Trinidad and Tobago", "United States"
59
  ],
60
  "Oceania": [
61
- "Australia", "Fiji", "Kiribati", "Marshall Islands", "Micronesia", "Nauru", "New Zealand",
62
- "Palau", "Papua New Guinea", "Samoa", "Solomon Islands", "Tonga", "Tuvalu", "Vanuatu"
63
  ],
64
  "South America": [
65
- "Argentina", "Bolivia", "Brazil", "Chile", "Colombia", "Ecuador", "Guyana", "Paraguay",
66
- "Peru", "Suriname", "Uruguay", "Venezuela"
67
  ]
68
  }
69
  countries = list(set(itertools.chain.from_iterable(
70
  countries_per_continent.values())))
71
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  INTIAL_VERSUS_IMAGE = "versus_images/Europe_Germany_49.069183_10.319444_im2gps3k.jpg"
73
  INITAL_VERSUS_STATE = {
74
  "image": INTIAL_VERSUS_IMAGE,
@@ -95,8 +210,8 @@ def predict(input_img):
95
  pred_id = probs.argmax().cpu().item()
96
  continent_probs = {label: prob for label,
97
  prob in zip(continents, probs.tolist()[0])}
98
-
99
- predicted_continent_countries = countries_per_continent[continents[pred_id]]
100
  inputs = processor(text=[f"A photo from {
101
  geo}." for geo in predicted_continent_countries], images=input_img, return_tensors="pt", padding=True)
102
  inputs = inputs.to(device)
@@ -104,57 +219,93 @@ def predict(input_img):
104
  outputs = country_model(**inputs)
105
  logits_per_image = outputs.logits_per_image
106
  probs = logits_per_image.softmax(dim=-1)
 
 
107
  country_probs = {label: prob for label, prob in zip(
108
  predicted_continent_countries, probs.tolist()[0])}
109
- return continent_probs, country_probs
110
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
111
 
112
  def make_versus_map(human_country, model_country, versus_state):
 
 
 
 
 
113
  fig = go.Figure()
114
- fig.add_trace(go.Scattergeo(
115
  lon=[versus_state["lon"]],
116
  lat=[versus_state["lat"]],
117
- text=["πŸ“·"],
118
- mode='text+markers',
 
119
  hoverinfo='text',
120
- hovertext=f"Photo taken in {versus_state['country']}, {
121
- versus_state['continent']}",
122
- marker=dict(size=14, color='#00B945'),
123
- showlegend=False
124
-
125
  ))
126
  if human_country == model_country:
127
- fig.add_trace(go.Scattergeo(
128
- locations=[human_country],
129
- locationmode='country names',
130
- text=["πŸ§‘πŸ€–"],
131
- mode='text',
132
- hoverinfo='location',
133
- showlegend=False
134
-
 
135
  ))
136
  else:
137
- fig.add_trace(go.Scattergeo(
138
- locations=[human_country],
139
- locationmode='country names',
140
- text=["πŸ§‘"],
141
- mode='text',
142
- hoverinfo='location',
143
- showlegend=False
144
-
 
 
 
 
 
 
 
 
 
 
 
 
145
  ))
146
- fig.add_trace(go.Scattergeo(
147
- locations=[model_country],
148
- locationmode='country names',
149
- text=["πŸ€–"],
150
- mode='text',
151
- hoverinfo='location',
152
- showlegend=False
153
-
154
- ))
155
- fig.update_geos(
156
- visible=True, resolution=110,
157
- showcountries=True, countrycolor="grey", fitbounds="locations", projection_type="natural earth",
 
 
158
  )
159
  return fig
160
 
@@ -174,11 +325,10 @@ def versus_mode_inputs(input_img, human_continent, human_country, versus_state):
174
  continent_result = "❌"
175
  human_result = f"The photo is from **{versus_state['country']}** {
176
  country_result} in **{versus_state['continent']}** {continent_result}"
177
- human_score_update = f"+{
178
- human_points} points" if human_points > 0 else "Wrong guess, try a new image."
179
  versus_state['score']['HUMAN'] += human_points
180
 
181
- continent_probs, country_probs = predict(input_img)
182
  model_country = max(country_probs, key=country_probs.get)
183
  model_continent = max(continent_probs, key=continent_probs.get)
184
  if model_country == versus_state["country"]:
@@ -191,8 +341,7 @@ def versus_mode_inputs(input_img, human_continent, human_country, versus_state):
191
  model_points += 1
192
  else:
193
  model_continent_result = "❌"
194
- model_score_update = f"+{
195
- model_points} points" if model_points > 0 else "The model was wrong, seems the world is not yet doomed."
196
  versus_state['score']['AI'] += model_points
197
 
198
  map = make_versus_map(human_country, model_country, versus_state)
@@ -230,8 +379,30 @@ def next_versus_image(versus_state):
230
  versus_state["image"] = versus_image
231
  return versus_image, versus_state, None, None
232
 
233
- demo = gr.Blocks()
 
 
 
 
 
 
 
 
 
 
 
 
234
  with demo:
 
 
 
 
 
 
 
 
 
 
235
  with gr.Tab("Image Geolocation Demo"):
236
  with gr.Row():
237
  with gr.Column():
@@ -243,12 +414,14 @@ with demo:
243
  gr.Examples(examples=example_images,
244
  inputs=image, examples_per_page=24)
245
  with gr.Column():
246
- continents_label = gr.Label(label="Continents")
247
- country_label = gr.Label(
248
- num_top_classes=5, label="Top countries")
249
- # continents_label.select(predict_country, inputs=[image, continents_label], outputs=country_label)
 
 
250
  predict_btn.click(predict, inputs=image, outputs=[
251
- continents_label, country_label])
252
 
253
  with gr.Tab("Versus Mode"):
254
  versus_state = gr.State(value=INITAL_VERSUS_STATE)
@@ -258,8 +431,7 @@ with demo:
258
  INITAL_VERSUS_STATE["image"], interactive=False)
259
  continent_selection = gr.Radio(
260
  continents, label="Continents", info="Where was this image taken? (1 Point)")
261
- country_selection = gr.Dropdown(countries, label="Countries", info="Can you guess the exact country? (2 Points)"
262
- ),
263
  with gr.Row():
264
  next_img_btn = gr.Button("Try new image")
265
  versus_btn = gr.Button("Submit guess")
@@ -268,13 +440,15 @@ with demo:
268
  # with gr.Accordion("View Map", open=False):
269
  map = gr.Plot(label="Locations")
270
  with gr.Accordion("Full Model Output", open=False):
271
- continents_label = gr.Label(label="Continents")
272
- country_label = gr.Label(
273
- num_top_classes=5, label="Top countries")
274
- next_img_btn.click(next_versus_image, inputs=[versus_state], outputs=[versus_image, versus_state, continent_selection, country_selection[0]])
 
 
275
  versus_btn.click(versus_mode_inputs, inputs=[versus_image, continent_selection, country_selection[0], versus_state], outputs=[
276
  versus_output, continents_label, country_label, map, versus_state])
277
 
278
 
279
  if __name__ == "__main__":
280
- demo.launch()
 
5
  import itertools
6
  import os
7
  import plotly.graph_objects as go
8
+ import hashlib
9
+ from PIL import Image
10
+ import json
11
+
12
+ os.environ["PYTHONHASHSEED"] = "42"
13
 
14
 
15
  CUDA_AVAILABLE = torch.cuda.is_available()
 
18
  print(f"count={torch.cuda.device_count()}")
19
  print(f"current={torch.cuda.get_device_name(torch.cuda.current_device())}")
20
 
21
+ continent_model = CLIPModel.from_pretrained("jrheiner/thesis-clip-geoloc-continent", token=os.getenv("token"))
22
+ country_model = CLIPModel.from_pretrained("jrheiner/thesis-clip-geoloc-country", token=os.getenv("token"))
23
+ processor = CLIPProcessor.from_pretrained("jrheiner/thesis-clip-geoloc-continent", token=os.getenv("token"))
24
  continent_model = continent_model.to(device)
25
  country_model = country_model.to(device)
26
 
 
29
  "North America", "Oceania", "South America"]
30
  countries_per_continent = {
31
  "Africa": [
32
+ "Botswana", "Eswatini", "Ghana", "Kenya", "Lesotho", "Nigeria", "Senegal",
33
+ "South Africa", "Rwanda", "Uganda", "Tanzania", "Madagascar", "Djibouti",
34
+ "Mali", "Libya", "Morocco", "Somalia", "Tunisia", "Egypt", "RΓ©union"
 
 
 
 
 
35
  ],
36
  "Asia": [
37
+ "Bangladesh", "Bhutan", "Cambodia", "China", "India", "Indonesia", "Israel",
38
+ "Japan", "Jordan", "Kyrgyzstan", "Laos", "Malaysia", "Mongolia", "Nepal",
39
+ "Palestine", "Philippines", "Singapore", "South Korea", "Sri Lanka",
40
+ "Taiwan", "Thailand", "United Arab Emirates", "Vietnam", "Afghanistan",
41
+ "Azerbaijan", "Cyprus", "Iran", "Syria", "Tajikistan", "Turkey", "Russia",
42
+ "Pakistan", "Hong Kong"
 
43
  ],
44
  "Europe": [
45
+ "Albania", "Andorra", "Austria", "Belgium", "Bulgaria", "Croatia", "Czechia",
46
+ "Denmark", "Estonia", "Finland", "France", "Germany", "Greece", "Hungary",
47
+ "Iceland", "Ireland", "Italy", "Latvia", "Lithuania", "Luxembourg",
48
+ "Montenegro", "Netherlands", "North Macedonia", "Norway", "Poland",
49
+ "Portugal", "Romania", "Russia", "Serbia", "Slovakia", "Slovenia", "Spain",
50
+ "Sweden", "Switzerland", "Ukraine", "United Kingdom", "Bosnia and Herzegovina",
51
+ "Cyprus", "Turkey", "Greenland", "Faroe Islands"
52
  ],
53
  "North America": [
54
+ "Canada", "Dominican Republic", "Guatemala", "Mexico", "United States",
55
+ "Bahamas", "Cuba", "Panama", "Puerto Rico", "Bermuda", "Greenland"
 
 
56
  ],
57
  "Oceania": [
58
+ "Australia", "New Zealand", "Fiji", "Papua New Guinea", "Solomon Islands", "Vanuatu"
 
59
  ],
60
  "South America": [
61
+ "Argentina", "Bolivia", "Brazil", "Chile", "Colombia", "Ecuador", "Paraguay",
62
+ "Peru", "Uruguay"
63
  ]
64
  }
65
  countries = list(set(itertools.chain.from_iterable(
66
  countries_per_continent.values())))
67
 
68
+ country_to_center_coords = {
69
+ "Indonesia": (-2.4833826, 117.8902853),
70
+ "Egypt": (26.2540493, 29.2675469),
71
+ "Dominican Republic": (19.0974031, -70.3028026),
72
+ "Russia": (64.6863136, 97.7453061),
73
+ "Denmark": (55.670249, 10.3333283),
74
+ "Latvia": (56.8406494, 24.7537645),
75
+ "Hong Kong": (22.350627, 114.1849161),
76
+ "Brazil": (-10.3333333, -53.2),
77
+ "Turkey": (38.9597594, 34.9249653),
78
+ "Paraguay": (-23.3165935, -58.1693445),
79
+ "Nigeria": (9.6000359, 7.9999721),
80
+ "United Kingdom": (54.7023545, -3.2765753),
81
+ "Argentina": (-34.9964963, -64.9672817),
82
+ "United Arab Emirates": (24.0002488, 53.9994829),
83
+ "Estonia": (58.7523778, 25.3319078),
84
+ "Greenland": (69.6354163, -42.1736914),
85
+ "Canada": (61.0666922, -107.991707),
86
+ "Andorra": (42.5407167, 1.5732033),
87
+ "Czechia": (49.7439047, 15.3381061),
88
+ "Australia": (-24.7761086, 134.755),
89
+ "Azerbaijan": (40.3936294, 47.7872508),
90
+ "Cambodia": (12.5433216, 104.8144914),
91
+ "Peru": (-6.8699697, -75.0458515),
92
+ "Slovakia": (48.7411522, 19.4528646),
93
+ "RΓ©union": (-21.130737949999997, 55.536480112992315),
94
+ "France": (46.603354, 1.8883335),
95
+ "Israel": (30.8124247, 34.8594762),
96
+ "China": (35.000074, 104.999927),
97
+ "Ecuador": (-1.3397668, -79.3666965),
98
+ "Poland": (52.215933, 19.134422),
99
+ "Switzerland": (46.7985624, 8.2319736),
100
+ "Singapore": (1.357107, 103.8194992),
101
+ "Kenya": (1.4419683, 38.4313975),
102
+ "Bhutan": (27.549511, 90.5119273),
103
+ "Laos": (20.0171109, 103.378253),
104
+ "Vietnam": (15.9266657, 107.9650855),
105
+ "Puerto Rico": (18.2247706, -66.4858295),
106
+ "Germany": (51.1638175, 10.4478313),
107
+ "Tanzania": (-6.5247123, 35.7878438),
108
+ "Colombia": (4.099917, -72.9088133),
109
+ "Italy": (42.6384261, 12.674297),
110
+ "Bahamas": (24.7736546, -78.0000547),
111
+ "Panama": (8.559559, -81.1308434),
112
+ "Bulgaria": (42.6073975, 25.4856617),
113
+ "Solomon Islands": (-8.7053941, 159.1070693851845),
114
+ "Afghanistan": (33.7680065, 66.2385139),
115
+ "Tajikistan": (38.6281733, 70.8156541),
116
+ "Portugal": (39.6621648, -8.1353519),
117
+ "Tunisia": (36.8002068, 10.1857757),
118
+ "Bolivia": (-17.0568696, -64.9912286),
119
+ "Malaysia": (4.5693754, 102.2656823),
120
+ "Lithuania": (55.3500003, 23.7499997),
121
+ "Sweden": (59.6749712, 14.5208584),
122
+ "Belgium": (50.6402809, 4.6667145),
123
+ "Libya": (26.8234472, 18.1236723),
124
+ "Guatemala": (15.5855545, -90.345759),
125
+ "India": (22.3511148, 78.6677428),
126
+ "Sri Lanka": (7.5554942, 80.7137847),
127
+ "New Zealand": (-41.5000831, 172.8344077),
128
+ "Iceland": (64.9841821, -18.1059013),
129
+ "Somalia": (8.3676771, 49.083416),
130
+ "Croatia": (45.3658443, 15.6575209),
131
+ "Bosnia and Herzegovina": (44.3053476, 17.5961467),
132
+ "Greece": (38.9953683, 21.9877132),
133
+ "Rwanda": (-1.9646631, 30.0644358),
134
+ "Hungary": (47.1817585, 19.5060937),
135
+ "Eswatini": (-26.5624806, 31.3991317),
136
+ "Kyrgyzstan": (41.5089324, 74.724091),
137
+ "Bangladesh": (23.6943117, 90.344352),
138
+ "Morocco": (28.3347722, -10.371337908392647),
139
+ "Finland": (63.2467777, 25.9209164),
140
+ "Luxembourg": (49.6112768, 6.129799),
141
+ "North Macedonia": (41.6171214, 21.7168387),
142
+ "Uruguay": (-32.8755548, -56.0201525),
143
+ "Chile": (-31.7613365, -71.3187697),
144
+ "Spain": (39.3260685, -4.8379791),
145
+ "South Korea": (36.638392, 127.6961188),
146
+ "Botswana": (-23.1681782, 24.5928742),
147
+ "Uganda": (1.5333554, 32.2166578),
148
+ "Papua New Guinea": (-5.6816069, 144.2489081),
149
+ "Mali": (16.3700359, -2.2900239),
150
+ "Philippines": (12.7503486, 122.7312101),
151
+ "Norway": (64.5731537, 11.52803643954819),
152
+ "Thailand": (14.8971921, 100.83273),
153
+ "Mongolia": (46.8651082, 103.8347844),
154
+ "Japan": (36.5748441, 139.2394179),
155
+ "Montenegro": (42.7044223, 19.3957785),
156
+ "Austria": (47.59397, 14.12456),
157
+ "Taiwan": (23.6978, 120.9605),
158
+ "Netherlands": (52.2434979, 5.6343227),
159
+ "Ukraine": (49.4871968, 31.2718321),
160
+ "Fiji": (-18.1239696, 179.0122737),
161
+ "Ghana": (8.0300284, -1.0800271),
162
+ "Cuba": (23.0131338, -80.8328748),
163
+ "Nepal": (28.3780464, 83.9999901),
164
+ "Faroe Islands": (62.0448724, -7.0322972),
165
+ "Slovenia": (46.1199444, 14.8153333),
166
+ "Cyprus": (34.9174159, 32.889902651331866),
167
+ "Serbia": (44.024322850000004, 21.07657433209902),
168
+ "Madagascar": (-18.9249604, 46.4416422),
169
+ "Pakistan": (30.3308401, 71.247499),
170
+ "Syria": (34.6401861, 39.0494106),
171
+ "Iran": (32.6475314, 54.5643516),
172
+ "Ireland": (52.865196, -7.9794599),
173
+ "South Africa": (-28.8166236, 24.991639),
174
+ "Albania": (41.1529058, 20.1605717),
175
+ "Lesotho": (-29.6039267, 28.3350193),
176
+ "Romania": (45.9852129, 24.6859225),
177
+ "Palestine": (31.947351, 35.227163),
178
+ "Vanuatu": (-16.5255069, 168.1069154),
179
+ "Mexico": (19.4326296, -99.1331785),
180
+ "Jordan": (31.279862, 37.1297454),
181
+ "Djibouti": (11.8145966, 42.8453061),
182
+ "Senegal": (14.4750607, -14.4529612),
183
+ "Bermuda": (32.3040273, -64.7563086),
184
+ "United States": (39.7837304, -100.445882)
185
+ }
186
+
187
  INTIAL_VERSUS_IMAGE = "versus_images/Europe_Germany_49.069183_10.319444_im2gps3k.jpg"
188
  INITAL_VERSUS_STATE = {
189
  "image": INTIAL_VERSUS_IMAGE,
 
210
  pred_id = probs.argmax().cpu().item()
211
  continent_probs = {label: prob for label,
212
  prob in zip(continents, probs.tolist()[0])}
213
+ model_continent = continents[pred_id]
214
+ predicted_continent_countries = countries_per_continent[model_continent]
215
  inputs = processor(text=[f"A photo from {
216
  geo}." for geo in predicted_continent_countries], images=input_img, return_tensors="pt", padding=True)
217
  inputs = inputs.to(device)
 
219
  outputs = country_model(**inputs)
220
  logits_per_image = outputs.logits_per_image
221
  probs = logits_per_image.softmax(dim=-1)
222
+ pred_id = probs.argmax().cpu().item()
223
+ model_country = predicted_continent_countries[pred_id]
224
  country_probs = {label: prob for label, prob in zip(
225
  predicted_continent_countries, probs.tolist()[0])}
226
+
227
+ hash = hashlib.sha1(np.asarray(input_img).data.tobytes()).hexdigest()
228
+ metadata_block = gr.Accordion(visible=False)
229
+ metadata_map = None
230
+ if hash in EXAMPLE_METADATA.keys():
231
+ model_result = ""
232
+ if model_continent == EXAMPLE_METADATA[hash]['continent'] and model_country == EXAMPLE_METADATA[hash]['country']:
233
+ model_result = "The AI πŸ€– correctly guessed continent and country βœ… βœ…."
234
+ elif model_continent == EXAMPLE_METADATA[hash]['continent']:
235
+ model_result = "The AI πŸ€– only guessed the correct continent ❌ βœ…."
236
+ elif model_country == EXAMPLE_METADATA[hash]['country'] and model_continent != EXAMPLE_METADATA[hash]['continent']:
237
+ model_result = "The AI πŸ€– only guessed the correct country βœ… ❌."
238
+ else:
239
+ model_result = "The AI πŸ€– failed to guess country and continent ❌ ❌."
240
+ metadata_block = gr.Accordion(visible=True, label=f"This photo was taken in {EXAMPLE_METADATA[hash]['country']}, {EXAMPLE_METADATA[hash]['continent']}.\n{model_result}")
241
+ metadata_map = make_versus_map(None, model_country, EXAMPLE_METADATA[hash])
242
+ return continent_probs, country_probs, metadata_block, metadata_map
243
 
244
  def make_versus_map(human_country, model_country, versus_state):
245
+ if human_country:
246
+ human_coordinates = country_to_center_coords[human_country]
247
+ else:
248
+ human_coordinates = (None, None)
249
+ model_coordinates = country_to_center_coords[model_country]
250
  fig = go.Figure()
251
+ fig.add_trace(go.Scattermapbox(
252
  lon=[versus_state["lon"]],
253
  lat=[versus_state["lat"]],
254
+ text=[f"πŸ“· Photo taken in {versus_state['country']}, {
255
+ versus_state['continent']}"],
256
+ mode='markers',
257
  hoverinfo='text',
258
+ marker=dict(size=14, color='#0C5DA5'),
259
+ showlegend=True,
260
+ name="πŸ“· Photo Location"
 
 
261
  ))
262
  if human_country == model_country:
263
+ fig.add_trace(go.Scattermapbox(
264
+ lat=[human_coordinates[0], model_coordinates[0]],
265
+ lon=[human_coordinates[1], model_coordinates[1]],
266
+ text=f"πŸ§‘ πŸ€– Human & AI guess {human_country}",
267
+ mode='markers',
268
+ hoverinfo='text',
269
+ marker=dict(size=14, color='#FF9500'),
270
+ showlegend=True,
271
+ name="πŸ§‘ πŸ€– Human & AI Guess"
272
  ))
273
  else:
274
+ if human_country:
275
+ fig.add_trace(go.Scattermapbox(
276
+ lat=[human_coordinates[0]],
277
+ lon=[human_coordinates[1]],
278
+ text=[f"πŸ§‘ Human guesses {human_country}"],
279
+ mode='markers',
280
+ hoverinfo='text',
281
+ marker=dict(size=14, color='#FF9500'),
282
+ showlegend=True,
283
+ name="πŸ§‘ Human Guess"
284
+ ))
285
+ fig.add_trace(go.Scattermapbox(
286
+ lat=[model_coordinates[0]],
287
+ lon=[model_coordinates[1]],
288
+ text=[f"πŸ€– AI guesses {model_country}"],
289
+ mode='markers',
290
+ hoverinfo='text',
291
+ marker=dict(size=14, color='#474747'),
292
+ showlegend=True,
293
+ name="πŸ€– AI Guess"
294
  ))
295
+
296
+ fig.update_layout(
297
+ mapbox=dict(
298
+ style="carto-positron",
299
+ center=dict(lat=float(versus_state["lat"]), lon=float(versus_state["lon"])),
300
+ zoom=2
301
+ ),
302
+ margin={"r": 0, "t": 0, "l": 0, "b": 0},
303
+ legend=dict(
304
+ yanchor="bottom",
305
+ y=0.01,
306
+ xanchor="left",
307
+ x=0.01
308
+ )
309
  )
310
  return fig
311
 
 
325
  continent_result = "❌"
326
  human_result = f"The photo is from **{versus_state['country']}** {
327
  country_result} in **{versus_state['continent']}** {continent_result}"
328
+ human_score_update = f"+{human_points} points" if human_points > 0 else "0 Points..."
 
329
  versus_state['score']['HUMAN'] += human_points
330
 
331
+ continent_probs, country_probs, _,_ = predict(input_img)
332
  model_country = max(country_probs, key=country_probs.get)
333
  model_continent = max(continent_probs, key=continent_probs.get)
334
  if model_country == versus_state["country"]:
 
341
  model_points += 1
342
  else:
343
  model_continent_result = "❌"
344
+ model_score_update = f"+{model_points} points" if model_points > 0 else "0 Points... The model was completely wrong, it seems the world is not doomed yet."
 
345
  versus_state['score']['AI'] += model_points
346
 
347
  map = make_versus_map(human_country, model_country, versus_state)
 
379
  versus_state["image"] = versus_image
380
  return versus_image, versus_state, None, None
381
 
382
+
383
+ example_images = get_example_images("kerger-test-images")
384
+ EXAMPLE_METADATA = {}
385
+ for img_path in example_images:
386
+ hash = hashlib.sha1(np.asarray(Image.open(img_path)).data.tobytes()).hexdigest()
387
+ EXAMPLE_METADATA[hash] = {
388
+ "continent": img_path.split("/")[-1].split("_")[0],
389
+ "country": img_path.split("/")[-1].split("_")[1],
390
+ "lat": img_path.split("/")[-1].split("_")[2],
391
+ "lon": img_path.split("/")[-1].split("_")[3],
392
+ }
393
+
394
+ demo = gr.Blocks(title="Thesis Demo")
395
  with demo:
396
+ gr.HTML("""
397
+ <h1 style="text-align: center; margin-bottom: 1rem">Image Geolocation Thesis Demo</h1>
398
+
399
+ <h3> This Demo showcases the developed models and allows interacting with the optimized prototype.</h3>
400
+ <p>Try the <b>"Image Geolocation Demo"</b> tab with your own images or with one of the examples. For all example image the ground truth is available and will be displayed together with the model predictions.</p>
401
+ <p>In the <b>"Versus Mode"</b> tab to play against the AI, guessing the country and continent where images where taken. Images in the versus mode are from the <a href="http://graphics.cs.cmu.edu/projects/im2gps/"><code>Im2GPS</code></a> and <a href="https://arxiv.org/abs/1705.04838"><code>Im2GPS3k</code></a> geolocation literature benchmarks. Can you beat the AI?
402
+
403
+ """)
404
+ with gr.Accordion(label="The demo currently encompasses 116 countries from 6 continents 🌍", open=False):
405
+ gr.Code(json.dumps(countries_per_continent, indent=2, ensure_ascii=False), label="countries_per_continent.json", language="json", interactive=False)
406
  with gr.Tab("Image Geolocation Demo"):
407
  with gr.Row():
408
  with gr.Column():
 
414
  gr.Examples(examples=example_images,
415
  inputs=image, examples_per_page=24)
416
  with gr.Column():
417
+ with gr.Accordion(visible=False) as metadata_block:
418
+ map = gr.Plot(label="Locations")
419
+ with gr.Group():
420
+ continents_label = gr.Label(label="Continents")
421
+ country_label = gr.Label(
422
+ num_top_classes=5, label="Top countries")
423
  predict_btn.click(predict, inputs=image, outputs=[
424
+ continents_label, country_label, metadata_block, map])
425
 
426
  with gr.Tab("Versus Mode"):
427
  versus_state = gr.State(value=INITAL_VERSUS_STATE)
 
431
  INITAL_VERSUS_STATE["image"], interactive=False)
432
  continent_selection = gr.Radio(
433
  continents, label="Continents", info="Where was this image taken? (1 Point)")
434
+ country_selection = gr.Dropdown(countries, label="Countries", info="Can you guess the exact country? (2 Points)"),
 
435
  with gr.Row():
436
  next_img_btn = gr.Button("Try new image")
437
  versus_btn = gr.Button("Submit guess")
 
440
  # with gr.Accordion("View Map", open=False):
441
  map = gr.Plot(label="Locations")
442
  with gr.Accordion("Full Model Output", open=False):
443
+ with gr.Group():
444
+ continents_label = gr.Label(label="Continents")
445
+ country_label = gr.Label(
446
+ num_top_classes=5, label="Top countries")
447
+ next_img_btn.click(next_versus_image, inputs=[versus_state], outputs=[
448
+ versus_image, versus_state, continent_selection, country_selection[0]])
449
  versus_btn.click(versus_mode_inputs, inputs=[versus_image, continent_selection, country_selection[0], versus_state], outputs=[
450
  versus_output, continents_label, country_label, map, versus_state])
451
 
452
 
453
  if __name__ == "__main__":
454
+ demo.launch(show_api=False)
countries_per_continent.json ADDED
@@ -0,0 +1,134 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "Africa": [
3
+ "Botswana",
4
+ "Eswatini",
5
+ "Ghana",
6
+ "Kenya",
7
+ "Lesotho",
8
+ "Nigeria",
9
+ "Senegal",
10
+ "South Africa",
11
+ "Rwanda",
12
+ "Uganda",
13
+ "Tanzania",
14
+ "Madagascar",
15
+ "Djibouti",
16
+ "Mali",
17
+ "Libya",
18
+ "Morocco",
19
+ "Somalia",
20
+ "Tunisia",
21
+ "Egypt",
22
+ "RΓ©union"
23
+ ],
24
+ "Asia": [
25
+ "Bangladesh",
26
+ "Bhutan",
27
+ "Cambodia",
28
+ "China",
29
+ "India",
30
+ "Indonesia",
31
+ "Israel",
32
+ "Japan",
33
+ "Jordan",
34
+ "Kyrgyzstan",
35
+ "Laos",
36
+ "Malaysia",
37
+ "Mongolia",
38
+ "Nepal",
39
+ "Palestine",
40
+ "Philippines",
41
+ "Singapore",
42
+ "South Korea",
43
+ "Sri Lanka",
44
+ "Taiwan",
45
+ "Thailand",
46
+ "United Arab Emirates",
47
+ "Vietnam",
48
+ "Afghanistan",
49
+ "Azerbaijan",
50
+ "Cyprus",
51
+ "Iran",
52
+ "Syria",
53
+ "Tajikistan",
54
+ "Turkey",
55
+ "Russia",
56
+ "Pakistan",
57
+ "Hong Kong"
58
+ ],
59
+ "Europe": [
60
+ "Albania",
61
+ "Andorra",
62
+ "Austria",
63
+ "Belgium",
64
+ "Bulgaria",
65
+ "Croatia",
66
+ "Czechia",
67
+ "Denmark",
68
+ "Estonia",
69
+ "Finland",
70
+ "France",
71
+ "Germany",
72
+ "Greece",
73
+ "Hungary",
74
+ "Iceland",
75
+ "Ireland",
76
+ "Italy",
77
+ "Latvia",
78
+ "Lithuania",
79
+ "Luxembourg",
80
+ "Montenegro",
81
+ "Netherlands",
82
+ "North Macedonia",
83
+ "Norway",
84
+ "Poland",
85
+ "Portugal",
86
+ "Romania",
87
+ "Russia",
88
+ "Serbia",
89
+ "Slovakia",
90
+ "Slovenia",
91
+ "Spain",
92
+ "Sweden",
93
+ "Switzerland",
94
+ "Ukraine",
95
+ "United Kingdom",
96
+ "Bosnia and Herzegovina",
97
+ "Cyprus",
98
+ "Turkey",
99
+ "Greenland",
100
+ "Faroe Islands"
101
+ ],
102
+ "North America": [
103
+ "Canada",
104
+ "Dominican Republic",
105
+ "Guatemala",
106
+ "Mexico",
107
+ "United States",
108
+ "Bahamas",
109
+ "Cuba",
110
+ "Panama",
111
+ "Puerto Rico",
112
+ "Bermuda",
113
+ "Greenland"
114
+ ],
115
+ "Oceania": [
116
+ "Australia",
117
+ "New Zealand",
118
+ "Fiji",
119
+ "Papua New Guinea",
120
+ "Solomon Islands",
121
+ "Vanuatu"
122
+ ],
123
+ "South America": [
124
+ "Argentina",
125
+ "Bolivia",
126
+ "Brazil",
127
+ "Chile",
128
+ "Colombia",
129
+ "Ecuador",
130
+ "Paraguay",
131
+ "Peru",
132
+ "Uruguay"
133
+ ]
134
+ }
kerger-test-images/{Africa_Botswana_-24.358520377382_23.5184910801.jpg β†’ Africa_Botswana_-24.358520377382_23.5184910801_kerger.jpg} RENAMED
File without changes
kerger-test-images/{Africa_Kenya_-0.21870999999999_37.023791.jpg β†’ Africa_Kenya_-0.21870999999999_37.023791_kerger.jpg} RENAMED
File without changes
kerger-test-images/{Africa_Madagascar_-16.078452454738_46.73369803641.jpg β†’ Africa_Madagascar_-16.078452454738_46.73369803641_kerger.jpg} RENAMED
File without changes
kerger-test-images/{Africa_South Africa_-23.590135077274_28.785944164821.jpg β†’ Africa_South Africa_-23.590135077274_28.785944164821_kerger.jpg} RENAMED
File without changes
kerger-test-images/{Africa_Tanzania_-3.3676537025657_36.716512872377.jpg β†’ Africa_Tanzania_-3.3676537025657_36.716512872377_kerger.jpg} RENAMED
File without changes
kerger-test-images/{Africa_Uganda_1.1212866787272_33.915204986261.jpg β†’ Africa_Uganda_1.1212866787272_33.915204986261_kerger.jpg} RENAMED
File without changes
kerger-test-images/{Asia_Israel_31.708865303742_34.94966916063.jpg β†’ Asia_Israel_31.708865303742_34.94966916063_kerger.jpg} RENAMED
File without changes
kerger-test-images/{Asia_Japan_35.381304970616_134.65860211972.jpg β†’ Asia_Japan_35.381304970616_134.65860211972_kerger.jpg} RENAMED
File without changes
kerger-test-images/{Asia_Pakistan_24.910493840503_69.506229024537.jpg β†’ Asia_Pakistan_24.910493840503_69.506229024537_kerger.jpg} RENAMED
File without changes
kerger-test-images/{Asia_Russia_54.597757883015_48.163689656865.jpg β†’ Asia_Russia_54.597757883015_48.163689656865_kerger.jpg} RENAMED
File without changes
kerger-test-images/{Asia_Russia_56.018311493214_38.359778952407.jpg β†’ Asia_Russia_56.018311493214_38.359778952407_kerger.jpg} RENAMED
File without changes
kerger-test-images/{Asia_Russia_60.27835356798_29.754665851696.jpg β†’ Asia_Russia_60.27835356798_29.754665851696_kerger.jpg} RENAMED
File without changes
kerger-test-images/{Asia_Thailand_19.824843951089_99.694080339609.jpg β†’ Asia_Thailand_19.824843951089_99.694080339609_kerger.jpg} RENAMED
File without changes
kerger-test-images/{Europe_Belgium_51.458478978514_5.0658042197252.jpg β†’ Europe_Belgium_51.458478978514_5.0658042197252_kerger.jpg} RENAMED
File without changes
kerger-test-images/{Europe_France_46.924166211593_4.8275962064792.jpg β†’ Europe_France_46.924166211593_4.8275962064792_kerger.jpg} RENAMED
File without changes
kerger-test-images/{Europe_Poland_53.481455371945_14.609283831884.jpg β†’ Europe_Poland_53.481455371945_14.609283831884_kerger.jpg} RENAMED
File without changes
kerger-test-images/{Europe_United Kingdom_55.876583292802_-3.3883270020737.jpg β†’ Europe_United Kingdom_55.876583292802_-3.3883270020737_kerger.jpg} RENAMED
File without changes
kerger-test-images/{North America_United States_37.477059817448_-76.614518600673.jpg β†’ North America_United States_37.477059817448_-76.614518600673_kerger.jpg} RENAMED
File without changes
kerger-test-images/{North America_United States_45.624602778152_-94.568541667454.jpg β†’ North America_United States_45.624602778152_-94.568541667454_kerger.jpg} RENAMED
File without changes
kerger-test-images/{Oceania_Australia_-30.713709784045_151.4584204031.jpg β†’ Oceania_Australia_-30.713709784045_151.4584204031_kerger.jpg} RENAMED
File without changes
kerger-test-images/{Oceania_Australia_-32.947127313081_151.47903359833.jpg β†’ Oceania_Australia_-32.947127313081_151.47903359833_kerger.jpg} RENAMED
File without changes
kerger-test-images/{South America_Brazil_-21.715605849876_-50.736049416477.jpg β†’ South America_Brazil_-21.715605849876_-50.736049416477_kerger.jpg} RENAMED
File without changes
kerger-test-images/{South America_Colombia_6.7532199340218_-72.975276747858.jpg β†’ South America_Colombia_6.7532199340218_-72.975276747858_kerger.jpg} RENAMED
File without changes
requirements.txt CHANGED
@@ -2,5 +2,5 @@ numpy
2
  gradio
3
  transformers
4
  torch
5
- itertools
6
- os
 
2
  gradio
3
  transformers
4
  torch
5
+ plotly
6
+ pillow
versus_images/Africa_Somaliland_9.562326_44.067363_im2gps3k.jpg DELETED
Binary file (46.2 kB)
 
versus_images/Asia_China_22.185338_113.537693_im2gps3k.jpg DELETED
Binary file (99 kB)
 
versus_images/{Asia_China_22.199246_114.1331_im2gps3k.jpg β†’ Asia_Hong Kong_22.199246_114.1331_im2gps3k.jpg} RENAMED
File without changes
versus_images/{Asia_China_22.220224_114.115591_im2gps3k.jpg β†’ Asia_Hong Kong_22.220224_114.115591_im2gps3k.jpg} RENAMED
File without changes
versus_images/{Asia_China_22.271782_114.148979_im2gps3k.jpg β†’ Asia_Hong Kong_22.271782_114.148979_im2gps3k.jpg} RENAMED
File without changes
versus_images/{Asia_China_22.2824_114.1464_im2gps.jpg β†’ Asia_Hong Kong_22.2824_114.1464_im2gps.jpg} RENAMED
File without changes
versus_images/{Asia_China_22.283457_114.170136_im2gps3k.jpg β†’ Asia_Hong Kong_22.283457_114.170136_im2gps3k.jpg} RENAMED
File without changes
versus_images/{Asia_China_22.2867_114.1526_im2gps.jpg β†’ Asia_Hong Kong_22.2867_114.1526_im2gps.jpg} RENAMED
File without changes
versus_images/{Asia_China_22.2885_114.23747_im2gps3k.jpg β†’ Asia_Hong Kong_22.2885_114.23747_im2gps3k.jpg} RENAMED
File without changes
versus_images/{Asia_China_22.297454_114.172539_im2gps3k.jpg β†’ Asia_Hong Kong_22.297454_114.172539_im2gps3k.jpg} RENAMED
File without changes
versus_images/{Asia_China_22.310061_114.252147_im2gps3k.jpg β†’ Asia_Hong Kong_22.310061_114.252147_im2gps3k.jpg} RENAMED
File without changes
versus_images/{Asia_China_22.319539_114.169996_im2gps3k.jpg β†’ Asia_Hong Kong_22.319539_114.169996_im2gps3k.jpg} RENAMED
File without changes
versus_images/{North America_United States_18.4695_-66.1198_im2gps.jpg β†’ North America_Puerto Rico_18.4695_-66.1198_im2gps.jpg} RENAMED
File without changes