4.14. Bases de la CSI¶
Le module csi est la façon dont le code Python pilote le capteur de la caméra. Tout script qui capture une trame suit la même structure en trois parties : les imports en haut, la configuration unique au milieu, et une boucle while True en bas qui récupère les trames de la caméra une par une.
4.14.1. La boucle typique¶
import csi, image, time
csi0 = csi.CSI()
csi0.reset()
csi0.pixformat(csi.RGB565)
csi0.framesize(csi.QVGA)
clock = time.clock()
while True:
clock.tick()
img = csi0.snapshot()
# process img here
print(clock.fps())
4.14.2. Ce que fait chaque appel¶
import csi, image, timeImporte trois modules.
csicontrôle le capteur,imagedéfinit la classeImageque renvoiesnapshot(), ettimefournit l’utilitairetime.clock()servant à mesurer les images par seconde.csi.CSI()Construit une instance
CSIqui encapsule un capteur de caméra physique. Le constructeur réserve le périphérique de caméra et enregistre la configuration propre au capteur. Les caméras à capteur unique ont une seule instanceCSI; les caméras à deux capteurs (couleur plus thermique, couleur plus événementiel) en ont deux, chacune sélectionnée par un argumentcidpassé au constructeur.csi0.reset()Alimente et configure le capteur. Par défaut, il génère une impulsion sur la broche de réinitialisation du capteur, puis écrit les registres I2C du capteur pour les placer dans un état de départ connu. Les appels de configuration suivants –
pixformat,framesize, les commandes de réglage automatique – envoient d’autres écritures de registre sur le même bus de contrôle I2C.csi0.pixformat(csi.RGB565)Écrit les registres du capteur qui sélectionnent le format de pixel de sortie. Les choix disponibles sont les formats présentés sur la page formats de pixels :
RGB565,GRAYSCALE,BAYER,YUV422etJPEGsur les capteurs qui le prennent en charge.csi0.framesize(csi.QVGA)Écrit les registres qui sélectionnent la résolution de sortie.
QVGAcorrespond à 320 × 240 ; les tailles nommées vont jusqu’àWQXGA2(2592 × 1944, environ 5 MP) sur les capteurs qui les prennent en charge. Un tuple(width, height)personnalisé fonctionne également, tant qu’il correspond aux capacités de sortie du capteur.clock = time.clock()Crée un utilitaire d’horloge. Chaque appel à
clock.tick()à l’intérieur de la boucle enregistre l’instant de début de l’itération ;time.clock.fps()indique la cadence récente de la boucle en images par seconde.img = csi0.snapshot()Capture une trame du capteur et la renvoie sous forme d”
Image. Le mécanisme par lequel cette trame se retrouve en mémoire mérite un examen plus approfondi.
4.14.3. Comment snapshot remplit la mémoire¶
Le capteur délivre les pixels sur le bus de données de pixels décrit dans bus de capteur à des débits de plusieurs centaines de méga-octets par seconde – bien trop rapide pour que le CPU les copie pixel par pixel en logiciel.
À la place, le MCU délègue le transfert à l”accès direct à la mémoire (DMA) – un moteur matériel distinct du CPU qui copie des octets d’un endroit à un autre à l’intérieur du MCU sans solliciter le CPU. Le périphérique d’entrée de la caméra capte chaque octet de pixel entrant dans une petite FIFO intégrée à la puce ; les étapes de l’ISP qui s’exécutent côté MCU traitent les données au passage ; et le moteur DMA écrit les pixels finis dans un tampon d’image en RAM, à la position de pixel correspondante. Aucun maillon de cette chaîne n’a besoin du CPU une fois le canal DMA programmé.
Lorsque snapshot() est appelé :
Le pilote CSI programme le moteur DMA avec l’adresse du tampon d’image, la longueur du transfert (la quantité de pixels d’une trame) et une fonction de rappel pour l’interruption de fin de DMA.
Le pilote active le périphérique d’entrée de la caméra et attend que le capteur signale le début de la trame suivante.
À mesure que le capteur diffuse la trame, le périphérique transmet chaque octet de pixel à travers l’ISP puis au moteur DMA, qui écrit le résultat en RAM à la position de tampon d’image suivante. Le CPU est libre d’exécuter d’autre code pendant le transfert.
Lorsque le dernier pixel de la trame arrive, le DMA déclenche son interruption de fin, le pilote encapsule le tampon d’image dans une
Image, etsnapshot()la renvoie au code utilisateur.
L”Image renvoyée ne possède pas une copie des données de pixels – elle pointe vers l’un des tampons d’image de la caméra en RAM. Le nombre de tampons d’image que conserve la caméra, et la façon dont ils sont échangés entre le DMA et le code utilisateur à chaque appel de snapshot(), dépendent du mode de mise en tampon que l’application a sélectionné via framebuffers().