diff --git a/.dockerignore b/.dockerignore
deleted file mode 100644
index 5ab9f6d..0000000
--- a/.dockerignore
+++ /dev/null
@@ -1,106 +0,0 @@
-# Notebooks de développement mais GARDER les samples
-notebooks/*.ipynb
-notebooks/p8_notebook.ipynb
-notebooks/requirements.txt
-.ipynb_checkpoints/
-# GARDER: notebooks/content/data/test_images_sample/ (nécessaire pour l'app)
-
-# Environment files (variables passées via docker run ou compose)
-.env
-.env.*
-!.env.example
-
-# Python cache et build files
-__pycache__/
-*.py[cod]
-*$py.class
-*.so
-.Python
-build/
-develop-eggs/
-dist/
-downloads/
-eggs/
-.eggs/
-lib/
-lib64/
-parts/
-sdist/
-var/
-wheels/
-pip-wheel-metadata/
-share/python-wheels/
-*.egg-info/
-.installed.cfg
-*.egg
-MANIFEST
-
-# Virtual environments
-venv/
-env/
-ENV/
-env.bak/
-venv.bak/
-.venv/
-
-# IDE et editor files
-.vscode/
-.idea/
-*.swp
-*.swo
-*~
-.DS_Store
-Thumbs.db
-
-# Git files
-.git/
-.gitignore
-.gitattributes
-
-# Documentation
-*.md
-!README.MD
-docs/
-documentation/
-
-# Test files
-tests/
-test_*/
-*_test.py
-debug_*.py
-pytest.ini
-tox.ini
-.coverage
-.pytest_cache/
-
-# Jupyter notebook outputs
-*.nbconvert
-
-# Fichiers temporaires
-.cache/
-.tmp/
-tmp/
-temp/
-*.tmp
-*.temp
-*.log
-logs/
-
-# OS generated files
-.DS_Store?
-ehthumbs.db
-Icon?
-
-# MLflow artifacts locaux (seront téléchargés depuis le registry)
-mlruns/
-mlruns.backup/
-mlartifacts/
-
-# Backup files
-*.bak
-*.backup
-
-# Large datasets (samples nécessaires sont gardés)
-*.zip
-*.tar.gz
-*.rar
diff --git a/.env.example b/.env.example
deleted file mode 100644
index 49f2004..0000000
--- a/.env.example
+++ /dev/null
@@ -1,41 +0,0 @@
-# =============================================================================
-# Configuration du serveur
-# =============================================================================
-# Port sur lequel nginx écoute (défaut: 8080 pour compatibilité Cloud Run)
-NGINX_PORT=8080
-
-# =============================================================================
-# Configuration MLflow (pour le versioning et le téléchargement des modèles)
-# =============================================================================
-# URI du serveur MLflow de tracking
-MLFLOW_TRACKING_URI=http://localhost:5000
-
-# URL du stockage S3/MinIO pour les artefacts MLflow
-MLFLOW_S3_ENDPOINT_URL=http://localhost:9000
-
-# Clés d'accès S3/MinIO
-AWS_ACCESS_KEY_ID=minio_access_key
-AWS_SECRET_ACCESS_KEY=minio_secret_key
-
-# =============================================================================
-# Configuration email (optionnel - pour les notifications)
-# =============================================================================
-# Serveur SMTP
-SMTP_SERVER=smtp.gmail.com
-SMTP_PORT=587
-
-# Identifiants email
-SMTP_EMAIL=noreply@yourcompany.com
-SMTP_PASSWORD=your_app_password
-SMTP_FROM_ALIAS=Multi-Segmentation API
-
-# Email de l'administrateur (destinataire des notifications)
-ADMIN_EMAIL=admin@yourcompany.com
-
-# =============================================================================
-# Configuration de l'API
-# =============================================================================
-# URL de base de l'API (utilisée par Streamlit pour faire les appels)
-# En développement local: http://localhost:8080/api
-# En production: https://your-domain.com/api
-MULTISEG_API_BASE_URL=http://localhost:8080/api
diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index 242c724..0000000
--- a/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-./mlruns*
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
deleted file mode 100644
index 925177b..0000000
--- a/Dockerfile
+++ /dev/null
@@ -1,44 +0,0 @@
-FROM python:3.12-slim
-
-WORKDIR /app
-
-# Install system dependencies (ajout de git pour segmentation_models)
-RUN apt-get update && \
- apt-get install -y nginx curl gettext-base git && \
- # Pour OpenCV si nécessaire
- apt-get install -y libglib2.0-0 libsm6 libxext6 libxrender-dev libgomp1 && \
- adduser --system --no-create-home --group www-data || true && \
- apt-get clean && \
- rm -rf /var/lib/apt/lists/*
-
-# Copy app/ d'abord pour avoir requirements.txt
-COPY app/ ./app/
-
-# Install requirements depuis le bon chemin
-RUN pip install --no-cache-dir -r app/requirements.txt
-
-# ✅ CORRECTION: Copy start.sh AVANT les permissions
-COPY start.sh ./start.sh
-
-# Copy du reste après installation (optimise les layers Docker)
-COPY utils/ ./utils/
-COPY cityscapes_config.json .
-COPY notebooks/content/data/test_images_sample/ ./notebooks/content/data/test_images_sample/
-COPY notebooks/content/data/train_images_sample/ ./notebooks/content/data/train_images_sample/
-
-# Copy nginx config
-COPY nginx.conf /etc/nginx/nginx.conf.template
-
-# ✅ CORRECTION: Setup permissions APRÈS avoir copié start.sh + correction fins de ligne
-RUN mkdir -p /var/log/nginx /var/lib/nginx /run && \
- sed -i 's/\r$//' ./start.sh && \
- chmod +x ./start.sh
-
-# Environment variables
-ENV NGINX_PORT=8080
-ENV MULTISEG_API_BASE_URL=http://localhost:8080/api
-
-EXPOSE $NGINX_PORT
-
-# ✅ CORRECTION: Chemin cohérent (./start.sh au lieu de /app/start.sh)
-CMD ["./start.sh"]
diff --git a/README.MD b/README.MD
deleted file mode 100644
index 6e14ca9..0000000
--- a/README.MD
+++ /dev/null
@@ -1,116 +0,0 @@
-# Street Vision PoC - Segmentation Sémantique Urbaine
-
-## 🎯 Description du Projet
-
-**Street Vision PoC** est une preuve de concept démontrant l'amélioration des performances de segmentation sémantique urbaine en comparant les architectures CNN traditionnelles (FPN) aux approches Transformer modernes (SegFormer).
-
-Ce projet évalue empiriquement le potentiel des **Vision Transformers** pour la compréhension de scènes urbaines complexes, avec un focus sur les classes critiques pour la sécurité (piétons, véhicules, signalétique).
-
-### 🔬 Contexte Technique
-
-- **Dataset** : Cityscapes (2,975 images haute résolution annotées pixel-par-pixel)
-- **Architectures comparées** :
- - **CNN traditionnel** : FPN + EfficientNet-B0/ResNet34
- - **Vision Transformer** : SegFormer-B0/B1
-- **Résolutions d'évaluation** : 512×512 et 768×768 pixels
-- **Métrique principale** : Mean Intersection over Union (mIoU)
-
-## 📊 Résultats Principaux
-
-| **Modèle** | **mIoU** | **Paramètres** | **Taille** | **Performance** |
-|------------|----------|----------------|------------|-----------------|
-| **SegFormer-B1** | **79.98%** | 13.68M | 52MB | â� **Meilleur** |
-| **FPN+ResNet34** | 79.22% | 23.16M | 88MB | 🔄 Baseline forte |
-| **FPN+EfficientNet-B0** | 78.67% | 5.76M | 22MB | 💡 Compact |
-| **SegFormer-B0** | 77.91% | 3.72M | 14MB | ⚡ Ultra-léger |
-
-**Analyse comparative** : SegFormer-B1 et FPN+ResNet34 atteignent des performances similaires (~79-80% mIoU), mais SegFormer-B1 présente l'avantage d'être plus compact et probablement plus rapide sur GPU. Les versions SegFormer-B2 à B5 promettraient des gains significatifs, mais mes contraintes matérielles n'ont pas permis leur évaluation.
-
-### 🎯 Gains Significatifs par Classes Critiques
-
-- **Human** : +1.78% IoU (sécurité critique)
-- **Vehicle** : +1.05% IoU (obstacles mobiles)
-- **Object** : +0.56% IoU (signalétique urbaine)
-
-## 🚀 Déploiement Rapide
-
-### Docker Hub
-
-L'application est containerisée et disponible sur Docker Hub :
-
-```bash
-docker pull grgmdmn/street-vision-poc_api
-```
-
-### Configuration avec Docker Compose
-
-1. Copiez le fichier d'exemple de configuration :
-```bash
-cp docker-compose.yml.example docker-compose.yml
-```
-
-2. Configurez les variables d'environnement dans `docker-compose.yml`.
-
-3. Lancez l'application :
-```bash
-docker-compose up -d
-```
-
-4. Accédez à l'interface : `http://localhost:$(port)`
-
-## 🎮 Fonctionnalités de l'Interface
-
-### Dashboard Interactif
-
-- **Upload d'images** : Glisser-déposer d'images urbaines
-- **Double inférence** : Comparaison simultanée FPN vs SegFormer
-- **Visualisation** : Masques de segmentation colorés par classe
-- **Métriques temps réel** : Temps d'inférence et scores de confiance
-- **Export** : Téléchargement des résultats de segmentation
-- **Accessibilité WCAG** : Interface conforme aux standards d'accessibilité
-
-### Analyse Exploratoire des Données
-
-- **Statistiques Cityscapes** : Distribution des classes, résolutions natives
-- **Graphiques interactifs** : Répartition pixel par méta-classe
-- **Exemples annotés** : Visualisation échantillons du dataset
-
-## 📈 Méthodologie d'Évaluation
-
-### Approche Comparative
-
-1. **Baseline CNN** : Réentraînement FPN+EfficientNet/ResNet aux résolutions supérieures
-2. **Nouvelle approche** : Évaluation SegFormer avec attention globale
-3. **Protocole rigoureux** : Validation croisée, métriques standardisées
-4. **Analyse par classe** : Performance détaillée sur 8 méta-classes urbaines
-
-### Limites Identifiées
-
-- **Résolution fixe** : Évaluation sans sliding window (vs protocole original)
-- **Ressources limitées** : Tests uniquement sur SegFormer-B0/B1
-- **Conditions contrôlées** : Dataset Cityscapes uniquement (météo favorable)
-
-## 🔬 Insights Techniques
-
-### Avantages SegFormer
-
-- **Attention globale** : Chaque pixel "voit" toute l'image simultanément
-- **Architecture plus légère** : Modèle compact avec moins de paramètres
-- **Robustesse contextuelle** : Meilleure gestion occlusions et objets complexes
-- **Potentiel d'amélioration** : Versions B2-B5 promettraient des gains significatifs
-
-### Trade-offs Identifiés
-
-- **Vitesse CPU classique** : ~2× plus lent que FPN sur processeurs haute performance (Xeon, 9600X)
-- **Vitesse CPU économe** : 3× plus rapide sur processeurs économes en énergie (N100)
-- **Optimisation GPU** : Architecture Transformer favorisée par accélération matérielle
-
-## 📚 Références
-
-- **Xie, E. et al.** (2021). *SegFormer: Simple and Efficient Design for Semantic Segmentation with Transformers*. NeurIPS 2021.
-- **Cordts, M. et al.** (2016). *The Cityscapes Dataset for Semantic Urban Scene Understanding*. CVPR 2016.
-- **Segmentation Models PyTorch** - [Framework d'implémentation utilisé](https://github.com/qubvel/segmentation_models.pytorch)
-
----
-
-**Note** : Cette preuve de concept démontre le potentiel des architectures Transformer pour la segmentation urbaine, tout en soulignant l'importance des ressources computationnelles pour exploiter pleinement leurs capacités.
\ No newline at end of file
diff --git a/app/README.MD b/app/README.MD
deleted file mode 100644
index 7b27e38..0000000
--- a/app/README.MD
+++ /dev/null
@@ -1,108 +0,0 @@
-
-# Dashboard de Comparaison de Modèles
-
-## Conformité aux Exigences
-
-### Analyse Exploratoire des Données Non Structurées (Images)
-
-**Présentation d'exemples d'images selon les catégories :**
-- Visualisation d'images du dataset Cityscapes organisées par 8 méta-classes de segmentation
-- Sélection interactive d'images d'entraînement et de test avec prévisualisation
-- Interface de navigation par catégories avec noms d'affichage conviviaux
-
-**Comptage et répartition des données :**
-- Graphiques en secteurs (pie charts) détaillant la répartition des 25,000 images Cityscapes
-- Visualisation de l'utilisation projet : 80% train / 20% validation / 100% test
-- Graphique de distribution des classes dans le dataset d'entraînement
-- Tableaux récapitulatifs avec statistiques détaillées par split
-
-**Transformations des images :**
-- Démonstration interactive du preprocessing : redimensionnement et normalisation
-- Visualisation des augmentations de données aléatoires (rotation, flip, luminosité, etc.)
-- Comparaison avant/après transformations avec alignement visuel
-- Documentation complète des 6 types d'augmentations possibles
-
-### Sélection de Données d'Entrée
-
-**Interface de sélection multiple :**
-- Liste déroulante pour images test Cityscapes avec informations sur la vérité terrain
-- Upload de fichiers personnels (JPEG, PNG) avec validation de format
-- Prévisualisation des images sélectionnées avant traitement
-- Gestion des erreurs et feedback utilisateur en temps réel
-
-### Résultats de Prédiction
-
-**Comparaison complète de modèles :**
-- Affichage côte à côte des prédictions des deux meilleurs modèles
-- Visualisations avec image originale, masques prédits et vérité terrain
-- Détection et mise en évidence des erreurs de segmentation
-- Statistiques détaillées par classe avec pourcentages et nombre de pixels
-
-**Métriques de performance :**
-- Temps d'inférence comparatif avec analyse de vitesse
-- Scores de performance (mIoU, Accuracy) par modèle
-- IoU par classe pour analyse fine des performances
-- Graphiques comparatifs interactifs des résultats
-
-### Déploiement Cloud
-
-**Architecture déployée :**
-- Application FastAPI pour l'API de comparaison de modèles
-- Interface Streamlit pour le dashboard utilisateur
-- Déploiement sur infrastructure cloud avec haute disponibilité
-- Gestion automatique des ressources et montée en charge
-
-### Accessibilité WCAG
-
-**Conformité aux critères essentiels :**
-
-#### Contraste des Couleurs (WCAG AA)
-- Palette de couleurs avec ratios de contraste ≥ 4.1:1 pour éléments graphiques
-- Ratios de contraste ≥ 4.5:1 pour le texte sur fond
-- 8 couleurs principales validées : bleu (#0066CC), rouge (#CC0000), vert (#006600), etc.
-- Remplacement des dégradés par des couleurs unies à contraste élevé
-
-#### Alternatives Textuelles
-- Descriptions alternatives détaillées pour tous les graphiques générées automatiquement
-- Textes explicatifs pour chaque visualisation (pie charts, bar charts)
-- Labels ARIA appropriés pour les éléments interactifs
-- Documentation textuelle complète des transformations d'images
-
-#### Indication Non-Couleur Uniquement
-- Motifs et hachures complémentaires aux couleurs (optionnel via checkbox)
-- 6 motifs différents : diagonales, verticales, horizontales, points, croix
-- Différenciation par forme et texture en plus des couleurs
-- Bordures et contours renforcés pour la distinction visuelle
-
-#### Navigation Clavier
-- CSS focus visible avec contours bleus (#0066CC) de 2px
-- Support complet de la navigation par tabulation
-- Indicateurs visuels clairs pour les éléments focusés
-- Respect de l'ordre logique de navigation
-
-#### Tableaux de Données Accessibles
-- Tableaux structurés complémentaires à tous les graphiques
-- En-têtes appropriés avec scope et descriptions
-- Données exportables et lisibles par lecteurs d'écran
-- Configuration responsive pour tous les écrans
-
-**Fonctionnalités d'assistance intégrées :**
-- Checkbox "Activer les motifs (accessibilité visuelle)" pour personnalisation
-- Descriptions automatiques des graphiques avec statistiques complètes
-- Interface adaptable aux besoins des utilisateurs en situation de handicap
-- Documentation complète des fonctionnalités d'accessibilité via endpoint `/accessibility-info`
-
-## Architecture Technique
-
-**Stack technologique :**
-- Backend : FastAPI + PyTorch pour l'inférence des modèles
-- Frontend : Streamlit avec composants accessibles
-- Visualisations : Matplotlib avec palettes WCAG
-- API REST documentée avec validation Pydantic
-- Gestion d'état optimisée pour les comparaisons de modèles
-
-**Performance et fiabilité :**
-- Temps d'inférence optimisés (< 1 seconde par image)
-- Gestion mémoire efficace avec fermeture automatique des figures
-- Validation des formats et tailles de fichiers
-- Nettoyage automatique des fichiers temporaires
diff --git a/app/main.py b/app/main.py
deleted file mode 100644
index a0c8cc8..0000000
--- a/app/main.py
+++ /dev/null
@@ -1,834 +0,0 @@
-import os
-import sys
-import traceback
-import tempfile
-import shutil
-from datetime import datetime
-from typing import Optional, List
-from pathlib import Path
-import mlflow
-from fastapi import FastAPI, HTTPException, File, UploadFile
-from fastapi.responses import FileResponse
-from pydantic import BaseModel
-import numpy as np
-import pickle
-import base64
-import matplotlib.pyplot as plt
-import matplotlib.image as mpimg
-
-
-# Configuration MLflow avec variables d'environnement
-def configure_mlflow():
- """Configure MLflow avec les variables d'environnement"""
- print("=== DEBUG VARIABLES D'ENVIRONNEMENT ===")
-
- mlflow_tracking_uri = os.getenv("MLFLOW_TRACKING_URI", "").strip()
- mlflow_s3_endpoint_url = os.getenv("MLFLOW_S3_ENDPOINT_URL", "").strip()
- aws_access_key_id = os.getenv("AWS_ACCESS_KEY_ID", "").strip()
- aws_secret_access_key = os.getenv("AWS_SECRET_ACCESS_KEY", "").strip()
-
- print(f"MLFLOW_TRACKING_URI: {mlflow_tracking_uri}")
- print(f"MLFLOW_S3_ENDPOINT_URL: {mlflow_s3_endpoint_url}")
- print(f"AWS_ACCESS_KEY_ID: {aws_access_key_id}")
- print(f"AWS_SECRET_ACCESS_KEY: {'***' if aws_secret_access_key else None} ({'set' if aws_secret_access_key else 'not set'})")
- print("============================================")
-
- if not mlflow_tracking_uri:
- raise ValueError("MLFLOW_TRACKING_URI not found in environment variables")
-
- mlflow.set_tracking_uri(mlflow_tracking_uri)
- print(f"MLflow Tracking URI: {mlflow_tracking_uri}")
-
- if not mlflow_s3_endpoint_url or not aws_access_key_id or not aws_secret_access_key:
- raise ValueError("Variables d'environnement MLflow manquantes (S3_ENDPOINT, ACCESS_KEY, SECRET_KEY)")
-
- os.environ["MLFLOW_S3_ENDPOINT_URL"] = mlflow_s3_endpoint_url
- os.environ["AWS_ACCESS_KEY_ID"] = aws_access_key_id
- os.environ["AWS_SECRET_ACCESS_KEY"] = aws_secret_access_key
- print(f"MLflow S3 Endpoint: {mlflow_s3_endpoint_url}")
- print("✅ Identifiants AWS configurés")
- print("✅ Configuration MLflow terminée")
-
-# Import des fonctions utils
-sys.path.append('.')
-sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
-from utils.utils import (
- load_cityscapes_config,
- load_model,
- run_inference_and_visualize,
- colorize_mask
-)
-
-# Configuration
-MODEL_NAME = "StreetsSegmentation"
-SAMPLE_IMAGES_DIR = "./notebooks/content/data/test_images_sample"
-TRAIN_IMAGES_DIR = "./notebooks/content/data/train_images_sample"
-CITYSCAPES_CONFIG_PATH = "./cityscapes_config.json"
-TEMP_UPLOAD_DIR = "/tmp/uploads"
-
-# Modèles de données mis à jour
-class ModelInfo(BaseModel):
- name: str
- run_id: str
- encoder_name: str
- input_size: tuple
- rank: int
- architecture: Optional[str] = None
- test_mean_iou: Optional[float] = None
- test_accuracy: Optional[float] = None
- class_ious: Optional[dict] = None
-
-class ComparisonResult(BaseModel):
- success: bool
- message: str
- model1_info: ModelInfo
- model2_info: ModelInfo
- image_path: Optional[str] = None
- mask_path: Optional[str] = None
- model1_stats: Optional[dict] = None
- model2_stats: Optional[dict] = None
- model1_inference_time: float
- model2_inference_time: float
- speed_comparison: dict
- ground_truth_available: bool = False
- figure_data: Optional[str] = None
-
-class ImageInfo(BaseModel):
- filename: str
- display_name: str
- has_ground_truth: bool
-
-class AvailableImagesResponse(BaseModel):
- images: List[ImageInfo]
- total_count: int
-
-class PreprocessingRequest(BaseModel):
- filename: str
- apply_augmentation: bool = False
-
-class PreprocessingResult(BaseModel):
- success: bool
- message: str
- original_image: Optional[str] = None
- normalized_image: Optional[str] = None
- augmented_image: Optional[str] = None
- transformations_applied: Optional[list] = None
-
-class SampleImageRequest(BaseModel):
- filename: str
-
-# Variables globales pour les deux modèles
-best_model = None
-second_best_model = None
-best_model_info = {}
-second_best_model_info = {}
-mapping_config = None
-
-def get_model_detailed_info(run_id, mapping_config):
- """Récupère les informations détaillées d'un modèle depuis MLflow"""
- client = mlflow.tracking.MlflowClient()
-
- try:
- run = mlflow.get_run(run_id)
- params = run.data.params
- metrics = run.data.metrics
-
- # Architecture depuis le paramètre model_architecture
- architecture = params.get("model_architecture", "Unknown").split('_')[0]
-
- # Métriques de performance
- test_mean_iou = metrics.get("test_mean_iou", None)
- test_accuracy = metrics.get("test_accuracy", None)
-
- # IoU par classe depuis les métriques class_X_iou
- class_ious = {}
- if mapping_config and 'group_names' in mapping_config:
- for i, class_name in enumerate(mapping_config['group_names']):
- metric_key = f"class_{i}_iou"
- if metric_key in metrics:
- class_ious[class_name] = round(metrics[metric_key], 3)
-
- return {
- "architecture": architecture,
- "test_mean_iou": test_mean_iou,
- "test_accuracy": test_accuracy,
- "class_ious": class_ious
- }
- except Exception as e:
- print(f"⚠� Erreur lors de la récupération des infos détaillées: {e}")
- return {
- "architecture": "Unknown",
- "test_mean_iou": None,
- "test_accuracy": None,
- "class_ious": {}
- }
-
-def initialize_models():
- """Initialise les deux meilleurs modèles au démarrage"""
- global best_model, second_best_model, best_model_info, second_best_model_info, mapping_config
-
- try:
- print("🔄 Configuration de MLflow...")
- configure_mlflow()
-
- print("🔄 Chargement de la configuration Cityscapes avec couleurs WCAG...")
- mapping_config = load_cityscapes_config(CITYSCAPES_CONFIG_PATH, verbose=False, use_wcag_colors=True)
- print("✅ Configuration Cityscapes chargée avec couleurs WCAG")
-
-
- print("🔄 Chargement du meilleur modèle...")
- best_model, best_run_id, best_encoder_name, best_img_size = load_model(
- experiment_name="OC Projet 9",
- metric="test_mean_iou",
- top_n=1
- )
-
- # Récupérer les infos détaillées du meilleur modèle
- best_detailed_info = get_model_detailed_info(best_run_id, mapping_config)
-
- best_model_info = {
- "name": "Meilleur modèle",
- "run_id": best_run_id,
- "encoder_name": best_encoder_name,
- "input_size": best_img_size,
- "rank": 1,
- "architecture": best_detailed_info["architecture"],
- "test_mean_iou": best_detailed_info["test_mean_iou"],
- "test_accuracy": best_detailed_info["test_accuracy"],
- "class_ious": best_detailed_info["class_ious"]
- }
-
- print("🔄 Chargement du deuxième meilleur modèle...")
- second_best_model, second_run_id, second_encoder_name, second_img_size = load_model(
- experiment_name="OC Projet 9",
- metric="test_mean_iou",
- top_n=2
- )
-
- # Récupérer les infos détaillées du deuxième modèle
- second_detailed_info = get_model_detailed_info(second_run_id, mapping_config)
-
- second_best_model_info = {
- "name": "Deuxième modèle",
- "run_id": second_run_id,
- "encoder_name": second_encoder_name,
- "input_size": second_img_size,
- "rank": 2,
- "architecture": second_detailed_info["architecture"],
- "test_mean_iou": second_detailed_info["test_mean_iou"],
- "test_accuracy": second_detailed_info["test_accuracy"],
- "class_ious": second_detailed_info["class_ious"]
- }
-
- os.makedirs(TEMP_UPLOAD_DIR, exist_ok=True)
-
- except Exception as e:
- print(f"� Erreur lors de l'initialisation: {e}")
- traceback.print_exc()
- raise e
-
-def get_accessibility_info():
- """Retourne les informations d'accessibilité pour le frontend"""
- return {
- "wcag_compliant": True,
- "color_palette": {
- "primary_blue": "#0066CC",
- "primary_red": "#CC0000",
- "primary_green": "#006600",
- "primary_orange": "#CC6600",
- "secondary_purple": "#663399",
- "secondary_teal": "#006666",
- "neutral_dark": "#333333",
- "neutral_medium": "#666666"
- },
- "contrast_ratios": {
- "primary_colors_vs_white": "≥ 4.1:1 (WCAG AA)",
- "text_vs_background": "≥ 4.5:1 (WCAG AA)"
- },
- "features": [
- "Couleurs à contraste élevé",
- "Motifs alternatifs aux couleurs",
- "Descriptions textuelles alternatives en cas d'absence d'images",
- "Tableaux de données complémentaires",
- "Navigation clavier supportée"
- ]
- }
-
-
-# Initialisation de l'API
-app = FastAPI(
- title="Multi-Class Segmentation Comparison API",
- description="API de comparaison de segmentation sémantique avec deux modèles",
- version="2.0.0"
-)
-
-@app.on_event("startup")
-async def startup_event():
- try:
- initialize_models()
- print("🚀 API démarrée avec succès - Modèles chargés!")
- except Exception as e:
- print(f"⚠� ATTENTION: Impossible de charger les modèles au démarrage: {e}")
-
-@app.get("/")
-def root():
- return {
- "message": "Multi-Class Segmentation Comparison API - Online",
- "models_loaded": best_model is not None and second_best_model is not None,
- "best_model": best_model_info if best_model else None,
- "second_best_model": second_best_model_info if second_best_model else None,
- "num_classes": mapping_config['num_classes'] if mapping_config else None
- }
-
-@app.get("/health")
-def health_check():
- if best_model is None or second_best_model is None or mapping_config is None:
- raise HTTPException(status_code=503, detail="Models not loaded")
- return {
- "status": "healthy",
- "models_loaded": True,
- "timestamp": datetime.utcnow().isoformat()
- }
-
-
-# Modifier le endpoint /models pour inclure des couleurs accessibles :
-@app.get("/models", response_model=dict)
-def get_models_info():
- if best_model is None or second_best_model is None:
- raise HTTPException(status_code=503, detail="Models not loaded")
-
- # NOUVELLE RÉPARTITION DES COULEURS selon votre mapping final
- wcag_accessible_colors = [
- [102, 102, 102], # Flat: neutral_medium (gris moyen pour routes/trottoirs)
- [204, 0, 0], # Human: primary_red (rouge pour piétons/cyclistes)
- [102, 51, 153], # Vehicle: secondary_purple (violet pour véhicules)
- [204, 102, 0], # Construction: primary_orange (orange pour bâtiments)
- [0, 102, 102], # Object: secondary_teal (teal pour objets/signalétique)
- [0, 102, 0], # Nature: primary_green (vert pour végétation)
- [0, 102, 204], # Sky: primary_blue (bleu pour ciel)
- [51, 51, 51] # Void: neutral_dark (gris foncé pour zones non-définies)
- ]
-
- # Mettre à jour la configuration avec les nouvelles couleurs
- if mapping_config:
- mapping_config['group_colors'] = np.array(wcag_accessible_colors, dtype=np.uint8)
-
- return {
- "best_model": best_model_info,
- "second_best_model": second_best_model_info,
- "num_classes": mapping_config['num_classes'],
- "class_names": mapping_config['group_names'],
- "class_colors": wcag_accessible_colors,
- "accessibility_info": get_accessibility_info(),
- "preprocessing_resolution": best_model_info.get("input_size", (512, 512))
- }
-
-
-
-@app.get("/dataset-info")
-def get_dataset_info():
- """Retourne les informations sur le dataset"""
- return {
- "name": "Cityscapes Dataset",
- "description": "Référence internationale pour l'évaluation des algorithmes de segmentation sémantique en environnement urbain",
- "total_images": 25000,
- "resolution": "2048×1024 pixels",
- "cities": 50,
- "countries": ["Allemagne", "Suisse"],
- "splits": {
- "train": {"images": 2975, "usage": "Entraînement avec annotations fines"},
- "validation": {"images": 500, "usage": "Validation avec annotations de référence"},
- "test": {"images": 1525, "usage": "Test (annotations non-publiques)"},
- "coarse": {"images": 20000, "usage": "Entraînement avec annotations grossières"}
- },
- "project_splits": {
- "train": {"images": 2380, "percentage": 80, "source": "Cityscapes train"},
- "validation": {"images": 595, "percentage": 20, "source": "Cityscapes train"},
- "test": {"images": 500, "percentage": 100, "source": "Cityscapes val"}
- },
- "meta_classes": mapping_config['group_names'] if mapping_config else [],
- "num_classes": mapping_config['num_classes'] if mapping_config else 0
- }
-
-@app.get("/train-images", response_model=AvailableImagesResponse)
-def get_train_images():
- """Retourne la liste des images d'entraînement disponibles"""
- try:
- original_dir = Path(TRAIN_IMAGES_DIR) / "original"
- mask_dir = Path(TRAIN_IMAGES_DIR) / "mask"
-
- if not original_dir.exists():
- raise HTTPException(status_code=404, detail="Train images directory not found")
-
- images = []
- for img_path in original_dir.glob("*leftImg8bit.png"):
- # Construire le nom du masque correspondant
- base_name = img_path.stem.replace("_leftImg8bit", "")
- mask_name = f"{base_name}_gtFine_labelIds.png"
- mask_path = mask_dir / mask_name
-
- # Créer un nom d'affichage plus convivial
- display_name = base_name.replace("_", " ").title()
-
- images.append(ImageInfo(
- filename=img_path.name,
- display_name=display_name,
- has_ground_truth=mask_path.exists()
- ))
-
- # Trier par nom pour un affichage cohérent
- images.sort(key=lambda x: x.filename)
-
- return AvailableImagesResponse(
- images=images,
- total_count=len(images)
- )
-
- except Exception as e:
- raise HTTPException(status_code=500, detail=f"Error listing train images: {str(e)}")
-
-@app.get("/train-image/{filename}")
-def get_train_image(filename: str):
- """Sert une image d'entraînement pour prévisualisation"""
- try:
- original_dir = Path(TRAIN_IMAGES_DIR) / "original"
- image_path = original_dir / filename
-
- if not image_path.exists():
- raise HTTPException(status_code=404, detail=f"Train image {filename} not found")
-
- # Vérifier que c'est bien un fichier image attendu
- if not filename.endswith('_leftImg8bit.png'):
- raise HTTPException(status_code=400, detail="Invalid image filename format")
-
- return FileResponse(
- image_path,
- media_type="image/png",
- headers={"Content-Disposition": f"inline; filename={filename}"}
- )
-
- except HTTPException:
- raise
- except Exception as e:
- raise HTTPException(status_code=500, detail=f"Error serving train image: {str(e)}")
-
-@app.get("/class-repartition")
-def get_class_repartition():
- """Sert le graphique de répartition des classes"""
- try:
- graph_path = Path(TRAIN_IMAGES_DIR) / "class_repartition.png"
-
- if not graph_path.exists():
- raise HTTPException(status_code=404, detail="Class repartition graph not found")
-
- return FileResponse(
- graph_path,
- media_type="image/png",
- headers={"Content-Disposition": "inline; filename=class_repartition.png"}
- )
-
- except HTTPException:
- raise
- except Exception as e:
- raise HTTPException(status_code=500, detail=f"Error serving class repartition graph: {str(e)}")
-
-@app.post("/preprocess-train-image", response_model=PreprocessingResult)
-def preprocess_train_image(request: PreprocessingRequest):
- """Prétraite une image d'entraînement et retourne les versions transformées"""
- if mapping_config is None:
- raise HTTPException(status_code=503, detail="Configuration not loaded")
-
- # Vérifier que le meilleur modèle est chargé
- if best_model is None or not best_model_info:
- raise HTTPException(status_code=503, detail="Best model not loaded")
-
- try:
- original_dir = Path(TRAIN_IMAGES_DIR) / "original"
- image_path = original_dir / request.filename
-
- if not image_path.exists():
- raise HTTPException(status_code=404, detail=f"Train image {request.filename} not found")
-
- # Importer les fonctions nécessaires
- import numpy as np
- import matplotlib.pyplot as plt
- from PIL import Image
- import io
- import base64
- from utils.utils import get_preprocessing_fn, apply_random_augmentation
-
- # Charger l'image originale
- original_pil = Image.open(image_path).convert('RGB')
- original_np = np.array(original_pil)
-
- # UTILISER LA RÉSOLUTION DU MEILLEUR MODÈLE au lieu de (512, 512)
- target_size = best_model_info.get("input_size", (512, 512))
- print(f"🎯 Utilisation de la taille du meilleur modèle: {target_size}")
-
- # Appliquer le preprocessing avec la résolution du meilleur modèle
- preprocess_fn = get_preprocessing_fn(img_size=target_size, encoder=None)
- normalized_tensor, _ = preprocess_fn(original_np, None)
-
- # Convertir le tensor en image pour affichage
- normalized_np = normalized_tensor.permute(1, 2, 0).numpy()
- # Dénormaliser pour l'affichage (tensor était normalisé 0-1)
- normalized_display = (normalized_np * 255).astype(np.uint8)
-
- # Créer les images en base64 pour l'envoi
- def img_to_base64(img_array):
- img_pil = Image.fromarray(img_array)
- buffer = io.BytesIO()
- img_pil.save(buffer, format='PNG')
- return base64.b64encode(buffer.getvalue()).decode()
-
- # Image originale redimensionnée pour comparaison (avec la taille du meilleur modèle)
- original_resized = np.array(original_pil.resize(target_size))
-
- result = PreprocessingResult(
- success=True,
- message="Preprocessing completed successfully",
- original_image=img_to_base64(original_resized),
- normalized_image=img_to_base64(normalized_display),
- transformations_applied=[f"Resize {target_size}", "Normalization (0-1)"]
- )
-
- # Appliquer l'augmentation si demandée
- if request.apply_augmentation:
- augmented_np, transforms_applied = apply_random_augmentation(original_np)
- # Appliquer aussi le preprocessing à l'image augmentée
- augmented_tensor, _ = preprocess_fn(augmented_np, None)
- augmented_display = (augmented_tensor.permute(1, 2, 0).numpy() * 255).astype(np.uint8)
-
- result.augmented_image = img_to_base64(augmented_display)
- result.transformations_applied.extend(transforms_applied)
-
- return result
-
- except Exception as e:
- raise HTTPException(status_code=500, detail=f"Preprocessing error: {str(e)}")
-
-@app.get("/best-model-resolution")
-def get_best_model_resolution():
- """Retourne la résolution utilisée par le meilleur modèle"""
- if best_model is None or not best_model_info:
- raise HTTPException(status_code=503, detail="Best model not loaded")
-
- return {
- "model_name": best_model_info.get("name", "Unknown"),
- "encoder_name": best_model_info.get("encoder_name", "Unknown"),
- "input_size": best_model_info.get("input_size", (512, 512)),
- "architecture": best_model_info.get("architecture", "Unknown")
- }
-
-@app.get("/sample-images", response_model=AvailableImagesResponse)
-def get_sample_images():
- try:
- original_dir = Path(SAMPLE_IMAGES_DIR) / "original"
- mask_dir = Path(SAMPLE_IMAGES_DIR) / "mask"
- if not original_dir.exists():
- raise HTTPException(status_code=404, detail="Sample images directory not found")
- images = []
- for img_path in original_dir.glob("*leftImg8bit.png"):
- base_name = img_path.stem.replace("_leftImg8bit", "")
- mask_name = f"{base_name}_gtFine_labelIds.png"
- mask_path = mask_dir / mask_name
- display_name = base_name.replace("_", " ").title()
- images.append(ImageInfo(
- filename=img_path.name,
- display_name=display_name,
- has_ground_truth=mask_path.exists()
- ))
- images.sort(key=lambda x: x.filename)
- return AvailableImagesResponse(images=images, total_count=len(images))
- except Exception as e:
- raise HTTPException(status_code=500, detail=f"Error listing sample images: {str(e)}")
-
-@app.get("/sample-image/{filename}")
-def get_sample_image(filename: str):
- try:
- original_dir = Path(SAMPLE_IMAGES_DIR) / "original"
- image_path = original_dir / filename
- if not image_path.exists():
- raise HTTPException(status_code=404, detail=f"Sample image {filename} not found")
- if not filename.endswith('_leftImg8bit.png'):
- raise HTTPException(status_code=400, detail="Invalid image filename format")
- return FileResponse(
- image_path,
- media_type="image/png",
- headers={"Content-Disposition": f"inline; filename={filename}"}
- )
- except HTTPException:
- raise
- except Exception as e:
- raise HTTPException(status_code=500, detail=f"Error serving image: {str(e)}")
-
-@app.post("/compare-sample", response_model=ComparisonResult)
-def compare_sample_image(request: SampleImageRequest):
- if best_model is None or second_best_model is None or mapping_config is None:
- raise HTTPException(status_code=503, detail="Models not loaded")
- try:
- original_dir = Path(SAMPLE_IMAGES_DIR) / "original"
- image_path = original_dir / request.filename
- if not image_path.exists():
- raise HTTPException(status_code=404, detail=f"Sample image {request.filename} not found")
- base_name = image_path.stem.replace("_leftImg8bit", "")
- mask_name = f"{base_name}_gtFine_labelIds.png"
- mask_path = Path(SAMPLE_IMAGES_DIR) / "mask" / mask_name
- mask_path_str = str(mask_path) if mask_path.exists() else None
-
- # Inférence modèle 1 avec sa résolution spécifique
- pred1, t1, fig1 = run_inference_and_visualize(
- image_path=str(image_path),
- mask_path=mask_path_str,
- model=best_model,
- encoder_name=None, # Normalisé de la même manière
- img_size=best_model_info["input_size"], # Utilise la résolution du modèle
- mapping_config=mapping_config,
- save_dir=None, show_stats=False, show_plot=False
- )
- # Inférence modèle 2 avec sa résolution spécifique
- pred2, t2, fig2 = run_inference_and_visualize(
- image_path=str(image_path),
- mask_path=mask_path_str,
- model=second_best_model,
- encoder_name=None, # Normalisé de la même manière
- img_size=second_best_model_info["input_size"], # Utilise la résolution du modèle
- mapping_config=mapping_config,
- save_dir=None, show_stats=False, show_plot=False
- )
-
- # Créer une figure combinée avec les deux modèles
- # Nombre de colonnes : 3 si pas de GT, 4 si GT disponible
- num_cols = 3 if not (mask_path_str and os.path.exists(mask_path_str)) else 4
- fig, axes = plt.subplots(2, num_cols, figsize=(5*num_cols, 8))
-
- # Récupérer les images depuis les figures individuelles
- axes1 = fig1.get_axes()
- axes2 = fig2.get_axes()
-
- # Ligne 1 : Modèle 1
- for i in range(min(len(axes1), num_cols)):
- ax_src = axes1[i]
- ax_dst = axes[0, i]
-
- # Copier toutes les images de l'axe source
- for img_obj in ax_src.get_images():
- ax_dst.imshow(
- img_obj.get_array(),
- cmap=img_obj.get_cmap(),
- alpha=img_obj.get_alpha(),
- vmin=img_obj.get_clim()[0] if img_obj.get_clim() else None,
- vmax=img_obj.get_clim()[1] if img_obj.get_clim() else None
- )
-
- # Copier le titre avec nom du modèle
- original_title = ax_src.get_title()
- if i == 0:
- new_title = "Image originale"
- elif "Prédit" in original_title:
- new_title = f"Prédiction {best_model_info['architecture']} - {best_model_info['encoder_name']}"
- else:
- new_title = original_title
-
- ax_dst.set_title(new_title)
- ax_dst.axis('off')
-
- # Ligne 2 : Modèle 2
- for i in range(min(len(axes2), num_cols)):
- ax_src = axes2[i]
- ax_dst = axes[1, i]
-
- # Copier toutes les images de l'axe source
- for img_obj in ax_src.get_images():
- ax_dst.imshow(
- img_obj.get_array(),
- cmap=img_obj.get_cmap(),
- alpha=img_obj.get_alpha(),
- vmin=img_obj.get_clim()[0] if img_obj.get_clim() else None,
- vmax=img_obj.get_clim()[1] if img_obj.get_clim() else None
- )
-
- # Copier le titre avec nom du modèle
- original_title = ax_src.get_title()
- if i == 0:
- new_title = "Image originale"
- elif "Prédit" in original_title:
- new_title = f"Prédiction {second_best_model_info['architecture']} - {second_best_model_info['encoder_name']}"
- else:
- new_title = original_title
-
- ax_dst.set_title(new_title)
- ax_dst.axis('off')
-
- plt.tight_layout()
-
- # Fermer les figures individuelles pour libérer la mémoire
- plt.close(fig1)
- plt.close(fig2)
-
- fig_b64 = base64.b64encode(pickle.dumps(fig)).decode()
- # Stats
- def calc(mask):
- uc, cnts = np.unique(mask, return_counts=True)
- stats = {}
- for cid, c in zip(uc, cnts):
- if cid < len(mapping_config['group_names']):
- stats[mapping_config['group_names'][cid]] = {
- "pixels": int(c),
- "percentage": round((c/mask.size)*100, 1)
- }
- return stats
- stats1, stats2 = calc(pred1), calc(pred2)
- faster = best_model_info['encoder_name'] if t1 < t2 else second_best_model_info['encoder_name']
- speedup = round(max(t1, t2) / min(t1, t2), 2)
- speed_comp = {"faster_model": faster, "speedup_ratio": speedup, "time_difference_ms": abs(t1-t2)*1000}
- return ComparisonResult(
- success=True, message="Comparison completed successfully",
- model1_info=ModelInfo(**best_model_info), model2_info=ModelInfo(**second_best_model_info),
- image_path=str(image_path), mask_path=mask_path_str,
- model1_stats=stats1, model2_stats=stats2,
- model1_inference_time=t1, model2_inference_time=t2,
- speed_comparison=speed_comp, ground_truth_available=mask_path.exists(),
- figure_data=fig_b64
- )
- except Exception as e:
- raise HTTPException(status_code=500, detail=f"Comparison error: {str(e)}")
-
-@app.post("/compare-upload", response_model=ComparisonResult)
-def compare_uploaded_image(file: UploadFile = File(...)):
- if best_model is None or second_best_model is None or mapping_config is None:
- raise HTTPException(status_code=503, detail="Models not loaded")
- allowed_types = ["image/jpeg", "image/jpg", "image/png"]
- if file.content_type not in allowed_types:
- raise HTTPException(status_code=400, detail=f"Invalid file type. Allowed: {', '.join(allowed_types)}")
- temp_file_path = None
- try:
- timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
- temp_filename = f"upload_{timestamp}_{file.filename}"
- temp_file_path = os.path.join(TEMP_UPLOAD_DIR, temp_filename)
- with open(temp_file_path, "wb") as buffer:
- shutil.copyfileobj(file.file, buffer)
- # Inférences avec résolutions spécifiques
- pred1, t1, fig1 = run_inference_and_visualize(
- image_path=temp_file_path, mask_path=None,
- model=best_model, encoder_name=None, # Normalisé de la même manière
- img_size=best_model_info["input_size"], mapping_config=mapping_config,
- save_dir=None, show_stats=False, show_plot=False,
- )
- pred2, t2, fig2 = run_inference_and_visualize(
- image_path=temp_file_path, mask_path=None,
- model=second_best_model, encoder_name=None, # Normalisé de la même manière
- img_size=second_best_model_info["input_size"], mapping_config=mapping_config,
- save_dir=None, show_stats=False, show_plot=False,
- )
-
- # Figure combinée pour uploads (pas de GT, donc 2 colonnes seulement)
- fig, axes = plt.subplots(2, 2, figsize=(10, 8))
-
- # Récupérer les images depuis les figures individuelles
- axes1 = fig1.get_axes()
- axes2 = fig2.get_axes()
-
- # Ligne 1 : Modèle 1 (Image originale + Prédiction)
- for i in range(min(len(axes1), 2)):
- ax_src = axes1[i]
- ax_dst = axes[0, i]
-
- # Copier toutes les images de l'axe source
- for img_obj in ax_src.get_images():
- ax_dst.imshow(
- img_obj.get_array(),
- cmap=img_obj.get_cmap(),
- alpha=img_obj.get_alpha(),
- vmin=img_obj.get_clim()[0] if img_obj.get_clim() else None,
- vmax=img_obj.get_clim()[1] if img_obj.get_clim() else None
- )
-
- # Copier le titre avec nom du modèle
- original_title = ax_src.get_title()
- if i == 0:
- new_title = "Image originale"
- else:
- new_title = f"Prédiction {best_model_info['architecture']} - {best_model_info['encoder_name']}"
-
- ax_dst.set_title(new_title)
- ax_dst.axis('off')
-
- # Ligne 2 : Modèle 2 (Image originale + Prédiction)
- for i in range(min(len(axes2), 2)):
- ax_src = axes2[i]
- ax_dst = axes[1, i]
-
- # Copier toutes les images de l'axe source
- for img_obj in ax_src.get_images():
- ax_dst.imshow(
- img_obj.get_array(),
- cmap=img_obj.get_cmap(),
- alpha=img_obj.get_alpha(),
- vmin=img_obj.get_clim()[0] if img_obj.get_clim() else None,
- vmax=img_obj.get_clim()[1] if img_obj.get_clim() else None
- )
-
- # Copier le titre avec nom du modèle
- original_title = ax_src.get_title()
- if i == 0:
- new_title = "Image originale"
- else:
- new_title = f"Prédiction {second_best_model_info['architecture']} - {second_best_model_info['encoder_name']}"
-
- ax_dst.set_title(new_title)
- ax_dst.axis('off')
-
- plt.tight_layout()
-
- # Fermer les figures individuelles pour libérer la mémoire
- plt.close(fig1)
- plt.close(fig2)
-
- fig_b64 = base64.b64encode(pickle.dumps(fig)).decode()
- # Stats
- def calc(mask):
- uc, cnts = np.unique(mask, return_counts=True)
- stats = {}
- for cid, c in zip(uc, cnts):
- if cid < len(mapping_config['group_names']):
- stats[mapping_config['group_names'][cid]] = {
- "pixels": int(c),
- "percentage": round((c/mask.size)*100, 1)
- }
- return stats
- stats1, stats2 = calc(pred1), calc(pred2)
- faster = best_model_info['encoder_name'] if t1 < t2 else second_best_model_info['encoder_name']
- speedup = round(max(t1, t2) / min(t1, t2), 2)
- speed_comp = {"faster_model": faster, "speedup_ratio": speedup, "time_difference_ms": abs(t1-t2)*1000}
- return ComparisonResult(
- success=True, message="Comparison completed successfully",
- model1_info=ModelInfo(**best_model_info), model2_info=ModelInfo(**second_best_model_info),
- image_path=temp_file_path,
- model1_stats=stats1, model2_stats=stats2,
- model1_inference_time=t1, model2_inference_time=t2,
- speed_comparison=speed_comp, ground_truth_available=False,
- figure_data=fig_b64
- )
- except Exception as e:
- raise HTTPException(status_code=500, detail=f"Comparison error: {str(e)}")
- finally:
- if temp_file_path and os.path.exists(temp_file_path):
- try: os.remove(temp_file_path)
- except Exception: pass
-
-@app.get("/metrics")
-def get_metrics():
- return {
- "models_loaded": best_model is not None and second_best_model is not None,
- "best_model_info": best_model_info,
- "second_best_model_info": second_best_model_info,
- "num_classes": mapping_config['num_classes'] if mapping_config else None,
- "timestamp": datetime.utcnow().isoformat()
- }
-
-# Ajouter cette route après les autres routes :
-@app.get("/accessibility-info")
-def get_accessibility_information():
- """Retourne les informations sur la conformité d'accessibilité"""
- return get_accessibility_info()
\ No newline at end of file
diff --git a/app/requirements.txt b/app/requirements.txt
deleted file mode 100644
index eff910c..0000000
--- a/app/requirements.txt
+++ /dev/null
@@ -1,71 +0,0 @@
-# =============================================================================
-# Multi-Class Segmentation API - Requirements
-# =============================================================================
-
-# ===== CORE WEB FRAMEWORK =====
-fastapi==0.115.14
-uvicorn==0.35.0
-starlette==0.46.2
-pydantic==2.11.7
-pydantic_core==2.33.2
-python-multipart==0.0.20 # uploads FastAPI
-
-# ===== STREAMLIT =====
-streamlit==1.46.1
-altair==5.5.0 # utilisé par Streamlit
-blinker==1.9.0 # dépendance Streamlit
-
-# ===== HTTP CLIENTS =====
-requests==2.32.4
-httpx==0.28.1 # utilisé en interne par FastAPI
-httpcore==1.0.9
-h11==0.16.0
-
-# ===== MACHINE LEARNING CORE (PyTorch) =====
-torch==2.8.0 # version stable PyTorch
-torchvision==0.23.0 # utile pour les modèles pré-entraînés
-torchaudio==2.8.0 # optionnel (mais recommandé pour compatibilité PyTorch)
-segmentation-models-pytorch==0.5.0
-albumentations==2.0.8
-# version PyTorch de ToTensor
-albumentations[imgaug,opencv]
-
-numpy>=1.24.0,<2.0.0
-scipy==1.16.0
-scikit-learn==1.7.0
-
-# ===== COMPUTER VISION =====
-pillow==11.3.0
-opencv-python-headless==4.9.0.80
-scikit-image==0.25.2
-imageio==2.37.0
-
-# ===== DATA SCIENCE =====
-pandas==2.3.0
-matplotlib==3.10.3
-networkx==3.5
-tifffile==2025.6.11
-lazy_loader==0.4
-
-# ===== MLFLOW & MODEL REGISTRY =====
-mlflow==3.2.0
-mlflow-skinny==3.2.0
-mlflow-tracing==3.2.0
-
-# ===== AWS/S3 SUPPORT =====
-boto3==1.39.2
-botocore==1.39.2
-s3transfer==0.13.0
-
-# ===== UTILITIES =====
-click==8.2.1
-tqdm==4.67.1
-joblib==1.5.1
-python-dateutil
-packaging
-typing_extensions==4.14.0
-
-# ===== MATPLOTLIB ADDONS =====
-cycler==0.12.1
-fonttools==4.58.5
-plotly==5.24.1
diff --git a/app/streamlit_app.py b/app/streamlit_app.py
deleted file mode 100644
index c80c8dd..0000000
--- a/app/streamlit_app.py
+++ /dev/null
@@ -1,1889 +0,0 @@
-import os
-import sys
-import requests
-import streamlit as st
-import pandas as pd
-import numpy as np
-import matplotlib.pyplot as plt
-import plotly.express as px
-import plotly.graph_objects as go
-from PIL import Image
-import io
-import base64
-import pickle
-
-# Configuration de l'API
-API_BASE_URL = os.getenv("MULTISEG_API_BASE_URL", "http://127.0.0.1:8080/api")
-
-# Import des fonctions utils pour l'affichage local
-sys.path.append('/app')
-sys.path.append('.')
-from utils.utils import colorize_mask
-
-# Configuration de la page avec titre approprié (WCAG 2.4.2)
-st.set_page_config(
- page_title="Street Vision - Segmentation Comparison | Dashboard Accessible",
- page_icon="🚗",
- layout="wide"
-)
-
-
-# Ajouts à placer au début de streamlit_app.py après les imports
-
-# Palettes de couleurs conformes WCAG AA (ratio contraste ≥ 3:1)
-WCAG_ACCESSIBLE_COLORS = {
- 'primary_blue': '#0066CC', # [0, 102, 204]
- 'primary_red': '#CC0000', # [204, 0, 0]
- 'primary_green': '#006600', # [0, 102, 0]
- 'primary_orange': '#CC6600', # [204, 102, 0]
- 'secondary_purple': '#663399', # [102, 51, 153]
- 'secondary_teal': '#006666', # [0, 102, 102]
- 'neutral_dark': '#333333', # [51, 51, 51]
- 'neutral_medium': '#666666', # [102, 102, 102]
- 'neutral_light': '#CCCCCC', # Pour éléments désactivés
- 'background_alt': '#F5F5F5' # Fond alternatif accessible
-}
-
-# Convertir hex vers RGB
-def hex_to_rgb(hex_color):
- """Convertit une couleur hex en tuple RGB"""
- hex_color = hex_color.lstrip('#')
- return tuple(int(hex_color[i:i+2], 16) for i in (0, 2, 4))
-
-# Couleurs RGB pour les masques (dans le même ordre que les classes)
-WCAG_RGB_COLORS = [
- hex_to_rgb(WCAG_ACCESSIBLE_COLORS['neutral_medium']), # Flat: gris moyen [102, 102, 102]
- hex_to_rgb(WCAG_ACCESSIBLE_COLORS['primary_red']), # Human: rouge [204, 0, 0]
- hex_to_rgb(WCAG_ACCESSIBLE_COLORS['secondary_purple']), # Vehicle: violet [102, 51, 153]
- hex_to_rgb(WCAG_ACCESSIBLE_COLORS['primary_orange']), # Construction: orange [204, 102, 0]
- hex_to_rgb(WCAG_ACCESSIBLE_COLORS['secondary_teal']), # Object: teal [0, 102, 102]
- hex_to_rgb(WCAG_ACCESSIBLE_COLORS['primary_green']), # Nature: vert [0, 102, 0]
- hex_to_rgb(WCAG_ACCESSIBLE_COLORS['primary_blue']), # Sky: bleu [0, 102, 204]
- hex_to_rgb(WCAG_ACCESSIBLE_COLORS['neutral_dark']) # Void: gris foncé [51, 51, 51]
-]
-
-
-# Motifs pour différencier sans couleur uniquement
-ACCESSIBILITY_PATTERNS = {
- 'solid': None,
- 'diagonal_lines': '///',
- 'vertical_lines': '|||',
- 'horizontal_lines': '---',
- 'dots': '...',
- 'crosses': 'xxx'
-}
-
-def create_accessible_pie_chart_conditional(sizes, labels, title, use_patterns=False):
- """Version corrigée qui règle le problème de lisibilité avec les motifs"""
- fig, ax = plt.subplots(figsize=(6, 6), tight_layout=True)
-
- accessible_colors = [
- WCAG_ACCESSIBLE_COLORS['primary_blue'], WCAG_ACCESSIBLE_COLORS['primary_red'],
- WCAG_ACCESSIBLE_COLORS['primary_green'], WCAG_ACCESSIBLE_COLORS['primary_orange'],
- WCAG_ACCESSIBLE_COLORS['secondary_purple'], WCAG_ACCESSIBLE_COLORS['secondary_teal']
- ]
- colors = accessible_colors[:len(sizes)]
-
- # SOLUTION : texte avec fond contrasté
- uniform_textprops = {
- 'fontsize': 10, 'fontweight': 'bold', 'color': 'white',
- 'bbox': dict(boxstyle="round,pad=0.3", facecolor='black', alpha=0.8)
- }
-
- try:
- wedges, texts, autotexts = ax.pie(
- sizes, labels=labels, colors=colors, autopct='%1.0f%%', startangle=90, shadow=True,
- textprops=uniform_textprops, wedgeprops={'edgecolor': 'white', 'linewidth': 2},
- pctdistance=0.85 # Éloigner les pourcentages
- )
-
- # Améliorer la lisibilité des pourcentages
- for autotext in autotexts:
- autotext.set_bbox(dict(boxstyle="round,pad=0.4", facecolor='black', alpha=0.9))
- autotext.set_color('white')
- autotext.set_fontweight('bold')
- autotext.set_fontsize(9)
-
- # Motifs APRÈS configuration du texte
- if use_patterns:
- patterns = ['///', '|||', '---', '...', 'xxx', '+++']
- for wedge, pattern in zip(wedges, patterns[:len(wedges)]):
- if pattern:
- wedge.set_hatch(pattern)
-
- ax.set_title(title, fontsize=10, fontweight='bold', pad=15, color='#333333')
- ax.axis('equal')
- chart_displayed = True
-
- except Exception as e:
- ax.text(0.5, 0.5, f"Erreur d'affichage du graphique\n{str(e)}",
- ha='center', va='center', transform=ax.transAxes, fontsize=10, color='red', weight='bold')
- chart_displayed = False
-
- return fig, ax, {'colors': colors, 'patterns': patterns if use_patterns else None}, chart_displayed
-
-# Fonctions Plotly pour graphiques interactifs
-def create_interactive_pie_chart(sizes, labels, title, models_info=None):
- """Crée un pie chart interactif avec les couleurs des classes définies dans models_info"""
-
- # Utiliser les couleurs des classes si disponibles
- if models_info and 'class_colors' in models_info and 'class_names' in models_info:
- colors = []
- class_names = models_info['class_names']
- class_colors = models_info['class_colors']
-
- for label in labels:
- if label in class_names:
- idx = class_names.index(label)
- color_rgb = class_colors[idx]
- color_hex = f"#{color_rgb[0]:02x}{color_rgb[1]:02x}{color_rgb[2]:02x}"
- colors.append(color_hex)
- else:
- # Couleur par défaut si classe non trouvée
- colors.append('#666666')
- else:
- # Fallback vers les couleurs WCAG
- accessible_colors_list = list(WCAG_ACCESSIBLE_COLORS.values())
- colors = accessible_colors_list[:len(sizes)]
-
- df = pd.DataFrame({'labels': labels, 'values': sizes, 'colors': colors})
-
- fig = go.Figure(data=[go.Pie(
- labels=df['labels'],
- values=df['values'],
- marker=dict(
- colors=df['colors'],
- line=dict(color='#FFFFFF', width=3),
- pattern=dict(
- shape=['', '/', '\\', '|', '-', '+', 'x', '.'][:len(sizes)],
- size=8,
- solidity=0.3
- )
- ),
- textinfo='label+percent',
- textposition='auto',
- textfont=dict(
- size=13,
- color='white',
- family="Arial Black"
- ),
- hovertemplate='%{label}
Valeur: %{value}
Pourcentage: %{percent}
',
- hoverlabel=dict(
- bgcolor="rgba(255,255,255,0.95)",
- bordercolor="#333333",
- font=dict(size=14, color="#333333")
- )
- )])
-
- fig.update_layout(
- title={
- 'text': title,
- 'x': 0.5,
- 'xanchor': 'center',
- 'font': {'size': 16, 'color': '#333333', 'family': 'Arial Black'}
- },
- showlegend=True,
- legend=dict(
- orientation="v",
- yanchor="middle",
- y=0.5,
- xanchor="left",
- x=1.02,
- font=dict(size=12, color='#333333'),
- bgcolor='rgba(255,255,255,0.9)',
- bordercolor='#333333',
- ),
- margin=dict(l=20, r=120, t=60, b=20),
- height=400,
- plot_bgcolor='rgba(0,0,0,0)',
- paper_bgcolor='rgba(0,0,0,0)',
- font=dict(color='#333333')
- )
-
- return fig
-
-
-def create_interactive_comparison_chart(model1_stats, model2_stats, model1_name, model2_name):
- """Crée un graphique en barres interactif WCAG-compliant pour comparer les deux modèles"""
- classes = list(set(model1_stats.keys()) | set(model2_stats.keys()))
-
- data = []
- for class_name in classes:
- val1 = model1_stats.get(class_name, {}).get('percentage', 0)
- val2 = model2_stats.get(class_name, {}).get('percentage', 0)
-
- data.append({'Classe': class_name, 'Modèle': model1_name, 'Pourcentage': val1, 'Pixels': model1_stats.get(class_name, {}).get('pixels', 0)})
- data.append({'Classe': class_name, 'Modèle': model2_name, 'Pourcentage': val2, 'Pixels': model2_stats.get(class_name, {}).get('pixels', 0)})
-
- df = pd.DataFrame(data)
-
- # Filtrer les données pour supprimer les lignes vides potentielles
- df = df[df['Modèle'].notna() & (df['Modèle'] != '')]
-
- fig = px.bar(
- df, x='Classe', y='Pourcentage', color='Modèle', barmode='group',
- title='Comparaison interactive des classes détectées',
- hover_data=['Pixels'],
- color_discrete_map={model1_name: '#0066CC', model2_name: '#CC0000'}
- # PAS de pattern_shape du tout
- )
-
- fig.update_layout(
- title={'x': 0.5, 'xanchor': 'center', 'font': {'size': 16, 'color': '#333333', 'family': 'Arial Black'}},
- xaxis=dict(
- title='Classes de segmentation',
- titlefont=dict(size=14, color='#666666'), # Plus clair comme vos pie charts
- tickfont=dict(size=12, color='#666666'), # Plus clair
- tickangle=45,
- showgrid=True,
- gridcolor='#E8E8E8', # Grille beaucoup plus claire
- gridwidth=1,
- linecolor='#AAAAAA', # Axe gris moyen
- linewidth=1,
- showline=True
- ),
- yaxis=dict(
- title='Pourcentage de l\'image (%)',
- titlefont=dict(size=14, color='#666666'), # Plus clair
- tickfont=dict(size=12, color='#666666'), # Plus clair
- showgrid=True,
- gridcolor='#E8E8E8', # Grille beaucoup plus claire
- gridwidth=1,
- linecolor='#AAAAAA', # Axe gris moyen
- linewidth=1,
- showline=True
- ),
- legend=dict(
- title='Modèles',
- font=dict(size=12, color='#333333'), # Comme vos pie charts
- bgcolor='rgba(255,255,255,0.9)',
- bordercolor='#333333',
- ),
- hovermode='x unified',
- height=500,
- plot_bgcolor='rgba(0,0,0,0)', # Transparent
- paper_bgcolor='rgba(0,0,0,0)', # Transparent
- font=dict(color='#333333') # Sans spécifier size qui peut poser problème
- )
-
- fig.update_traces(
- texttemplate='%{y:.1f}%',
- textposition='outside',
- textfont=dict(size=11, color='#666666'), # Plus clair pour lisibilité
- marker=dict(line=dict(color='#FFFFFF', width=1)) # Bordures blanches comme vos pie charts
- )
-
- return fig
-
-
-def create_dataset_interactive_overview():
- """Vue d'ensemble interactive du dataset avec les MÊMES couleurs que 'Visualisations accessibles'"""
-
- # RÉORGANISER les données pour que l'ordre soit logique et que les couleurs correspondent
- dataset_data = {
- 'Split': ['Train (notre projet)', 'Validation (notre projet)', 'Test final', 'Non utilisé'],
- 'Images': [2380, 595, 500, 21525],
- 'Utilisation': ['Entraînement', 'Validation', 'Test', 'Non utilisé']
- }
-
- df = pd.DataFrame(dataset_data)
-
- # Couleurs dans l'ordre exact des données
- colors = [
- WCAG_ACCESSIBLE_COLORS['primary_blue'], # Train (notre projet) - bleu
- WCAG_ACCESSIBLE_COLORS['primary_red'], # Validation (notre projet) - rouge
- WCAG_ACCESSIBLE_COLORS['primary_orange'], # Test final - orange
- WCAG_ACCESSIBLE_COLORS['neutral_dark'] # Non utilisé - gris foncé
- ]
-
- # FORCER l'ordre avec category_orders
- fig = px.pie(
- df,
- values='Images',
- names='Split',
- title='Répartition interactive du dataset Cityscapes',
- color_discrete_sequence=colors,
- hover_data=['Utilisation'],
- category_orders={'Split': ['Train (notre projet)', 'Validation (notre projet)', 'Test final', 'Non utilisé']}
- )
-
- # FORCER la correspondance couleur-catégorie avec color_discrete_map
- color_map = {
- 'Train (notre projet)': WCAG_ACCESSIBLE_COLORS['primary_blue'],
- 'Validation (notre projet)': WCAG_ACCESSIBLE_COLORS['primary_red'],
- 'Test final': WCAG_ACCESSIBLE_COLORS['primary_orange'],
- 'Non utilisé': WCAG_ACCESSIBLE_COLORS['neutral_dark']
- }
-
- fig.update_traces(
- marker=dict(
- colors=[color_map[split] for split in df['Split']], # Forcer les couleurs exactes
- line=dict(color='#FFFFFF', width=3),
- pattern=dict(
- shape=['|', '/', '\\', ''],
- size=8,
- solidity=0.3
- )
- ),
- textposition='auto',
- textinfo='percent+label',
- textfont=dict(size=12, color='white', family="Arial Black"),
- hovertemplate='%{label}
Images: %{value}
Usage: %{customdata[0]}'
- )
-
- fig.update_layout(
- title={'x': 0.5, 'xanchor': 'center', 'font': {'size': 16, 'color': '#333333'}},
- height=500,
- legend=dict(
- font=dict(size=12, color='#333333'),
- bgcolor='rgba(255,255,255,0.9)',
- bordercolor='#333333',
- ),
- font=dict(color='#333333')
- )
-
- return fig
-
-
-def create_accessible_bar_chart_conditional(data, labels, title, colors=None, use_patterns=False):
- """
- Crée un bar chart accessible - descriptions uniquement si erreur d'affichage
- """
- import matplotlib.pyplot as plt
-
- fig, ax = plt.subplots(figsize=(10, 6))
-
- if colors is None:
- colors = [WCAG_ACCESSIBLE_COLORS['primary_blue']] * len(data)
-
- # Motifs pour différenciation
- patterns = None
- if use_patterns:
- pattern_list = list(ACCESSIBILITY_PATTERNS.values())
- patterns = pattern_list[:len(data)]
-
- try:
- bars = ax.bar(
- labels,
- data,
- color=colors,
- alpha=0.8,
- edgecolor='#333333',
- linewidth=1
- )
-
- # Ajouter des motifs
- if patterns:
- for bar, pattern in zip(bars, patterns):
- if pattern:
- bar.set_hatch(pattern)
-
- # Style accessible
- ax.set_ylabel('Valeur', fontweight='bold', color='#333333')
- ax.set_xlabel('Catégories', fontweight='bold', color='#333333')
- ax.set_title(title, fontsize=14, fontweight='bold', pad=20, color='#333333')
-
- # Grille pour faciliter la lecture
- ax.grid(axis='y', alpha=0.3, linestyle='--', color='#666666')
- ax.set_axisbelow(True)
-
- # Valeurs sur les barres pour accessibilité
- for bar, value in zip(bars, data):
- height = bar.get_height()
- ax.text(bar.get_x() + bar.get_width()/2., height + max(data) * 0.01,
- f'{value:.1f}' if isinstance(value, float) else str(value),
- ha='center', va='bottom', fontsize=10, fontweight='bold', color='#333333')
-
- # Style des axes
- ax.spines['top'].set_visible(False)
- ax.spines['right'].set_visible(False)
- ax.spines['left'].set_color('#666666')
- ax.spines['bottom'].set_color('#666666')
-
- plt.xticks(rotation=45, ha='right', color='#333333')
- plt.yticks(color='#333333')
-
- chart_displayed = True
-
- except Exception as e:
- # En cas d'erreur, message d'erreur
- ax.text(0.5, 0.5, f"Erreur d'affichage du graphique\n{str(e)}",
- ha='center', va='center', transform=ax.transAxes,
- fontsize=12, color='red', weight='bold')
- chart_displayed = False
-
- return fig, ax, chart_displayed
-
-# Fonction pour générer du texte alternatif (WCAG 1.1.1)
-def generate_alt_text_for_pie(sizes, labels, title):
- """
- Génère un texte alternatif détaillé pour un pie chart
- """
- total = sum(sizes)
- descriptions = []
-
- for size, label in zip(sizes, labels):
- percentage = (size / total) * 100
- descriptions.append(f"{label}: {size} éléments ({percentage:.1f}%)")
-
- alt_text = f"Graphique en secteurs: {title}. "
- alt_text += f"Total de {total} éléments répartis comme suit: "
- alt_text += "; ".join(descriptions) + "."
-
- return alt_text
-
-# Fonction pour générer du texte alternatif (WCAG 1.1.1)
-def generate_alt_text_for_images(image_type, model_name=None, stats=None):
- """Génère un texte alternatif détaillé pour les images de segmentation"""
- if image_type == "original":
- return "Image originale en couleur montrant une scène urbaine typique du dataset Cityscapes"
- elif image_type == "segmentation":
- base_text = f"Masque de segmentation sémantique prédit par le modèle {model_name or 'IA'}"
- if stats:
- # Ajouter les statistiques principales
- main_classes = sorted(stats.items(), key=lambda x: x[1]['percentage'], reverse=True)[:3]
- stats_text = ". Classes principales détectées: " + ", ".join([
- f"{name} ({data['percentage']:.1f}%)" for name, data in main_classes
- ])
- return base_text + stats_text
- return base_text
- elif image_type == "comparison":
- return "Visualisation comparative des prédictions de deux modèles de segmentation sémantique"
- else:
- return "Image de segmentation sémantique"
-
-def generate_alt_text_for_bar(data, labels, title, unit=""):
- """
- Génère un texte alternatif détaillé pour un bar chart
- """
- descriptions = []
-
- for value, label in zip(data, labels):
- descriptions.append(f"{label}: {value}{unit}")
-
- alt_text = f"Graphique en barres: {title}. "
- alt_text += "Valeurs: " + "; ".join(descriptions) + "."
-
- return alt_text
-
-def generate_comprehensive_alt_text(image_type, model_name=None, stats=None, comparison_data=None):
- """Génère un texte alternatif complet selon WCAG 1.1.1"""
- if image_type == "preprocessing_original":
- return "Image urbaine originale redimensionnée à la résolution d'entraînement du modèle, montrant une scène typique du dataset Cityscapes avec véhicules, piétons et infrastructure urbaine"
-
- elif image_type == "preprocessing_normalized":
- return "Même image après normalisation des pixels pour l'entraînement du modèle IA, les couleurs peuvent paraître légèrement différentes"
-
- elif image_type == "preprocessing_augmented":
- return "Image avec augmentations de données appliquées (rotation, changement de luminosité, etc.) pour améliorer la robustesse du modèle"
-
- elif image_type == "segmentation_prediction":
- base_text = f"Masque de segmentation sémantique coloré prédit par le modèle {model_name or 'IA'}"
- if stats:
- main_classes = sorted(stats.items(), key=lambda x: x[1]['percentage'], reverse=True)[:3]
- stats_text = ". Classes principales détectées : " + ", ".join([
- f"{name} ({data['percentage']:.1f}% de l'image)" for name, data in main_classes
- ])
- return base_text + stats_text
- return base_text
-
- elif image_type == "comparison_grid":
- return "Grille comparative montrant l'image originale et les prédictions de segmentation de deux modèles d'IA différents côte à côte pour évaluation"
-
- else:
- return "Image de segmentation sémantique urbaine générée par intelligence artificielle"
-
-def create_data_table(data, columns, title, description=""):
- """
- Crée un tableau de données accessible complémentaire aux graphiques
- """
- import pandas as pd
-
- df = pd.DataFrame(data, columns=columns)
-
- st.markdown(f"**Tableau de données: {title}**")
- if description:
- st.markdown(f"*{description}*")
-
- # Configuration accessible du dataframe
- st.dataframe(
- df,
- use_container_width=True,
- hide_index=True,
- column_config={
- col: st.column_config.TextColumn(col, width="medium")
- for col in columns
- }
- )
-
- return df
-
-# CSS amélioré pour l'accessibilité complète
-ENHANCED_WCAG_CSS = """
-
-"""
-
-st.markdown(ENHANCED_WCAG_CSS, unsafe_allow_html=True)
-
-# En-tête principal
-st.markdown("""
-
-
🚗 Street Vision - Comparaison de Modèles
-
Évaluation comparative SegFormer vs FPN sur le dataset Cityscapes
-
-""", unsafe_allow_html=True)
-
-# Fonctions utilitaires
-def get_models_info():
- """Récupère les informations des deux modèles"""
- try:
- response = requests.get(f"{API_BASE_URL}/models")
- if response.status_code == 200:
- return response.json()
- else:
- st.error(f"Erreur lors de la récupération des infos modèles: {response.status_code}")
- return None
- except Exception as e:
- st.error(f"Erreur de connexion à l'API: {e}")
- return None
-
-def get_dataset_info():
- """Récupère les informations sur le dataset"""
- try:
- response = requests.get(f"{API_BASE_URL}/dataset-info")
- if response.status_code == 200:
- return response.json()
- else:
- st.error(f"Erreur lors de la récupération des infos dataset: {response.status_code}")
- return None
- except Exception as e:
- st.error(f"Erreur de connexion à l'API: {e}")
- return None
-
-def get_train_images():
- """Récupère la liste des images d'entraînement"""
- try:
- response = requests.get(f"{API_BASE_URL}/train-images")
- if response.status_code == 200:
- return response.json()
- else:
- st.error(f"Erreur lors de la récupération des images: {response.status_code}")
- return None
- except Exception as e:
- st.error(f"Erreur de connexion à l'API: {e}")
- return None
-
-def get_class_repartition():
- """Récupère le graphique de répartition des classes"""
- try:
- response = requests.get(f"{API_BASE_URL}/class-repartition", timeout=10)
- if response.status_code == 200:
- return response.content
- else:
- return None
- except Exception as e:
- st.warning(f"Graphique de répartition non disponible: {e}")
- return None
-
-def preprocess_train_image(filename, apply_augmentation=False):
- """Lance le preprocessing sur une image d'entraînement"""
- try:
- data = {
- "filename": filename,
- "apply_augmentation": apply_augmentation
- }
- response = requests.post(
- f"{API_BASE_URL}/preprocess-train-image",
- json=data,
- headers={"Content-Type": "application/json"}
- )
-
- if response.status_code == 200:
- return response.json()
- else:
- st.error(f"Erreur API: {response.status_code} - {response.text}")
- return None
- except Exception as e:
- st.error(f"Erreur lors du preprocessing: {e}")
- return None
-
-def get_sample_images():
- """Récupère la liste des images d'exemple"""
- try:
- response = requests.get(f"{API_BASE_URL}/sample-images")
- if response.status_code == 200:
- return response.json()
- else:
- st.error(f"Erreur lors de la récupération des images: {response.status_code}")
- return None
- except Exception as e:
- st.error(f"Erreur de connexion à l'API: {e}")
- return None
-
-def compare_sample_image(filename):
- """Lance une comparaison sur une image d'exemple"""
- try:
- data = {"filename": filename}
- response = requests.post(
- f"{API_BASE_URL}/compare-sample",
- json=data,
- headers={"Content-Type": "application/json"}
- )
-
- if response.status_code == 200:
- return response.json()
- else:
- st.error(f"Erreur API: {response.status_code} - {response.text}")
- return None
- except Exception as e:
- st.error(f"Erreur lors de la comparaison: {e}")
- return None
-
-def compare_uploaded_image(uploaded_file):
- """Lance une comparaison sur une image uploadée"""
- try:
- files = {"file": (uploaded_file.name, uploaded_file.getvalue(), uploaded_file.type)}
- response = requests.post(f"{API_BASE_URL}/compare-upload", files=files)
-
- if response.status_code == 200:
- return response.json()
- else:
- st.error(f"Erreur API: {response.status_code} - {response.text}")
- return None
- except Exception as e:
- st.error(f"Erreur lors de la comparaison: {e}")
- return None
-
-def display_comparison_results(result, models_info, context=""):
- """Affiche les résultats de comparaison avec graphiques interactifs et accessibilité complète"""
- if not result or not result['success']:
- st.error("Aucun résultat de comparaison disponible")
- return
-
- # Informations des modèles
- st.markdown("### � Modèles Comparés")
-
- col1, col2 = st.columns(2)
-
- with col1:
- model1 = result['model1_info']
- # Formater les métriques séparément
- miou1 = f"{model1.get('test_mean_iou'):.4f}" if model1.get('test_mean_iou') is not None else 'N/A'
- acc1 = f"{model1.get('test_accuracy'):.4f}" if model1.get('test_accuracy') is not None else 'N/A'
-
- st.markdown(f"""
-
-
🥇 Modèle #1
- {model1.get('architecture', 'N/A')} - {model1['encoder_name']}
- � Taille: {model1['input_size']}
- 📊 mIoU: {miou1}
- 🎯 Accuracy: {acc1}
-
- """, unsafe_allow_html=True)
-
- with col2:
- model2 = result['model2_info']
- # Formater les métriques séparément
- miou2 = f"{model2.get('test_mean_iou'):.4f}" if model2.get('test_mean_iou') is not None else 'N/A'
- acc2 = f"{model2.get('test_accuracy'):.4f}" if model2.get('test_accuracy') is not None else 'N/A'
-
- st.markdown(f"""
-
-
🥈 Modèle #2
- {model2.get('architecture', 'N/A')} - {model2['encoder_name']}
- � Taille: {model2['input_size']}
- 📊 mIoU: {miou2}
- 🎯 Accuracy: {acc2}
-
- """, unsafe_allow_html=True)
-
- # Comparaison des temps d'inférence
- st.markdown("### �� Comparaison des Performances")
-
- speed_comp = result['speed_comparison']
- model1_time = result['model1_inference_time'] * 1000
- model2_time = result['model2_inference_time'] * 1000
-
- col1, col2, col3 = st.columns(3)
-
- with col1:
- winner_class = "speed-winner" if speed_comp['faster_model'] == model1['encoder_name'] else "speed-slower"
- st.markdown(f"""
-
-
🥇 {model1.get('architecture', 'N/A')} - {model1['encoder_name']}
- {model1_time:.1f} ms
-
- """, unsafe_allow_html=True)
-
- with col2:
- st.markdown(f"""
-
-
âš¡ Comparaison
- {speed_comp['faster_model']}
- est {speed_comp['speedup_ratio']}x plus rapide
- Différence: {speed_comp['time_difference_ms']:.1f} ms
-
- """, unsafe_allow_html=True)
-
- with col3:
- winner_class = "speed-winner" if speed_comp['faster_model'] == model2['encoder_name'] else "speed-slower"
- st.markdown(f"""
-
-
🥈 {model2.get('architecture', 'N/A')} - {model2['encoder_name']}
- {model2_time:.1f} ms
-
- """, unsafe_allow_html=True)
-
- # Affichage des segmentations avec descriptions alternatives CONDITIONNELLES
- if result.get('figure_data'):
- st.markdown("### 🎨 Résultats de Segmentation")
-
- try:
- fig_bytes = base64.b64decode(result['figure_data'])
- fig = pickle.loads(fig_bytes)
-
- st.pyplot(fig)
- plt.close(fig)
-
- except Exception as e:
- st.error(f"Erreur lors de l'affichage: {e}")
- # Description alternative SEULEMENT en cas d'erreur
- alt_text = generate_comprehensive_alt_text("comparison_grid")
- st.warning(f"**Description alternative:** {alt_text}")
-
- # Section interactive (CE2 - Graphiques interactifs) - SEULEMENT 2 ONGLETS
- st.markdown("### 📊 Analyse Interactive des Résultats")
-
- if result.get('model1_stats') and result.get('model2_stats'):
- # SUPPRIMER l'onglet "Performances"
- tab1, tab2 = st.tabs(["🥧 Répartitions", "📊 Comparaison"])
-
- with tab1:
- col1, col2 = st.columns(2)
-
- with col1:
- st.markdown("#### Répartition Modèle 1")
- sizes1 = [data['percentage'] for data in result['model1_stats'].values()]
- labels1 = list(result['model1_stats'].keys())
-
- fig_pie1 = create_interactive_pie_chart(sizes1, labels1,
- f"Distribution - {result['model1_info'].get('architecture', 'N/A')} {result['model1_info']['encoder_name']}",
- models_info)
- # AJOUTER key unique pour éviter l'erreur Streamlit
- st.plotly_chart(fig_pie1, use_container_width=True, key=f"pie_model1_{context}")
-
- with col2:
- st.markdown("#### Répartition Modèle 2")
- sizes2 = [data['percentage'] for data in result['model2_stats'].values()]
- labels2 = list(result['model2_stats'].keys())
-
- fig_pie2 = create_interactive_pie_chart(sizes2, labels2,
- f"Distribution - {result['model2_info'].get('architecture', 'N/A')} {result['model2_info']['encoder_name']}",
- models_info)
- # AJOUTER key unique pour éviter l'erreur Streamlit
- st.plotly_chart(fig_pie2, use_container_width=True, key=f"pie_model2_{context}")
-
- with tab2:
- st.markdown("#### Comparaison Interactive des Classes")
-
- fig_comparison = create_interactive_comparison_chart(
- result['model1_stats'], result['model2_stats'],
- f"{result['model1_info'].get('architecture', 'N/A')} {result['model1_info']['encoder_name']}",
- f"{result['model2_info'].get('architecture', 'N/A')} {result['model2_info']['encoder_name']}"
- )
- # AJOUTER key unique pour éviter l'erreur Streamlit
- st.plotly_chart(fig_comparison, use_container_width=True, key=f"comparison_chart_{context}")
-
- st.info("💡 **Interactivité :** Survolez les barres, cliquez sur la légende, zoomez en sélectionnant une zone.")
- # SUPPRIMER la description systématique
-
- # Garder seulement le tableau détaillé (sans graphique redondant)
- if result.get('model1_stats') and result.get('model2_stats'):
- display_class_comparison(result['model1_stats'], result['model2_stats'],
- result['model1_info'], result['model2_info'], models_info)
-
-# def display_model_stats_chart(stats, models_info, title):
-# """Affiche les statistiques d'un modèle sous forme de graphique accessible"""
-# if not stats:
-# st.warning("Aucune statistique disponible")
-# return
-
-# # Utiliser l'ordre des classes du modèle pour la cohérence
-# if models_info and 'class_names' in models_info:
-# ordered_class_names = [name for name in models_info['class_names'] if name in stats]
-# else:
-# ordered_class_names = sorted(stats.keys())
-
-# percentages = [stats[name]['percentage'] for name in ordered_class_names]
-
-# # Couleurs accessibles WCAG
-# accessible_colors = [
-# WCAG_ACCESSIBLE_COLORS['neutral_medium'], # Flat: gris moyen
-# WCAG_ACCESSIBLE_COLORS['primary_red'], # Human: rouge
-# WCAG_ACCESSIBLE_COLORS['secondary_purple'], # Vehicle: violet
-# WCAG_ACCESSIBLE_COLORS['primary_orange'], # Construction: orange
-# WCAG_ACCESSIBLE_COLORS['secondary_teal'], # Object: teal
-# WCAG_ACCESSIBLE_COLORS['primary_green'], # Nature: vert
-# WCAG_ACCESSIBLE_COLORS['primary_blue'], # Sky: bleu
-# WCAG_ACCESSIBLE_COLORS['neutral_dark'] # Void: gris foncé
-# ]
-
-# colors = accessible_colors[:len(ordered_class_names)]
-
-# # Créer le graphique accessible
-# fig, ax, displayed = create_accessible_bar_chart_conditional(
-# percentages, ordered_class_names, title,
-# colors=colors, use_patterns=True
-# )
-
-# # Description alternative SEULEMENT si erreur d'affichage
-# if not displayed:
-# alt_text = generate_alt_text_for_bar(
-# percentages, ordered_class_names, title, unit="%"
-# )
-# st.warning(f"**Description du graphique:** {alt_text}")
-
-# st.pyplot(fig)
-# plt.close(fig)
-
-# # Tableau de données complémentaire (toujours affiché)
-# table_data = []
-# for name, percentage in zip(ordered_class_names, percentages):
-# pixels = stats[name]['pixels']
-# table_data.append([name, f"{percentage:.1f}%", f"{pixels:,} pixels"])
-
-# create_data_table(
-# table_data,
-# ["Classe", "Pourcentage", "Nombre de pixels"],
-# f"Données - {title}",
-# "Répartition détaillée des classes de segmentation"
-# )
-
-def display_class_comparison(stats1, stats2, model1, model2, models_info):
- """Affiche uniquement le tableau détaillé de comparaison des classes (sans graphique redondant)"""
- st.markdown("### 🔎 Tableau Détaillé des Comparaisons")
-
- # Préparer les données
- if models_info and 'class_names' in models_info:
- all_classes_in_stats = set(stats1.keys()) | set(stats2.keys())
- ordered_all_classes = [name for name in models_info['class_names'] if name in all_classes_in_stats]
- else:
- all_classes = set(stats1.keys()) | set(stats2.keys())
- ordered_all_classes = sorted(all_classes)
-
- class_names = ordered_all_classes
- model1_values = [stats1.get(name, {}).get('percentage', 0) for name in class_names]
- model2_values = [stats2.get(name, {}).get('percentage', 0) for name in class_names]
-
- # SUPPRIMER tout le code de génération du graphique matplotlib
- # GARDER seulement le tableau
-
- table_data = []
- for i, name in enumerate(class_names):
- val1 = model1_values[i]
- val2 = model2_values[i]
- diff = val1 - val2
-
- if abs(diff) < 1:
- category = "🟢 Similaire"
- elif abs(diff) < 5:
- category = "🟡 Différence modérée"
- else:
- category = "🔴 Différence importante"
-
- table_data.append([
- name,
- f"{val1:.1f}%",
- f"{val2:.1f}%",
- f"{diff:+.1f}%",
- category
- ])
-
- create_data_table(
- table_data,
- [
- "Classe",
- f"🥇 {model1.get('architecture', 'N/A')[:15]} (%)",
- f"🥈 {model2.get('architecture', 'N/A')[:15]} (%)",
- "Différence",
- "Évaluation"
- ],
- "Comparaison détaillée par classe",
- "Analyse des écarts de performance entre les deux modèles pour chaque classe de segmentation"
- )
-
-# def display_class_comparison(stats1, stats2, model1, model2, models_info):
-# """Affiche une comparaison accessible des classes entre les deux modèles"""
-# st.markdown("### � Analyse Comparative par Classe")
-
-# # Préparer les données
-# if models_info and 'class_names' in models_info:
-# all_classes_in_stats = set(stats1.keys()) | set(stats2.keys())
-# ordered_all_classes = [name for name in models_info['class_names'] if name in all_classes_in_stats]
-# else:
-# all_classes = set(stats1.keys()) | set(stats2.keys())
-# ordered_all_classes = sorted(all_classes)
-
-# class_names = ordered_all_classes
-# model1_values = [stats1.get(name, {}).get('percentage', 0) for name in class_names]
-# model2_values = [stats2.get(name, {}).get('percentage', 0) for name in class_names]
-
-# # Couleurs accessibles avec motifs différents
-# fig, ax = plt.subplots(figsize=(12, 7))
-
-# x = np.arange(len(class_names))
-# width = 0.35
-
-# # Couleurs accessibles
-# color1 = WCAG_ACCESSIBLE_COLORS['primary_blue']
-# color2 = WCAG_ACCESSIBLE_COLORS['primary_red']
-
-# bars1 = ax.bar(x - width/2, model1_values, width,
-# label=f"{model1.get('architecture', 'N/A')} - {model1['encoder_name']}",
-# color=color1, alpha=0.8, edgecolor='#333333')
-
-# bars2 = ax.bar(x + width/2, model2_values, width,
-# label=f"{model2.get('architecture', 'N/A')} - {model2['encoder_name']}",
-# color=color2, alpha=0.8, edgecolor='#333333', hatch='///')
-
-# # Style accessible
-# ax.set_xlabel('Classes', fontsize=11, fontweight='bold', color='#333333')
-# ax.set_ylabel('Pourcentage (%)', fontsize=11, fontweight='bold', color='#333333')
-# ax.set_title('Comparaison des classes entre les deux modèles',
-# fontsize=13, fontweight='bold', pad=15, color='#333333')
-# ax.set_xticks(x)
-
-# if len(class_names) <= 4:
-# ax.set_xticklabels(class_names, fontsize=10, color='#333333')
-# elif len(class_names) <= 6:
-# ax.set_xticklabels(class_names, rotation=30, ha='right', fontsize=9, color='#333333')
-# else:
-# ax.set_xticklabels(class_names, rotation=45, ha='right', fontsize=9, color='#333333')
-
-# ax.legend(loc='upper right', fontsize=10)
-# ax.grid(axis='y', alpha=0.3, linestyle='--', color='#666666')
-# ax.set_axisbelow(True)
-
-# # Style des axes
-# ax.spines['top'].set_visible(False)
-# ax.spines['right'].set_visible(False)
-# ax.spines['left'].set_color('#666666')
-# ax.spines['bottom'].set_color('#666666')
-
-# # Valeurs sur les barres
-# for bar1, bar2, val1, val2 in zip(bars1, bars2, model1_values, model2_values):
-# height1, height2 = bar1.get_height(), bar2.get_height()
-# ax.text(bar1.get_x() + bar1.get_width()/2., height1 + 0.5,
-# f'{val1:.1f}%', ha='center', va='bottom', fontsize=8,
-# fontweight='bold', color='#333333')
-# ax.text(bar2.get_x() + bar2.get_width()/2., height2 + 0.5,
-# f'{val2:.1f}%', ha='center', va='bottom', fontsize=8,
-# fontweight='bold', color='#333333')
-
-# plt.tight_layout()
-
-# # Description alternative
-# alt_text = f"Graphique comparatif en barres des classes entre {model1['encoder_name']} et {model2['encoder_name']}. "
-# comparisons = []
-# for name, val1, val2 in zip(class_names, model1_values, model2_values):
-# comparisons.append(f"{name}: {val1:.1f}% vs {val2:.1f}%")
-# alt_text += "Comparaisons: " + "; ".join(comparisons)
-
-# st.markdown(f"**Description du graphique:** {alt_text}")
-# st.pyplot(fig)
-# plt.close(fig)
-
-# # Tableau détaillé accessible
-# st.markdown("**🔎 Tableau détaillé des comparaisons:**")
-
-# table_data = []
-# for i, name in enumerate(class_names):
-# val1 = model1_values[i]
-# val2 = model2_values[i]
-# diff = val1 - val2
-
-# if abs(diff) < 1:
-# category = "🟢 Similaire"
-# elif abs(diff) < 5:
-# category = "🟡 Différence modérée"
-# else:
-# category = "🔴 Différence importante"
-
-# table_data.append([
-# name,
-# f"{val1:.1f}%",
-# f"{val2:.1f}%",
-# f"{diff:+.1f}%",
-# category
-# ])
-
-# create_data_table(
-# table_data,
-# [
-# "Classe",
-# f"🥇 {model1.get('architecture', 'N/A')[:15]} (%)",
-# f"🥈 {model2.get('architecture', 'N/A')[:15]} (%)",
-# "Différence",
-# "Évaluation"
-# ],
-# "Comparaison détaillée par classe",
-# "Analyse des écarts de performance entre les deux modèles pour chaque classe de segmentation"
-# )
-
-
-# Onglets principaux
-main_tab1, main_tab2 = st.tabs(["📊 Présentation Jeu de données Cityscapes", "🔄 Comparaison de performances"])
-
-# ===== ONGLET 1: PRÉSENTATION DATASET =====
-with main_tab1:
- st.markdown("## 📊 Analyse Exploratoire - Dataset Cityscapes")
-
- # Informations générales sur le dataset
- dataset_info = get_dataset_info()
-
- if dataset_info:
- # Section méthodologique MODIFIÉE
- st.markdown("""
- ### 🎯 Présentation générale du dataset Cityscapes
-
- #### Dataset retenu
-
- **Cityscapes Dataset : Référence en Segmentation Urbaine**
- """)
-
- # Spécificités techniques
- st.markdown("""
- ### ⚙� Spécificités techniques
-
- - **Taille Datase**: 25 000 images haute résolution
- - **Résolutions d'acquisition** : Données natives 2048×1024 pixels
- - **Conditions d'acquisition** : Conditions météo bonnes à moyennes, pas de conditions adverses (pluie, neige)
- - **Diversité géographique** : Villes allemandes et suisses (architectures variées)
- - **Annotations pixel-perfect** : Masques de segmentation précis au pixel près (Train + Val)
-
- Ce dataset permet d'évaluer la capacité des modèles à comprendre les scènes urbaines complexes, élément fondamental pour les applications de conduite autonome et de surveillance urbaine intelligente.
- """)
-
- # Composition du dataset avec pie charts NOUVEAU
- st.markdown("### 🗂� Composition et utilisation du dataset")
-
- # Version finale qui combine : tailles uniformes + couleurs WCAG + descriptions conditionnelles
- if dataset_info.get('splits'):
- splits_info = dataset_info['splits']
- project_splits = dataset_info.get('project_splits', {})
-
- st.markdown("#### 📊 Visualisations accessibles")
-
- # Option pour activer les motifs (accessibilité)
- use_patterns = st.checkbox(
- "🎨 Activer les motifs (accessibilité visuelle)",
- help="Active les motifs en plus des couleurs pour faciliter la distinction des données",
- value=True
- )
-
- # Organiser en 1 ligne de 4 colonnes
- col1, col2, col3, col4 = st.columns(4)
-
- # Configuration uniforme pour tous les graphiques (SOLUTION QUI MARCHAIT)
- uniform_figsize = (6, 6)
- uniform_textprops = {'fontsize': 8, 'fontweight': 'bold', 'color': '#333333'}
- uniform_title_props = {'fontsize': 10, 'fontweight': 'bold', 'pad': 15}
-
- # Couleurs WCAG accessibles
- accessible_colors = {
- 'blue': WCAG_ACCESSIBLE_COLORS['primary_blue'],
- 'red': WCAG_ACCESSIBLE_COLORS['primary_red'],
- 'orange': WCAG_ACCESSIBLE_COLORS['primary_orange'],
- 'gray': WCAG_ACCESSIBLE_COLORS['neutral_medium'],
- 'light_gray': WCAG_ACCESSIBLE_COLORS['neutral_light']
- }
-
- # Motifs pour accessibilité
- patterns = ['///', '|||', '---', '...', 'xxx', None] if use_patterns else [None] * 6
-
- # Données pour le tableau récapitulatif
- pie_data_for_table = []
-
- with col1:
- # Pie chart Train (avec répartition projet)
- fig_train, ax_train = plt.subplots(figsize=uniform_figsize, tight_layout=True)
-
- train_total = splits_info['train']['images']
- train_our_train = project_splits['train']['images']
- train_our_val = project_splits['validation']['images']
-
- sizes = [train_our_train, train_our_val]
- labels = [f'Notre Entraînement\n{train_our_train} images (80%)',
- f'Notre Validation\n{train_our_val} images (20%)']
- colors = [accessible_colors['blue'], accessible_colors['red']]
- explode = (0.05, 0.05)
-
- try:
- wedges, texts, autotexts = ax_train.pie(
- sizes, labels=labels, colors=colors, autopct='%1.0f%%',
- startangle=90, explode=explode, shadow=True,
- textprops=uniform_textprops,
- wedgeprops={'edgecolor': 'white', 'linewidth': 2}
- )
-
- # Ajouter des motifs si demandé
- if use_patterns:
- for wedge, pattern in zip(wedges, patterns[:2]):
- if pattern:
- wedge.set_hatch(pattern)
-
- ax_train.set_title(f'Split Train Original\n{train_total} images total',
- **uniform_title_props, color='#333333')
- ax_train.axis('equal')
-
- chart_displayed = True
-
- except Exception as e:
- ax_train.text(0.5, 0.5, f"Erreur d'affichage\n{str(e)}",
- ha='center', va='center', transform=ax_train.transAxes,
- fontsize=10, color='red', weight='bold')
- chart_displayed = False
-
- # Description SEULEMENT si erreur
- if not chart_displayed:
- alt_text = generate_alt_text_for_pie(sizes, labels, "Split Train")
- st.warning(f"**Description du graphique:** {alt_text}")
-
- st.pyplot(fig_train)
- plt.close(fig_train)
-
- pie_data_for_table.extend([
- ["Train - Entraînement", train_our_train, "80%", "Entraînement des modèles"],
- ["Train - Validation", train_our_val, "20%", "Validation pendant entraînement"]
- ])
-
- with col2:
- # Pie chart Validation (utilisation complète)
- fig_val, ax_val = plt.subplots(figsize=uniform_figsize, tight_layout=True)
-
- val_total = splits_info['validation']['images']
- val_our_test = project_splits['test']['images']
-
- sizes = [val_our_test]
- labels = [f'Notre Test Final\n{val_our_test} images (100%)']
- colors = [accessible_colors['orange']]
-
- try:
- wedges, texts, autotexts = ax_val.pie(
- sizes, labels=labels, colors=colors, autopct='%1.0f%%',
- startangle=90, shadow=True, textprops=uniform_textprops,
- wedgeprops={'edgecolor': 'white', 'linewidth': 2}
- )
-
- if use_patterns and patterns[2]:
- wedges[0].set_hatch(patterns[2])
-
- ax_val.set_title(f'Split Validation Original\n{val_total} images total',
- **uniform_title_props, color='#333333')
- ax_val.axis('equal')
-
- chart_displayed = True
-
- except Exception as e:
- ax_val.text(0.5, 0.5, f"Erreur d'affichage\n{str(e)}",
- ha='center', va='center', transform=ax_val.transAxes,
- fontsize=10, color='red', weight='bold')
- chart_displayed = False
-
- if not chart_displayed:
- alt_text = generate_alt_text_for_pie(sizes, labels, "Split Validation")
- st.warning(f"**Description du graphique:** {alt_text}")
-
- st.pyplot(fig_val)
- plt.close(fig_val)
-
- pie_data_for_table.append(["Validation - Test", val_our_test, "100%", "Test final des modèles"])
-
- with col3:
- # Pie chart Test (non utilisé)
- fig_test, ax_test = plt.subplots(figsize=uniform_figsize, tight_layout=True)
-
- test_total = splits_info['test']['images']
-
- sizes = [test_total]
- labels = [f'Non utilisé dans notre projet\n{test_total} images\n(annotations privées)']
- colors = [accessible_colors['gray']]
-
- try:
- wedges, texts, autotexts = ax_test.pie(
- sizes, labels=labels, colors=colors, autopct='',
- startangle=90, shadow=True, textprops=uniform_textprops,
- wedgeprops={'edgecolor': 'white', 'linewidth': 2}
- )
-
- if use_patterns and patterns[3]:
- wedges[0].set_hatch(patterns[3])
-
- ax_test.set_title(f'Split Test Original\n{test_total} images total',
- **uniform_title_props, color='#333333')
- ax_test.axis('equal')
-
- chart_displayed = True
-
- except Exception as e:
- ax_test.text(0.5, 0.5, f"Erreur d'affichage\n{str(e)}",
- ha='center', va='center', transform=ax_test.transAxes,
- fontsize=10, color='red', weight='bold')
- chart_displayed = False
-
- if not chart_displayed:
- alt_text = generate_alt_text_for_pie(sizes, labels, "Split Test")
- st.warning(f"**Description du graphique:** {alt_text}")
-
- st.pyplot(fig_test)
- plt.close(fig_test)
-
- pie_data_for_table.append(["Test", 0, "0%", "Non utilisé (annotations privées)"])
-
- with col4:
- # Pie chart Coarse (non utilisé)
- fig_coarse, ax_coarse = plt.subplots(figsize=uniform_figsize, tight_layout=True)
-
- coarse_total = splits_info['coarse']['images']
-
- sizes = [coarse_total]
- labels = [f'Non utilisé dans notre projet\n{coarse_total} images\n(annotations grossières)']
- colors = [accessible_colors['light_gray']]
-
- try:
- wedges, texts, autotexts = ax_coarse.pie(
- sizes, labels=labels, colors=colors, autopct='',
- startangle=90, shadow=True, textprops=uniform_textprops,
- wedgeprops={'edgecolor': 'white', 'linewidth': 2}
- )
-
- if use_patterns and patterns[4]:
- wedges[0].set_hatch(patterns[4])
-
- ax_coarse.set_title(f'Split Coarse Original\n{coarse_total} images total',
- **uniform_title_props, color='#333333')
- ax_coarse.axis('equal')
-
- chart_displayed = True
-
- except Exception as e:
- ax_coarse.text(0.5, 0.5, f"Erreur d'affichage\n{str(e)}",
- ha='center', va='center', transform=ax_coarse.transAxes,
- fontsize=10, color='red', weight='bold')
- chart_displayed = False
-
- if not chart_displayed:
- alt_text = generate_alt_text_for_pie(sizes, labels, "Split Coarse")
- st.warning(f"**Description du graphique:** {alt_text}")
-
- st.pyplot(fig_coarse)
- plt.close(fig_coarse)
-
- pie_data_for_table.append(["Coarse", 0, "0%", "Non utilisé (annotations grossières)"])
-
-
-
-
- st.markdown("### 📊 Exploration Interactive du Dataset")
-
- fig_dataset = create_dataset_interactive_overview()
-
- try:
- st.plotly_chart(fig_dataset, use_container_width=True, key="dataset_overview")
- except Exception as e:
- st.warning("**Description :** Graphique circulaire interactif montrant la répartition de l'utilisation du dataset Cityscapes dans notre projet.")
- st.info("💡 **Interactivité :** Survolez les sections pour voir les détails, cliquez sur la légende pour masquer/afficher des catégories.")
-
- # Tableau de données accessible (toujours affiché)
- st.markdown("#### 📋 Tableau récapitulatif des données")
-
- create_data_table(
- pie_data_for_table,
- ["Split", "Images utilisées", "Pourcentage", "Utilisation"],
- "Répartition du dataset Cityscapes",
- "Détail de l'utilisation de chaque split du dataset original dans notre projet"
- )
-
-
-
- # Architecture des classes
- st.markdown("### �� Architecture de classes hiérarchique")
- st.markdown("""
- Le dataset organise 34 classes détaillées en **8 méta-classes** pour la segmentation :
-
- | Méta-classe | Description | Importance |
- |-------------|-------------|------------|
- | **Flat** | Route, trottoir, parkings | Navigation de base |
- | **Human** | Piéton, cycliste | **Sécurité critique** |
- | **Vehicle** | Voiture, camion, bus, train | Obstacles dynamiques |
- | **Construction** | Bâtiment, mur, clôture, pont | Structure urbaine |
- | **Object** | Poteau, feu, panneau | Signalétique |
- | **Nature** | Végétation, terrain | Environnement |
- | **Sky** | Ciel | Contexte |
- | **Void** | Zones non-définies | Exclusion |
- """)
-
- # Graphique de répartition des classes
- st.markdown("### 📊 Répartition des classes dans le dataset d'entraînement")
-
- class_repartition_data = get_class_repartition()
- if class_repartition_data:
- try:
- class_repartition_image = Image.open(io.BytesIO(class_repartition_data))
- st.image(
- class_repartition_image,
- caption="Distribution des classes dans les images d'entraînement Cityscapes",
- use_container_width=True
- )
- except Exception as e:
- st.warning("Impossible d'afficher le graphique de répartition des classes")
- else:
- st.info("Graphique de répartition des classes non disponible")
-
- # Section preprocessing des images
- st.markdown("---")
- st.markdown("### 🔧 Exemple de Preprocessing d'Images")
-
- # Récupérer les images d'entraînement disponibles
- train_data = get_train_images()
- if train_data and train_data['images']:
- # Sélecteur d'image
- image_options = {img['display_name']: img['filename'] for img in train_data['images']}
- selected_display_name = st.selectbox(
- "Choisissez une image d'entraînement pour voir les transformations:",
- options=list(image_options.keys()),
- help=f"{train_data['total_count']} images disponibles",
- key="train_image_selector"
- )
-
- selected_filename = image_options[selected_display_name]
-
- # Preview de l'image sélectionnée (avant preprocessing)
- if selected_filename and "preprocessing_result" not in st.session_state:
- try:
- image_url = f"{API_BASE_URL}/train-image/{selected_filename}"
- response = requests.get(image_url, timeout=5)
-
- if response.status_code == 200:
- preview_image = Image.open(io.BytesIO(response.content))
- st.image(
- preview_image,
- caption=f"Aperçu de l'image sélectionnée : {selected_display_name}",
- use_container_width=True
- )
- except:
- st.info("Aperçu non disponible")
-
- # Options de preprocessing
- col1, col2 = st.columns(2)
- with col1:
- show_augmentation = st.checkbox(
- "Inclure l'augmentation aléatoire",
- help="Affiche un exemple d'augmentation de données utilisée pendant l'entraînement. Cliquez plusieurs fois sur 'Appliquer le Preprocessing' pour tester différentes augmentations aléatoires !",
- key="augmentation_checkbox"
- )
-
- with col2:
- if st.button("🔧 Appliquer le Preprocessing", type="primary", key="apply_preprocessing"):
- with st.spinner("Application des transformations..."):
- result = preprocess_train_image(selected_filename, show_augmentation)
-
- if result and result['success']:
- st.session_state.preprocessing_result = result
- st.success("Preprocessing terminé!")
- st.rerun()
- else:
- st.error("Erreur lors du preprocessing")
-
- # Bouton pour revenir à l'aperçu
- if "preprocessing_result" in st.session_state:
- if st.button("🔄 Choisir une nouvelle image", type="secondary", key="reset_preprocessing"):
- del st.session_state.preprocessing_result
- st.rerun()
-
- # Affichage des résultats de preprocessing
- if "preprocessing_result" in st.session_state:
- result = st.session_state.preprocessing_result
-
- # Affichage des images transformées sur toute la largeur
- st.markdown("#### Résultats des transformations :")
-
- if show_augmentation and result.get('augmented_image'):
- cols = st.columns(3)
- col_titles = ["Image Originale (redimensionnée)", "Après Normalisation", "Avec Augmentation Aléatoire"]
- col_data = [result.get('original_image'), result.get('normalized_image'), result.get('augmented_image')]
- else:
- cols = st.columns(2)
- col_titles = ["Image Originale (redimensionnée)", "Après Normalisation"]
- col_data = [result.get('original_image'), result.get('normalized_image')]
-
- for i, (col, title, data) in enumerate(zip(cols, col_titles, col_data)):
- with col:
- st.markdown(f"**{title}**")
- if data:
- img_data = base64.b64decode(data)
- img = Image.open(io.BytesIO(img_data))
- st.image(img, use_container_width=True)
-
-
- # Explications des transformations appliquées
- if result.get('transformations_applied'):
- st.markdown("#### 📋 Transformations appliquées :")
-
- # Préparer les transformations pour l'alignement
- transforms = result['transformations_applied']
-
- # Extraire les transformations de base (toujours présentes)
- base_transforms = [t for t in transforms if "Resize" in t or "Normalization" in t]
- augmentation_transforms = [t for t in transforms if "Resize" not in t and "Normalization" not in t]
-
- if show_augmentation and result.get('augmented_image'):
- # 3 colonnes quand augmentation active
- col1, col2, col3 = st.columns(3)
-
- with col1:
- st.markdown("**Image Originale (redimensionnée)**")
- resize_transform = next((t for t in base_transforms if "Resize" in t), "1. Resize (512x512)")
- st.write(f"• {resize_transform}")
-
- with col2:
- st.markdown("**Après Normalisation**")
- norm_transform = next((t for t in base_transforms if "Normalization" in t), "2. Normalization (0-1)")
- st.write(f"• {norm_transform}")
-
- with col3:
- st.markdown("**Avec Augmentation Aléatoire**")
- if augmentation_transforms:
- for i, transform in enumerate(augmentation_transforms, 3):
- st.write(f"• {i}. {transform}")
- else:
- st.write("• 3. Aucune augmentation appliquée (aléatoire)")
-
- else:
- # 2 colonnes quand pas d'augmentation
- col1, col2 = st.columns(2)
-
- with col1:
- st.markdown("**Image Originale (redimensionnée)**")
- resize_transform = next((t for t in base_transforms if "Resize" in t), "1. Resize (512x512)")
- st.write(f"• {resize_transform}")
-
- with col2:
- st.markdown("**Après Normalisation**")
- norm_transform = next((t for t in base_transforms if "Normalization" in t), "2. Normalization (0-1)")
- st.write(f"• {norm_transform}")
-
- # Explications détaillées avec description complète des augmentations
- with st.expander("ℹ� Détails des transformations possibles"):
- st.markdown("""
- **Normalisation standard (toujours appliquée) :**
- - **Redimensionnement** : Toutes les images sont redimensionnées à 512×512 pixels
- - **Normalisation** : Les valeurs de pixels sont normalisées de [0-255] vers [0-1]
- - Cette normalisation uniforme est appliquée à tous les modèles (paramètre encoder non utilisé)
-
- **Augmentations de données possibles (si activées) :**
-
- Le système sélectionne aléatoirement entre 1 et 4 transformations parmi les suivantes :
-
- 1. **Rotation aléatoire** : Rotation de l'image entre -15° et +15°
- 2. **Flip horizontal** : Miroir horizontal avec 50% de probabilité
- 3. **Changement de luminosité/contraste** : Ajustement de ±20% de la luminosité et du contraste
- 4. **Flou gaussien léger** : Application d'un flou gaussien subtil (blur 1-3 pixels)
- 5. **Décalage couleur** : Modification de la teinte, saturation et valeur (±10-15%)
- 6. **Zoom aléatoire** : Zoom de -10% à +10% (avec probabilité réduite)
-
- **Important :** Les augmentations sont **aléatoires** à chaque application. Cliquez plusieurs fois sur
- "Appliquer le Preprocessing" pour voir différentes combinaisons ! Le résultat peut inclure une ou
- plusieurs transformations, ou même aucune selon le hasard.
-
- Ces transformations permettent d'améliorer la robustesse et la généralisation du modèle pendant
- l'entraînement en exposant le modèle à des variations réalistes des données.
- """)
- else:
- st.warning("Aucune image d'entraînement disponible pour la démonstration")
-
-# ===== ONGLET 2: COMPARAISON DE PERFORMANCES =====
-with main_tab2:
- # Variables de session pour les résultats
- if "sample_comparison_result" not in st.session_state:
- st.session_state.sample_comparison_result = None
- if "upload_comparison_result" not in st.session_state:
- st.session_state.upload_comparison_result = None
-
- def reset_sample_comparison():
- st.session_state.sample_comparison_result = None
-
- def reset_upload_comparison():
- st.session_state.upload_comparison_result = None
-
- # Sous-onglets pour la comparaison
- sub_tab1, sub_tab2 = st.tabs(["�� Images Test Cityscapes", "📤 Upload Personnel"])
-
- # SUB-TAB 1: Images Test Cityscapes
- with sub_tab1:
- st.markdown("## �� Comparaison sur Images Test Cityscapes")
- st.markdown("Comparez les performances des deux modèles sur des images Cityscapes avec masques de vérité.")
-
- # Récupérer les images d'exemple
- sample_data = get_sample_images()
- if sample_data and sample_data['images']:
- # Sélecteur d'image
- image_options = {img['display_name']: img['filename'] for img in sample_data['images']}
- selected_display_name = st.selectbox(
- "Choisissez une image:",
- options=list(image_options.keys()),
- help=f"{sample_data['total_count']} images disponibles"
- )
-
- selected_filename = image_options[selected_display_name]
-
- # Afficher les infos de l'image sélectionnée
- selected_img_info = next(img for img in sample_data['images'] if img['filename'] == selected_filename)
-
- col1, col2 = st.columns([2, 1])
- with col1:
- st.info(f"� **Fichier:** {selected_filename}")
- with col2:
- ground_truth_status = "✅ Disponible" if selected_img_info['has_ground_truth'] else "� Non disponible"
- st.info(f"🎯 **Vérité terrain:** {ground_truth_status}")
-
- # Prévisualisation de l'image sélectionnée
- if selected_filename:
- try:
- image_url = f"{API_BASE_URL}/sample-image/{selected_filename}"
- response = requests.get(image_url, timeout=5)
-
- if response.status_code == 200:
- sample_image = Image.open(io.BytesIO(response.content))
- st.image(
- sample_image,
- caption=f"Aperçu: {selected_display_name}",
- use_container_width=True
- )
- except:
- st.info("📷 Aperçu non disponible - L'image sera chargée lors de la comparaison")
-
- # Bouton de comparaison
- if st.button("🔄 Lancer la Comparaison", key="compare_sample", type="primary"):
- if selected_filename:
- with st.spinner("Comparaison en cours..."):
- result = compare_sample_image(selected_filename)
- if result and result['success']:
- st.session_state.sample_comparison_result = result
- st.success("✅ Comparaison terminée!")
- st.rerun()
- else:
- st.error("� Erreur lors de la comparaison")
- else:
- st.warning("Aucune image d'exemple disponible")
-
- # Affichage des résultats de comparaison
- if st.session_state.sample_comparison_result:
- st.markdown("---")
- models_info = get_models_info()
- display_comparison_results(st.session_state.sample_comparison_result, models_info, "sample")
-
- # Bouton de reset
- if st.button("🔄 Nouvelle Comparaison", key="reset_sample", type="secondary"):
- reset_sample_comparison()
- st.rerun()
-
- # SUB-TAB 2: Upload Personnel
- with sub_tab2:
- st.markdown("## 📤 Comparaison sur Image Personnelle")
- st.markdown("Uploadez une image pour comparer les performances des deux modèles.")
-
- uploaded_file = st.file_uploader(
- "Sélectionnez une image:",
- type=['jpg', 'jpeg', 'png'],
- help="Taille maximale recommandée: 5MB"
- )
-
- if uploaded_file is not None:
- # Afficher l'image uploadée
- image = Image.open(uploaded_file)
- st.image(image, caption=f"Image uploadée: {uploaded_file.name}", use_container_width=True)
-
- # Informations sur le fichier
- file_size_mb = len(uploaded_file.getvalue()) / 1024 / 1024
- st.info(f"� **Fichier:** {uploaded_file.name} | 📊 **Taille:** {file_size_mb:.2f} MB")
-
- # Bouton de comparaison
- if st.button("🔄 Lancer la Comparaison", key="compare_upload", type="primary"):
- with st.spinner("Comparaison en cours..."):
- result = compare_uploaded_image(uploaded_file)
- if result and result['success']:
- st.session_state.upload_comparison_result = result
- st.success("✅ Comparaison terminée!")
- st.rerun()
- else:
- st.error("� Erreur lors de la comparaison")
-
- # Affichage des résultats de comparaison
- if st.session_state.upload_comparison_result:
- st.markdown("---")
- models_info = get_models_info()
- display_comparison_results(st.session_state.upload_comparison_result, models_info, "upload")
-
- # Bouton de reset
- if st.button("🔄 Nouvelle Comparaison", key="reset_upload", type="secondary"):
- reset_upload_comparison()
- st.rerun()
-
-# Sidebar avec informations des modèles
-with st.sidebar:
- st.markdown("## 🔧 Informations des Modèles")
-
- models_info = get_models_info()
- if models_info:
- st.success("✅ Modèles chargés")
-
- # Modèle 1
- best_model = models_info.get('best_model', {})
- st.markdown("**🥇 Meilleur Modèle:**")
- st.write(f"**Architecture:** {best_model.get('architecture', 'N/A')}")
- st.write(f"**Encoder:** {best_model.get('encoder_name', 'N/A')}")
- st.write(f"**Résolution:** {best_model.get('input_size', 'N/A')}")
-
- # Modèle 2
- second_model = models_info.get('second_best_model', {})
- st.markdown("**🥈 Deuxième Modèle:**")
- st.write(f"**Architecture:** {second_model.get('architecture', 'N/A')}")
- st.write(f"**Encoder:** {second_model.get('encoder_name', 'N/A')}")
- st.write(f"**Résolution:** {second_model.get('input_size', 'N/A')}")
- else:
- st.error("� Modèles non disponibles")
-
- st.markdown("---")
- st.markdown("## 🎯 Classes Segmentées (IoU)")
-
- # Affichage avec carrés colorés et IoU
- if models_info and 'class_names' in models_info and 'class_colors' in models_info:
- class_names = models_info['class_names']
- class_colors = models_info['class_colors']
-
- # Récupérer les IoU des modèles
- best_ious = best_model.get('class_ious', {}) if models_info else {}
- second_ious = second_model.get('class_ious', {}) if models_info else {}
-
- for i, (class_name, color) in enumerate(zip(class_names, class_colors)):
- color_hex = f"#{color[0]:02x}{color[1]:02x}{color[2]:02x}"
-
- # Construire la chaîne IoU
- iou_str = ""
- if best_ious.get(class_name) is not None and second_ious.get(class_name) is not None:
- best_iou = best_ious[class_name]
- second_iou = second_ious[class_name]
- iou_str = f" (🥇{best_iou:.2f} - 🥈{second_iou:.2f})"
- elif best_ious.get(class_name) is not None:
- best_iou = best_ious[class_name]
- iou_str = f" (🥇{best_iou:.2f})"
- elif second_ious.get(class_name) is not None:
- second_iou = second_ious[class_name]
- iou_str = f" (🥈{second_iou:.2f})"
-
- st.markdown(f"""
-
-
-
{i}. {class_name}{iou_str}
-
- """, unsafe_allow_html=True)
-
-# Footer
-st.markdown("---")
-st.markdown("""
-
- 🚗 Street Vision - Comparaison de Modèles -
- Évaluation comparative de modèles de segmentation sémantique
- Développé avec FastAPI, Streamlit et PyTorch
-
-""", unsafe_allow_html=True)
-
-
-with st.sidebar:
- st.markdown("---")
- st.markdown("## ♿ Conformité WCAG 2.1")
-
- criteria_status = {
- "1.1.1 Contenu non textuel": "✅",
- "1.4.1 Utilisation de la couleur": "✅",
- "1.4.3 Contraste (minimum)": "✅",
- "1.4.4 Redimensionnement du texte": "✅",
- "2.4.2 Titre de page": "✅"
- }
-
- for criterion, status in criteria_status.items():
- st.write(f"{status} {criterion}")
-
- st.markdown("**Niveau :** AA | **Référence :** [WCAG 2.1](https://www.w3.org/WAI/WCAG21/quickref/)")
-
diff --git a/cityscapes_config.json b/cityscapes_config.json
deleted file mode 100644
index 4b61838..0000000
--- a/cityscapes_config.json
+++ /dev/null
@@ -1,63 +0,0 @@
-{
- "class_groups": {
- "flat": ["road", "sidewalk", "parking", "rail track"],
- "human": ["person", "rider"],
- "vehicle": ["car", "truck", "bus", "train", "motorcycle", "bicycle", "caravan", "trailer"],
- "construction": ["building", "wall", "fence", "guard rail", "bridge", "tunnel"],
- "object": ["pole", "pole group", "traffic sign", "traffic light"],
- "nature": ["vegetation", "terrain"],
- "sky": ["sky"],
- "void": ["unlabeled", "ego vehicle", "rectification border", "out of roi", "static", "dynamic", "ground"]
- },
- "cityscapes_mapping": {
- "0": 7, "1": 7, "2": 7, "3": 7, "4": 7, "5": 7, "6": 7,
- "7": 0, "8": 0, "9": 0, "10": 0,
- "11": 3, "12": 3, "13": 3, "14": 3, "15": 3, "16": 3,
- "17": 4, "18": 4, "19": 4, "20": 4,
- "21": 5, "22": 5,
- "23": 6,
- "24": 1, "25": 1,
- "26": 2, "27": 2, "28": 2, "29": 2, "30": 2, "31": 2, "32": 2, "33": 2
- },
- "id_to_label": {
- "0": "unlabeled",
- "1": "ego vehicle",
- "2": "rectification border",
- "3": "out of roi",
- "4": "static",
- "5": "dynamic",
- "6": "ground",
- "7": "road",
- "8": "sidewalk",
- "9": "parking",
- "10": "rail track",
- "11": "building",
- "12": "wall",
- "13": "fence",
- "14": "guard rail",
- "15": "bridge",
- "16": "tunnel",
- "17": "pole",
- "18": "pole group",
- "19": "traffic light",
- "20": "traffic sign",
- "21": "vegetation",
- "22": "terrain",
- "23": "sky",
- "24": "person",
- "25": "rider",
- "26": "car",
- "27": "truck",
- "28": "bus",
- "29": "caravan",
- "30": "trailer",
- "31": "train",
- "32": "motorcycle",
- "33": "bicycle"
- },
- "group_colors": [
- [128, 64, 128], [220, 20, 60], [0, 0, 142], [70, 70, 70],
- [220, 220, 0], [107, 142, 35], [70, 130, 180], [0, 0, 0]
- ],
- "group_names": ["flat", "human", "vehicle", "construction", "object", "nature", "sky", "void"]
-}
diff --git a/docker-compose.yml.example b/docker-compose.yml.example
deleted file mode 100644
index f05e457..0000000
--- a/docker-compose.yml.example
+++ /dev/null
@@ -1,47 +0,0 @@
-version: '3.8'
-
-services:
- street-vision-api:
- # ✅ PRODUCTION: Image depuis Docker Hub
- image: grgmdmn/street-vision_api:latest
-
- container_name: street_vision_api
-
- ports:
- - "${NGINX_PORT:-8080}:${NGINX_PORT:-8080}" # Port nginx configurable
-
- environment:
- # Configuration du port nginx
- NGINX_PORT: "${NGINX_PORT:-8080}"
-
- # Configuration MLflow pour le suivi des modèles
- MLFLOW_TRACKING_URI: "${MLFLOW_TRACKING_URI}" # ex: https://mlflow.domain.com
- MLFLOW_S3_ENDPOINT_URL: "${MLFLOW_S3_ENDPOINT_URL}" # ex: url MinIO ou S3
- AWS_ACCESS_KEY_ID: "${AWS_ACCESS_KEY_ID}" # clé ID S3
- AWS_SECRET_ACCESS_KEY: "${AWS_SECRET_ACCESS_KEY}" # clé secrète S3
-
- # Configuration email pour notifications (optionnel)
- SMTP_SERVER: "${SMTP_SERVER:-}" # serveur SMTP
- SMTP_PORT: "${SMTP_PORT:-587}" # port SMTP (ex: 587)
- SMTP_EMAIL: "${SMTP_EMAIL:-}" # email expéditeur
- SMTP_PASSWORD: "${SMTP_PASSWORD:-}" # mot de passe SMTP
- SMTP_FROM_ALIAS: "${SMTP_FROM_ALIAS:-Street Vision API}" # alias (optionnel)
- ADMIN_EMAIL: "${ADMIN_EMAIL:-}" # email admin destinataire
-
- # URL de base de l'API (utilisée par Streamlit pour rediriger vers FastAPI)
- MULTISEG_API_BASE_URL: "${MULTISEG_API_BASE_URL}" # ex: https://vision.domain.com/api
-
- # Pour une mise à jour automatique par watchtower
- labels:
- com.centurylinklabs.watchtower.enable: "true"
-
- # Seulement si vous avez un reverse proxy server
- # networks:
- # - swag
-
- restart: unless-stopped
-
-# Seulement si vous avez un reverse proxy server
-# networks:
-# swag:
-# external: true
diff --git a/docs/Cordts_The_Cityscapes_Dataset_CVPR_2016_paper.pdf b/docs/Cordts_The_Cityscapes_Dataset_CVPR_2016_paper.pdf
deleted file mode 100644
index 5145822..0000000
--- a/docs/Cordts_The_Cityscapes_Dataset_CVPR_2016_paper.pdf
+++ /dev/null
@@ -1,21162 +0,0 @@
-%PDF-1.3
-1 0 obj
-<<
-/Kids [ 3 0 R 4 0 R 5 0 R 6 0 R 7 0 R 8 0 R 9 0 R 10 0 R 11 0 R 12 0 R 13 0 R ]
-/Type /Pages
-/Count 11
->>
-endobj
-2 0 obj
-<<
-/Title (The Cityscapes Dataset for Semantic Urban Scene Understanding)
-/Producer (PyPDF2)
-/Author (Marius Cordts\054 Mohamed Omran\054 Sebastian Ramos\054 Timo Rehfeld\054 Markus Enzweiler\054 Rodrigo Benenson\054 Uwe Franke\054 Stefan Roth\054 Bernt Schiele)
-/Subject (2016 IEEE Conference on Computer Vision and Pattern Recognition)
->>
-endobj
-3 0 obj
-<<
-/Parent 1 0 R
-/Rotate 0
-/Contents 15 0 R
-/Resources <<
-/XObject <<
-/x8 16 0 R
-/x10 19 0 R
-/R48 22 0 R
-/x6 23 0 R
-/x12 26 0 R
-/R51 29 0 R
-/R52 30 0 R
->>
-/ExtGState <<
-/s9 31 0 R
-/s11 34 0 R
-/a0 <<
-/CA 1
-/ca 1
->>
-/R37 37 0 R
-/s5 38 0 R
-/s7 41 0 R
->>
-/Font <<
-/R49 44 0 R
-/R46 48 0 R
-/R44 51 0 R
-/R42 55 0 R
-/R40 58 0 R
-/F2 62 0 R
-/F1 63 0 R
-/R38 64 0 R
-/R55 68 0 R
-/R53 71 0 R
->>
-/ProcSet [ /Text /ImageC /ImageB /PDF /ImageI ]
->>
-/CropBox [ 0 0 612 792 ]
-/MediaBox [ 0 0 612 792 ]
-/Annots [ 75 0 R 76 0 R 77 0 R 78 0 R 79 0 R 80 0 R 81 0 R 82 0 R 83 0 R 84 0 R 85 0 R 86 0 R 87 0 R 88 0 R 89 0 R 90 0 R 91 0 R 92 0 R 93 0 R 94 0 R 95 0 R 96 0 R 97 0 R 98 0 R 99 0 R 100 0 R 101 0 R ]
-/Type /Page
->>
-endobj
-4 0 obj
-<<
-/Parent 1 0 R
-/Rotate 0
-/Contents 102 0 R
-/Resources <<
-/XObject <<
-/R78 103 0 R
-/R79 107 0 R
-/R76 108 0 R
-/R98 110 0 R
-/R99 111 0 R
-/R89 112 0 R
-/R88 113 0 R
-/R82 114 0 R
-/R83 115 0 R
-/R91 116 0 R
-/R81 117 0 R
-/R80 118 0 R
-/R87 119 0 R
-/R86 120 0 R
-/R85 121 0 R
-/R84 122 0 R
-/R93 123 0 R
-/R106 124 0 R
-/R101 125 0 R
-/R100 126 0 R
-/R103 127 0 R
-/R102 128 0 R
-/R105 129 0 R
-/R104 130 0 R
-/R95 131 0 R
-/R94 132 0 R
-/R96 133 0 R
-/R92 134 0 R
-/R97 135 0 R
-/R90 136 0 R
->>
-/ExtGState <<
-/R109 137 0 R
-/R37 37 0 R
-/R110 138 0 R
-/R75 109 0 R
-/R69 104 0 R
-/R68 139 0 R
-/R77 105 0 R
->>
-/Font <<
-/R72 140 0 R
-/R113 143 0 R
-/R70 146 0 R
-/R111 149 0 R
-/R107 153 0 R
-/R53 71 0 R
-/F2 156 0 R
-/R115 157 0 R
-/F1 161 0 R
-/R38 64 0 R
-/R55 68 0 R
-/R40 58 0 R
->>
-/ProcSet [ /ImageC /Text /PDF /ImageI /ImageB ]
->>
-/CropBox [ 0 0 612 792 ]
-/MediaBox [ 0 0 612 792 ]
-/Annots [ 162 0 R 163 0 R 164 0 R 165 0 R 166 0 R ]
-/Type /Page
->>
-endobj
-5 0 obj
-<<
-/Parent 1 0 R
-/Rotate 0
-/Contents 167 0 R
-/Resources <<
-/XObject <<
-/R145 168 0 R
-/R144 169 0 R
-/R146 170 0 R
-/R141 171 0 R
-/R140 172 0 R
-/R143 173 0 R
-/R142 174 0 R
-/R133 175 0 R
-/R134 176 0 R
-/R135 177 0 R
-/R136 178 0 R
-/R138 179 0 R
-/R139 181 0 R
->>
-/ExtGState <<
-/R37 37 0 R
-/R69 104 0 R
-/R68 139 0 R
-/R77 105 0 R
-/R137 180 0 R
->>
-/Font <<
-/R147 182 0 R
-/R72 140 0 R
-/R55 68 0 R
-/R70 146 0 R
-/R149 185 0 R
-/R40 58 0 R
-/F2 189 0 R
-/R131 190 0 R
-/F1 194 0 R
-/R38 64 0 R
-/R115 157 0 R
-/R53 71 0 R
->>
-/ProcSet [ /ImageC /Text /PDF /ImageI /ImageB ]
->>
-/CropBox [ 0 0 612 792 ]
-/MediaBox [ 0 0 612 792 ]
-/Annots [ 195 0 R 196 0 R 197 0 R 198 0 R 199 0 R 200 0 R 201 0 R 202 0 R ]
-/Type /Page
->>
-endobj
-6 0 obj
-<<
-/Parent 1 0 R
-/Rotate 0
-/Contents 203 0 R
-/Resources <<
-/XObject <<
-/R192 204 0 R
-/R193 205 0 R
-/R190 206 0 R
-/R191 207 0 R
-/R185 208 0 R
-/R187 209 0 R
-/R194 210 0 R
-/R195 211 0 R
-/R189 212 0 R
-/R188 213 0 R
-/R186 214 0 R
-/R183 215 0 R
-/R182 216 0 R
-/R184 217 0 R
->>
-/ExtGState <<
-/R37 37 0 R
-/R69 104 0 R
-/R77 105 0 R
-/R137 180 0 R
->>
-/Font <<
-/F2 218 0 R
-/R131 190 0 R
-/R147 182 0 R
-/F1 219 0 R
-/R72 140 0 R
-/R55 68 0 R
-/R70 146 0 R
-/R40 58 0 R
-/R53 71 0 R
->>
-/ProcSet [ /ImageC /Text /PDF /ImageI /ImageB ]
->>
-/CropBox [ 0 0 612 792 ]
-/MediaBox [ 0 0 612 792 ]
-/Annots [ 220 0 R 221 0 R 222 0 R 223 0 R 224 0 R 225 0 R 226 0 R 227 0 R 228 0 R 229 0 R 230 0 R 231 0 R 232 0 R 233 0 R 234 0 R 235 0 R 236 0 R 237 0 R 238 0 R 239 0 R 240 0 R 241 0 R 242 0 R 243 0 R 244 0 R ]
-/Type /Page
->>
-endobj
-7 0 obj
-<<
-/Parent 1 0 R
-/Rotate 0
-/Contents 245 0 R
-/Resources <<
-/ExtGState <<
-/R37 37 0 R
->>
-/Font <<
-/R113 143 0 R
-/R53 71 0 R
-/F2 246 0 R
-/F1 247 0 R
-/R38 64 0 R
-/R55 68 0 R
-/R40 58 0 R
->>
-/ProcSet [ /ImageC /Text /PDF /ImageI /ImageB ]
->>
-/CropBox [ 0 0 612 792 ]
-/MediaBox [ 0 0 612 792 ]
-/Annots [ 248 0 R 249 0 R 250 0 R 251 0 R 252 0 R 253 0 R 254 0 R 255 0 R 256 0 R 257 0 R 258 0 R 259 0 R 260 0 R 261 0 R ]
-/Type /Page
->>
-endobj
-8 0 obj
-<<
-/Parent 1 0 R
-/Rotate 0
-/Contents 262 0 R
-/Resources <<
-/ExtGState <<
-/R37 37 0 R
->>
-/Font <<
-/R147 182 0 R
-/R55 68 0 R
-/R70 146 0 R
-/R40 58 0 R
-/F2 263 0 R
-/R131 190 0 R
-/F1 264 0 R
-/R38 64 0 R
-/R53 71 0 R
-/R276 265 0 R
->>
-/ProcSet [ /ImageC /Text /PDF /ImageI /ImageB ]
->>
-/CropBox [ 0 0 612 792 ]
-/MediaBox [ 0 0 612 792 ]
-/Annots [ 269 0 R 270 0 R 271 0 R 272 0 R 273 0 R 274 0 R 275 0 R 276 0 R 277 0 R 278 0 R 279 0 R 280 0 R 281 0 R 282 0 R 283 0 R 284 0 R 285 0 R 286 0 R 287 0 R 288 0 R 289 0 R 290 0 R 291 0 R 292 0 R 293 0 R 294 0 R 295 0 R 296 0 R 297 0 R 298 0 R 299 0 R 300 0 R 301 0 R 302 0 R 303 0 R 304 0 R 305 0 R 306 0 R 307 0 R 308 0 R 309 0 R 310 0 R 311 0 R 312 0 R 313 0 R 314 0 R 315 0 R 316 0 R 317 0 R 318 0 R 319 0 R 320 0 R 321 0 R ]
-/Type /Page
->>
-endobj
-9 0 obj
-<<
-/Parent 1 0 R
-/Rotate 0
-/Contents 322 0 R
-/Resources <<
-/ExtGState <<
-/R37 37 0 R
->>
-/Font <<
-/R113 143 0 R
-/R70 146 0 R
-/R53 71 0 R
-/F2 323 0 R
-/R131 190 0 R
-/F1 324 0 R
-/R38 64 0 R
-/R55 68 0 R
-/R40 58 0 R
-/R115 157 0 R
->>
-/ProcSet [ /ImageC /Text /PDF /ImageI /ImageB ]
->>
-/CropBox [ 0 0 612 792 ]
-/MediaBox [ 0 0 612 792 ]
-/Annots [ 325 0 R 326 0 R 327 0 R 328 0 R 329 0 R 330 0 R 331 0 R 332 0 R 333 0 R 334 0 R 335 0 R 336 0 R 337 0 R 338 0 R 339 0 R 340 0 R 341 0 R 342 0 R 343 0 R 344 0 R 345 0 R 346 0 R 347 0 R 348 0 R 349 0 R 350 0 R 351 0 R 352 0 R 353 0 R 354 0 R 355 0 R 356 0 R 357 0 R 358 0 R 359 0 R 360 0 R 361 0 R 362 0 R 363 0 R 364 0 R 365 0 R ]
-/Type /Page
->>
-endobj
-10 0 obj
-<<
-/Parent 1 0 R
-/Rotate 0
-/Contents 366 0 R
-/Resources <<
-/XObject <<
-/R361 367 0 R
-/R360 368 0 R
-/R344 369 0 R
-/R349 370 0 R
-/R348 371 0 R
-/R350 372 0 R
-/R346 373 0 R
-/R352 374 0 R
-/R353 375 0 R
-/R354 376 0 R
-/R355 377 0 R
-/R356 378 0 R
-/R357 379 0 R
-/R341 380 0 R
-/R340 381 0 R
-/R343 382 0 R
-/R342 383 0 R
-/R359 384 0 R
-/R347 385 0 R
-/R358 386 0 R
-/R351 387 0 R
->>
-/ExtGState <<
-/R37 37 0 R
->>
-/Font <<
-/R147 182 0 R
-/R72 140 0 R
-/R55 68 0 R
-/R70 146 0 R
-/R40 58 0 R
-/F2 388 0 R
-/R131 190 0 R
-/F1 389 0 R
-/R38 64 0 R
-/R115 157 0 R
-/R53 71 0 R
->>
-/ProcSet [ /Text /ImageC /ImageB /PDF /ImageI ]
->>
-/CropBox [ 0 0 612 792 ]
-/MediaBox [ 0 0 612 792 ]
-/Annots [ 390 0 R 391 0 R 392 0 R 393 0 R 394 0 R 395 0 R 396 0 R 397 0 R 398 0 R 399 0 R 400 0 R 401 0 R 402 0 R ]
-/Type /Page
->>
-endobj
-11 0 obj
-<<
-/Parent 1 0 R
-/Rotate 0
-/Contents 403 0 R
-/Resources <<
-/ExtGState <<
-/R37 37 0 R
->>
-/Font <<
-/F2 404 0 R
-/F1 405 0 R
-/R40 58 0 R
-/R38 64 0 R
-/R53 71 0 R
->>
-/ProcSet [ /ImageC /Text /PDF /ImageI /ImageB ]
->>
-/CropBox [ 0 0 612 792 ]
-/MediaBox [ 0 0 612 792 ]
-/Annots [ 406 0 R 407 0 R 408 0 R 409 0 R 410 0 R 411 0 R 412 0 R 413 0 R 414 0 R 415 0 R 416 0 R 417 0 R 418 0 R 419 0 R 420 0 R 421 0 R 422 0 R 423 0 R 424 0 R 425 0 R 426 0 R 427 0 R 428 0 R 429 0 R 430 0 R 431 0 R 432 0 R 433 0 R 434 0 R 435 0 R 436 0 R 437 0 R 438 0 R 439 0 R 440 0 R 441 0 R 442 0 R 443 0 R 444 0 R 445 0 R 446 0 R 447 0 R 448 0 R 449 0 R 450 0 R 451 0 R 452 0 R 453 0 R 454 0 R 455 0 R 456 0 R 457 0 R 458 0 R 459 0 R 460 0 R 461 0 R 462 0 R 463 0 R 464 0 R 465 0 R 466 0 R 467 0 R ]
-/Type /Page
->>
-endobj
-12 0 obj
-<<
-/Parent 1 0 R
-/Rotate 0
-/Contents 468 0 R
-/Resources <<
-/ExtGState <<
-/R37 37 0 R
->>
-/Font <<
-/F2 469 0 R
-/F1 470 0 R
-/R40 58 0 R
-/R53 71 0 R
->>
-/ProcSet [ /ImageC /Text /PDF /ImageI /ImageB ]
->>
-/CropBox [ 0 0 612 792 ]
-/MediaBox [ 0 0 612 792 ]
-/Annots [ 471 0 R 472 0 R 473 0 R 474 0 R 475 0 R 476 0 R 477 0 R 478 0 R 479 0 R 480 0 R 481 0 R 482 0 R 483 0 R 484 0 R 485 0 R 486 0 R 487 0 R 488 0 R 489 0 R 490 0 R 491 0 R 492 0 R 493 0 R 494 0 R 495 0 R 496 0 R 497 0 R 498 0 R 499 0 R 500 0 R 501 0 R 502 0 R 503 0 R 504 0 R 505 0 R 506 0 R 507 0 R 508 0 R 509 0 R 510 0 R 511 0 R 512 0 R 513 0 R 514 0 R 515 0 R 516 0 R 517 0 R 518 0 R 519 0 R 520 0 R 521 0 R 522 0 R 523 0 R 524 0 R ]
-/Type /Page
->>
-endobj
-13 0 obj
-<<
-/Parent 1 0 R
-/Rotate 0
-/Contents 525 0 R
-/Resources <<
-/ExtGState <<
-/R37 37 0 R
->>
-/Font <<
-/F2 526 0 R
-/F1 527 0 R
-/R40 58 0 R
-/R53 71 0 R
->>
-/ProcSet [ /ImageC /Text /PDF /ImageI /ImageB ]
->>
-/CropBox [ 0 0 612 792 ]
-/MediaBox [ 0 0 612 792 ]
-/Annots [ 528 0 R 529 0 R 530 0 R 531 0 R 532 0 R 533 0 R 534 0 R ]
-/Type /Page
->>
-endobj
-14 0 obj
-<<
-/Type /Catalog
-/Pages 1 0 R
->>
-endobj
-15 0 obj
-<<
-/Length 22951
->>
-stream
-q
-q
-q
-0.10000 0 0 0.10000 0 0 cm
-/R37 gs
-0 g
-q
-10 0 0 10 0 0 cm
-BT
-/R38 14.34620 Tf
-1 0 0 1 96.76020 675.06700 Tm
-[ (The) -249.99300 (Cityscapes) -250.00700 (Dataset) -250.00300 (f) 24.99230 (or) -249.99500 (Semantic) -250 (Urban) -249.99600 (Scene) -250.01200 (Understanding) ] TJ
-/R40 11.95520 Tf
--12.43630 -37.85820 Td
-[ (Marius) -249.99400 (Cordts) ] TJ
-/R42 7.97010 Tf
-68.74100 4.33906 Td
-[ (1) -0.29866 ] TJ
-/R44 7.97010 Tf
-4.23398 0 Td
-[ (\073) -0.09955 ] TJ
-/R42 7.97010 Tf
-2.35312 0 Td
-[ (2) -0.29866 ] TJ
-/R40 11.95520 Tf
-33.44220 -4.33906 Td
-[ (Mohamed) -250.00400 (Omran) ] TJ
-/R42 7.97010 Tf
-84.66600 4.33906 Td
-[ (3) -0.30019 ] TJ
-/R40 11.95520 Tf
-33.44180 -4.33906 Td
-[ (Sebastian) -249.98300 (Ramos) ] TJ
-/R42 7.97010 Tf
-82.02420 4.33906 Td
-[ (1) -0.30019 ] TJ
-/R44 7.97010 Tf
-4.23398 0 Td
-[ (\073) -0.10109 ] TJ
-/R42 7.97010 Tf
-2.35195 0 Td
-[ (4) -0.30019 ] TJ
-/R40 11.95520 Tf
-33.44300 -4.33906 Td
-[ (T) 34.98980 (imo) -249.99300 (Rehfeld) ] TJ
-/R42 7.97010 Tf
-66.32580 4.33906 Td
-[ (1) -0.30019 ] TJ
-/R44 7.97010 Tf
-4.23398 0 Td
-[ (\073) -0.09802 ] TJ
-/R42 7.97010 Tf
-2.35312 0 Td
-[ (2) -0.30019 ] TJ
-/R40 11.95520 Tf
--447.69700 -18.28590 Td
-[ (Markus) -250.01400 (Enzweiler) ] TJ
-/R42 7.97010 Tf
-87.97700 4.33789 Td
-[ (1) -0.29866 ] TJ
-/R40 11.95520 Tf
-29.04690 -4.33789 Td
-[ (Rodrigo) -250.01600 (Benenson) ] TJ
-/R42 7.97010 Tf
-89.32890 4.33789 Td
-[ (3) -0.30019 ] TJ
-/R40 11.95520 Tf
-29.04730 -4.33789 Td
-[ (Uwe) -249.99500 (Frank) 10.00440 (e) ] TJ
-/R42 7.97010 Tf
-58.63980 4.33789 Td
-[ (1) -0.30019 ] TJ
-/R40 11.95520 Tf
-29.04690 -4.33789 Td
-[ (Stef) 10.00440 (an) -250.01000 (Roth) ] TJ
-/R42 7.97010 Tf
-56.66720 4.33789 Td
-[ (2) -0.30019 ] TJ
-/R40 11.95520 Tf
-29.04800 -4.33789 Td
-[ (Bernt) -249.98900 (Schiele) ] TJ
-/R42 7.97010 Tf
-64.74800 4.33789 Td
-[ (3) -0.30019 ] TJ
--400.18600 -22.53400 Td
-[ (1) -0.29866 ] TJ
-/R40 11.95520 Tf
-4.73203 -4.33906 Td
-[ (Daimler) -250.00300 (A) 39.99410 (G) -249.98800 (R\046D\054) ] TJ
-/R42 7.97010 Tf
-93.82380 4.33906 Td
-[ (2) -0.30019 ] TJ
-/R40 11.95520 Tf
-4.73203 -4.33906 Td
-[ (TU) -249.99300 (Darmstadt\054) ] TJ
-/R42 7.97010 Tf
-74.70700 4.33906 Td
-[ (3) -0.30019 ] TJ
-/R40 11.95520 Tf
-4.73203 -4.33906 Td
-[ (MPI) -250.01400 (Informatics\054) ] TJ
-/R42 7.97010 Tf
-85.33480 4.33906 Td
-[ (4) -0.30019 ] TJ
-/R40 11.95520 Tf
-4.73320 -4.33906 Td
-[ (TU) -249.99300 (Dresden) ] TJ
-ET
-Q
-0 1 0 0 k
-q
-10 0 0 10 0 0 cm
-BT
-/R46 11.95520 Tf
-1 0 0 1 204.11300 586.77900 Tm
-[ (www\056cityscapes\055) -41.99230 (dataset\056net) ] TJ
-ET
-Q
-q
-1633.54000 0 0 638.10000 501.12000 5087.71000 cm
-/R48 Do
-Q
-1 g
-q
-10 0 0 10 0 0 cm
-BT
-/R49 7.97010 Tf
-1 0 0 1 59.91290 513.67200 Tm
-[ (tr) 10.02360 (ain\057v) 25 (al) -277.99700 (\226) -277.97600 <026e65> -278.02300 (annotation) -277.98600 (\226) ] TJ
-/R42 7.97010 Tf
-97.63200 0 Td
-[ (3) -0.29866 (4) -0.30019 (7) -0.29866 (5) -0.29866 ] TJ
-/R49 7.97010 Tf
-19.15310 0 Td
-(images) Tj
-ET
-Q
-q
-1633.44000 0 0 638.06200 2159.37000 5087.71000 cm
-/R51 Do
-Q
-q
-10 0 0 10 0 0 cm
-BT
-/R49 7.97010 Tf
-1 0 0 1 223.28700 513.67200 Tm
-[ (tr) 10.02280 (ain) -277.98300 (\226) -277.97700 (coarse) -278.00400 (annotation) -277.98600 (\226) ] TJ
-/R42 7.97010 Tf
-96.50080 0 Td
-[ (2) -0.30019 (0) -177.29200 (0) -0.30019 (0) -0.29713 (0) -0.30019 ] TJ
-/R49 7.97010 Tf
-24.79800 0 Td
-(images) Tj
-ET
-Q
-q
-1633.54000 0 0 638.10000 3817.61000 5087.71000 cm
-/R52 Do
-Q
-q
-10 0 0 10 0 0 cm
-BT
-/R49 7.97010 Tf
-1 0 0 1 398.09600 513.67200 Tm
-[ (test) -278.02300 (\226) -277.97400 <026e65> -278.02300 (annotation) -277.98600 (\226) ] TJ
-/R42 7.97010 Tf
-82.85590 0 Td
-[ (1) -0.30019 (5) -0.30019 (2) -0.30019 (5) -0.29407 ] TJ
-/R49 7.97010 Tf
-19.15310 0 Td
-(images) Tj
-ET
-Q
-0 g
-q
-10 0 0 10 0 0 cm
-BT
-/R38 11.95520 Tf
-1 0 0 1 145.99500 481.87200 Tm
-(Abstract) Tj
-/R53 9.96260 Tf
--83.92770 -23.90980 Td
-[ (V) 73.99130 (isual) -331.99200 (under) 10.01550 (standing) -332.01700 (of) -330.99100 (comple) 20.00770 (x) -331.98900 (urban) -331.99600 (str) 36.99380 (eet) -331.98600 (scenes) -332.01800 (is) ] TJ
--11.95510 -11.95510 Td
-[ (an) -352.01000 (enabling) -351.98500 (factor) -351.99400 (for) -352.00100 (a) -352.01500 (wide) -351.99900 (r) 14.98400 (ang) 10.01300 (e) -351.98500 (of) -352.00700 (applications\056) -617.01000 (Ob\055) ] TJ
-11.95510 TL
-T*
-[ (ject) -440 (detection) -441.00100 (has) -439.98900 <62656e6502746564> -441.01000 (enormously) -440.01000 (fr) 44.98510 (om) -441.01700 (lar) 36.99140 (g) 10.00320 (e\055scale) ] TJ
-11.95590 TL
-T*
-[ (datasets\054) -442.00400 (especially) -403.01000 (in) -403.99900 (the) -402.98400 (conte) 20.00520 (xt) -404.00900 (of) -403.99900 (deep) -402.98900 (learning) 15.01470 (\056) -771.00600 (F) 105.00700 (or) ] TJ
-11.95510 TL
-T*
-[ (semantic) -345.99600 (urban) -345.01500 (scene) -345.98400 (under) 10.01550 (standing) 10.00450 (\054) -368.99500 (howe) 14.99750 (ver) 110.99900 (\054) -370.01400 (no) -346.01100 (curr) 36.98650 (ent) ] TJ
-T*
-[ (dataset) -412.99800 (adequately) -413.00200 (captur) 36.99870 (es) -412.00800 (the) -412.98300 (comple) 20.00890 (xity) -412.98500 (of) -413.01700 (r) 37.01830 (eal\055world) ] TJ
-T*
-[ (urban) -316 (scenes\056) -507.00700 (T) 92 (o) -315.00100 (addr) 36.99510 (ess) -316.01800 (this\054) -331.99500 (we) -316.01700 (intr) 44.99740 (oduce) ] TJ
-/R40 9.96260 Tf
-182.30200 0 Td
-(Cityscapes) Tj
-/R53 9.96260 Tf
-43.16720 0 Td
-[ (\054) -331.98100 (a) ] TJ
--225.46900 -11.95510 Td
-[ (benc) 15.01830 (hmark) -370.00200 (suite) -369.99600 (and) -370.00200 (lar) 36.99260 (g) 10.00320 (e\055scal) 0.98635 (e) -369.98200 (dataset) -369.98500 (to) -370.00400 (tr) 14.99010 (ain) -370 (and) -370.00200 (test) ] TJ
-T*
-[ (appr) 44.99370 (oac) 14.98340 (hes) -348.01400 (for) -346.98300 (pixel\055le) 14.98770 (vel) -347.98200 (and) -348.00600 (i) 0.98758 (nstance\055le) 14.99750 (vel) -347.98400 (semantic) -347.99600 (la\055) ] TJ
-11.95590 TL
-T*
-[ (beling) 15.00300 (\056) -618.01200 (Cityscapes) -351.98300 (is) -352.98600 (comprised) -351.99200 (of) -352.98800 (a) -352.01500 (lar) 36.99140 (g) 10.00320 (e) 9.99343 (\054) -378.99300 (diver) 10.00810 (se) -352.01700 (set) -352.99000 (of) ] TJ
-11.95510 TL
-T*
-[ (ster) 36.98950 (eo) -253.01600 (video) -251.98900 (sequences) -253.00700 (r) 37.01960 (ecor) 37.01590 (ded) -251.99100 (in) -253.00400 (str) 36.99380 (eets) -253.01200 (fr) 44.98510 (om) ] TJ
-/R55 9.96260 Tf
-190.55600 0 Td
-(50) Tj
-/R53 9.96260 Tf
-12.47930 0 Td
-[ (dif) 18.01660 (fer) 36.98400 (ent) ] TJ
--203.03500 -11.95510 Td
-(cities\056) Tj
-/R55 9.96260 Tf
-29.75590 0 Td
-(5000) Tj
-/R53 9.96260 Tf
-23.46520 0 Td
-[ (of) -354.98700 (these) -356.00900 (ima) 10.01300 (g) 10.00320 (es) -354.99800 (have) -354.99800 (high) -355.01700 (quality) -355.98700 (pixel\055le) 14.98770 (vel) ] TJ
--53.22110 -11.95510 Td
-(annotations\073) Tj
-/R55 9.96260 Tf
-54.44490 0 Td
-[ (20) -166.98200 (000) ] TJ
-/R53 9.96260 Tf
-30.11410 0 Td
-[ (additional) -356 (ima) 10.01300 (g) 10.00320 (es) -356.01700 (have) -356.01700 (coar) 10.01060 (se) -356.01700 (anno\055) ] TJ
--84.55900 -11.95470 Td
-[ (tations) -392.99000 (to) -392.98100 (enable) -394 (methods) -393.00500 (that) -393.00800 (le) 14.98030 (ver) 15.01470 (a) 10.00320 (g) 10.00320 (e) -392.99800 (lar) 36.99140 (g) 10.00320 (e) -392.99800 (volumes) -393.99600 (of) ] TJ
-T*
-[ (weakly\055labeled) -387.98400 (data\056) -722.99200 (Crucially) 55.01290 (\054) -422.00600 (our) -387.01800 (ef) 18 (fort) -387.98900 (e) 19.99180 (xceeds) -387.98200 (pr) 36.98650 (e) 15.01220 (vi\055) ] TJ
-11.95590 TL
-T*
-[ (ous) -326.00800 (attempts) -325.98800 (in) -326.01200 (terms) -326.00600 (of) -326.01200 (dataset) -325.99300 (size) 10.01300 (\054) -344.99900 (annotation) -326.00700 (ric) 14.98770 (hness\054) ] TJ
-11.95510 TL
-T*
-[ (scene) -325.00600 (variability) 55.01900 (\054) -344.99900 (and) -324.99000 (comple) 20.00770 (xity) 55.01660 (\056) -535.98700 (Our) -324.99000 (accompanying) -325.99200 (em\055) ] TJ
-T*
-[ (pirical) -381.00100 (study) -381.01500 (pr) 44.98390 (o) 10.00320 (vides) -380.00500 (an) -380.98500 (in\055depth) -381.00800 (analysis) -380.99800 (of) -380.98300 (the) -380.98800 (dataset) ] TJ
-T*
-[ (c) 15.01280 (har) 14.99380 (acteristics\054) -241.01600 (as) -239.00800 (well) -238.99600 (as) -239.00800 (a) -239.01400 (performance) -240.00900 (e) 15.01220 (valuation) -239.01600 (of) -239.00700 (se) 15.01960 (v\055) ] TJ
-T*
-[ (er) 15.01890 (al) -249.98500 (state\055of\055the\055art) -249.98600 (appr) 44.99370 (oac) 14.98400 (hes) -249.99000 (based) -249.98000 (on) -249.98800 (our) -249.98000 (benc) 15.01960 (hmark\056) ] TJ
-/R38 11.95520 Tf
-35.24380 TL
-T*
-[ (1\056) -249.99000 (Intr) 18.01460 (oduction) ] TJ
-/R40 9.96260 Tf
-11.95510 -18.92930 Td
-[ (V) 59.99310 (isual) -338.98100 (scene) -337.98500 (understanding) -338.99700 (has) -338.01500 (mo) 14.99500 (v) 14.98280 (ed) -339.00200 (from) -338.01200 (an) -339.00200 (elusi) 24.99830 (v) 14.98280 (e) ] TJ
--11.95510 -11.95470 Td
-[ (goal) -411.01700 (to) -411.01700 (a) -410.99500 (focus) -410.00100 (of) -410.98900 (much) -411.01100 (recent) -410.99400 (research) -411.00300 (in) -411.01700 (computer) -411.00700 (vi\055) ] TJ
-11.95510 TL
-T*
-[ (sion) -242.01500 (\133) ] TJ
-ET
-Q
-0 1 0 rg
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 72.44840 152.73100 Tm
-(27) Tj
-ET
-Q
-0 g
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 82.41090 152.73100 Tm
-[ (\135\056) -307.98800 (Semantic) -242.00500 (reasoning) -242.01700 (about) -243 (the) -241.99100 (contents) -242.01100 (of) -241.99600 (a) -242.98400 (scene) ] TJ
--32.29880 -11.95510 Td
-[ (is) -459.98800 (thereby) -459.99100 (done) -459.99100 (on) -459.99200 (se) 25.01670 (v) 14.98280 (eral) -460.00700 (le) 25.01790 (v) 14.98280 (els) -459.99300 (of) -460 (abstraction\056) -940.01000 (Scene) ] TJ
-11.95510 TL
-T*
-[ (recognition) -410.99500 (aims) -409.98900 (to) -411.01700 (determine) -411.00900 (the) -410.00300 (o) 14.98280 (v) 14.98280 (erall) -410.98800 (scene) -410.99300 (cate) 15.01220 (gory) ] TJ
-11.95590 TL
-T*
-[ (by) -257.00600 (putting) -257.01300 (emphasis) -256.00300 (on) -257.00600 (understanding) -257.01100 (its) -256.99600 (global) -256.99100 (properties\054) ] TJ
-/R53 9.96260 Tf
-11.95510 TL
-T*
-[ (e) 15.01280 (\056g) ] TJ
-/R40 9.96260 Tf
-11.74610 0 Td
-[ (\056) -360.99600 (\133) ] TJ
-ET
-Q
-0 1 0 rg
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 71.26290 104.91000 Tm
-(46) Tj
-ET
-Q
-0 g
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 81.22540 104.91000 Tm
-(\054) Tj
-ET
-Q
-0 1 0 rg
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 85.74840 104.91000 Tm
-(82) Tj
-ET
-Q
-0 g
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 95.71090 104.91000 Tm
-[ (\135\056) -642.01100 (Scene) -360.01200 (labeling) -361.01000 (methods\054) -388.99400 (on) -360.00900 (the) -360.99100 (other) -360.98900 (hand\054) ] TJ
--45.59880 -11.95510 Td
-[ (seek) -305.00500 (to) -304.01500 (identify) -305.01800 (the) -303.98100 (indi) 25 (vidual) -304.98300 (constituent) -303.98100 (parts) -304.99800 (of) -303.98600 (a) -305.01300 (whole) ] TJ
-11.95510 TL
-T*
-[ (scene) -323.00700 (as) -323.98300 (well) -322.99300 (as) -323.00400 (their) -324.01200 (interrelations) -323.00600 (on) -324.01500 (a) -323.01000 (more) -322.99500 (local) -324.01500 (pix) 14.99500 (el\055) ] TJ
-258.75000 400.87200 Td
-[ (and) -295.98500 (instance\055le) 24.99340 (v) 14.98280 (el\054) ] TJ
-/R53 9.96260 Tf
-77.81800 0 Td
-[ (e) 15.01220 (\056g) ] TJ
-/R40 9.96260 Tf
-11.74610 0 Td
-[ (\056) -295.98700 (\133) ] TJ
-ET
-Q
-0 1 0 rg
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 407.18300 481.87200 Tm
-(41) Tj
-ET
-Q
-0 g
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 417.14600 481.87200 Tm
-(\054) Tj
-ET
-Q
-0 1 0 rg
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 421.23000 481.87200 Tm
-(71) Tj
-ET
-Q
-0 g
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 431.19300 481.87200 Tm
-[ (\135\056) -448.00400 (Specialized) -296.00500 (object\055centric) ] TJ
--122.33100 -11.95510 Td
-[ (methods) -275.01500 (f) 9.99588 (all) -273.98400 (some) 24.99580 (where) -275.01800 (in) -275.00300 (between) -275.00800 (by) -273.98400 (focusing) -274.98800 (on) -275.00300 (detect\055) ] TJ
-11.95510 TL
-T*
-[ (ing) -231.98300 (a) -232.00500 (certain) -231.99800 (subset) -232.01500 (of) -231.99800 (\050mostly) -232 (dynamic\051) -232.01500 (scene) -232 (constituents\054) ] TJ
-/R53 9.96260 Tf
-T*
-[ (e) 15.01220 (\056g) ] TJ
-/R40 9.96260 Tf
-11.74610 0 Td
-[ (\056) -194.98500 (\133) ] TJ
-ET
-Q
-0 1 0 rg
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 328.35900 446.00700 Tm
-(6) Tj
-ET
-Q
-0 g
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 333.34000 446.00700 Tm
-(\054) Tj
-ET
-Q
-0 1 0 rg
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 336.22000 446.00700 Tm
-(12) Tj
-ET
-Q
-0 g
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 346.18200 446.00700 Tm
-(\054) Tj
-ET
-Q
-0 1 0 rg
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 349.06100 446.00700 Tm
-(13) Tj
-ET
-Q
-0 g
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 359.02400 446.00700 Tm
-(\054) Tj
-ET
-Q
-0 1 0 rg
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 361.90300 446.00700 Tm
-(15) Tj
-ET
-Q
-0 g
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 371.86600 446.00700 Tm
-[ (\135\056) -291.99000 (Despite) -195.98700 <7369676e690263616e74> -195.01600 (adv) 24.98110 (ances\054) -206.00500 (visual) -196.02100 (scene) ] TJ
--63.00350 -11.95630 Td
-[ (understanding) -323 (remains) -324.00500 (challenging\054) -341.00700 (particularly) -322.98000 (when) -324.01500 (tak\055) ] TJ
-11.95510 TL
-T*
-[ (ing) -250.02000 (human) -250.01500 (performance) -249.99700 (as) -249.99700 (a) -250.00200 (reference\056) ] TJ
-11.95510 -15.13090 Td
-[ (The) -329 (resurrection) -330.01100 (of) -329.00100 (deep) -329.98400 (learning) -328.98400 (\133) ] TJ
-ET
-Q
-0 1 0 rg
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 463.37200 406.96500 Tm
-(34) Tj
-ET
-Q
-0 g
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 473.33400 406.96500 Tm
-[ (\135) -329.00900 (has) -330.01800 (had) -329 (a) -329.98900 (major) ] TJ
--164.47200 -11.95510 Td
-[ (impact) -365.01500 (on) -364.00800 (the) -364.99100 (current) -364.99500 (state\055of\055the\055art) -364.00800 (in) -364.98800 (machine) -364.98300 (learning) ] TJ
-11.95470 TL
-T*
-[ (and) -354.99500 (computer) -355.99700 (vision\056) -626.01600 (Man) 14.98770 (y) -354.99500 (top\055performing) -356.01900 (methods) -355.00400 (in) -356.00900 (a) ] TJ
-T*
-[ (v) 24.98110 (ariety) -231.99300 (of) -231.99800 (applications) -231.01800 (are) -232.01000 (no) 24.98600 (w) 10.00320 (adays) -231.99100 (b) 20.00160 (uilt) -232.01500 (around) -231.98600 (deep) -232 (neu\055) ] TJ
-T*
-[ (ral) -394.01300 (netw) 10.00810 (orks) -395.02000 (\133) ] TJ
-ET
-Q
-0 1 0 rg
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 366.97400 359.14500 Tm
-(30) Tj
-ET
-Q
-0 g
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 376.93700 359.14500 Tm
-(\054) Tj
-ET
-Q
-0 1 0 rg
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 381.67900 359.14500 Tm
-(41) Tj
-ET
-Q
-0 g
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 391.64100 359.14500 Tm
-(\054) Tj
-ET
-Q
-0 1 0 rg
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 396.39400 359.14500 Tm
-(66) Tj
-ET
-Q
-0 g
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 406.35600 359.14500 Tm
-[ (\135\056) -743.01300 (A) -394.00800 (major) -395.01700 (contrib) 20.01630 (uting) -393.98300 (f) 9.99343 (actor) -394.99300 (to) ] TJ
--97.49410 -11.95590 Td
-[ (their) -203.01300 (success) -203.01500 (is) -201.99300 (the) -203.01800 (a) 19.99180 (v) 24.98110 (ailability) -202.98100 (of) -202.98600 (lar) 17.99700 (ge\055scale\054) -212.00400 (publicly) -202.98600 (a) 19.99180 (v) 24.98110 (ail\055) ] TJ
-11.95510 TL
-T*
-[ (able) -376.01300 (datasets) -375.99600 (such) -376.00300 (as) ] TJ
-/R53 9.96260 Tf
-89.68400 0 Td
-[ (Ima) 10.00320 (g) 10.00320 (eNet) ] TJ
-/R40 9.96260 Tf
-42.46090 0 Td
-(\133) Tj
-ET
-Q
-0 1 0 rg
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 444.32500 335.23400 Tm
-(59) Tj
-ET
-Q
-0 g
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 454.28700 335.23400 Tm
-(\135\054) Tj
-/R53 9.96260 Tf
-9.86914 0 Td
-[ (P) 89.98990 (ASCAL) -376.01600 (V) 30 (OC) ] TJ
-/R40 9.96260 Tf
-61.86800 0 Td
-(\133) Tj
-ET
-Q
-0 1 0 rg
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 529.34200 335.23400 Tm
-(14) Tj
-ET
-Q
-0 g
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 539.30400 335.23400 Tm
-(\135\054) Tj
-/R53 9.96260 Tf
--230.44200 -11.95510 Td
-[ (P) 89.98990 (ASCAL\055Conte) 19.98200 (xt) ] TJ
-/R40 9.96260 Tf
-72.48400 0 Td
-(\133) Tj
-ET
-Q
-0 1 0 rg
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 384.66400 323.27900 Tm
-(45) Tj
-ET
-Q
-0 g
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 394.62600 323.27900 Tm
-[ (\135\054) -396.99300 (and) ] TJ
-/R53 9.96260 Tf
-27.81210 0 Td
-[ (Micr) 44.98270 (osoft) -367.98800 (COCO) ] TJ
-/R40 9.96260 Tf
-73.29690 0 Td
-(\133) Tj
-ET
-Q
-0 1 0 rg
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 499.05300 323.27900 Tm
-(38) Tj
-ET
-Q
-0 g
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 509.01500 323.27900 Tm
-[ (\135) -367.98300 (that) -366.98300 (al\055) ] TJ
--200.15300 -11.95510 Td
-[ (lo) 24.98850 (w) -249.99500 (deep) -249.99500 (neural) -249.99300 (netw) 10.00810 (orks) -249.98300 (to) -249.98800 (de) 25.01540 (v) 14.98280 (elop) -249.98300 (their) -249.98800 (full) -249.98300 (potential\056) ] TJ
-11.95510 -15.13090 Td
-[ (Despite) -369.99700 (the) -370.00900 (e) 15.01220 (xisting) -370.99400 (g) 4.98446 (ap) -370.01700 (to) -370.00700 (human) -369.99200 (performance\054) -400.98700 (scene) ] TJ
--11.95510 -11.95510 Td
-[ (understanding) -440.98000 (approaches) -440 (ha) 19.99670 (v) 14.98280 (e) -440.99000 (started) -439.99000 (to) -441.01500 (become) -441.01500 (essen\055) ] TJ
-11.95590 TL
-T*
-[ (tial) -397.01500 (components) -396.99000 (of) -398.01000 (adv) 24.98110 (anced) -396.99700 (real\055w) 9.99343 (orld) -397.01700 (systems\056) -751.99200 (A) -396.98800 (par) 19.99180 (\055) ] TJ
-11.95510 TL
-T*
-[ (ticularly) -280.00500 (popular) -280.01200 (and) -279.98800 (challenging) -279.99700 (application) -281.01700 (in) 40.00310 (v) 20.00160 (olv) 14.99750 (es) -279.99200 (self\055) ] TJ
-T*
-[ (dri) 24.98600 (ving) -540.00500 (cars\054) -612.01800 (which) -540.01300 (mak) 10.01300 (e) -539.01300 (e) 15.01220 (xtreme) -540.01300 (demands) -540.00300 (on) -540.01800 (system) ] TJ
-T*
-[ (performance) -370.01700 (and) -370.01200 (reliability) 65.00880 (\056) -670 (Consequently) 64.98430 (\054) -400.98700 <7369676e690263616e74> -370.00700 (re\055) ] TJ
-T*
-[ (search) -363.98300 (ef) 25.00810 (forts) -364.98600 (ha) 19.99670 (v) 14.98280 (e) -363.98300 (gone) -364.00800 (into) -365.01300 (ne) 25.01540 (w) -364.01300 (vision) -363.98300 (technologies) -364.99800 (for) ] TJ
-T*
-[ (understanding) -412.00500 (comple) 14.99750 (x) -412.00500 (traf) 25.01050 <0263> -411.02000 (scenes) -412.00500 (and) -412.00500 (dri) 24.98600 (ving) -411.98500 (scenar) 19.99180 (\055) ] TJ
-11.95590 TL
-T*
-[ (ios) -332.98600 (\133) ] TJ
-ET
-Q
-0 1 0 rg
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 327.12300 200.55200 Tm
-(4) Tj
-ET
-Q
-0 g
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 332.10500 200.55200 Tm
-(\054) Tj
-ET
-Q
-0 1 0 rg
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 336.43800 200.55200 Tm
-(16) Tj
-ET
-Q
-0 g
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 346.40100 200.55200 Tm
-(\226) Tj
-ET
-Q
-0 1 0 rg
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 351.38200 200.55200 Tm
-(18) Tj
-ET
-Q
-0 g
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 361.34500 200.55200 Tm
-(\054) Tj
-ET
-Q
-0 1 0 rg
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 365.68800 200.55200 Tm
-(58) Tj
-ET
-Q
-0 g
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 375.65100 200.55200 Tm
-(\054) Tj
-ET
-Q
-0 1 0 rg
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 379.98400 200.55200 Tm
-(62) Tj
-ET
-Q
-0 g
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 389.94700 200.55200 Tm
-[ (\135\056) -559.98500 (Also) -332.98400 (in) -332.99300 (this) -333.01800 (area\054) -353.99500 (research) -333.01800 (progress) ] TJ
--81.08480 -11.95510 Td
-[ (can) -359.98200 (be) -358.99900 (hea) 19.99420 (vily) -359.99400 (link) 9.98363 (ed) -360.01800 (to) -358.98700 (the) -360.00900 (e) 15.01220 (xistence) -359.99900 (of) -358.99900 (datasets) -359.99900 (such) -360.00900 (as) ] TJ
-11.95510 TL
-(the) '
-/R53 9.96260 Tf
-14.10700 0 Td
-[ (KITTI) -194.01200 (V) 73.99260 (ision) -194.01700 (Benc) 15.01710 (hmark) -193.99200 (Suite) ] TJ
-/R40 9.96260 Tf
-121.96400 0 Td
-(\133) Tj
-ET
-Q
-0 1 0 rg
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 448.25100 176.64100 Tm
-(19) Tj
-ET
-Q
-0 g
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 458.21300 176.64100 Tm
-(\135\054) Tj
-/R53 9.96260 Tf
-7.85273 0 Td
-[ (CamV) 74.01220 (id) ] TJ
-/R40 9.96260 Tf
-34.12190 0 Td
-(\133) Tj
-ET
-Q
-0 1 0 rg
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 503.50500 176.64100 Tm
-(7) Tj
-ET
-Q
-0 g
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 508.48700 176.64100 Tm
-(\135\054) Tj
-/R53 9.96260 Tf
-7.85352 0 Td
-(Leuven) Tj
-/R40 9.96260 Tf
--207.47800 -11.95510 Td
-(\133) Tj
-ET
-Q
-0 1 0 rg
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 312.18000 164.68600 Tm
-(35) Tj
-ET
-Q
-0 g
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 322.14200 164.68600 Tm
-[ (\135\054) -214.00400 (and) ] TJ
-/R53 9.96260 Tf
-24.37380 0 Td
-[ (Daimler) -204.99800 (Urban) -205.98000 (Se) 39.99330 (gmentation) ] TJ
-/R40 9.96260 Tf
-119.19100 0 Td
-(\133) Tj
-ET
-Q
-0 1 0 rg
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 469.02500 164.68600 Tm
-(61) Tj
-ET
-Q
-0 g
-q
-10 0 0 10 0 0 cm
-BT
-/R40 9.96260 Tf
-1 0 0 1 478.98700 164.68600 Tm
-[ (\135) -204.99000 (datasets\056) -294.99000 (These) ] TJ
--170.12500 -11.95510 Td
-[ (urban) -340.01400 (scene) -339.98500 (datasets) -340.00200 (are) -339.99500 (often) -340.01200 (much) -340.00200 (smaller) -340.00200 (than) -340.00700 (datasets) ] TJ
-11.95510 TL
-T*
-[ (addressing) -286.00400 (more) -285.00100 (general) -285.99100 (settings\056) -416.98400 (Moreo) 14.99260 (v) 14.98280 (er) 39.98350 (\054) -295.00500 (we) -285.99100 (ar) 17.98720 (gue) -285.98700 (that) ] TJ
-11.95590 TL
-T*
-[ (the) 14.98520 (y) -457.01700 (do) -457.99200 (not) -457.00500 (fully) -457.98000 (capture) -456.98300 (the) -457.99200 (v) 24.98110 (ariability) -456.98700 (and) -457.99700 (comple) 14.99750 (xity) ] TJ
-11.95510 TL
-T*
-[ (of) -343 (real\055w) 9.99343 (orld) -342.00700 (inner) 20.00650 (\055city) -342.98900 (traf) 25.01050 <0263> -342.01200 (scenes\056) -588.01500 (Both) -343.01100 (shortcomings) ] TJ
-T*
-[ (currently) -425.01200 (inhibit) -424.98300 (further) -424.98500 (progress) -425.01200 (in) -425.01700 (visual) -425.00300 (understanding) ] TJ
-T*
-[ (of) -382.01200 (street) -382.00700 (scenes\056) -707.01200 (T) 79.99160 (o) -382.01000 (this) -383.01000 (end\054) -414.98000 (we) -382.01500 (propose) -381.99500 (the) ] TJ
-/R53 9.96260 Tf
-193.08300 0 Td
-(Cityscapes) Tj
-/R40 9.96260 Tf
--193.08300 -11.95510 Td
-[ (benchmark) -360.98100 (suit) 1.00473 (e) -361.00300 (and) -360.99400 (a) -359.98400 (corresponding) -361.00300 (dataset\054) -387.99900 <73706563690263616c6c79> ] TJ
--13.74100 -29.88790 Td
-(1) Tj
-ET
-Q
-Q
-Q
-q
-q
-1 1 1 rg
-/a0 gs
-48.40600 786.42200 515.18800 -52.69900 re
-f
-q
-/s5 gs
-/x6 Do
-Q
-q
-/s7 gs
-/x8 Do
-Q
-q
-/s9 gs
-/x10 Do
-Q
-q
-/s11 gs
-/x12 Do
-Q
-Q
-Q
-Q
-q
-1 0 0 1 0 0 cm
-BT
-/F1 12 Tf
-14.40000 TL
-ET
-1 1 1 rg
-n
-270 47 72 14 re
-f*
-0.50000 0.50000 0.50000 rg
-BT
-/F2 9 Tf
-10.80000 TL
-ET
-BT
-1 0 0 1 297 50 Tm
-(3213) Tj
-T*
-ET
-Q
-
-endstream
-endobj
-16 0 obj
-<<
-/Filter /FlateDecode
-/Resources <<
-/ExtGState <<
-/a0 <<
-/CA 1
-/ca 1
->>
->>
-/XObject <<
-/x18 17 0 R
->>
->>
-/Length 28
-/Group <<
-/Type /Group
-/S /Transparency
-/CS /DeviceRGB
-/I true
->>
-/BBox [ 78 746 96 765 ]
-/Type /XObject
-/Subtype /Form
->>
-stream
-xœ+äÒO4PH/VЯ0´PpÉç
-ä 0 ž
-
-endstream
-endobj
-17 0 obj
-<<
-/Filter /FlateDecode
-/Resources 18 0 R
-/Length 107
-/Type /XObject
-/BBox [ 78 746 96 765 ]
-/Subtype /Form
->>
-stream
-xœe�»
ACó©Â˜ý̬wÊ Ž ‰=p™õü,?Ð]%…¡áª+H-<ñÚpºloÓ䮬ž9L±©C>ØJÇœc�Êèõ ¾ƒ"82wÒ8VõSnÿGW;Û"
-endstream
-endobj
-18 0 obj
-<<
-/ExtGState <<
-/a0 <<
-/CA 1
-/ca 1
->>
->>
->>
-endobj
-19 0 obj
-<<
-/Filter /FlateDecode
-/Resources <<
-/ExtGState <<
-/a0 <<
-/CA 1
-/ca 1
->>
->>
-/XObject <<
-/x21 20 0 R
->>
->>
-/Length 28
-/Group <<
-/Type /Group
-/S /Transparency
-/CS /DeviceRGB
-/I true
->>
-/BBox [ 96 752 110 775 ]
-/Type /XObject
-/Subtype /Form
->>
-stream
-xœ+äÒO4PH/VЯ02TpÉç
-ä 0w˜
-
-endstream
-endobj
-20 0 obj
-<<
-/Filter /FlateDecode
-/Resources 21 0 R
-/Length 118
-/Type /XObject
-/BBox [ 96 752 110 775 ]
-/Subtype /Form
->>
-stream
-xœeÎ=QàžSp„Ã#lãZìêýq’×Í|ÅdîÀdì…LÃB:D¨[ácÅÓ¸>¡™*FI&î(\Tù…í=s–˜²×&ŒáGuJÑ©Iªÿ�Y\I³ é}Ìü#
·ùë.ð�!.ð
-endstream
-endobj
-21 0 obj
-<<
-/ExtGState <<
-/a0 <<
-/CA 1
-/ca 1
->>
->>
->>
-endobj
-22 0 obj
-<<
-/Filter /DCTDecode
-/BitsPerComponent 8
-/Height 200
-/Length 11847
-/ColorSpace /DeviceRGB
-/Width 512
-/Subtype /Image
->>
-stream
-ÿØÿî Adobe d ÿÛ C
-
$, !$4.763.22:ASF:=N>22HbINVX]^]8EfmeZlS[]YÿÛ C**Y;2;YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYÿÀ È " ÿÄ
-ÿÄ µ } !1AQa"q2�‘¡#B±ÁRÑð$3br‚
-%&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúÿÄ
-ÿÄ µ w !1AQaq"2�B‘¡±Á #3RðbrÑ
-$4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùúÿÚ ? ä׆Z› Ž•ëRõDìGËØiÆiÎ2M78÷ u5,Gƒô¨‡SRÄh$8#Ì