muk42 commited on
Commit
d077224
·
1 Parent(s): f2387b1

split map logic; add osm output

Browse files
inference_tab/inference_logic.py CHANGED
@@ -616,6 +616,13 @@ def fuzzyMatch(score_th,tile_dict):
616
  RES_PATH=os.path.join(OUTPUT_DIR,f"street_matches_tile{tile_number}.csv")
617
  results_df.to_csv(RES_PATH, index=False)
618
 
 
 
 
 
 
 
 
619
  # remove street labels from blobs folder that are more than or equal to score threshold
620
  manual_df = results_df[results_df['osm_match_score'] >= int(score_th)]
621
 
@@ -630,4 +637,4 @@ def fuzzyMatch(score_th,tile_dict):
630
  if os.path.exists(margin_path):
631
  os.remove(margin_path)
632
 
633
- yield f"{RES_PATH}"
 
616
  RES_PATH=os.path.join(OUTPUT_DIR,f"street_matches_tile{tile_number}.csv")
617
  results_df.to_csv(RES_PATH, index=False)
618
 
619
+ # NEW: Save OSM shapefile export as CSV
620
+ OSM_CSV_PATH = os.path.join(OUTPUT_DIR, f"osm_extract_tile{tile_number}.csv")
621
+ osm_export_df = osm_gdf[["name", "geometry"]].copy()
622
+ # convert geometry to WKT for CSV storage
623
+ osm_export_df["geometry"] = osm_export_df["geometry"].apply(lambda g: g.wkt)
624
+ osm_export_df.to_csv(OSM_CSV_PATH, index=False)
625
+
626
  # remove street labels from blobs folder that are more than or equal to score threshold
627
  manual_df = results_df[results_df['osm_match_score'] >= int(score_th)]
628
 
 
637
  if os.path.exists(margin_path):
638
  os.remove(margin_path)
639
 
