Comment EIP découple-t-il acquisition, traitement, enregistrement et service web tout en conservant une chronologie unique des trames ?
Objet, question et périmètre
Cet article décrit l’état d’Embedded Imaging Platform au 5 octobre 2026. Il s’appuie sur le code, la documentation d’architecture, les mesures de performance archivées et l’historique Git de ce dépôt, qui commence avec le premier commit de cette nouvelle mouture, le 14 août 2026. Il ne cherche pas à déduire la qualité du logiciel de sa taille : le nombre de lignes est utilisé uniquement comme indicateur d’ampleur et de progression.
J’imagine PolarScope dès 2019 comme un viseur numérique pour ma monture d’astronomie EM-10 Takahashi ; mes notes sur ce prototype, avec caméra Raspberry Pi et Pi Zero, documentent aussi des essais de calibration et de corrélation stellaire. Cette première version inachevée sert de base à la nouvelle mouture de 2026, beaucoup plus ambitieuse.
Le support imprimé adaptait un objectif CS à la caméra et permettait son montage sur l’EM-10. La vue éclatée ci-dessous documente la conception mécanique de ce premier prototype avec son support de test avant l’adaptation monture.
EIP est un serveur d’imagerie embarquée C++17 complété par des applications web et un client natif secondaire. Son rôle couvre l’acquisition, le transport des données brutes du capteur (RAW), la prévisualisation, l’enregistrement, le stockage, la télémétrie, l’astronomie et la caractérisation de capteurs.
Invariant d’architecture : un propriétaire, un monolithe modulaire
Le déploiement principal repose sur un processus imaging-server. Ce choix donne un propriétaire unique au matériel, évite une sérialisation interprocessus des trames et maintient les métadonnées dans la même chronologie que les pixels. Il ne signifie pas que le code forme un bloc indivisible.
Les dépendances suivent quatre niveaux :
Le sens des dépendances est Applications → Astronomie → Cœur d’imagerie → Pilotes. Toutes les applications ne mobilisent pas nécessairement les services astronomiques. Les backends implémentent un contrat commun et publient leurs capacités ; le serveur ne suppose donc ni une famille de capteurs ni une profondeur RAW unique.
Évolution observée dans Git
| Date | Étape | Conséquence architecturale |
|---|---|---|
| 14-17 août | libcamera en mémoire, acquisition continue, client asynchrone | La cadence du capteur n’est plus liée à la boucle d’affichage. |
| 19 août | Séparation client/serveur | Le protocole caméra devient générique. |
| 24-29 août | Contrôle web, MJPEG, analyse asynchrone, double tampon | Le navigateur devient un client complet sans bloquer l’acquisition. |
| 17-23 septembre | PiNox, Dashboard, portail et configuration EIP | Le projet initial évolue vers un socle générique multi-application. |
| 25 septembre | Interfaces compilées et PIMPL | Réduction du couplage et du coût de recompilation sur les petits Pi. |
| 28 septembre | Imagerie, stockage et fichiers consolidés | La capture locale haute cadence rejoint le portail commun. |
| 29 septembre-1er octobre | Chemin ISP mesuré | Le backend peut produire RAW et RGB appairés avec repli logiciel. |
| 2-5 octobre | Caractérisation C++ en mémoire | Acquisition, analyse et rapport sont intégrés au même serveur. |
Plan de données et plan de contrôle
Le serveur distingue implicitement deux plans. Le plan de données transporte les charges utiles volumineuses : /snapshot/raw, /stream/raw, /stream.mjpg, /preview.png et les écrivains locaux AVI, SER ou PNG. Le plan de contrôle utilise des réponses structurées pour les réglages, la télémétrie et l’état des modules.
Cette séparation évite d’utiliser la prévisualisation compressée comme source scientifique. En plein format IMX477, le flux RAW HTTP mesuré plafonne autour de 105 à 115 MB/s alors que la capture peut être plus rapide. Le chemin d’enregistrement local se branche donc avant le réseau.
Cycle d’une trame et mutualisation par frame_id
- Le backend acquiert le buffer et les métadonnées du capteur.
- Le producteur publie un instantané de trame identifié par
frame_id. - Le RAW peut être transmis, analysé ou placé dans la file d’enregistrement sans passer par un fichier intermédiaire.
- La prévisualisation sélectionne le rendu brut, luminance ou couleur et applique la réduction demandée.
- La luminance, les buffers de travail et le JPEG encodé sont mis en cache pour cette trame.
- Chaque client reçoit au plus une partie MJPEG pour ce
frame_id.
Avec le backend libcamera et le processeur de signal d’image (ISP) actif, le RAW et la sortie couleur rouge-vert-bleu (RGB) du pipeline matériel proviennent de la même requête. Le traitement scientifique continue à consommer le RAW ; cette sortie sert uniquement de point de départ à la prévisualisation.
Domaines d’exécution, files et tampons
Le serveur ne repose pas sur une unique boucle événementielle. Les domaines présents ou activés selon la configuration comprennent :
- le fil de capture du backend et le producteur de trames du serveur ;
- un fil par connexion HTTP acceptée ;
- les fils d’annotation, de dispersion atmosphérique et de suivi de région d’intérêt ;
- le fil d’écriture asynchrone de l’enregistreur RAW ;
- la surveillance de veille, les journaux et les tâches de caractérisation ;
- les travaux ponctuels de benchmark de volume ou de communication entre instances EIP.
Les opérations par pixel utilisent OpenMP (Open Multi-Processing, interface de programmation parallèle) au-dessus d’un seuil de taille afin que le coût d’ordonnancement et de synchronisation du travail parallèle ne dépasse pas le gain attendu. Le solveur de résolution de champ sans centre initial connu fonctionne lorsque l’échantillonnage approximatif est disponible : il teste des régions du catalogue et peut appliquer un filtre d’horizon si la position et l’heure de l’observateur sont valides. Il utilise le même mécanisme, avec au plus quatre fils de calcul et un cœur laissé disponible lorsque plusieurs cœurs sont annoncés. Il s’agit donc d’une résolution sans centre initial connu, mais pas sans a priori : l’échantillonnage approximatif est fourni et, lorsque la position et l’heure de l’observateur sont disponibles, le filtre d’horizon peut réduire le domaine de recherche.
Cette architecture utilise des verrous, variables de condition et files protégées. Elle n’est pas présentée comme sans verrou. Sa propriété recherchée est l’isolement des rythmes : une écriture lente ou une analyse coûteuse ne doit pas imposer son temps de service à la caméra.
Files d’écriture, tampons et surcharge
L’enregistreur reçoit une référence vers la charge utile RAW et la confie à un fil d’écriture dédié. Sa file est limitée par un budget mémoire ; un arrêt normal la vide avant de fermer le conteneur, tandis qu’un abandon explicite comptabilise les trames rejetées. Cette différence évite de produire silencieusement un fichier incomplet.
La prévisualisation utilise le double tampon : pendant que le JPEG de la trame N est encodé, la trame N+1 peut être préparée. La frame courante, le JPEG et les buffers intermédiaires sont réutilisés pour limiter les allocations, les copies et le swap sur Pi Zero.
Cache partagé et cadence d’analyse
Le cache est indexé par l’identité de la source et par les paramètres qui affectent le rendu. Le JPEG n’est pas réencodé pour chaque navigateur. La luminance sur cellules Bayer peut être partagée entre la vidéo et l’overlay. Lorsque l’analyse d’un ciel vide ne produit aucun changement utile, sa cadence peut descendre vers une analyse par seconde afin de préserver la vidéo.
Le correctif du 23 septembre impose également l’attente d’une nouvelle trame. Avant lui, une boucle plus rapide que la caméra pouvait renvoyer plusieurs fois le même JPEG. Après correction, les mesures IMX477 en 1332 × 990 donnent 47,7 images capturées, 47,7 images RAW et 47,7 images MJPEG distinctes par seconde, avec 0 % de doublons.
Performances mesurées : double tampon et ISP
Le benchmark du 29 août utilise une OV5647, une exposition de 20 ms et un gain 8. Les images JPEG distinctes sont comptées, sans confondre répétition HTTP et nouvelle trame.
| Plateforme et mode | Rendu | Avant | Après | Gain |
|---|---|---|---|---|
| Pi 4, bin2 | Couleur | 31,1 IPS | 45,4 IPS | +46 % |
| Pi 4, bin2 | Couleur + balance | 31,2 IPS | 45,4 IPS | +45 % |
| Pi Zero 2 W, bin2 | Luminance | 16,5 IPS | 27,2 IPS | +65 % |
| Pi Zero 2 W, bin2 | Couleur | 11,2 IPS | 19,2 IPS | +71 % |
| Pi Zero 2 W, bin2 | Couleur + balance | 11,2 IPS | 19,3 IPS | +72 % |
Sur Pi 4 en bin1, la cadence reste proche de 15 IPS avant et après : la lecture du capteur est alors le facteur limitant. Le résultat est important méthodologiquement, car il montre que le parallélisme ne crée pas un gain lorsque le goulot se situe en amont.
Intégration de l’ISP
Le chemin ISP introduit un accélérateur matériel sans modifier le contrat du cœur. La sélection auto, software ou isp appartient aux réglages de prévisualisation. Un profil de tuning neutralisé doit être présent et validé pour le capteur ; sinon le mode automatique revient au logiciel et publie la raison.
Sur IMX477/Pi 4 en 4056 × 3040, la cadence mesurée reste voisine de 11,2 IPS, limitée par l’acquisition, mais la charge du processus passe de 232,6 % à 93,4 % et la latence de 55,7 à 40,2 ms. Sur OV5647/Pi 3 en 2592 × 1944, la cadence passe de 12,80 à 14,92 IPS, la charge du processeur central (CPU) de 299,0 % à 113,7 % et la latence de 72,8 à 42,2 ms.
Modularisation et coût de compilation
Le serveur historique était largement défini dans les fichiers d’en-tête. Toute modification pouvait forcer la recompilation d’une grande partie du projet et augmenter fortement la mémoire du compilateur, ce qui est pénalisant sur Pi Zero. La séquence de restructuration du 25 septembre déplace les implémentations dans des unités .cpp, réduit les inclusions transitives et masque les détails lourds derrière des façades PIMPL.
Ont notamment été isolés le transport HTTP, les assets web, les réglages caméra, les backends, l’enregistrement RAW, la supervision, les catalogues, les solveurs, les opérations d’image et les modules applicatifs. Le serveur HTTP conserve encore une responsabilité d’orchestration importante : cette dette est documentée plutôt que masquée.
Progression du volume de code
La série utilise douze instantanés du dernier commit disponible à la fin de chaque date. Le périmètre de production est limité aux extensions C/C++, JavaScript, CSS et HTML sous src/ et assets/web/. Le périmètre de test contient les sources C/C++, JavaScript et shell sous tests/. Les lignes vides sont retirées. Sont exclus : documentation, site éditorial web/, bases, catalogues, données scientifiques, figures, dépendances, benchmarks, scripts de déploiement et outils ponctuels.
Sur ce périmètre, le logiciel livré est multiplié par 7,45 et l’ensemble logiciel plus tests par 9,27 en 52 jours. Les tests représentent 21,5 % du total final. Ces ratios décrivent la croissance du dépôt ; ils ne constituent pas une mesure de maintenabilité ou de qualité.
Résilience et fonctionnement embarqué
Le serveur supervise les blocages de capture, borne le nombre de flux MJPEG par adresse, sépare la veille des poses longues et peut maintenir l’acquisition active pendant une opération qui interdit l’économie d’énergie. Les reconfigurations caméra sont sérialisées. Les longues poses utilisent une requête unique à partir d’une seconde, indépendamment du mode ou de la résolution, afin d’éviter une trame de prévisualisation longue supplémentaire.
Le portail repose sur la découverte de services : une application non compilée ou masquée n’est pas affichée. Un profil léger peut retirer PiNox pour les cibles à faibles ressources. La Projection fonctionne dans un navigateur et peut aussi être lancée localement lorsqu’une sortie HDMI est détectée.
Conclusion
L’originalité d’EIP ne réside pas dans le nombre de fils d’exécution pris isolément. Elle tient à la combinaison d’un propriétaire unique de la caméra, de deux chemins de données cohérents, de caches associés aux trames, de traitements asynchrones et d’une API partagée entre plusieurs applications.
Les mesures montrent où cette architecture produit un gain réel et où elle atteint simplement la limite du capteur. Cette distinction est essentielle : l’objectif n’est pas d’occuper tous les cœurs, mais de préserver l’acquisition, la traçabilité scientifique et la réactivité du service lorsque plusieurs usages coexistent sur le même Raspberry Pi.
Pour continuer
Autre niveau de lecture
Dans le moteur d’EIP — version découverte · Comprendre les chemins de données et les choix d’architecture par les schémas.