lichih commited on
Commit
cdd6c01
1 Parent(s): 8678a49
Files changed (6) hide show
  1. app.py +185 -0
  2. core.py +356 -0
  3. examples/beach.jpg +0 -0
  4. examples/field.jpg +0 -0
  5. examples/sky.jpg +0 -0
  6. requirements.txt +10 -0
app.py ADDED
@@ -0,0 +1,185 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from core import Ladeco
3
+ from matplotlib.figure import Figure
4
+ import matplotlib.pyplot as plt
5
+ import matplotlib as mpl
6
+ import spaces
7
+ from PIL import Image
8
+
9
+
10
+ mpl.style.use("dark_background")
11
+ ladeco = Ladeco()
12
+
13
+
14
+ @spaces.GPU
15
+ def infer(img: str) -> tuple[Figure, Figure]:
16
+ out = ladeco.predict(img)
17
+
18
+ seg = out.visualize(level=2)[0].image
19
+ colormap = out.color_map(level=2)
20
+
21
+ area = out.area()[0]
22
+
23
+ # match the color of segmentation image and pie chart
24
+ colors = []
25
+ l2_area = {}
26
+ for labelname, area_ratio in area.items():
27
+ if labelname.startswith("l2") and area_ratio > 0:
28
+ colors.append(colormap[labelname])
29
+ labelname = labelname.replace("l2_", "").capitalize()
30
+ l2_area[labelname] = area_ratio
31
+
32
+ pie = plot_pie(l2_area, colors=colors)
33
+
34
+ return seg, pie
35
+
36
+
37
+ def plot_pie(data: dict[str, float], colors=None) -> Figure:
38
+ fig, ax = plt.subplots()
39
+
40
+ labels = list(data.keys())
41
+ sizes = list(data.values())
42
+
43
+ *_, autotexts = ax.pie(sizes, labels=labels, autopct="%1.1f%%", colors=colors)
44
+
45
+ for percent_text in autotexts:
46
+ percent_text.set_color("k")
47
+
48
+ ax.axis("equal")
49
+
50
+ return fig
51
+
52
+
53
+ def choose_example(imgpath: str) -> gr.Image:
54
+ img = Image.open(imgpath)
55
+ width, height = img.size
56
+ ratio = 512 / max(width, height)
57
+ img = img.resize((int(width * ratio), int(height * ratio)))
58
+ return gr.Image(value=img, label="輸入影像(不支援 SVG 格式)", type="filepath")
59
+
60
+
61
+ css = """
62
+ .reference {
63
+ text-align: center;
64
+ font-size: 1.2em;
65
+ color: #d1d5db;
66
+ margin-bottom: 20px;
67
+ }
68
+ .reference a {
69
+ color: #FB923C;
70
+ text-decoration: none;
71
+ }
72
+ .reference a:hover {
73
+ text-decoration: underline;
74
+ color: #FB923C;
75
+ }
76
+ .description {
77
+ text-align: center;
78
+ font-size: 1.1em;
79
+ color: #d1d5db;
80
+ margin-bottom: 25px;
81
+ }
82
+ .footer {
83
+ text-align: center;
84
+ margin-top: 30px;
85
+ padding-top: 20px;
86
+ border-top: 1px solid #ddd;
87
+ color: #d1d5db;
88
+ font-size: 14px;
89
+ }
90
+ .main-title {
91
+ font-size: 24px;
92
+ font-weight: bold;
93
+ text-align: center;
94
+ margin-bottom: 20px;
95
+ }
96
+ .selected-image {
97
+ height: 756px;
98
+ }
99
+ .example-image {
100
+ height: 220px;
101
+ }
102
+ """.strip()
103
+ theme = gr.themes.Base(
104
+ primary_hue="orange",
105
+ secondary_hue="orange",
106
+ neutral_hue="gray",
107
+ font=gr.themes.GoogleFont("Source Sans Pro"),
108
+ ).set(
109
+ background_fill_primary="*neutral_950", # 主背景色(深黑)
110
+ button_primary_background_fill="*primary_500", # 按鈕顏色(橘色)
111
+ body_text_color="*neutral_200", # 文字顏色(淺色)
112
+ )
113
+ with gr.Blocks(css=css, theme=theme) as demo:
114
+ gr.HTML(
115
+ """
116
+ <div class="main-title">LaDeco 景觀環境影像語意分析模型</div>
117
+ <div class="reference">
118
+ 引用資料:
119
+ <a href="https://www.sciencedirect.com/science/article/pii/S1574954123003187" target="_blank">
120
+ Li-Chih Ho (2023), LaDeco: A Tool to Analyze Visual Landscape Elements, Ecological Informatics, vol. 78.
121
+ </a>
122
+ </div>
123
+ """.strip()
124
+ )
125
+ with gr.Row(equal_height=True):
126
+ with gr.Group():
127
+ img = gr.Image(
128
+ label="輸入影像(不支援 SVG 格式)",
129
+ type="filepath",
130
+ elem_classes="selected-image",
131
+ )
132
+ gr.Label("範例影像", show_label=False)
133
+ with gr.Row():
134
+ ex1 = gr.Image(
135
+ value="examples/beach.jpg",
136
+ show_label=False,
137
+ type="filepath",
138
+ elem_classes="example-image",
139
+ interactive=False,
140
+ show_download_button=False,
141
+ show_fullscreen_button=False,
142
+ )
143
+ ex2 = gr.Image(
144
+ value="examples/field.jpg",
145
+ show_label=False,
146
+ type="filepath",
147
+ elem_classes="example-image",
148
+ interactive=False,
149
+ show_download_button=False,
150
+ show_fullscreen_button=False,
151
+ )
152
+ ex3 = gr.Image(
153
+ value="examples/sky.jpg",
154
+ show_label=False,
155
+ type="filepath",
156
+ elem_classes="example-image",
157
+ interactive=False,
158
+ show_download_button=False,
159
+ show_fullscreen_button=False,
160
+ )
161
+
162
+ with gr.Column():
163
+ seg = gr.Plot(label="語意分割")
164
+ pie = gr.Plot(label="元素面積比例")
165
+
166
+ start = gr.Button("開始分析", variant="primary")
167
+
168
+ gr.HTML(
169
+ """
170
+ <div class="footer">
171
+ © 2024 LaDeco 版權所���<br>
172
+ 開發者:何立智、楊哲睿
173
+ </div>
174
+ """.strip()
175
+ )
176
+
177
+ start.click(fn=infer, inputs=img, outputs=[seg, pie])
178
+
179
+ ex1.select(fn=choose_example, inputs=ex1, outputs=img)
180
+ ex2.select(fn=choose_example, inputs=ex2, outputs=img)
181
+ ex3.select(fn=choose_example, inputs=ex3, outputs=img)
182
+
183
+
184
+ if __name__ == "__main__":
185
+ demo.launch()
core.py ADDED
@@ -0,0 +1,356 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Core part of LaDeco v2
2
+
3
+ Example usage:
4
+ >>> from core import Ladeco
5
+ >>> from PIL import Image
6
+ >>> from pathlib import Path
7
+ >>>
8
+ >>> # predict
9
+ >>> ldc = Ladeco()
10
+ >>> imgs = (thing for thing in Path("example").glob("*.jpg"))
11
+ >>> out = ldc.predict(imgs)
12
+ >>>
13
+ >>> # output - visualization
14
+ >>> segs = out.visualize(level=2)
15
+ >>> segs[0].image.show()
16
+ >>>
17
+ >>> # output - element area
18
+ >>> area = out.area()
19
+ >>> area[0]
20
+ {"fid": "example/.jpg", "l1_nature": 0.673, "l1_man_made": 0.241, ...}
21
+ """
22
+ from matplotlib.patches import Rectangle
23
+ from pathlib import Path
24
+ from PIL import Image
25
+ from transformers import AutoModelForUniversalSegmentation, AutoProcessor
26
+ import math
27
+ import matplotlib as mpl
28
+ import matplotlib.pyplot as plt
29
+ import numpy as np
30
+ import torch
31
+ from functools import lru_cache
32
+ from matplotlib.figure import Figure
33
+ import numpy.typing as npt
34
+ from typing import Iterable, NamedTuple, Generator
35
+ from tqdm import tqdm
36
+
37
+
38
+ class LadecoVisualization(NamedTuple):
39
+ filename: str
40
+ image: Figure
41
+
42
+
43
+ class Ladeco:
44
+
45
+ def __init__(self,
46
+ model_name: str = "shi-labs/oneformer_ade20k_swin_large",
47
+ area_threshold: float = 0.01,
48
+ device: str | None = None,
49
+ ):
50
+ if device is None:
51
+ self.device = "cuda" if torch.cuda.is_available() else "cpu"
52
+ else:
53
+ self.device = device
54
+
55
+ self.processor = AutoProcessor.from_pretrained(model_name)
56
+ self.model = AutoModelForUniversalSegmentation.from_pretrained(model_name).to(self.device)
57
+
58
+ self.area_threshold = area_threshold
59
+
60
+ self.ade20k_labels = {
61
+ name.strip(): int(idx)
62
+ for name, idx in self.model.config.label2id.items()
63
+ }
64
+ self.ladeco2ade20k: dict[str, tuple[int]] = _get_ladeco_labels(self.ade20k_labels)
65
+
66
+ def predict(
67
+ self, image_paths: str | Path | Iterable[str | Path], show_progress: bool = False
68
+ ) -> "LadecoOutput":
69
+ if isinstance(image_paths, (str, Path)):
70
+ imgpaths = [image_paths]
71
+ else:
72
+ imgpaths = list(image_paths)
73
+
74
+ images = (
75
+ Image.open(img_path).convert("RGB")
76
+ for img_path in imgpaths
77
+ )
78
+
79
+ # batch inference functionality of OneFormer is broken
80
+ masks: list[torch.Tensor] = []
81
+ for img in tqdm(images, total=len(imgpaths), desc="Segmenting", disable=not show_progress):
82
+ samples = self.processor(
83
+ images=img, task_inputs=["semantic"], return_tensors="pt"
84
+ ).to(self.device)
85
+
86
+ with torch.no_grad():
87
+ outputs = self.model(**samples)
88
+
89
+ masks.append(
90
+ self.processor.post_process_semantic_segmentation(outputs)[0]
91
+ )
92
+
93
+ return LadecoOutput(imgpaths, masks, self.ladeco2ade20k, self.area_threshold)
94
+
95
+
96
+ class LadecoOutput:
97
+
98
+ def __init__(
99
+ self,
100
+ filenames: list[str | Path],
101
+ masks: torch.Tensor,
102
+ ladeco2ade: dict[str, tuple[int]],
103
+ threshold: float,
104
+ ):
105
+ self.filenames = filenames
106
+ self.masks = masks
107
+ self.ladeco2ade: dict[str, tuple[int]] = ladeco2ade
108
+ self.ade2ladeco: dict[int, str] = {
109
+ idx: label
110
+ for label, indices in self.ladeco2ade.items()
111
+ for idx in indices
112
+ }
113
+ self.threshold = threshold
114
+
115
+ def visualize(self, level: int) -> list[LadecoVisualization]:
116
+ return list(self.ivisualize(level))
117
+
118
+ def ivisualize(self, level: int) -> Generator[LadecoVisualization, None, None]:
119
+ colormaps = self.color_map(level)
120
+ labelnames = [name for name in self.ladeco2ade if name.startswith(f"l{level}")]
121
+
122
+ for fname, mask in zip(self.filenames, self.masks):
123
+ size = mask.shape + (3,) # (H, W, RGB)
124
+ vis = torch.zeros(size, dtype=torch.uint8)
125
+ for name in labelnames:
126
+ for idx in self.ladeco2ade[name]:
127
+ color = torch.tensor(colormaps[name] * 255, dtype=torch.uint8)
128
+ vis[mask == idx] = color
129
+
130
+ with Image.open(fname) as img:
131
+ target_size = img.size
132
+ vis = Image.fromarray(vis.numpy(), mode="RGB").resize(target_size)
133
+
134
+ fig, ax = plt.subplots()
135
+ ax.imshow(vis)
136
+ ax.axis('off')
137
+
138
+ yield LadecoVisualization(filename=str(fname), image=fig)
139
+
140
+ def area(self) -> list[dict[str, float | str]]:
141
+ return list(self.iarea())
142
+
143
+ def iarea(self) -> Generator[dict[str, float | str], None, None]:
144
+ n_label_ADE20k = 150
145
+ for filename, mask in zip(self.filenames, self.masks):
146
+ ade_ratios = torch.tensor([(mask == i).count_nonzero() / mask.numel() for i in range(n_label_ADE20k)])
147
+ #breakpoint()
148
+ ldc_ratios: dict[str, float] = {
149
+ label: round(ade_ratios[list(ade_indices)].sum().item(), 4)
150
+ for label, ade_indices in self.ladeco2ade.items()
151
+ }
152
+ ldc_ratios: dict[str, float] = {
153
+ label: 0 if ratio < self.threshold else ratio
154
+ for label, ratio in ldc_ratios.items()
155
+ }
156
+ others = round(1 - ldc_ratios["l1_nature"] - ldc_ratios["l1_man_made"], 4)
157
+ nfi = round(ldc_ratios["l1_nature"]/ (ldc_ratios["l1_nature"] + ldc_ratios.get("l1_man_made", 0) + 1e-6), 4)
158
+
159
+ yield {
160
+ "fid": str(filename), **ldc_ratios, "others": others, "LC_NFI": nfi,
161
+ }
162
+
163
+ def color_map(self, level: int) -> dict[str, npt.NDArray[np.float64]]:
164
+ "returns {'label_name': (R, G, B), ...}, where (R, G, B) in range [0, 1]"
165
+ labels = [
166
+ name for name in self.ladeco2ade.keys() if name.startswith(f"l{level}")
167
+ ]
168
+ if len(labels) == 0:
169
+ raise RuntimeError(
170
+ f"LaDeco only has 4 levels in 1, 2, 3, 4. You assigned {level}."
171
+ )
172
+ colormap = mpl.colormaps["viridis"].resampled(len(labels)).colors[:, :-1]
173
+ # [:, :-1]: discard alpha channel
174
+ return {name: color for name, color in zip(labels, colormap)}
175
+
176
+ def color_legend(self, level: int) -> Figure:
177
+ colors = self.color_map(level)
178
+
179
+ match level:
180
+ case 1:
181
+ ncols = 1
182
+ case 2:
183
+ ncols = 1
184
+ case 3:
185
+ ncols = 2
186
+ case 4:
187
+ ncols = 5
188
+
189
+ cell_width = 212
190
+ cell_height = 22
191
+ swatch_width = 48
192
+ margin = 12
193
+
194
+ nrows = math.ceil(len(colors) / ncols)
195
+
196
+ width = cell_width * ncols + 2 * margin
197
+ height = cell_height * nrows + 2 * margin
198
+ dpi = 72
199
+
200
+ fig, ax = plt.subplots(figsize=(width / dpi, height / dpi), dpi=dpi)
201
+ fig.subplots_adjust(margin/width, margin/height,
202
+ (width-margin)/width, (height-margin*2)/height)
203
+ ax.set_xlim(0, cell_width * ncols)
204
+ ax.set_ylim(cell_height * (nrows-0.5), -cell_height/2.)
205
+ ax.yaxis.set_visible(False)
206
+ ax.xaxis.set_visible(False)
207
+ ax.set_axis_off()
208
+
209
+ for i, name in enumerate(colors):
210
+ row = i % nrows
211
+ col = i // nrows
212
+ y = row * cell_height
213
+
214
+ swatch_start_x = cell_width * col
215
+ text_pos_x = cell_width * col + swatch_width + 7
216
+
217
+ ax.text(text_pos_x, y, name, fontsize=14,
218
+ horizontalalignment='left',
219
+ verticalalignment='center')
220
+
221
+ ax.add_patch(
222
+ Rectangle(xy=(swatch_start_x, y-9), width=swatch_width,
223
+ height=18, facecolor=colors[name], edgecolor='0.7')
224
+ )
225
+
226
+ ax.set_title(f"LaDeco Color Legend - Level {level}")
227
+
228
+ return fig
229
+
230
+
231
+ def _get_ladeco_labels(ade20k: dict[str, int]) -> dict[str, tuple[int]]:
232
+ labels = {
233
+ # level 4 labels
234
+ # under l3_architecture
235
+ "l4_hovel": (ade20k["hovel, hut, hutch, shack, shanty"],),
236
+ "l4_building": (ade20k["building"], ade20k["house"]),
237
+ "l4_skyscraper": (ade20k["skyscraper"],),
238
+ "l4_tower": (ade20k["tower"],),
239
+ # under l3_archi_parts
240
+ "l4_step": (ade20k["step, stair"],),
241
+ "l4_canopy": (ade20k["awning, sunshade, sunblind"], ade20k["canopy"]),
242
+ "l4_arcade": (ade20k["arcade machine"],),
243
+ "l4_door": (ade20k["door"],),
244
+ "l4_window": (ade20k["window"],),
245
+ "l4_wall": (ade20k["wall"],),
246
+ # under l3_roadway
247
+ "l4_stairway": (ade20k["stairway, staircase"],),
248
+ "l4_sidewalk": (ade20k["sidewalk, pavement"],),
249
+ "l4_road": (ade20k["road, route"],),
250
+ # under l3_furniture
251
+ "l4_sculpture": (ade20k["sculpture"],),
252
+ "l4_flag": (ade20k["flag"],),
253
+ "l4_can": (ade20k["trash can"],),
254
+ "l4_chair": (ade20k["chair"],),
255
+ "l4_pot": (ade20k["pot"],),
256
+ "l4_booth": (ade20k["booth"],),
257
+ "l4_streetlight": (ade20k["street lamp"],),
258
+ "l4_bench": (ade20k["bench"],),
259
+ "l4_fence": (ade20k["fence"],),
260
+ "l4_table": (ade20k["table"],),
261
+ # under l3_vehicle
262
+ "l4_bike": (ade20k["bicycle"],),
263
+ "l4_motorbike": (ade20k["minibike, motorbike"],),
264
+ "l4_van": (ade20k["van"],),
265
+ "l4_truck": (ade20k["truck"],),
266
+ "l4_bus": (ade20k["bus"],),
267
+ "l4_car": (ade20k["car"],),
268
+ # under l3_sign
269
+ "l4_traffic_sign": (ade20k["traffic light"],),
270
+ "l4_poster": (ade20k["poster, posting, placard, notice, bill, card"],),
271
+ "l4_signboard": (ade20k["signboard, sign"],),
272
+ # under l3_vert_land
273
+ "l4_rock": (ade20k["rock, stone"],),
274
+ "l4_hill": (ade20k["hill"],),
275
+ "l4_mountain": (ade20k["mountain, mount"],),
276
+ # under l3_hori_land
277
+ "l4_ground": (ade20k["earth, ground"], ade20k["land, ground, soil"]),
278
+ "l4_field": (ade20k["field"],),
279
+ "l4_sand": (ade20k["sand"],),
280
+ "l4_dirt": (ade20k["dirt track"],),
281
+ "l4_path": (ade20k["path"],),
282
+ # under l3_flower
283
+ "l4_flower": (ade20k["flower"],),
284
+ # under l3_grass
285
+ "l4_grass": (ade20k["grass"],),
286
+ # under l3_shrub
287
+ "l4_flora": (ade20k["plant"],),
288
+ # under l3_arbor
289
+ "l4_tree": (ade20k["tree"],),
290
+ "l4_palm": (ade20k["palm, palm tree"],),
291
+ # under l3_hori_water
292
+ "l4_lake": (ade20k["lake"],),
293
+ "l4_pool": (ade20k["pool"],),
294
+ "l4_river": (ade20k["river"],),
295
+ "l4_sea": (ade20k["sea"],),
296
+ "l4_water": (ade20k["water"],),
297
+ # under l3_vert_water
298
+ "l4_fountain": (ade20k["fountain"],),
299
+ "l4_waterfall": (ade20k["falls"],),
300
+ # under l3_human
301
+ "l4_person": (ade20k["person"],),
302
+ # under l3_animal
303
+ "l4_animal": (ade20k["animal"],),
304
+ # under l3_sky
305
+ "l4_sky": (ade20k["sky"],),
306
+ }
307
+ labels = labels | {
308
+ # level 3 labels
309
+ # under l2_landform
310
+ "l3_hori_land": labels["l4_ground"] + labels["l4_field"] + labels["l4_sand"] + labels["l4_dirt"] + labels["l4_path"],
311
+ "l3_vert_land": labels["l4_mountain"] + labels["l4_hill"] + labels["l4_rock"],
312
+ # under l2_vegetation
313
+ "l3_woody_plant": labels["l4_tree"] + labels["l4_palm"] + labels["l4_flora"],
314
+ "l3_herb_plant": labels["l4_grass"],
315
+ "l3_flower": labels["l4_flower"],
316
+ # under l2_water
317
+ "l3_hori_water": labels["l4_water"] + labels["l4_sea"] + labels["l4_river"] + labels["l4_pool"] + labels["l4_lake"],
318
+ "l3_vert_water": labels["l4_fountain"] + labels["l4_waterfall"],
319
+ # under l2_bio
320
+ "l3_human": labels["l4_person"],
321
+ "l3_animal": labels["l4_animal"],
322
+ # under l2_sky
323
+ "l3_sky": labels["l4_sky"],
324
+ # under l2_archi
325
+ "l3_architecture": labels["l4_building"] + labels["l4_hovel"] + labels["l4_tower"] + labels["l4_skyscraper"],
326
+ "l3_archi_parts": labels["l4_wall"] + labels["l4_window"] + labels["l4_door"] + labels["l4_arcade"] + labels["l4_canopy"] + labels["l4_step"],
327
+ # under l2_street
328
+ "l3_roadway": labels["l4_road"] + labels["l4_sidewalk"] + labels["l4_stairway"],
329
+ "l3_furniture": labels["l4_table"] + labels["l4_chair"] + labels["l4_fence"] + labels["l4_bench"] + labels["l4_streetlight"] + labels["l4_booth"] + labels["l4_pot"] + labels["l4_can"] + labels["l4_flag"] + labels["l4_sculpture"],
330
+ "l3_vehicle": labels["l4_car"] + labels["l4_bus"] + labels["l4_truck"] + labels["l4_van"] + labels["l4_motorbike"] + labels["l4_bike"],
331
+ "l3_sign": labels["l4_signboard"] + labels["l4_poster"] + labels["l4_traffic_sign"],
332
+ }
333
+ labels = labels | {
334
+ # level 2 labels
335
+ # under l1_nature
336
+ "l2_landform": labels["l3_hori_land"] + labels["l3_vert_land"],
337
+ "l2_vegetation": labels["l3_woody_plant"] + labels["l3_herb_plant"] + labels["l3_flower"],
338
+ "l2_water": labels["l3_hori_water"] + labels["l3_vert_water"],
339
+ "l2_bio": labels["l3_human"] + labels["l3_animal"],
340
+ "l2_sky": labels["l3_sky"],
341
+ # under l1_man_made
342
+ "l2_archi": labels["l3_architecture"] + labels["l3_archi_parts"],
343
+ "l2_street": labels["l3_roadway"] + labels["l3_furniture"] + labels["l3_vehicle"] + labels["l3_sign"],
344
+ }
345
+ labels = labels | {
346
+ # level 1 labels
347
+ "l1_nature": labels["l2_landform"] + labels["l2_vegetation"] + labels["l2_water"] + labels["l2_bio"] + labels["l2_sky"],
348
+ "l1_man_made": labels["l2_archi"] + labels["l2_street"],
349
+ }
350
+ return labels
351
+
352
+
353
+ if __name__ == "__main__":
354
+ ldc = Ladeco()
355
+ image = Path("images") / "canyon_3011_00002354.jpg"
356
+ out = ldc.predict(image)
examples/beach.jpg ADDED
examples/field.jpg ADDED
examples/sky.jpg ADDED
requirements.txt ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ --extra-index-url https://download.pytorch.org/whl/cu121
2
+ torch==2.5.1
3
+ torchvision
4
+ tokenizers==0.20.3
5
+ transformers==4.46.2
6
+ tqdm
7
+ matplotlib
8
+ pillow==10.4.0
9
+ scipy
10
+ gradio