13.3.1.3. Frames streamen

Een script dat frames op de cam vastlegt, kan elk frame terugsturen naar de host via USB. Het patroon bestaat uit twee aanroepen op de openmv.Camera-instantie: streaming() om de stream in of uit te schakelen, en read_frame() om het volgende frame uit het kanaal te halen.

13.3.1.3.1. Een minimale stream-en-weergaveloop

Het script aan de cam-zijde is de gebruikelijke snapshotloop; wat nieuw is, is dat de host streaming opent en het resultaat terugleest:

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

De cam legt continu frames vast; de host haalt elk frame uit de streambuffer zodra het binnenkomt. De cam overschrijft de streambuffer bij elke nieuwe momentopname, dus een host die langzamer polt dan de cam vastlegt zal stilzwijgend frames laten vallen – dat is het juiste gedrag voor viewer-achtige toepassingen.

13.3.1.3.2. De frame-dict

read_frame() retourneert ofwel None (er staat geen frame klaar) of een dict met vijf vermeldingen:

Sleutel

Betekenis

width

Framebreedte in pixels.

height

Framehoogte in pixels.

format

Pixelformaat-identifier die de cam heeft opgegeven (een geheel getal uit de csi-constanten van de cam).

depth

Voor gecomprimeerde formaten (JPEG, PNG), de grootte van de gecomprimeerde afbeelding in bytes. Niet gebruikt voor ongecomprimeerde formaten.

data

Het frame als een bytes-buffer in RGB888. Elke pixel is drie bytes (R, G, B); de totale lengte is width * height * 3.

raw_size

Bytes die de cam via USB verstuurde vóór het decoderen. Nuttig voor de werkelijke doorvoerberekening.

Het pakket converteert het oorspronkelijke formaat van de cam (GRAYSCALE, RGB565, JPEG) naar RGB888 voordat het wordt geretourneerd, zodat de host nooit zelf met het bit-gepackte RGB565 of de JPEG-decompressie hoeft om te gaan. Grijswaardenframes komen terug met de luma-waarde gerepliceerd in alle drie de kanalen.

De data-buffer is rij voor rij opgebouwd, van boven naar beneden; het rechtstreeks doorgeven aan een weergavebibliotheek of het opslaan als ruw RGB-bestand werkt zonder verdere bewerking.

13.3.1.3.3. Raw-streamingmodus

Standaard comprimeert de cam elk vastgelegd frame met JPEG voordat het in het streamkanaal wordt geplaatst, en decomprimeert read_frame() op de host. Op cams zonder hardware-JPEG-ondersteuning is de softwarecompressie de traagste stap in de loop. Door raw=True mee te geven wordt deze overgeslagen:

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

De cam verstuurt de pixelbuffer dan ongecomprimeerd. Ongecomprimeerde frames zijn veel groter dan hun JPEG-equivalenten, dus de cam schaalt elk vastgelegd frame omlaag zodat het in het streamkanaal past voordat het wordt verstuurd; het argument resolution=(width, height) stelt dat doel in. De host ontvangt nog steeds RGB888 in het data-veld – het pakket converteert vanuit het pixelformaat dat de cam in format heeft gerapporteerd.

13.3.1.3.4. Events de loop laten aansturen

Een pollingloop die read_frame() sneller aanroept dan de cam frames produceert, besteedt de meeste tijd aan het terugkrijgen van None. Wanneer de host ook ander werk te doen heeft (een UI bijwerken, andere kanalen pollen), is read_status() de goedkopere controle: het retourneert een dict die elke geregistreerde kanaalnaam koppelt aan een boolean van “data is gereed”:

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

Dit is de loopvorm die de CLI-viewer zelf gebruikt.

13.3.1.3.5. De stream stoppen

Roep streaming() aan met enable=False om te stoppen. De cam blijft zijn script uitvoeren, maar vult de streambuffer niet langer; read_frame() retourneert vanaf dat moment gewoon None. Het aanroepen van stop() doet hetzelfde impliciet door het script te stoppen.