DEV Community

Cover image for đŸš—đŸ‘ïž Segmentation d'Images pour le systĂšme embarquĂ© d’une voiture autonome
David Scanu
David Scanu

Posted on • Edited on

đŸš—đŸ‘ïž Segmentation d'Images pour le systĂšme embarquĂ© d’une voiture autonome

Image description

🌐 Introduction

Ce projet s'inscrit dans le développement d'un systÚme embarqué de vision par ordinateur pour véhicules autonomes chez Future Vision Transport. L'entreprise conçoit des systÚmes permettant aux véhicules autonomes de percevoir leur environnement grùce à l'analyse d'images en temps réel.

En tant qu'ingĂ©nieur IA dans l'Ă©quipe R&D, notre mission est de dĂ©velopper le module de segmentation d'images (composant 3) qui s'intĂšgre entre le module de traitement d'images (2) et le systĂšme de dĂ©cision (4). Ce module doit ĂȘtre capable d'identifier et de segmenter prĂ©cisĂ©ment 8 catĂ©gories principales d'objets dans des images de camĂ©ras embarquĂ©es.

Cette note technique présente la conception et l'implémentation d'un modÚle de segmentation d'images optimisé pour la compréhension des scÚnes urbaines. Le systÚme développé s'intÚgre dans une chaßne complÚte comprenant l'acquisition d'images en temps réel, le traitement des images, la segmentation sémantique (notre contribution) et le systÚme de décision final.


🎯 Objectifs

  • DĂ©velopper un modĂšle de segmentation d'images performant avec Keras/TensorFlow
  • Concevoir et dĂ©ployer une API REST avec FastAPI
  • CrĂ©er une application web de dĂ©monstration avec Next.js
  • Documenter le processus et les rĂ©sultats de façon claire et professionnelle

đŸ’Ÿ DĂ©pĂŽt GitHub

L'intégralité du code du projet (notebook, backend et frontend) est disponible sur le dépÎt GitHub : Projet 8 : Traitement d'images pour le systÚme embarqué d'une voiture autonome.


👋 À propos

Projet développé par David Scanu dans le cadre du parcours AI Engineer d'OpenClassrooms : Projet 8 - Traitez les images pour le systÚme embarqué d'une voiture autonome.


đŸ‘ïž 1. DĂ©veloppement du ModĂšle de Segmentation

Le notebook complet de conception du modĂšle de segmentation d'image est disponible sur Colab.

1.1 Contexte et Enjeux

La segmentation sémantique d'image dans le contexte automobile représente un défi technique majeur. Contrairement à la classification d'images qui attribue une étiquette à une image entiÚre, la segmentation sémantique doit identifier et catégoriser chaque pixel de l'image. Pour un véhicule autonome, cette capacité est cruciale : il faut distinguer la route des trottoirs, identifier les véhicules, détecter les piétons, reconnaßtre la végétation, etc.

La segmentation sĂ©mantique consiste Ă  Ă©tiqueter chaque pixel d’une image avec une classe correspondante Ă  ce qui est reprĂ©sentĂ©. On parle aussi de "prĂ©diction dense", car chaque pixel doit ĂȘtre prĂ©dit. Elle gĂ©nĂšre une image, sur laquelle chaque pixel est classifiĂ©.

1.2 Étude du jeu de donnĂ©es et prĂ©paration pour l'entraĂźnement

1.2.1 Le jeu de données Cityscapes

Image description

Nous avons choisi le jeu de données Cityscapes, une référence dans le domaine de la segmentation urbaine. Ce dataset présente plusieurs avantages décisifs pour notre cas d'usage :

  • 5 000 images avec annotations fines rĂ©parties en 2 975 images d'entraĂźnement, 500 de validation et 1 525 de test
  • DiversitĂ© gĂ©ographique : 50 villes europĂ©ennes diffĂ©rentes
  • Conditions variĂ©es : Plusieurs saisons, conditions mĂ©tĂ©orologiques bonnes Ă  moyennes
  • Richesse des annotations : 30 classes dĂ©taillĂ©es avec des annotations polygonales prĂ©cises
  • RĂ©alisme : Images capturĂ©es depuis des vĂ©hicules en circulation rĂ©elle

1.2.2 Stratégie de Regroupement des Classes

L'une des décisions techniques les plus importantes a été le regroupement des 30+ classes originales de Cityscapes en 8 catégories pertinentes pour la navigation autonome. Cette simplification répond à plusieurs objectifs :

  1. Pertinence fonctionnelle : Regrouper les Ă©lĂ©ments ayant la mĂȘme importance pour la dĂ©cision de navigation
  2. Performance computationnelle : Réduire la complexité du modÚle
  3. Robustesse : Éviter la sur-spĂ©cialisation sur des classes trĂšs spĂ©cifiques

Notre mapping final :

class_groups = {
    'flat': ['road', 'sidewalk', 'parking', 'rail track'],
    'human': ['person', 'rider'], 
    'vehicle': ['car', 'truck', 'bus', 'motorcycle', 'bicycle', ...],
    'construction': ['building', 'wall', 'fence', 'bridge', ...],
    'object': ['pole', 'traffic sign', 'traffic light', ...],
    'nature': ['vegetation', 'terrain'],
    'sky': ['sky'],
    'void': ['unlabeled', 'out of roi', ...]
}
Enter fullscreen mode Exit fullscreen mode

