Aurel-test commited on
Commit
de055a4
·
1 Parent(s): 90cae6b

Add app.py and requirements

Browse files
Files changed (2) hide show
  1. app.py +541 -0
  2. requirements.txt +12 -0
app.py ADDED
@@ -0,0 +1,541 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import torch
3
+ from transformers import SegformerForSemanticSegmentation, SegformerImageProcessor
4
+ from PIL import Image
5
+ import plotly.graph_objects as go
6
+ import numpy as np
7
+ import os
8
+ import torch.nn as nn
9
+ from sklearn.metrics import jaccard_score, accuracy_score
10
+ from collections import Counter
11
+ import matplotlib.pyplot as plt
12
+ import seaborn as sns
13
+ import torch.nn.functional as F
14
+ import seaborn as sns
15
+ from functools import partial
16
+ from pytorch_grad_cam.utils.image import (
17
+ show_cam_on_image,
18
+ preprocess_image as grad_preprocess,
19
+ )
20
+ from pytorch_grad_cam import GradCAM
21
+ import cv2
22
+ import transformers
23
+ from torchvision import transforms
24
+ import albumentations as A
25
+
26
+ device = "cuda" if torch.cuda.is_available() else "cpu"
27
+ data_folder = "data_sample"
28
+ id2label = {
29
+ 0: "void",
30
+ 1: "flat",
31
+ 2: "construction",
32
+ 3: "object",
33
+ 4: "nature",
34
+ 5: "sky",
35
+ 6: "human",
36
+ 7: "vehicle",
37
+ }
38
+ label2id = {v: k for k, v in id2label.items()}
39
+ num_labels = len(id2label)
40
+ checkpoint = "nvidia/segformer-b4-finetuned-cityscapes-1024-1024"
41
+ image_processor = SegformerImageProcessor()
42
+ state_dict_path = f"runs/{checkpoint}_v1/best_model.pt"
43
+ model = SegformerForSemanticSegmentation.from_pretrained(
44
+ checkpoint,
45
+ num_labels=num_labels,
46
+ id2label=id2label,
47
+ label2id=label2id,
48
+ ignore_mismatched_sizes=True,
49
+ )
50
+ loaded_state_dict = torch.load(state_dict_path)
51
+ model.load_state_dict(loaded_state_dict)
52
+ model = model.to(device)
53
+ model.eval()
54
+
55
+ # ---- Partie Segmentation
56
+
57
+
58
+ def load_and_prepare_images(image_name, segformer=False):
59
+ image_path = os.path.join(data_folder, "images", image_name)
60
+ mask_name = image_name.replace("_leftImg8bit.png", "_gtFine_labelIds.png")
61
+ mask_path = os.path.join(data_folder, "masks", mask_name)
62
+ fpn_pred_path = os.path.join(data_folder, "resnet101_mask", image_name)
63
+
64
+ if not os.path.exists(image_path):
65
+ raise FileNotFoundError(f"Image not found: {image_path}")
66
+ if not os.path.exists(mask_path):
67
+ raise FileNotFoundError(f"Mask not found: {mask_path}")
68
+ if not os.path.exists(fpn_pred_path):
69
+ raise FileNotFoundError(f"FPN prediction not found: {fpn_pred_path}")
70
+
71
+ original_image = Image.open(image_path).convert("RGB")
72
+ original = original_image.resize((1024, 512))
73
+ true_mask = np.array(Image.open(mask_path))
74
+ fpn_pred = np.array(Image.open(fpn_pred_path))
75
+ if segformer:
76
+ segformer_pred = predict_segmentation(original)
77
+ return original, true_mask, fpn_pred, segformer_pred
78
+
79
+ return original, true_mask, fpn_pred
80
+
81
+
82
+ def predict_segmentation(image):
83
+ # Charger et préparer l'image
84
+ inputs = image_processor(images=image, return_tensors="pt")
85
+
86
+ # Utiliser GPU si disponible
87
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
88
+ model.to(device)
89
+
90
+ # Déplacer les inputs sur le bon device et faire la prédiction
91
+ pixel_values = inputs.pixel_values.to(device)
92
+
93
+ with torch.no_grad(): # Désactiver le calcul des gradients pour l'inférence
94
+ outputs = model(pixel_values=pixel_values)
95
+ logits = outputs.logits
96
+
97
+ # Redimensionner les logits à la taille de l'image d'origine
98
+ upsampled_logits = nn.functional.interpolate(
99
+ logits,
100
+ size=image.size[::-1], # (height, width)
101
+ mode="bilinear",
102
+ align_corners=False,
103
+ )
104
+
105
+ # Obtenir la prédiction finale
106
+ pred_seg = upsampled_logits.argmax(dim=1)[0].cpu().numpy()
107
+
108
+ return pred_seg
109
+
110
+
111
+ def process_image(image_name):
112
+ original, true_mask, fpn_pred, segformer_pred = load_and_prepare_images(
113
+ image_name, segformer=True
114
+ )
115
+ true_mask_colored = colorize_mask(true_mask)
116
+ true_mask_colored = Image.fromarray(true_mask_colored.astype("uint8"))
117
+ true_mask_colored = true_mask_colored.resize((1024, 512))
118
+ # fpn_pred_colored = colorize_mask(fpn_pred)
119
+ segformer_pred_colored = colorize_mask(segformer_pred)
120
+ segformer_pred_colored = Image.fromarray(segformer_pred_colored.astype("uint8"))
121
+ segformer_pred_colored = segformer_pred_colored.resize((1024, 512))
122
+
123
+ return [
124
+ (original, "Image originale"),
125
+ (true_mask_colored, "Masque réel"),
126
+ (fpn_pred, "Prédiction FPN"),
127
+ (segformer_pred_colored, "Prédiction SegFormer"),
128
+ ]
129
+
130
+
131
+ def create_cityscapes_label_colormap():
132
+ colormap = np.zeros((256, 3), dtype=np.uint8)
133
+ colormap[0] = [78, 82, 110]
134
+ colormap[1] = [128, 64, 128]
135
+ colormap[2] = [154, 156, 153]
136
+ colormap[3] = [168, 167, 18]
137
+ colormap[4] = [80, 108, 28]
138
+ colormap[5] = [112, 164, 196]
139
+ colormap[6] = [168, 28, 52]
140
+ colormap[7] = [16, 18, 112]
141
+ return colormap
142
+
143
+
144
+ # Créer la colormap une fois
145
+ cityscapes_colormap = create_cityscapes_label_colormap()
146
+
147
+
148
+ def blend_images(original_image, colored_segmentation, alpha=0.6):
149
+ blended_image = Image.blend(original_image, colored_segmentation, alpha)
150
+ return blended_image
151
+
152
+
153
+ def colorize_mask(mask):
154
+ return cityscapes_colormap[mask]
155
+
156
+
157
+ # ---- Fin Partie Segmentation
158
+
159
+ # def compare_masks(real_mask, fpn_mask, segformer_mask):
160
+ # """
161
+ # Compare les masques prédits par FPN et SegFormer avec le masque réel.
162
+ # Retourne un score IoU et une précision pixel par pixel pour chaque modèle.
163
+
164
+ # Args:
165
+ # real_mask (np.array): Le masque réel de référence
166
+ # fpn_mask (np.array): Le masque prédit par le modèle FPN
167
+ # segformer_mask (np.array): Le masque prédit par le modèle SegFormer
168
+
169
+ # Returns:
170
+ # dict: Dictionnaire contenant les scores IoU et les précisions pour chaque modèle
171
+ # """
172
+
173
+ # assert real_mask.shape == fpn_mask.shape == segformer_mask.shape, "Les masques doivent avoir la même forme"
174
+
175
+ # real_flat = real_mask.flatten()
176
+ # fpn_flat = fpn_mask.flatten()
177
+ # segformer_flat = segformer_mask.flatten()
178
+
179
+ # # Calcul du score de Jaccard (IoU)
180
+ # iou_fpn = jaccard_score(real_flat, fpn_flat, average='weighted')
181
+ # iou_segformer = jaccard_score(real_flat, segformer_flat, average='weighted')
182
+
183
+ # # Calcul de la précision pixel par pixel
184
+ # accuracy_fpn = accuracy_score(real_flat, fpn_flat)
185
+ # accuracy_segformer = accuracy_score(real_flat, segformer_flat)
186
+
187
+ # return {
188
+ # 'FPN': {'IoU': iou_fpn, 'Precision': accuracy_fpn},
189
+ # 'SegFormer': {'IoU': iou_segformer, 'Precision': accuracy_segformer}
190
+ # }
191
+
192
+ # ---- Partie EDA
193
+
194
+
195
+ def analyse_mask(real_mask, num_labels):
196
+ # Compter les occurrences de chaque classe
197
+ counts = np.bincount(real_mask.ravel(), minlength=num_labels)
198
+
199
+ # Calculer le nombre total de pixels
200
+ total_pixels = real_mask.size
201
+
202
+ # Calculer les proportions
203
+ class_proportions = counts / total_pixels
204
+
205
+ # Créer un dictionnaire avec les proportions
206
+ return dict(enumerate(class_proportions))
207
+
208
+
209
+ def show_eda(image_name):
210
+ original_image, true_mask, _ = load_and_prepare_images(image_name)
211
+ class_proportions = analyse_mask(true_mask, num_labels)
212
+ cityscapes_colormap = create_cityscapes_label_colormap()
213
+ true_mask_colored = colorize_mask(true_mask)
214
+ true_mask_colored = Image.fromarray(true_mask_colored.astype("uint8"))
215
+ true_mask_colored = true_mask_colored.resize((1024, 512))
216
+
217
+ # Trier les classes par proportion croissante
218
+ sorted_classes = sorted(
219
+ class_proportions.keys(), key=lambda x: class_proportions[x]
220
+ )
221
+
222
+ # Préparer les données pour le barplot
223
+ categories = [id2label[i] for i in sorted_classes]
224
+ values = [class_proportions[i] for i in sorted_classes]
225
+ color_list = [
226
+ f"rgb({cityscapes_colormap[i][0]}, {cityscapes_colormap[i][1]}, {cityscapes_colormap[i][2]})"
227
+ for i in sorted_classes
228
+ ]
229
+
230
+ # Distribution des classes avec la colormap personnalisée
231
+ fig = go.Figure()
232
+
233
+ fig.add_trace(
234
+ go.Bar(
235
+ x=categories,
236
+ y=values,
237
+ marker_color=color_list,
238
+ text=[f"{v:.2f}" for v in values],
239
+ textposition="outside",
240
+ )
241
+ )
242
+
243
+ # Ajouter un titre et des labels, modifier la rotation et la taille de la police
244
+ fig.update_layout(
245
+ title={"text": "Distribution des classes", "font": {"size": 24}},
246
+ xaxis_title={"text": "Catégories", "font": {"size": 18}},
247
+ yaxis_title={"text": "Proportion", "font": {"size": 18}},
248
+ xaxis_tickangle=0, # Rotation modifiée à -45 degrés
249
+ uniformtext_minsize=12,
250
+ uniformtext_mode="hide",
251
+ font=dict(size=14),
252
+ autosize=True,
253
+ bargap=0.2,
254
+ height=600,
255
+ margin=dict(l=20, r=20, t=50, b=20),
256
+ )
257
+
258
+ return original_image, true_mask_colored, fig
259
+
260
+
261
+ # ----Fin Partie EDA
262
+
263
+ # ----Partie Explication GradCam
264
+
265
+
266
+ class SegformerWrapper(nn.Module):
267
+ def __init__(self, model):
268
+ super().__init__()
269
+ self.model = model
270
+
271
+ def forward(self, x):
272
+ output = self.model(x)
273
+ return output.logits
274
+
275
+
276
+ class SemanticSegmentationTarget:
277
+ def __init__(self, category, mask):
278
+ self.category = category
279
+ self.mask = torch.from_numpy(mask)
280
+ if torch.cuda.is_available():
281
+ self.mask = self.mask.cuda()
282
+
283
+ def __call__(self, model_output):
284
+ if isinstance(
285
+ model_output, (dict, transformers.modeling_outputs.SemanticSegmenterOutput)
286
+ ):
287
+ logits = (
288
+ model_output["logits"]
289
+ if isinstance(model_output, dict)
290
+ else model_output.logits
291
+ )
292
+ elif isinstance(model_output, torch.Tensor):
293
+ logits = model_output
294
+ else:
295
+ raise ValueError(f"Unexpected model_output type: {type(model_output)}")
296
+
297
+ if logits.dim() == 4: # [batch, classes, height, width]
298
+ return (logits[0, self.category, :, :] * self.mask).sum()
299
+ elif logits.dim() == 3: # [classes, height, width]
300
+ return (logits[self.category, :, :] * self.mask).sum()
301
+ else:
302
+ raise ValueError(f"Unexpected logits shape: {logits.shape}")
303
+
304
+
305
+ def segformer_reshape_transform_huggingface(tensor, width, height):
306
+ result = tensor.reshape(tensor.size(0), height, width, tensor.size(2))
307
+ result = result.transpose(2, 3).transpose(1, 2)
308
+ return result
309
+
310
+
311
+ def explain_model(image_name, category_name):
312
+ original_image, _, _ = load_and_prepare_images(image_name)
313
+ rgb_img = np.float32(original_image) / 255
314
+ img_tensor = transforms.ToTensor()(rgb_img)
315
+ input_tensor = transforms.Normalize(
316
+ mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]
317
+ )(img_tensor)
318
+ input_tensor = input_tensor.unsqueeze(0).to(device)
319
+ wrapped_model = SegformerWrapper(model).to(device)
320
+ with torch.no_grad():
321
+ output = wrapped_model(input_tensor)
322
+ upsampled_logits = nn.functional.interpolate(
323
+ output, size=input_tensor.shape[-2:], mode="bilinear", align_corners=False
324
+ )
325
+
326
+ normalized_masks = torch.nn.functional.softmax(upsampled_logits, dim=1).cpu()
327
+ category = label2id[category_name]
328
+ mask = normalized_masks[0].argmax(dim=0).numpy()
329
+ mask_float = np.float32(mask == category)
330
+ reshape_transform = partial(
331
+ segformer_reshape_transform_huggingface, # réorganise les dimensions du tenseur pour qu'elles correspondent au format attendu par GradCAM.
332
+ width=img_tensor.shape[2] // 32,
333
+ height=img_tensor.shape[1] // 32,
334
+ )
335
+ target_layers = [wrapped_model.model.segformer.encoder.layer_norm[-1]]
336
+ mask_float_resized = cv2.resize(mask_float, (output.shape[3], output.shape[2]))
337
+ targets = [SemanticSegmentationTarget(category, mask_float_resized)]
338
+ cam = GradCAM(
339
+ model=wrapped_model,
340
+ target_layers=target_layers,
341
+ reshape_transform=reshape_transform,
342
+ )
343
+
344
+ grayscale_cam = cam(input_tensor=input_tensor, targets=targets)
345
+ threshold = 0.01 # Seuil de 1% de sureté
346
+ thresholded_cam = grayscale_cam.copy()
347
+ thresholded_cam[grayscale_cam < threshold] = 0
348
+ if np.max(thresholded_cam) > 0:
349
+ thresholded_cam = thresholded_cam / np.max(thresholded_cam)
350
+ else:
351
+ thresholded_cam = grayscale_cam[0]
352
+ resized_cam = cv2.resize(
353
+ thresholded_cam[0], (input_tensor.shape[3], input_tensor.shape[2])
354
+ )
355
+ masked_cam = resized_cam * mask_float
356
+ if np.max(masked_cam) > 0:
357
+ cam_image = show_cam_on_image(rgb_img, masked_cam, use_rgb=True)
358
+ else:
359
+ cam_image = original_image
360
+ fig, ax = plt.subplots(figsize=(15, 10))
361
+ ax.imshow(cam_image)
362
+ ax.axis("off")
363
+ ax.set_title(f"Masque de chaleur GradCam pour {category_name}", color="white")
364
+ margin = 0.02 # Adjust this value to change the size of the margin
365
+ margin_color = "#0a0f1e"
366
+ fig.subplots_adjust(left=margin, right=1 - margin, top=1 - margin, bottom=margin)
367
+ fig.patch.set_facecolor(margin_color)
368
+ plt.close()
369
+
370
+ return fig
371
+
372
+
373
+ # ----Fin Partie Explication GradCam
374
+
375
+ # ----Partie Data augmentation
376
+ import random
377
+
378
+
379
+ def change_image():
380
+ image_dir = (
381
+ "data_sample/images" # Remplacez par le chemin de votre dossier d'images
382
+ )
383
+ image_list = [f for f in os.listdir(image_dir) if f.endswith(".png")]
384
+ random_image = random.choice(image_list)
385
+ return Image.open(os.path.join(image_dir, random_image))
386
+
387
+
388
+ def apply_augmentation(image, augmentation_names):
389
+ augmentations = {
390
+ "Horizontal Flip": A.HorizontalFlip(p=1),
391
+ "Shift Scale Rotate": A.ShiftScaleRotate(p=1),
392
+ "Random Brightness Contrast": A.RandomBrightnessContrast(p=1),
393
+ "RGB Shift": A.RGBShift(p=1),
394
+ "Blur": A.Blur(blur_limit=(5, 7), p=1),
395
+ "Gaussian Noise": A.GaussNoise(p=1),
396
+ "Grid Distortion": A.GridDistortion(p=1),
397
+ "Random Sun": A.RandomSunFlare(p=1),
398
+ }
399
+
400
+ image_array = np.array(image)
401
+
402
+ if augmentation_names is not None:
403
+ selected_augs = [
404
+ augmentations[name] for name in augmentation_names if name in augmentations
405
+ ]
406
+ compose = A.Compose(selected_augs)
407
+
408
+ # Appliquer la composition d'augmentations
409
+ augmented = compose(image=image_array)
410
+ return Image.fromarray(augmented["image"])
411
+ else:
412
+ return image
413
+
414
+
415
+ # ---- Fin Partie Data augmentation
416
+
417
+ image_list = [
418
+ f for f in os.listdir(os.path.join(data_folder, "images")) if f.endswith(".png")
419
+ ]
420
+ category_list = list(id2label.values())
421
+ image_name = "dusseldorf_000012_000019_leftImg8bit.png"
422
+ default_image = os.path.join(data_folder, "images", image_name)
423
+
424
+ my_theme = gr.Theme.from_hub("YenLai/Superhuman")
425
+ with gr.Blocks(title="Preuve de concept", theme=my_theme) as demo:
426
+ gr.Markdown("# Projet 10 - Développer une preuve de concept")
427
+ with gr.Tab("Prédictions"):
428
+ gr.Markdown("## Comparaison de segmentation d'images Cityscapes")
429
+ gr.Markdown(
430
+ "### Sélectionnez une image pour voir la comparaison entre le masque réel, la prédiction FPN et la prédiction SegFormer."
431
+ )
432
+
433
+ image_input = gr.Dropdown(choices=image_list, label="Sélectionnez une image")
434
+
435
+ gallery_output = gr.Gallery(
436
+ label="Résultats de segmentation",
437
+ show_label=True,
438
+ elem_id="gallery",
439
+ columns=[2],
440
+ rows=[2],
441
+ object_fit="contain",
442
+ height="512px",
443
+ min_width="1024px",
444
+ )
445
+
446
+ image_input.change(fn=process_image, inputs=image_input, outputs=gallery_output)
447
+
448
+ with gr.Tab("EDA"):
449
+ gr.Markdown("## Analyse Exploratoire des données Cityscapes")
450
+ gr.Markdown(
451
+ "### Visualisations de la distribution de chaque classe selon l'image choisie."
452
+ )
453
+ eda_image_input = gr.Dropdown(
454
+ choices=image_list,
455
+ label="Sélectionnez une image",
456
+ )
457
+
458
+ with gr.Row():
459
+ original_image_output = gr.Image(type="pil", label="Image originale")
460
+ original_mask_output = gr.Image(type="pil", label="Masque original")
461
+ class_distribution_plot = gr.Plot(label="Distribution des classes")
462
+ eda_image_input.change(
463
+ fn=show_eda,
464
+ inputs=eda_image_input,
465
+ outputs=[
466
+ original_image_output,
467
+ original_mask_output,
468
+ class_distribution_plot,
469
+ ],
470
+ )
471
+
472
+ with gr.Tab("Explication SegFormer"):
473
+ gr.Markdown("## Explication du modèle SegFormer")
474
+ gr.Markdown(
475
+ "### La méthode Grad-CAM est une technique populaire de visualisation qui est utile pour comprendre comment un réseau neuronal convolutif a été conduit à prendre une décision de classification. Elle est spécifique à chaque classe, ce qui signifie qu’elle peut produire une visualisation distincte pour chaque classe présente dans l’image."
476
+ )
477
+ gr.Markdown(
478
+ "### NB: Si l'image s'affiche sans masque, c'est que le modèle ne trouve pas de zones significatives pour une catégorie donnée."
479
+ )
480
+
481
+ with gr.Row():
482
+ explain_image_input = gr.Dropdown(
483
+ choices=image_list, label="Sélectionnez une image"
484
+ )
485
+ explain_category_input = gr.Dropdown(
486
+ choices=category_list, label="Sélectionnez une catégorie"
487
+ )
488
+
489
+ explain_button = gr.Button("Expliquer")
490
+ explain_output = gr.Plot(label="Explication SegFormer", min_width=200)
491
+ explain_button.click(
492
+ fn=explain_model,
493
+ inputs=[explain_image_input, explain_category_input],
494
+ outputs=explain_output,
495
+ )
496
+
497
+ with gr.Tab("Data Augmentation"):
498
+ gr.Markdown("## Visualisation de l'augmentation de données")
499
+ gr.Markdown(
500
+ "### Sélectionnez une ou plusieurs augmentations pour l'appliquer à l'image."
501
+ )
502
+ gr.Markdown("### Vous pouvez également changer d'image.")
503
+
504
+ with gr.Row():
505
+ image_display = gr.Image(
506
+ value=default_image,
507
+ label="Image",
508
+ show_download_button=False,
509
+ interactive=False,
510
+ )
511
+ augmented_image = gr.Image(label="Image Augmentée")
512
+
513
+ with gr.Row():
514
+ change_image_button = gr.Button("Changer image")
515
+ augmentation_dropdown = gr.Dropdown(
516
+ choices=[
517
+ "Horizontal Flip",
518
+ "Shift Scale Rotate",
519
+ "Random Brightness Contrast",
520
+ "RGB Shift",
521
+ "Blur",
522
+ "Gaussian Noise",
523
+ "Grid Distortion",
524
+ "Random Sun",
525
+ ],
526
+ label="Sélectionnez une augmentation",
527
+ multiselect=True,
528
+ )
529
+ apply_button = gr.Button("Appliquer l'augmentation")
530
+
531
+ change_image_button.click(fn=change_image, outputs=image_display)
532
+
533
+ apply_button.click(
534
+ fn=apply_augmentation,
535
+ inputs=[image_display, augmentation_dropdown],
536
+ outputs=augmented_image,
537
+ )
538
+
539
+
540
+ # Lancer l'application
541
+ demo.launch(favicon_path="static/favicon.ico", share=True)
requirements.txt ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ gradio
2
+ torch
3
+ transformers
4
+ Pillow
5
+ plotly
6
+ numpy
7
+ scikit-learn
8
+ matplotlib
9
+ seaborn
10
+ pytorch-grad-cam
11
+ opencv-python
12
+ albumentations