10.2. Zwracanie zrzutu obrazu

Punkt końcowy ze statusem jest w porządku, ale powodem istnienia kamery jest obiektyw. Dodaj punkt końcowy, który zwraca obraz JPEG tego, na co sensor patrzy w danej chwili.

import csi
from microdot import Response

csi0 = csi.CSI()
csi0.reset()
csi0.pixformat(csi.RGB565)
csi0.framesize(csi.QVGA)

@app.get('/snapshot.jpg')
async def snapshot(request):
    img = csi0.snapshot().compress(quality=85)
    return Response(
        body=img.bytearray(),
        headers={'Content-Type': 'image/jpeg'},
    )

Wejdź pod http://<cam-ip>/snapshot.jpg z przeglądarki, a obraz JPEG bieżącego widoku wypełni kartę. Odśwież, a otrzymasz nowy.

10.2.1. Obiekt Response

Procedura obsługi zwracająca słownik pozwala microdot zrobić resztę. Bajty JPEG wymagają pełnej formy: jawnie skonstruowanego obiektu microdot.Response. Argument body przyjmuje dowolną wartość przypominającą bajty – bufor image.Image kamery jest udostępniany przez bytearray(), więc ten sam bufor, do którego zapisał sensor, trafia prosto do gniazda.

Content-Type: image/jpeg to to, co mówi przeglądarce, aby wyrenderowała treść jako obraz. Bez tego przeglądarka próbowałaby wyświetlić bajty JPEG jako tekst i zobaczyłbyś pełen ekran śmieci.

image.Image.compress() uruchamia kodowanie JPEG na istniejącym buforze obrazu w miejscu i zwraca ten sam obraz (teraz w formacie JPEG), aby jego bajty mogły zostać wysłane takie, jakie są. quality=85 to zwykła wartość domyślna – na tyle wysoka, że obraz jest ostry, i na tyle niska, że plik mieści się w wolnym łączu.

10.2.2. Przechwytywanie blokuje pętlę

csi.CSI.snapshot() czeka, aż sensor zakończy ekspozycję i transfer DMA ramki, zanim zwróci wynik. Wewnątrz asynchronicznej procedury obsługi oznacza to, że pętla zdarzeń zatrzymuje się na czas ekspozycji – dziesięć, dwadzieścia, pięćdziesiąt milisekund, w zależności od oświetlenia. Przy jednym kliencie pytającym o jedną trasę naraz jest to niezauważalne; przy wielu klientach lub przy korutynie przechwytującej działającej równolegle blokowałoby to wszystko inne.

Dla przypadku z wieloma korutynami istnieje nieblokujący wariant snapshot() (blocking=False zwraca następną gotową ramkę lub None). Dla jednego zrzutu na żądanie domyślne blokujące wywołanie jest w porządku.

Właściciel może teraz odpytać URL i otrzymać świeżą ramkę.