Cette approche nous permet de maintenir une granularité suffisante pour la prise de décision tout en gardant un modÚle tractable.

1.2.3 Pipeline de Préparation des Données

Notre pipeline de préparation des données intÚgre plusieurs étapes :

Redimensionnement intelligent : Les images Cityscapes originales (2048×1024) sont redimensionnĂ©es Ă  224×224, un compromis entre qualitĂ© visuelle et performance computationnelle. Cette taille est Ă©galement optimale pour l'utilisation de MobileNetV2 prĂ©-entraĂźnĂ©.

Stratégie de validation : Pour éviter le "data leakage", nous avons adopté une approche rigoureuse :

  • Division du dataset 'train' original en 80% entraĂźnement / 20% validation
  • Utilisation du dataset 'val' original comme dataset de test final : cette approche garantit que notre Ă©valuation finale est rĂ©alisĂ©e sur des donnĂ©es jamais vues
  • Les masques du dataset 'test' Ă©taient indisponibles (complĂštement noirs) : nous n'avons pas utilisĂ© ce dossier

Augmentation de données : Nous avons implémenté des techniques d'augmentation adaptées à la segmentation :

  1. Flip horizontal aléatoire (50% de probabilité)

    • AppliquĂ© de maniĂšre synchronisĂ©e sur l'image et le masque
  2. Variation de luminosité aléatoire

    • AppliquĂ©e uniquement sur l'image (pas sur le masque)
    • Amplitude : ±0.1
    • Avec clipping pour maintenir les valeurs dans [0,1]
def augment_data(image, mask):
    # Flip horizontal synchronisé image/masque
    if tf.random.uniform(()) > 0.5:
        image = tf.image.flip_left_right(image)
        mask = tf.image.flip_left_right(mask)

    # Variation de luminosité (image seulement)
    image = tf.image.random_brightness(image, 0.1)
    return image, mask
Enter fullscreen mode Exit fullscreen mode

1.3 Architecture du ModĂšle : MobileNetV2-UNet

Nous avons développé une architecture qui combine la puissance de MobileNetV2 (un réseau léger et efficace) avec la structure en forme de U de l'architecture U-Net pour réaliser une segmentation d'images.

Image description

Architecture U-Net avec backbone MobileNetV2 pour segmentation sémantique d'images

1.3.1 Structure générale en forme de U

Notre modÚle hybride combine la puissance de MobileNetV2 pour l'extraction de caractéristiques avec la capacité de U-Net à reconstruire des segmentations précises.

  • Forme en U : L'architecture suit une forme en "U" avec une partie descendante (encodeur) et une partie ascendante (dĂ©codeur).
  • Objectif : Attribuer une classe Ă  chaque pixel de l'image (segmentation).
Partie encodeur (descendante)
  • Backbone MobileNetV2 : Utilisation de MobileNetV2 comme encodeur lĂ©ger et optimisĂ© pour les appareils mobiles.
  • Gel des poids : Avec base_model.trainable = False, les poids prĂ©-entraĂźnĂ©s sur ImageNet sont conservĂ©s, ce qui accĂ©lĂšre l'entraĂźnement et limite le surapprentissage.
  • Extraction multi-Ă©chelle : Les caractĂ©ristiques sont extraites Ă  diffĂ©rents niveaux de rĂ©solution pour les connexions de saut :
    • skip1 : 112×112
    • skip2 : 56×56
    • skip3 : 28×28
    • skip4 : 14×14
    • bottleneck : 7×7 (le niveau le plus profond du U-Net)

L'encodeur extrait des caractéristiques à cinq niveaux de résolution différents. Cette extraction multi-échelle est cruciale : les premiÚres couches capturent des détails fins (textures, contours) tandis que les couches profondes encodent des informations sémantiques de haut niveau.

Stratégie de Transfer Learning : Nous avons opté pour une approche de "frozen encoder" (enoder gelé) dans notre configuration "baseline".

Cette décision présente plusieurs avantages :

  • EntraĂźnement plus rapide (moins de paramĂštres Ă  optimiser)
  • StabilitĂ© accrue (les caractĂ©ristiques ImageNet sont dĂ©jĂ  robustes)
  • RĂ©duction du risque de sur-apprentissage
  • PossibilitĂ© d'entraĂźnement avec des ressources limitĂ©es
Partie décodeur (ascendante)
  • Reconstruction progressive : À chaque Ă©tape, la rĂ©solution est doublĂ©e Ă  l'aide de convolutions transposĂ©es :
    • 7×7 → 14×14
    • 14×14 → 28×28
    • 28×28 → 56×56
    • 56×56 → 112×112
    • 112×112 → 224×224
  • Connexions de saut (Skip connections) : Chaque niveau du dĂ©codeur est enrichi par les caractĂ©ristiques du niveau correspondant de l’encodeur pour prĂ©server les dĂ©tails spatiaux.
  • Traitement post-upsampling : Chaque Ă©tape comprend :
    • Convolution transposĂ©e
    • BatchNormalization
    • Activation ReLU
    • ConcatĂ©nation avec les features de l’encodeur
    • Convolution 3×3 pour affiner

