4.15. Tampons d’image

Une fois le capteur de la caméra initialisé, il émet des trames en continu à sa cadence d’images – une nouvelle trame à chaque période de trame, que l’application soit prête ou non à la recevoir. Chaque trame a besoin d’un emplacement en RAM où atterrir, sinon elle est perdue. Le pool de tampons d’image est l’endroit où ces trames résident entre le moment où elles quittent le DMA et celui où elles sont traitées par le code utilisateur, et le nombre de tampons d’image que la caméra conserve dans ce pool détermine la façon dont le DMA et l’application se les partagent. Ce choix est exposé via framebuffers(), et quatre modes sont disponibles, sélectionnés par le nombre de tampons.

4.15.1. Tampon unique (count = 1)

Un seul tampon d’image en RAM. Le DMA le remplit ; l’application y lit ; le prochain appel à snapshot() ne peut pas démarrer tant que l’application n’a pas libéré le tampon, car le même tampon est nécessaire pour les deux.

La caméra et l’application fonctionnent de manière synchronisée. Le DMA doit attendre que l’application termine, et l’application doit attendre que le DMA termine, ce qui signifie que la cadence d’images atteignable est au mieux la moitié de celle du capteur – une trame sur deux émise par le capteur arrive pendant que le tampon est occupé et est perdue.

Ce mode est le plus économe en RAM et le plus lent en débit. Ne l’utilisez que lorsque la RAM est trop limitée pour allouer un second tampon.

4.15.2. Double tampon (count = 2)

Deux tampons d’image en RAM : un tampon arrière que le DMA remplit, et un tampon avant que l’application lit. Lorsque l’application a terminé avec le tampon avant, les deux rôles s’échangent, et le DMA commence à remplir le tampon fraîchement libéré pendant que l’application lit celui qui vient d’être rempli.

Tant que l’application traite chaque trame en moins d’une période de trame de la caméra, l’application voit la cadence d’images complète du capteur – la trame suivante du DMA attend déjà dans le tampon arrière lorsque l’application appelle de nouveau snapshot(). Dès que le temps de traitement dépasse une période de trame, en revanche, la cadence est divisée par deux : la caméra produira deux trames pendant que l’application en traite une, et seule la seconde de ces deux trames sera délivrée.

Au-delà de ce point, la cadence se dégrade progressivement avec le temps de traitement. Chaque fois que le DMA termine une nouvelle trame dans le tampon arrière pendant que l’application travaille encore sur le tampon avant, la nouvelle trame écrase la capture précédente sur place plutôt que d’être rejetée. L’application obtient toujours la trame la plus récente produite par la caméra lors de son prochain snapshot(), et la cadence atteignable par l’application devient l’inverse de son temps de traitement.

4.15.3. Triple tampon (count = 3)

Trois tampons d’image en RAM : deux tampons arrière que le DMA parcourt en alternance et un tampon avant sur lequel l’application travaille actuellement. Il s’agit du mode par défaut que choisit l’OpenMV Cam lorsqu’il y a suffisamment de RAM disponible, avec un repli automatique vers le double ou le simple tampon dans le cas contraire.

Le troisième tampon découple entièrement la cadence d’images de la caméra de celle de l’application. Le DMA dispose toujours d’un tampon où écrire ; l’application dispose toujours d’un tampon où lire ; à chaque snapshot(), le tampon arrière prêt le plus récent devient le nouveau tampon avant et le tampon avant précédent est libéré pour le DMA. La cadence d’images de l’application correspond au temps qu’il faut réellement pour traiter chaque trame – sans le palier de 1/2 dans lequel tombe le double tampon lorsque le temps de traitement dépasse de peu une période de trame.

4.15.4. FIFO vidéo (count = 4 ou plus)

Quatre tampons d’image ou plus en RAM, disposés en un anneau de trames capturées les unes après les autres. Chaque trame que la caméra délivre est mise en file dans le FIFO, et snapshot() renvoie la trame la plus ancienne en file plutôt que la plus récente. L’application parcourt les trames capturées dans l’ordre de capture, dans le temps dont elle dispose réellement pour chacune.

Ce mode est le bon choix lorsque chaque trame compte et que de brèves interruptions de traitement sont attendues : écriture de vidéo sur une carte SD dont la pile de stockage peut se bloquer pendant des dizaines de millisecondes lors d’un effacement, diffusion en continu via USB vers un hôte qui cesse brièvement de lire, ou mise en tampon d’une courte rafale d’un événement rapide pour inspection dans le code.

Deux politiques gèrent le cas où le FIFO se remplit avant que l’application ne l’ait vidé.

  • Rejeter les anciennes trames (par défaut). Lorsque le FIFO se remplit, toutes les trames en file sauf celle active sont rejetées afin que le prochain snapshot() renvoie une trame récente plutôt qu’une trame périmée. Le DMA continue de capturer pendant tout ce temps, de sorte que l’application voit toujours des données fraîches après une interruption. C’est la bonne politique lorsque l’objectif est de maintenir le flux capturé à jour – enregistrement vidéo, diffusion en direct.

  • Arrêter la capture en cas de débordement. Passez fflush=False au constructeur CSI et le DMA cesse de remplir le FIFO lorsqu’il est plein, laissant les trames en file intactes. snapshot() continue de renvoyer les trames dans l’ordre de capture jusqu’à ce que l’application les ait toutes vidées, après quoi le DMA reprend. C’est la bonne politique lorsque l’objectif est de préserver chaque trame d’une courte rafale – capturer un mouvement rapide pour l’inspecter trame par trame dans le code par la suite.

Consultez csi.CSI.framebuffers() pour l’API complète.

4.15.5. Mode déclenché

Une alternative aux modes en fonctionnement continu ci-dessus est la capture déclenchée, où le capteur n’émet une trame que lorsque snapshot() en demande une. La caméra reste inactive entre les captures et démarre une nouvelle exposition à chaque fois que l’application appelle.

Le coût est le débit : une capture déclenchée ne peut pas se chevaucher avec la précédente, de sorte que la cadence d’images maximale atteignable est la moitié de la cadence normale du capteur. L’avantage est la synchronisation de l’exposition. La capture contrôle exactement le moment où l’exposition commence, ce que recherche une application lorsque l’exposition doit coïncider avec un événement externe – un flash stroboscopique, un capteur de position de convoyeur, une impulsion sur une ligne GPIO – plutôt que de tomber là où se trouve la trame déroulante du capteur en fonctionnement libre au moment où l’application est prête à la lire.

Le mode déclenché est spécifique au capteur. Sur les capteurs pris en charge, il est activé en appelant csi0.ioctl(csi.IOCTL_SET_TRIGGERED_MODE, True) et désactivé en passant False.