10.2. Повернення знімка#

Кінцева точка статусу – це добре, але причина існування камери – це об’єктив. Додайте кінцеву точку, що повертає JPEG того, що датчик бачить прямо зараз.

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'},
    )

Відкрийте http://<cam-ip>/snapshot.jpg у браузері, і у вкладці з’явиться JPEG поточного виду. Оновіть сторінку – отримаєте свіжий знімок.

10.2.1. Об’єкт Response#

Обробник, що повертає словник, дозволяє microdot зробити все інше. JPEG-байти потребують повної форми: явно побудованого microdot.Response. Аргумент body приймає будь-яке байтоподібне значення – буфер image.Image камери доступний через bytearray(), тому той самий буфер, у який записав датчик, відправляється прямо до сокета.

Content-Type: image/jpeg повідомляє браузеру, що тіло відповіді є зображенням. Без цього браузер намагатиметься відобразити JPEG-байти як текст, і ви побачите екран беззмістовних символів.

image.Image.compress() виконує JPEG-кодування наявного буфера зображення на місці і повертає те саме зображення (тепер у форматі JPEG), щоб його байти можна було відправити без змін. quality=85 – звичайне значення за замовчуванням – достатньо високе для чіткого зображення, і достатньо низьке, щоб файл вмістився через повільне з’єднання.

10.2.2. Захоплення блокує цикл#

csi.CSI.snapshot() чекає, поки датчик завершить витримку та передачу кадру через DMA, перш ніж повернути результат. Усередині асинхронного обробника це означає, що цикл подій зупиняється на час витримки – десять, двадцять, п’ятдесят мілісекунд залежно від освітлення. При одному клієнті, що запитує один маршрут за раз, це непомітно; але при кількох клієнтах або сопрограмі захоплення, що виконується паралельно, це заблокує все інше.

Неблокуючий варіант snapshot() існує для випадку з кількома сопрограмами (blocking=False повертає наступний готовий кадр або None). Для одного знімка на запит стандартний блокуючий виклик є прийнятним.

Тепер власник може відкрити URL і отримати свіжий кадр.