1.3.2 Construction et EntraĂźnement du ModĂšle

Le choix de SparseCategoricalCrossentropy est adapté car nos masques contiennent directement les indices des classes (format sparse) plutÎt que des vecteurs one-hot.

def create_segmentation_model(num_classes=8, input_size=(224, 224, 3),
                            learning_rate=0.0001, base_trainable=False):
    """
    Create a segmentation model with configurable parameters
    """
    # Input tensor
    inputs = keras.layers.Input(shape=input_size)

    # Create MobileNetV2 base model
    base_model = keras.applications.MobileNetV2(
        input_shape=input_size,
        include_top=False,
        weights='imagenet'
    )

    # Configuration de l'entraĂźnement du modĂšle de base
    base_model.trainable = base_trainable

    # Create encoder using MobileNetV2
    # Get outputs at different levels for skip connections
    skip1 = base_model.get_layer('block_1_expand_relu').output      # 112x112
    skip2 = base_model.get_layer('block_3_expand_relu').output      # 56x56
    skip3 = base_model.get_layer('block_6_expand_relu').output      # 28x28
    skip4 = base_model.get_layer('block_13_expand_relu').output     # 14x14

    # Get bottleneck
    bottleneck = base_model.get_layer('block_16_project').output    # 7x7

    # Use Model API to create encoder model
    encoder = keras.Model(inputs=base_model.input, outputs=[skip1, skip2, skip3, skip4, bottleneck])

    # Encoder part - use the encoder model
    x = inputs
    skips = encoder(x)

    # Bottleneck
    x = skips[4]  # Use the bottleneck from encoder

    # Decoder part - upsampling and skip connections
    # First upsampling: 7x7 -> 14x14
    x = keras.layers.Conv2DTranspose(256, 3, strides=2, padding='same')(x)
    x = keras.layers.BatchNormalization()(x)
    x = keras.layers.Activation('relu')(x)
    x = keras.layers.Concatenate()([x, skips[3]])
    x = keras.layers.Conv2D(256, 3, padding='same', activation='relu')(x)

    # Second upsampling: 14x14 -> 28x28
    x = keras.layers.Conv2DTranspose(128, 3, strides=2, padding='same')(x)
    x = keras.layers.BatchNormalization()(x)
    x = keras.layers.Activation('relu')(x)
    x = keras.layers.Concatenate()([x, skips[2]])
    x = keras.layers.Conv2D(128, 3, padding='same', activation='relu')(x)

    # Third upsampling: 28x28 -> 56x56
    x = keras.layers.Conv2DTranspose(64, 3, strides=2, padding='same')(x)
    x = keras.layers.BatchNormalization()(x)
    x = keras.layers.Activation('relu')(x)
    x = keras.layers.Concatenate()([x, skips[1]])
    x = keras.layers.Conv2D(64, 3, padding='same', activation='relu')(x)

    # Fourth upsampling: 56x56 -> 112x112
    x = keras.layers.Conv2DTranspose(32, 3, strides=2, padding='same')(x)
    x = keras.layers.BatchNormalization()(x)
    x = keras.layers.Activation('relu')(x)
    x = keras.layers.Concatenate()([x, skips[0]])
    x = keras.layers.Conv2D(32, 3, padding='same', activation='relu')(x)

    # Final upsampling: 112x112 -> 224x224
    x = keras.layers.Conv2DTranspose(16, 3, strides=2, padding='same')(x)
    x = keras.layers.BatchNormalization()(x)
    x = keras.layers.Activation('relu')(x)
    x = keras.layers.Conv2D(16, 3, padding='same', activation='relu')(x)

    # Output layer
    outputs = keras.layers.Conv2D(num_classes, 1, padding='same', activation='softmax')(x)

    # Create model
    model = keras.Model(inputs=inputs, outputs=outputs, name="MobileNetV2-UNet")

    # Compile model avec learning rate configurable
    model.compile(
        optimizer=keras.optimizers.Adam(learning_rate=learning_rate),
        loss=keras.losses.SparseCategoricalCrossentropy(),
        metrics=[
            keras.metrics.SparseCategoricalAccuracy(),
            # keras.metrics.MeanIoU(num_classes=num_classes)
        ]
    )

    return model
Enter fullscreen mode Exit fullscreen mode
Détails des paramÚtres
  • Total des paramĂštres : 5,418,600
    • EntraĂźnables : 3,575,624 (dĂ©codeur et tĂȘte de segmentation)
    • Non-entraĂźnables : 1,842,976 (backbone gelĂ©)
  • Si base_trainable=True, tous les paramĂštres deviennent entraĂźnables, offrant plus de flexibilitĂ© au prix d'un entraĂźnement plus long.

1.3.3 Justification du choix architectural

Le choix de l'architecture MobileNetV2-UNet résulte d'une analyse approfondie des contraintes de notre projet embarqué, combinant les avantages complémentaires de deux architectures éprouvées :

