13.3.1.3. Transmiterea în flux a cadrelor

Un script care capturează cadre pe cameră poate transmite în flux fiecare cadru înapoi către gazdă prin USB. Modelul constă în două apeluri pe instanța openmv.Camera: streaming() pentru a activa sau dezactiva fluxul și read_frame() pentru a extrage următorul cadru din canal.

13.3.1.3.1. O buclă minimă de transmitere și afișare

Scriptul de pe partea camerei este bucla obișnuită de instantanee; ceea ce este nou este faptul că gazda deschide transmiterea în flux și citește rezultatul înapoi:

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")

Camera capturează cadre în mod continuu; gazda extrage fiecare cadru din tamponul de flux pe măsură ce acesta sosește. Camera suprascrie tamponul de flux la fiecare nou instantaneu, astfel încât o gazdă care interoghează mai lent decât capturează camera va pierde în mod silențios cadre – acesta este comportamentul corect pentru cazurile de utilizare de tip vizualizator.

13.3.1.3.2. Dicționarul cadrului

read_frame() returnează fie None (niciun cadru nu așteaptă), fie un dict cu cinci intrări:

Cheie

Semnificație

width

Lățimea cadrului în pixeli.

height

Înălțimea cadrului în pixeli.

format

Identificatorul formatului de pixeli declarat de cameră (un întreg din constantele csi ale camerei).

depth

Pentru formatele comprimate (JPEG, PNG), dimensiunea imaginii comprimate în octeți. Neutilizat pentru formatele necomprimate.

data

Cadrul ca tampon bytes în RGB888. Fiecare pixel are trei octeți (R, G, B); lungimea totală este width * height * 3.

raw_size

Octeții pe care camera i-a trimis prin USB înainte de decodare. Util pentru calculul efectiv al debitului.

Pachetul convertește formatul nativ al camerei (GRAYSCALE, RGB565, JPEG) în RGB888 înainte de returnare, astfel încât gazda nu trebuie niciodată să se ocupe ea însăși de RGB565 cu împachetare pe biți sau de calea de decomprimare JPEG. Cadrele în tonuri de gri revin cu valoarea de luminanță replicată în toate cele trei canale.

Tamponul data este dispus rând cu rând, de sus în jos; transmiterea lui direct către o bibliotecă de afișare sau salvarea ca fișier RGB brut funcționează fără nicio rearanjare suplimentară.

13.3.1.3.3. Modul de transmitere brută

În mod implicit, camera comprimă în JPEG fiecare cadru capturat înainte de a-l plasa în canalul de flux, iar read_frame() îl decomprimă pe gazdă. Pe camerele fără suport hardware pentru JPEG, comprimarea software este pasul cel mai lent din buclă. Transmiterea raw=True îl omite:

cam.streaming(True, raw=True, resolution=(320, 240))

Camera trimite apoi tamponul de pixeli necomprimat. Cadrele necomprimate sunt mult mai mari decât echivalentele lor JPEG, așa că camera reduce scara fiecărui cadru capturat pentru a se încadra în canalul de flux înainte de a-l trimite; argumentul resolution=(width, height) stabilește acea țintă. Gazda primește în continuare RGB888 în câmpul data – pachetul convertește din orice format de pixeli pe care camera l-a raportat în format.

13.3.1.3.4. Lăsarea evenimentelor să conducă bucla

O buclă de interogare care apelează read_frame() mai rapid decât produce camera cadre își petrece cea mai mare parte a timpului primind None înapoi. Atunci când gazda are și alte sarcini de îndeplinit (o interfață de actualizat, alte canale de interogat), read_status() este verificarea mai ieftină: returnează un dicționar care asociază fiecărui nume de canal înregistrat o valoare booleană de „datele sunt gata”:

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 ...

Aceasta este forma de buclă pe care o folosește vizualizatorul CLI însuși.

13.3.1.3.5. Oprirea fluxului

Apelați streaming() cu enable=False pentru a opri. Camera își continuă rularea scriptului, dar nu mai umple tamponul de flux; read_frame() returnează doar None din acel moment. Apelarea stop() face același lucru în mod implicit prin oprirea scriptului.