Retour d'expérience · 2026

VISION Studio

Studio de computer vision qui exécute onze modes d'analyse (objets, visages, poses, silhouette, mains, style transfer…) intégralement dans le navigateur. Cette page revient sur les choix techniques, les problèmes rencontrés et ce que je retiens de l'expérience.

Point de départ

Le site est positionné sur un profil « ingénieur IA ». Je voulais qu'un recruteur puisse ouvrir une démonstration concrète en un clic, sans installer quoi que ce soit, et se faire une idée du travail réel plutôt que de la seule liste de compétences.

Les contraintes que je me suis fixées :

  • Pas de backend. L'hébergement est mutualisé chez IONOS, sans GPU. Tout doit s'exécuter côté client.
  • Aucune donnée transmise. Les vidéos et images uploadées restent dans l'onglet de l'utilisateur.
  • Aucun cookie, aucun tracker, aucun outil d'analytics.
  • Un budget total inférieur à 300 Mo pour les modèles les plus lourds, avec chargement à la demande.
  • Un fonctionnement correct sur un ordinateur portable grand public, sans GPU dédié.

Choix techniques

Trois runtimes plutôt qu'un seul

Chaque modèle a un environnement d'exécution qui le sert mieux qu'un autre. J'ai donc utilisé trois runtimes en parallèle :

  • TensorFlow.js pour COCO-SSD (détection d'objets), MoveNet (poses), MobileNet (classification de scènes), BodyPix (segmentation corporelle) et face-api (visages et émotions). Backend WebGL par défaut, WASM en repli.
  • ONNX Runtime Web pour les quatre modèles de style transfer (fast_neural_style : mosaïque, pointillisme, udnie) et AnimeGANv3_PortraitSketch. La disponibilité de ces modèles est meilleure au format ONNX qu'au format TF.js.
  • MediaPipe (Google) pour la détection des mains avec 21 keypoints par main. C'est le seul runtime qui tient 60 images par seconde de manière stable sur mobile.

Contrepartie : trois API à connaître, trois cycles de mise à jour à suivre. Chaque modèle bénéficie en revanche du runtime qui lui correspond le mieux.

WebGPU activé par défaut, avec repli WebGL

WebGPU accélère l'inférence d'un facteur 2 à 4 sur les modèles les plus gros, mais son support reste inégal (Safari récent uniquement, mobile parfois instable). L'implémentation détecte le meilleur backend disponible et affiche un indicateur dans l'interface, pour que l'utilisateur sache sur quoi il tourne.

Hébergement des modèles

Les modèles étaient initialement chargés depuis tfhub.dev. Le service a été déprécié en 2026 et les URL sont devenues instables. J'ai migré MoveNet et MobileNet vers un hébergement personnel sur le domaine, et récupéré les modèles restants depuis Kaggle Models. Kaggle ayant ensuite bloqué le hotlinking, il a fallu tout réhéberger localement. La leçon principale : sur un projet solo, il est prudent d'archiver une copie de chaque modèle et son hash plutôt que de dépendre d'un CDN tiers, même officiel.

Politique de sécurité (CSP)

Chaque nouveau modèle ajoute un domaine à autoriser dans la Content-Security-Policy. Plutôt qu'une CSP globale trop permissive, j'ai scopé les autorisations avec un bloc <If REQUEST_URI ~ m#/jeux/vision/#> dans le .htaccess IONOS. Ce scope n'est effectif que si un Header unset Content-Security-Policy précède la nouvelle règle, sinon Apache concatène les headers et le navigateur applique l'intersection, ce qui bloque tout.

Organisation des onze modes en cinq familles

Onze modes affichés à plat rendaient l'interface illisible. Je les ai regroupés en familles fonctionnelles :

  • Détection : objets, visages, poses, scènes, mains.
  • Segmentation : anatomie, silhouette avec fond automatique.
  • Extraction : OCR.
  • Transformation : style transfer, floutage anonymisant.
  • Comparaison : deux vidéos synchronisées ou split-screen avant/après.

Ce qui a bien fonctionné

  • Le mode Silhouette (fond vert automatique) donne un résultat très propre. BodyPix produit un masque brut qui devient exploitable après un lissage temporel (majorité mobile sur cinq images) et des opérations de morphologie mathématique (dilate/erode). Quatre post-traitements de mise en valeur (halo cyan, glow, néon rouge, isolement du sujet) sont ensuite disponibles.
  • Le suivi des mains avec 21 keypoints par main tient 60 images par seconde grâce à MediaPipe. La détection multi-échelle permet de suivre une main proche ou éloignée sans réglage. Jusqu'à quatre mains simultanément.
  • Le split-screen avant/après avec un curseur de séparation permet de comparer deux instances synchronisées du même modèle. Il est notamment utilisé pour confronter COCO-SSD v1 et v2 côte à côte.
  • Le filtre par catégories via cases à cocher rend l'interface exploitable malgré les 80 classes de COCO-SSD et les 1000 classes d'ImageNet. Les libellés d'ImageNet sont traduits en français.

Ce qui n'a pas fonctionné

Toutes les tentatives n'ont pas abouti. Les mentionner me semble plus utile qu'un récit uniquement positif.

  • Détection et floutage des plaques d'immatriculation. L'objectif était d'anonymiser automatiquement les vidéos pour un usage RGPD. J'ai enchaîné une trentaine d'approches : YOLOv8n-plate en ONNX, Tesseract OCR sur l'image entière, vision classique avec Sobel et morphologie, scoring de candidats, apprentissage global des zones dessinées manuellement. Aucune approche n'a atteint le niveau de fiabilité requis pour un floutage automatique. Les faux positifs (pare-brise, panneau) et les faux négatifs (plaque abîmée, angle serré) restaient trop fréquents. J'ai retiré le mode plutôt que de laisser une fonctionnalité peu fiable sur laquelle un utilisateur pourrait s'appuyer pour publier une vidéo.
  • Colorisation sémantique d'images en noir et blanc. Le modèle testé rendait des résultats visuellement peu convaincants sur les images réelles. Le mode a été retiré avant d'investir dans l'interface.
  • Style transfer via Magenta. La bibliothèque Magenta de TensorFlow s'appuyait sur tfhub.dev, déprécié. J'ai migré vers fast_neural_style au format ONNX, hébergé sur GitHub via media.githubusercontent.com, puis AnimeGANv3 sur HuggingFace. HuggingFace ayant ensuite migré son stockage vers Xet (cas-bridge.xethub.hf.co), la CSP a demandé un nouveau réglage.
  • face-api en production. Le détecteur SsdMobilenetv1 appelle eval() en interne dans TF.js, ce que la CSP stricte bloquait. J'ai ajouté 'unsafe-eval' uniquement pour /jeux/vision/ et audité les entrées possibles pour vérifier qu'aucune injection ne pouvait tirer parti de cette autorisation locale.

Enseignements

  1. Le travail sur le modèle représente une petite partie de l'implémentation. Charger COCO-SSD tient en trois lignes ; suivre un objet à travers les images (IoU + Kalman léger), filtrer les faux positifs et afficher vingt détections lisibles sans saturer l'écran demande beaucoup plus d'attention.
  2. Sécurité, performance et compatibilité sont couplées. Une CSP stricte empêche eval(), ce qui casse certains chargements TF.js. WebGPU accélère l'inférence mais reste instable sur Safari mobile. Chaque décision technique a une contrepartie côté configuration serveur.
  3. La chaîne modèle → CDN → serveur → CSP est fragile. Un CDN qui migre, un Header unset oublié, une clé de CSP mal scopée : chaque maillon peut interrompre l'application. Pour un projet mono-développeur, il est prudent de documenter chaque URL de modèle avec son hash et de conserver une copie locale.
  4. Retirer une fonctionnalité qui ne tient pas ses promesses est parfois la meilleure décision. Le mode plaques représentait environ trente heures de travail réparties sur une trentaine d'itérations. Le maintenir en production aurait dégradé la crédibilité de l'ensemble.
  5. L'exécution locale est un vrai différenciateur, notamment côté français et européen. Aucune vidéo ne quitte le navigateur, ce qui simplifie la conformité RGPD et rassure les utilisateurs sur un sujet aussi sensible que la reconnaissance faciale.

Chiffres

  • Onze modes livrés en production, un retiré.
  • Six modèles TF.js, quatre modèles ONNX, trois estimateurs MediaPipe, un pipeline Tesseract.
  • Environ 4 000 lignes de JavaScript dans la version actuelle (vision-v18.js).
  • Aucun backend, aucun cookie, aucun tracker.
  • Environ 300 Mo de modèles chargeables au maximum, à la demande.
  • Contraste des contrôles conforme à WCAG AA (vérifié via mesure en navigateur).
  • Synchronisation du split-screen A/B à ±33 ms.
Ouvrir VISION Me contacter Voir tous les projets