Pourquoi U-Net ?

  • Architecture de rĂ©fĂ©rence pour la segmentation sĂ©mantique avec structure encoder-decoder
  • Connexions rĂ©siduelles (skip connections) prĂ©servant les dĂ©tails spatiaux fins lors de la reconstruction
  • AdaptĂ©e Ă  la reconstruction de rĂ©solution complĂšte depuis des caractĂ©ristiques compressĂ©es

Pourquoi MobileNetV2 ?

  • Conception spĂ©cifique pour les applications mobiles et embarquĂ©es avec ressources limitĂ©es
  • Optimisations avancĂ©es via les "depthwise separable convolutions" pour un rapport performance/efficacitĂ© optimal
  • Transfer learning efficace grĂące aux poids prĂ©-entraĂźnĂ©s sur ImageNet
  • Vitesse d'exĂ©cution compatible avec les contraintes temps rĂ©el du vĂ©hicule autonome

Cette architecture hybride MobileNetV2-UNet présente des bénéfices uniques pour notre cas d'usage :

  • EfficacitĂ© computationnelle : OptimisĂ©e pour les environnements Ă  ressources contraintes
  • Robustesse par transfer learning : Exploitation des reprĂ©sentations ImageNet pour une convergence rapide
  • AdaptabilitĂ© multi-tĂąches : Architecture gĂ©nĂ©rique applicable Ă  diverses tĂąches de segmentation urbaine
  • PrĂ©servation de l'information : Maintien des dĂ©tails spatiaux critiques pour la prĂ©cision de segmentation

Cette combinaison offre le meilleur compromis entre précision de segmentation et efficacité embarquée, essentiel pour un systÚme de vision automobile en temps réel.

1.4 EntraĂźnement et optimisation

1.4.1 Stratégie d'entraßnement

Notre approche d'entraĂźnement intĂšgre plusieurs techniques d'optimisation :

Callbacks Avancés
callbacks = [
    keras.callbacks.ReduceLROnPlateau(
        monitor='val_loss', factor=0.2, patience=2, min_lr=1e-6
    ),
    keras.callbacks.EarlyStopping(
        monitor='val_sparse_categorical_accuracy', 
        patience=5, restore_best_weights=True
    ),
    keras.callbacks.ModelCheckpoint(
        filepath='best_model.keras',
        save_best_only=True, mode='max'
    )
]
Enter fullscreen mode Exit fullscreen mode
  • ReduceLROnPlateau : RĂ©duction adaptative du taux d'apprentissage
  • EarlyStopping : ArrĂȘt anticipĂ© pour Ă©viter le sur-apprentissage
  • ModelCheckpoint : Sauvegarde du meilleur modĂšle
Gestion des expériences de Machine Learning avec MLflow

Nous avons intégré MLflow pour le suivi des expériences, permettant :

  • Versioning des modĂšles et configurations
  • TraçabilitĂ© complĂšte des hyperparamĂštres
  • Comparaison objective des performances
  • ReproductibilitĂ© des rĂ©sultats

1.4.2 Configuration Baseline

Notre configuration "baseline" établit un point de référence solide :

EXPERIMENT_CONFIG = {
    "exp_name": "exp_001_baseline",
    "description": "Baseline MobileNetV2-UNet avec frozen encoder",
    "params": {
        "learning_rate": 0.0001,
        "batch_size": 8, 
        "epochs": 20,
        "base_model_trainable": False,
        "validation_split": 0.2,
        "augmentation": True
    }
}
Enter fullscreen mode Exit fullscreen mode

Cette configuration privilégie la stabilité et la reproductibilité, servant de fondation pour les expérimentations futures.

1.4.3 Analyse de l'entraĂźnement du modĂšle

L'entraßnement de notre modÚle MobileNetV2-UNet s'est déroulé sur 18 époques avec une convergence satisfaisante. Les graphiques d'évolution révÚlent un comportement d'apprentissage sain et typique d'un modÚle bien configuré.

Image description

Évolution de la Perte : La courbe de loss montre une dĂ©croissance rapide et rĂ©guliĂšre depuis des valeurs initiales Ă©levĂ©es (≈1.4) vers une stabilisation autour de 0.25 pour l'entraĂźnement et 0.4 pour la validation. Cette convergence rapide durant les 5 premiĂšres Ă©poques tĂ©moigne de l'efficacitĂ© du transfer learning avec MobileNetV2 prĂ©-entraĂźnĂ© sur ImageNet. L'Ă©cart modĂ©rĂ© entre les courbes train et validation (≈0.15) indique un niveau de sur-apprentissage acceptable, sans divergence critique.

Progression de l'Accuracy : L'évolution de la précision confirme l'apprentissage efficace avec une montée rapide de 55% à plus de 85% en quelques époques, puis une stabilisation progressive vers 91% pour l'entraßnement et 87% pour la validation. Cette convergence démontre que le modÚle a atteint sa capacité d'apprentissage optimale avec la configuration actuelle (encoder gelé). L'écart final de 4% entre train et validation reste dans une fourchette acceptable pour un modÚle de production, suggérant une bonne généralisation sur des données non vues.

Cette dynamique d'entraßnement valide notre approche conservative avec encoder gelé, offrant un modÚle stable et performant en un temps d'entraßnement réduit, parfaitement adapté aux contraintes de développement rapide d'un systÚme embarqué.

1.5 Évaluation et MĂ©triques

