13.3.1.3. Diffusion de trames¶
Un script qui capture des trames sur la caméra peut diffuser chaque trame vers l’hôte via USB. Le principe repose sur deux appels sur l’instance openmv.Camera : streaming() pour activer ou désactiver la diffusion, et read_frame() pour extraire la trame suivante du canal.
13.3.1.3.1. Une boucle minimale de diffusion et d’affichage¶
Le script côté caméra est la boucle de capture habituelle ; ce qui est nouveau, c’est que l’hôte ouvre la diffusion et lit le résultat:
from openmv import Camera
script = """
import csi
csi0 = csi.CSI()
csi0.reset()
csi0.pixformat(csi.RGB565)
csi0.framesize(csi.QVGA)
while True:
csi0.snapshot()
"""
with Camera('/dev/ttyACM0') as cam:
cam.stop()
cam.exec(script)
cam.streaming(True)
while True:
if frame := cam.read_frame():
print(f"{frame['width']}x{frame['height']}, "
f"{frame['raw_size']} bytes")
La caméra capture des trames en continu ; l’hôte extrait chacune d’elles du tampon de diffusion à mesure qu’elles arrivent. La caméra écrase le tampon de diffusion à chaque nouvelle capture, de sorte qu’un hôte qui interroge plus lentement que la caméra ne capture perdra silencieusement des trames – ce qui est le comportement adapté aux cas d’usage de type visualiseur.
13.3.1.3.2. Le dictionnaire de trame¶
read_frame() renvoie soit None (aucune trame en attente), soit un dict comportant cinq entrées :
Clé |
Signification |
|---|---|
|
Largeur de la trame en pixels. |
|
Hauteur de la trame en pixels. |
|
Identifiant du format de pixel déclaré par la caméra (un entier issu des constantes |
|
Pour les formats compressés (JPEG, PNG), la taille de l’image compressée en octets. Inutilisé pour les formats non compressés. |
|
La trame sous forme de tampon |
|
Octets envoyés par la caméra via USB avant décodage. Utile pour le calcul réel du débit. |
Le paquet convertit le format natif de la caméra (GRAYSCALE, RGB565, JPEG) en RGB888 avant de le renvoyer, de sorte que l’hôte n’a jamais à gérer lui-même le RGB565 compacté en bits ou la décompression JPEG. Les trames en niveaux de gris reviennent avec la valeur de luminance répliquée sur les trois canaux.
Le tampon data est organisé ligne par ligne, de haut en bas ; le fournir directement à une bibliothèque d’affichage ou l’enregistrer comme fichier RGB brut fonctionne sans aucun réarrangement supplémentaire.
13.3.1.3.3. Mode de diffusion brute¶
Par défaut, la caméra compresse en JPEG chaque trame capturée avant de la placer dans le canal de diffusion, et read_frame() la décompresse côté hôte. Sur les caméras sans prise en charge matérielle du JPEG, la compression logicielle est l’étape la plus lente de la boucle. Passer raw=True la contourne:
cam.streaming(True, raw=True, resolution=(320, 240))
La caméra envoie alors le tampon de pixels sans compression. Les trames non compressées sont bien plus volumineuses que leurs équivalents JPEG, de sorte que la caméra réduit chaque trame capturée pour qu’elle tienne dans le canal de diffusion avant de l’envoyer ; l’argument resolution=(width, height) définit cette cible. L’hôte reçoit toujours du RGB888 dans le champ data – le paquet effectue la conversion à partir du format de pixel signalé par la caméra dans format.
13.3.1.3.4. Laisser les événements piloter la boucle¶
Une boucle d’interrogation qui appelle read_frame() plus vite que la caméra ne produit de trames passe l’essentiel de son temps à recevoir None. Lorsque l’hôte a aussi d’autres tâches à accomplir (une interface à mettre à jour, d’autres canaux à interroger), read_status() constitue une vérification moins coûteuse : elle renvoie un dictionnaire associant chaque nom de canal enregistré à un booléen indiquant si « des données sont prêtes »:
while True:
status = cam.read_status()
if status.get('stream'):
frame = cam.read_frame()
# ... process the frame ...
if status.get('stdout'):
text = cam.read_stdout()
print(text, end='')
if status.get('my_channel'):
data = cam.channel_read('my_channel')
# ... process custom-channel data ...
C’est la forme de boucle qu’utilise le visualiseur en ligne de commande lui-même.
13.3.1.3.5. Arrêter la diffusion¶
Appelez streaming() avec enable=False pour arrêter. La caméra continue d’exécuter son script mais ne remplit plus le tampon de diffusion ; read_frame() renvoie simplement None à partir de ce moment. Appeler stop() produit le même effet de manière implicite en interrompant le script.