640
+ yield f"Saved results: {RES_PATH}, {OSM_CSV_PATH}"
map_tab/map_logic.py CHANGED
@@ -0,0 +1,156 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import folium
3
+ from folium.raster_layers import ImageOverlay
4
+ from geopy.geocoders import Nominatim
5
+ import rasterio
6
+ import numpy as np
7
+ from matplotlib import cm, colors
8
+ import pandas as pd
9
+ import pyproj
10
+ import matplotlib.pyplot as plt
11
+ from branca.colormap import linear
12
+ from config import OUTPUT_DIR
13
+
14
+ CELL_SIZE_M = 100 # meters
15
+
16
+
17
+ def export_georeferenced_png(raster_path, png_path):
18
+ """Export the raster to a georeferenced PNG that aligns with Folium ImageOverlay."""
19
+ with rasterio.open(raster_path) as src:
20
+ arr = src.read()
21
+ if arr.shape[0] >= 3:
22
+ img = arr[:3].transpose(1, 2, 0) # (H, W, RGB)
23
+ else:
24
+ img = arr[0]
25
+ bounds = src.bounds
26
+
27
+ plt.imshow(img, extent=[bounds.left, bounds.right, bounds.bottom, bounds.top])
28
+ plt.axis("off")
29
+ plt.savefig(png_path, bbox_inches="tight", pad_inches=0, transparent=True)
30
+ plt.close()
31
+
32
+
33
+ def make_map(city, show_grid, show_georef):
34
+ city = city.strip()
35
+ if not city:
36
+ return "Please enter a city"
37
+
38
+ geolocator = Nominatim(
39
+ user_agent="histOSM_gradioAPP (maria.u.kuznetsova@gmail.com)",
40
+ timeout=10
41
+ )
42
+ loc = geolocator.geocode(city)
43
+ if loc is None:
44
+ return f"Could not find '{city}'"
45
+
46
+ m = folium.Map(location=[loc.latitude, loc.longitude], zoom_start=12)
47
+
48
+ raster_path = os.path.join(OUTPUT_DIR, "georeferenced.tif")
49
+ if not os.path.exists(raster_path):
50
+ return "Georeferenced raster not found"
51
+
52
+ with rasterio.open(raster_path) as src:
53
+ bounds = src.bounds
54
+ crs = src.crs
55
+
56
+ xmin, ymin, xmax, ymax = bounds
57
+ transformer = pyproj.Transformer.from_crs(crs, "EPSG:4326", always_xy=True)
58
+
59
+ # Convert raster bounds to lat/lon
60
+ lon0, lat0 = transformer.transform(xmin, ymin)
61
+ lon1, lat1 = transformer.transform(xmax, ymax)
62
+ lat_min, lat_max = sorted([lat0, lat1])
63
+ lon_min, lon_max = sorted([lon0, lon1])
64
+
65
+ # Overlay raster if requested
66
+ if show_georef:
67
+ raster_img_path = os.path.join(OUTPUT_DIR, "georeferenced_rgba.png")
68
+ if not os.path.exists(raster_img_path):
69
+ export_georeferenced_png(raster_path, raster_img_path)
70
+
71
+ ImageOverlay(
72
+ image=raster_img_path,
73
+ bounds=[[lat_min, lon_min], [lat_max, lon_max]],
74
+ opacity=0.85,
75
+ interactive=True,
76
+ ).add_to(m)
77
+
78
+ # Debug markers
79
+ folium.Marker([loc.latitude, loc.longitude], tooltip="City center").add_to(m)
80
+ cx, cy = (xmin + xmax) / 2, (ymin + ymax) / 2
81
+ clon, clat = transformer.transform(cx, cy)
82
+ folium.Marker([clat, clon], tooltip="Raster center").add_to(m)
83
+
84
+ # Grid overlay
85
+ if show_grid:
86
+ _add_grid_overlay(m, transformer)
87
+
88
+ return m._repr_html_()
89
+
90
+
91
+ def _add_grid_overlay(m, transformer):
92
+ grid_values = []
93
+
94
+ for fname in os.listdir(OUTPUT_DIR):
95
+ if fname.startswith("street_matches_tile") and fname.endswith(".csv"):
96
+ df = pd.read_csv(os.path.join(OUTPUT_DIR, fname))
97
+ if df.empty:
98
+ continue
99
+
100
+ tile_xmin, tile_xmax = df['x'].min(), df['x'].max()
101
+ tile_ymin, tile_ymax = df['y'].min(), df['y'].max()
102
+ n_cols = int(np.ceil((tile_xmax - tile_xmin) / CELL_SIZE_M))
103
+ n_rows = int(np.ceil((tile_ymax - tile_ymin) / CELL_SIZE_M))
104
+
105
+ grid = np.zeros((n_rows, n_cols))
106
+ counts = np.zeros((n_rows, n_cols))
107
+
108
+ for _, row in df.iterrows():
109
+ col = int((row['x'] - tile_xmin) // CELL_SIZE_M)
110
+ row_idx = int((row['y'] - tile_ymin) // CELL_SIZE_M)
111
+ if 0 <= col < n_cols and 0 <= row_idx < n_rows:
112
+ grid[row_idx, col] += row['osm_match_score']
113
+ counts[row_idx, col] += 1
114
+
115
+ mask = counts > 0
116
+ grid[mask] /= counts[mask]
117
+ grid_values.append((grid, tile_xmin, tile_ymin, n_rows, n_cols))
118
+
119
+ if not grid_values:
120
+ return
121
+
122
+ all_scores = np.concatenate([g[0].flatten() for g in grid_values])
123
+ min_val, max_val = all_scores.min(), all_scores.max()
124
+ if min_val == max_val:
125
+ max_val = min_val + 1e-6
126
+
127
+ cmap = cm.get_cmap("Reds")
128
+ colormap = linear.Reds_09.scale(min_val, max_val)
129
+ colormap.caption = "Average OSM Match Score"
130
+ colormap.add_to(m)
131
+
132
+ for grid, tile_xmin, tile_ymin, n_rows, n_cols in grid_values:
133
+ for r in range(n_rows):
134
+ for c in range(n_cols):
135
+ val = grid[r, c]
136
+ if val <= 0:
137
+ continue
138
+ norm_val = (val - min_val) / (max_val - min_val)
139
+ color = colors.to_hex(cmap(norm_val))
140
+ x0 = tile_xmin + c * CELL_SIZE_M
141
+ y0 = tile_ymin + r * CELL_SIZE_M
142
+ x1 = x0 + CELL_SIZE_M
143
+ y1 = y0 + CELL_SIZE_M
144
+ lon0, lat0 = transformer.transform(x0, y0)
145
+ lon1, lat1 = transformer.transform(x1, y1)
146
+ lat_min, lat_max = sorted([lat0, lat1])
147
+ lon_min, lon_max = sorted([lon0, lon1])
148
+ folium.Rectangle(
149
+ bounds=[[lat_min, lon_min], [lat_max, lon_max]],
150
+ color=None,
151
+ weight=0,
152
+ fill=True,
153
+ fill_color=color,
154
+ fill_opacity=0.7,
155
+ popup=f"{val:.2f}",
156
+ ).add_to(m)
map_tab/map_setup.py CHANGED
@@ -1,160 +1,5 @@
1
- import os
2
  import gradio as gr
3
- import folium
4
- from folium.raster_layers import ImageOverlay
5
- from geopy.geocoders import Nominatim
6
- import rasterio
7
- import numpy as np
8
- from matplotlib import cm, colors
9
- import pandas as pd
10
- import pyproj
11
- import matplotlib.pyplot as plt
12
- from config import OUTPUT_DIR
13
- from branca.colormap import linear
14
-
15
- CELL_SIZE_M = 100 # meters
16
-
17
-
18
- def export_georeferenced_png(raster_path, png_path):
19
- """
20
- Export the raster to a georeferenced PNG
21
- that aligns with Folium ImageOverlay.
22
- """
23
- with rasterio.open(raster_path) as src:
24
- # Read all bands (or just 1 if grayscale)
25
- arr = src.read()
26
-
27
- # Handle RGB or single-band case
28
- if arr.shape[0] >= 3:
29
- img = arr[:3].transpose(1, 2, 0) # (H, W, RGB)
30
- else:
31
- img = arr[0]
32
-
33
- bounds = src.bounds
34
-
35
- plt.imshow(img, extent=[bounds.left, bounds.right, bounds.bottom, bounds.top])
36
- plt.axis("off")
37
- plt.savefig(png_path, bbox_inches="tight", pad_inches=0, transparent=True)
38
- plt.close()
39
-
40
-
41
- def make_map(city, show_grid, show_georef):
42
- city = city.strip()
43
- if not city:
44
- return "Please enter a city"
45
-
46
- geolocator = Nominatim(user_agent="histOSM_gradioAPP (maria.u.kuznetsova@gmail.com)",
47
- timeout=10)
48
- loc = geolocator.geocode(city)
49
- if loc is None:
50
- return f"Could not find '{city}'"
51
-
52
- m = folium.Map(location=[loc.latitude, loc.longitude], zoom_start=12)
53
-
54
- raster_path = os.path.join(OUTPUT_DIR, "georeferenced.tif")
55
- if not os.path.exists(raster_path):
56
- return "Georeferenced raster not found"
57
-
58
- with rasterio.open(raster_path) as src:
59
- bounds = src.bounds
60
- crs = src.crs
61
-
62
- xmin, ymin, xmax, ymax = bounds
63
- transformer = pyproj.Transformer.from_crs(crs, "EPSG:4326", always_xy=True)
64
-
65
- # Convert raster bounds to lat/lon
66
- lon0, lat0 = transformer.transform(xmin, ymin)
67
- lon1, lat1 = transformer.transform(xmax, ymax)
68
-
69
- # Enforce correct ordering for Folium
70
- lat_min, lat_max = sorted([lat0, lat1])
71
- lon_min, lon_max = sorted([lon0, lon1])
72
-
73
- # Show georeferenced raster if requested
74
- if show_georef:
75
- raster_img_path = os.path.join(OUTPUT_DIR, "georeferenced_rgba.png")
76
- if not os.path.exists(raster_img_path):
77
- export_georeferenced_png(raster_path, raster_img_path)
78
-
79
- ImageOverlay(
80
- image=raster_img_path,
81
- bounds=[[lat_min, lon_min], [lat_max, lon_max]],
82
- opacity=0.85,
83
- interactive=True,
84
- ).add_to(m)
85
-
86
- # Debug markers (optional, helps see alignment)
87
- folium.Marker([loc.latitude, loc.longitude], tooltip="City center").add_to(m)
88
- cx, cy = (xmin + xmax) / 2, (ymin + ymax) / 2
89
- clon, clat = transformer.transform(cx, cy)
90
- folium.Marker([clat, clon], tooltip="Raster center").add_to(m)
91
-
92
- # Grid overlay
93
- if show_grid:
94
- grid_values = []
95
- for fname in os.listdir(OUTPUT_DIR):
96
- if fname.startswith("street_matches_tile") and fname.endswith(".csv"):
97
- df = pd.read_csv(os.path.join(OUTPUT_DIR, fname))
98
- if df.empty:
99
- continue
100
-
101
- tile_xmin, tile_xmax = df['x'].min(), df['x'].max()
102
- tile_ymin, tile_ymax = df['y'].min(), df['y'].max()
103
- n_cols = int(np.ceil((tile_xmax - tile_xmin) / CELL_SIZE_M))
104
- n_rows = int(np.ceil((tile_ymax - tile_ymin) / CELL_SIZE_M))
105
-
106
- grid = np.zeros((n_rows, n_cols))
107
- counts = np.zeros((n_rows, n_cols))
108
-
109
- for _, row in df.iterrows():
110
- col = int((row['x'] - tile_xmin) // CELL_SIZE_M)
111
- row_idx = int((row['y'] - tile_ymin) // CELL_SIZE_M)
112
- if 0 <= col < n_cols and 0 <= row_idx < n_rows:
113
- grid[row_idx, col] += row['osm_match_score']
114
- counts[row_idx, col] += 1
115
-
116
- mask = counts > 0
117
- grid[mask] /= counts[mask]
118
- grid_values.append((grid, tile_xmin, tile_ymin, n_rows, n_cols))
119
-
120
- if grid_values:
121
- all_scores = np.concatenate([g[0].flatten() for g in grid_values])
122
- min_val, max_val = all_scores.min(), all_scores.max()
123
- if min_val == max_val:
124
- max_val = min_val + 1e-6
125
-
126
- cmap = cm.get_cmap("Reds")
127
- colormap = linear.Reds_09.scale(min_val, max_val)
128
- colormap.caption = "Average OSM Match Score"
129
- colormap.add_to(m)
130
-
131
- for grid, tile_xmin, tile_ymin, n_rows, n_cols in grid_values:
132
- for r in range(n_rows):
133
- for c in range(n_cols):
134
- val = grid[r, c]
135
- if val <= 0:
136
- continue
137
- norm_val = (val - min_val) / (max_val - min_val)
138
- color = colors.to_hex(cmap(norm_val))
139
- x0 = tile_xmin + c * CELL_SIZE_M
140
- y0 = tile_ymin + r * CELL_SIZE_M
141
- x1 = x0 + CELL_SIZE_M
142
- y1 = y0 + CELL_SIZE_M
143
- lon0, lat0 = transformer.transform(x0, y0)
144
- lon1, lat1 = transformer.transform(x1, y1)
145
- lat_min, lat_max = sorted([lat0, lat1])
146
- lon_min, lon_max = sorted([lon0, lon1])
147
- folium.Rectangle(
148
- bounds=[[lat_min, lon_min], [lat_max, lon_max]],
149
- color=None,
150
- weight=0,
151
- fill=True,
152
- fill_color=color,
153
- fill_opacity=0.7,
154
- popup=f"{val:.2f}",
155
- ).add_to(m)
156
-
157
- return m._repr_html_()
158
 
159
 
160
  def get_map_widgets(city_component):
 
 
1
  import gradio as gr
2
+ from map_logic import make_map
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
 
4
 
5
  def get_map_widgets(city_component):