1.5.1 Métriques de Performance

L'évaluation de modÚles de segmentation nécessite des métriques spécialisées. Nous utilisons principalement :

Intersection over Union (IoU)

Mesure le chevauchement entre la prédiction et la vérité terrain.

IoU = Intersection / Union
Enter fullscreen mode Exit fullscreen mode

Cette métrique est particuliÚrement pertinente car elle pénalise à la fois les faux positifs et les faux négatifs.

Mean IoU (mIoU)

Moyenne des IoU de toutes les classes, offrant une vue d'ensemble des performances.

Précision Pixel-wise

Pourcentage de pixels correctement classifiĂ©s, mĂ©trique intuitive mais pouvant ĂȘtre biaisĂ©e par les classes majoritaires.

1.5.2 Résultats de la Configuration Baseline

Notre modĂšle baseline atteint des performances encourageantes :

  • Mean IoU : 63.25%
  • PrĂ©cision globale : 87.95%
  • Perte finale : 0.4123
Analyse par Classe :
Classe IoU Commentaire
flat 0.9084 🟱 Excellent (routes bien dĂ©tectĂ©es)
human 0.3196 🔮 Difficile (objets petits/variables)
vehicle 0.7469 đŸ”” Bon (formes caractĂ©ristiques)
construction 0.7454 đŸ”” Bon (structures larges)
object 0.0648 🔮 Trùs difficile (objets fins)
nature 0.7983 đŸ”” Bon (textures distinctives)
sky 0.8339 🟱 Excellent (rĂ©gion homogĂšne)
void 0.6425 🟠 Acceptable
Matrice de confusion

La matrice de confusion constitue un outil d'Ă©valuation pour les modĂšles de classification, particuliĂšrement crucial en segmentation sĂ©mantique oĂč chaque pixel doit ĂȘtre correctement assignĂ© Ă  sa classe.

Dans le contexte de la classification et de la segmentation sĂ©mantique, chaque prĂ©diction peut ĂȘtre catĂ©gorisĂ©e selon quatre types fondamentaux qui dĂ©terminent la qualitĂ© du modĂšle :

  • Vrai positif (VP) : Le modĂšle dĂ©tecte correctement la prĂ©sence d'une classe lĂ  oĂč elle existe rĂ©ellement
  • Vrai nĂ©gatif (VN) : Le modĂšle rejette correctement une classe lĂ  oĂč elle n'existe pas
  • Faux positif (FP) : Le modĂšle gĂ©nĂšre une fausse alerte en dĂ©tectant une classe absente (surestimation)
  • Faux nĂ©gatif (FN) : Le modĂšle manque une classe prĂ©sente, Ă©chouant Ă  la dĂ©tecter (sous-estimation)

Pour un systÚme de vision automobile, cette analyse est importante car elle révÚle quelles confusions pourraient compromettre la sécurité (ex: confondre un piéton avec un objet statique).

Image description

1.5.3 Analyse des Performances

Points Forts :
  • Excellente dĂ©tection des surfaces planes (routes, ciel)
  • Bonne segmentation des grandes structures (bĂątiments, vĂ©gĂ©tation)
Points d'Amélioration :
  • DĂ©tection des objets fins (poteaux, panneaux) perfectible
  • Segmentation des humains variable (due Ă  leur taille et variabilitĂ©)
  • Besoin d'optimisation pour les petits objets

1.6 Pipeline de Prédiction

Pour valider les performances de notre modÚle en conditions réelles, nous avons développé un pipeline de prédiction complet permettant de traiter aussi bien des images du jeu de données de test que des images externes. Ce pipeline intÚgre toutes les étapes nécessaires depuis le chargement du modÚle jusqu'à l'analyse statistique des résultats.

def predict_single_image(model, config, image_path=None, image_array=None, img_size=(224, 224)):
    """Réalise une prédiction complÚte avec préprocessing et post-analyse"""

    # Chargement et préprocessing adaptatif
    if image_path is not None:
        image_pil = Image.open(image_path).convert('RGB')
        image_array = np.array(image_pil)

    # Pipeline de normalisation identique Ă  l'entraĂźnement
    image_resized = tf.image.resize(image_array, img_size, method='bilinear')
    image_normalized = tf.cast(image_resized, tf.float32) / 255.0
    image_batch = tf.expand_dims(image_normalized, axis=0)

    # Prédiction et conversion en masque de classes
    predictions = model.predict(image_batch, verbose=0)
    pred_mask = tf.argmax(predictions, axis=-1)[0].numpy()

    # Analyse statistique automatique par classe
    unique_classes, counts = np.unique(pred_mask, return_counts=True)
    total_pixels = pred_mask.size

    class_stats = []
    for class_id, count in zip(unique_classes, counts):
        class_name = config['group_names'][class_id]
        percentage = (count / total_pixels) * 100
        class_stats.append({
            'class_id': int(class_id),
            'class_name': class_name,
            'pixel_count': int(count),
            'percentage': percentage
        })

    return {
        'prediction_mask': pred_mask,
        'class_statistics': class_stats,
        'predictions_raw': predictions[0]
    }
Enter fullscreen mode Exit fullscreen mode

1.6.1. Résultats de prédiction

Les résultats de prédiction se présentent sous la forme suivante :

Masque de Segmentation (pixels) : Le rĂ©sultat principal est un masque 224×224 oĂč chaque pixel contient l'ID de la classe prĂ©dite (0-7). Cette reprĂ©sentation permet une analyse spatiale prĂ©cise de la scĂšne.

Distribution Statistique des Classes : Pour chaque prédiction, nous générons automatiquement un tableau statistique détaillant la répartition des classes :

📊 Classes dĂ©tectĂ©es:
           flat:    19536 pixels ( 38.9%)  # Routes et surfaces de circulation
   construction:    14510 pixels ( 28.9%)  # BĂątiments et infrastructures  
         nature:     8285 pixels ( 16.5%)  # Végétation et terrain naturel
           void:     5459 pixels ( 10.9%)  # Zones non classifiées
        vehicle:     1630 pixels (  3.2%)  # Véhicules en circulation
          human:      594 pixels (  1.2%)  # Piétons et cyclistes
            sky:       98 pixels (  0.2%)  # Ciel visible
         object:       64 pixels (  0.1%)  # Signalisation et mobilier urbain
Enter fullscreen mode Exit fullscreen mode

Visualisation Tripartite : Notre systÚme génÚre systématiquement trois vues : l'image originale, la vérité terrain (quand disponible), et la prédiction colorisée selon notre palette de couleurs spécifique au domaine automobile.

Image description

4.3 Analyse qualitative des performances

L'évaluation sur des images réelles révÚle des performances encourageantes avec des points forts et des axes d'amélioration clairement identifiés :

Excellente Détection des Structures Dominantes : Notre modÚle démontre une capacité remarquable à identifier les éléments structurants de la scÚne urbaine. La segmentation des surfaces planes (routes, trottoirs) atteint 38.9% de couverture dans l'exemple analysé, avec des contours nets et une classification cohérente. Les bùtiments et constructions (28.9%) sont également trÚs bien délimités, ce qui est crucial pour la navigation autonome.

Robustesse sur la végétation et l'environnement : La détection de la végétation (16.5%) montre une bonne capacité de généralisation du modÚle. Les arbres, buissons et espaces verts sont correctement identifiés malgré leur variabilité de texture et de forme, témoignant de l'efficacité du transfer learning depuis ImageNet.

Défis sur les objets de petite taille : L'analyse révÚle des difficultés attendues sur les éléments fins et de petite taille. Les objets de signalisation ne représentent que 0.1% des pixels détectés, ce qui correspond à la fois à leur faible représentation spatiale réelle et aux limitations du modÚle sur ces éléments critiques.

Gestion Intelligente des Zones AmbiguĂ«s : La catĂ©gorie "void" (10.9%) capture efficacement les zones d'incertitude et les Ă©lĂ©ments non classifiables, Ă©vitant les fausses classifications qui pourraient ĂȘtre dangereuses. Cette approche conservative est prĂ©fĂ©rable dans un contexte automobile.

Cette analyse confirme que notre architecture MobileNetV2-UNet offre un équilibre optimal pour les contraintes d'un systÚme de vision embarqué, avec des performances robustes sur les éléments critiques pour la prise de décision de navigation tout en maintenant une efficacité computationnelle compatible avec les ressources limitées d'un véhicule autonome.

1.7 Innovations et optimisations futures

1.7.1 Pistes d'amélioration identifiées

EntraĂźnement Progressif
Stratégie en deux phases :

  1. Phase 1 : Encoder gelé (configuration actuelle)
  2. Phase 2 : Fine-tuning avec encoder dégelé et taux d'apprentissage réduit

Augmentation de données avancée

  • Simulation de conditions mĂ©tĂ©orologiques (pluie, brouillard)
  • Variations d'Ă©clairage plus poussĂ©es
  • Transformations gĂ©omĂ©triques adaptĂ©es au contexte automobile

Architecture Hybride
Exploration de techniques comme :

  • Attention mechanisms pour amĂ©liorer la dĂ©tection des petits objets
  • Multi-scale training pour robustesse aux variations d'Ă©chelle
  • Ensembling de modĂšles pour amĂ©liorer la robustesse

1.8 Conclusion de la partie modélisation

Le développement de notre modÚle de segmentation MobileNetV2-UNet représente un équilibre réussi entre performance et efficacité computationnelle. Avec un Mean IoU de 63.25 % et une précision globale de 87.95 %, notre modÚle "baseline" fournit une base solide pour le systÚme de vision du véhicule autonome.

L'architecture choisie démontre sa pertinence pour les contraintes embarquées, et les résultats détaillés par classe révÚlent des performances cohérentes avec les attentes pour un modÚle de premiÚre génération. Les pistes d'amélioration identifiées offrent un roadmap clair pour les développements futurs.

La mise en place d'un pipeline MLOps avec MLflow et notre organisation modulaire garantissent la reproductibilité et facilitent l'itération continue sur les performances du modÚle.


🔼 2. DĂ©veloppement du Backend FastAPI - API de Segmentation SĂ©mantique

Le backend de l'application est une API REST développée avec FastAPI. Cette API expose notre modÚle de deep learning (MobileNetV2-UNet) entraßné pour la segmentation sémantique d'images urbaines du dataset Cityscapes.

Architecture technique

app/backend/
├── main.py              # Point d'entrĂ©e FastAPI
├── config.py            # Configuration et variables d'environnement
├── models/
│   └── predictor.py     # Logique de prĂ©diction et chargement du modĂšle
├── routers/
│   └── segmentation.py  # Endpoints de l'API
├── schemas/
│   └── prediction.py    # Modùles Pydantic pour validation
├── utils/
│   └── image_processing.py  # Utilitaires de traitement d'image
└── requirements.txt     # DĂ©pendances Python
Enter fullscreen mode Exit fullscreen mode

Fonctionnalités principales

1. Chargement du modĂšle depuis MLflow

Le modÚle est hébergé sur MLflow et chargé dynamiquement au démarrage de l'API :

  • ModĂšle : MobileNetV2-UNet (format Keras 3.x)
  • Poids : ~25MB
  • Classes : 8 catĂ©gories (flat, human, vehicle, construction, object, nature, sky, void)

2. Prédiction avec génération d'artefacts

L'API génÚre pour chaque prédiction :

  • Masque de segmentation : Classification pixel par pixel
  • Visualisations : Images cĂŽte Ă  cĂŽte et superposition
  • Statistiques : Distribution des classes dĂ©tectĂ©e
  • Sauvegarde : Artefacts de prĂ©diction sauvegardĂ©s dans le dossier /predictions

Endpoints de l'API

POST /api/v1/segmentation/predict

Notre endpoint principal pour la segmentation d'images.

Entrée : Image (PNG, JPEG) via multipart/form-data
Sortie : JSON contenant :

{
  "class_statistics": [...],
  "image_size": [largeur, hauteur],
  "dominant_class": "flat",
  "dominant_class_percentage": 42.5,
  "images": {
    "original": "data:image/png;base64,...",
    "prediction_mask": "data:image/png;base64,...",
    "overlay": "data:image/png;base64,...",
    "side_by_side": "data:image/png;base64,..."
  }
}
Enter fullscreen mode Exit fullscreen mode

GET /api/v1/segmentation/health

Ce endpoint vérifie l'état de santé de l'API.

{
  "status": "healthy",
  "model_loaded": true
}
Enter fullscreen mode Exit fullscreen mode

GET /api/v1/segmentation/model/info

Ce endpooint renvoie des informations détaillées sur le modÚle chargé.

{
  "model_name": "MobileNetV2-UNet",
  "input_shape": [null, 224, 224, 3],
  "num_classes": 8,
  "class_names": ["flat", "human", "vehicle", ...],
  "tensorflow_version": "2.18.0"
}
Enter fullscreen mode Exit fullscreen mode

GET /docs

Documentation interactive Swagger UI gĂ©nĂ©rĂ©e automatiquement par FastAPI. Ce endpoint est trĂšs utile pour effectuer des requĂȘtes de tests vers notre API, en attendant de dĂ©velopper le frontend.

Image description

Technologies utilisées

  • FastAPI : Framework web asynchrone haute performance
  • TensorFlow 2.18 (CPU) : InfĂ©rence du modĂšle
  • Gunicorn + Uvicorn : Serveur ASGI pour la production
  • Pillow : Manipulation d'images
  • MLflow : Gestion et versioning du modĂšle

Optimisations pour la production

  1. TensorFlow CPU : Version allégée sans GPU (250MB vs 500MB)
  2. Workers limités : 1 worker pour économiser la RAM
  3. Timeout ajusté : 120s pour les prédictions complexes
  4. Stockage temporaire : Utilisation de /tmp sur Railway

Déploiement sur Railway

Notre backend FastAPI est déployée sur Railway qui offre des ressources suffisante pour déployer un modÚle de segmentation d'image, gratuitement.

Configuration Railway

Le déploiement sur Railway utilise un fichier railway.json :

{
  "$schema": "https://railway.app/railway.schema.json",
  "build": {
    "builder": "NIXPACKS",
    "buildCommand": "pip install -r requirements.txt"
  },
  "deploy": {
    "startCommand": "uvicorn main:app --host 0.0.0.0 --port $PORT",
    "restartPolicyType": "ON_FAILURE",
    "restartPolicyMaxRetries": 10
  }
}
Enter fullscreen mode Exit fullscreen mode

Variables d'environnement

Les "credentials" sont configurés via le dashboard Railway :

  • MLFLOW_TRACKING_URI : URL du serveur MLflow
  • AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY : AccĂšs S3 pour MLflow
  • RUN_ID : Identifiant de l'expĂ©rience MLflow
  • PORT : Port d'Ă©coute (gĂ©rĂ© automatiquement)
  • FRONTEND_URL : URL de l'interface frontend (pour Ă©viter les erreurs CORS)

Processus de déploiement

  1. Initialisation : railway init pour créer le projet
  2. Configuration : Ajout des variables via le dashboard
  3. Déploiement : railway up pour déployer le code
  4. Domaine : railway domain pour générer l'URL publique

URL de production

L'API est accessible à : https://future-vision-api-*******.up.railway.app (URL masquée car non protégée par un mécanisme d'authentification)

Cette architecture permet un dĂ©ploiement rapide et scalable d'un modĂšle de deep learning, avec une API REST moderne et bien documentĂ©e, idĂ©ale pour ĂȘtre consommĂ©e par une application frontend.


⚡ 3. DĂ©veloppement de l'interface frontend Next.js

3.1 Architecture et choix techniques

L'interface utilisateur a été développée avec Next.js 15.3 en JavaScript, privilégiant la simplicité et la performance. Le framework React permet de développer une interface adaptée aux besoins de visualisation des résultats de segmentation.

Stack technique

  • Next.js 15.3 : Framework React pour le dĂ©veloppement frontend
  • Bootstrap 5.3 : Framework CSS pour un design responsive et professionnel
  • Fetch API : Communication avec l'API FastAPI de prĂ©diction
  • Base64 : Gestion des images encodĂ©es retournĂ©es par l'API

3.2 Fonctionnalités principales

L'application propose une interface intuitive pour tester le modÚle de segmentation sémantique :

  • Upload d'images : SĂ©lection et prĂ©visualisation des images (formats JPEG, PNG, GIF)
  • Validation : ContrĂŽle de la taille maximale (4096x4096px) et du format
  • PrĂ©diction en temps rĂ©el : Appel Ă  l'API avec feedback visuel de progression
  • Visualisation multi-format :
    • Image avec overlay de segmentation semi-transparent
    • Comparaison cĂŽte Ă  cĂŽte (originale vs prĂ©diction)
    • Masque de segmentation isolĂ©
  • Statistiques dĂ©taillĂ©es : Distribution des classes, classe dominante, mĂ©tadonnĂ©es

3.3 Interface utilisateur

L'interface suit les principes de design UX/UI pour une utilisation professionnelle :

État initial

  • Formulaire d'upload central avec instructions claires
  • Validation en temps rĂ©el du fichier sĂ©lectionnĂ©
  • Boutons d'action dĂ©sactivĂ©s tant qu'aucune image n'est sĂ©lectionnĂ©e

Image description

Résultats de prédiction

  • Affichage principal de l'image avec overlay de segmentation
  • Panneau latĂ©ral avec statistiques et distribution des classes
  • Section de comparaison dĂ©taillĂ©e avec visualisations multiples
  • Design responsive adaptĂ© aux diffĂ©rentes tailles d'Ă©cran

Image description

3.4 Déploiement et Accessibilité

L'application est déployée sur Vercel :

  • URL de production : https://oc-ai-engineer-p08-*******.vercel.app/ (URL masquĂ©e car non protĂ©gĂ©e par un mĂ©canisme d'authentification)
  • DĂ©ploiement automatique : IntĂ©gration continue depuis le repository Git
  • Configuration : Variables d'environnement pour l'URL de l'API backend
    • NEXT_PUBLIC_API_URL : URL de l'API REST de prĂ©diction

3.5 Intégration API

L'interface communique avec l'API FastAPI de sĂ©gmentation sĂ©mantique d'images via des requĂȘtes HTTP :

  • Endpoint : POST /predict pour l'analyse d'images
  • Format : Multipart/form-data pour l'upload de fichiers
  • RĂ©ponse : JSON contenant les images encodĂ©es et statistiques

Cette architecture facilite la maintenance et permet une évolution future vers des fonctionnalités avancées comme la gestion de lots d'images ou l'historique des prédictions.


📋 Conclusion

Ce projet de développement d'un systÚme de segmentation d'images pour véhicule autonome a permis de concevoir une solution complÚte, de la modélisation au déploiement en production.

Réalisations techniques

Modélisation IA : Nous avons développé un modÚle MobileNetV2-UNet atteignant 63.25% de Mean IoU sur 8 catégories d'objets urbains. L'architecture hybride combine l'efficacité de MobileNetV2 pour les contraintes embarquées avec la précision de U-Net pour la reconstruction spatiale.

Pipeline MLOps : L'intégration de MLflow a permis un suivi rigoureux des expériences et le versioning des modÚles, garantissant la reproductibilité et la traçabilité des développements.

Architecture API : Le backend FastAPI expose le modÚle via une API REST moderne avec génération automatique de visualisations et statistiques détaillées, optimisée pour un déploiement efficient.

Interface Utilisateur : L'application Next.js offre une interface intuitive pour tester le modÚle avec visualisations multi-formats (overlay, comparaison, masques) et facilement déployée sur Vercel.

Axes d'Amélioration

Les principales pistes d'optimisation incluent un entraĂźnement progressif (encoder dĂ©gelĂ© en phase 2), une augmentation de donnĂ©es avancĂ©e simulant conditions mĂ©tĂ©orologiques et variations d'Ă©clairage, l'intĂ©gration d'attention mechanisms pour amĂ©liorer la dĂ©tection des petits objets (panneaux, poteaux). Également, l'ajout d'un systĂšme d'authentification API, d'un cache de prĂ©dictions et de mĂ©triques de monitoring en production complĂ©terait l'industrialisation du systĂšme.

A propos de ce projet

Ce projet démontre la faisabilité technique d'un module de segmentation pour Future Vision Transport, avec une base solide pour l'évolution vers un systÚme de production robuste.

Top comments (0)