13.3.1.3. Потокова передача кадрів¶
Скрипт, який захоплює кадри на камері, може передавати кожен кадр назад на хост через USB. Шаблон складається з двох викликів на екземплярі openmv.Camera: streaming() для увімкнення або вимкнення потоку, та read_frame() для отримання наступного кадру з каналу.
13.3.1.3.1. Мінімальний цикл потокової передачі та відображення¶
Скрипт на боці камери — це звичайний цикл знімків; нове тут те, що хост відкриває потік і зчитує результат:
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")
Камера безперервно захоплює кадри; хост витягує кожен із буфера потоку в міру їх надходження. Камера перезаписує буфер потоку при кожному новому знімку, тому хост, який опитує повільніше, ніж камера захоплює, мовчки втрачатиме кадри — це правильна поведінка для сценаріїв типу переглядача.
13.3.1.3.2. Словник кадру¶
read_frame() повертає або None (кадр не очікує), або dict з п’ятьма записами:
Ключ |
Значення |
|---|---|
|
Ширина кадру в пікселях. |
|
Висота кадру в пікселях. |
|
Ідентифікатор піксельного формату, оголошений камерою (ціле число з констант |
|
Для стиснених форматів (JPEG, PNG) — розмір стисненого зображення в байтах. Не використовується для нестиснених форматів. |
|
Кадр у вигляді буфера |
|
Байти, надіслані камерою через USB до декодування. Корисно для обчислення фактичної пропускної здатності. |
Пакет перетворює власний формат камери (GRAYSCALE, RGB565, JPEG) у RGB888 перед поверненням, тому хосту ніколи не потрібно самостійно обробляти упакований RGB565 або шлях декомпресії JPEG. Кадри у відтінках сірого повертаються з яскравістю, скопійованою в усі три канали.
Буфер data розміщений рядок за рядком, зверху вниз; передача його безпосередньо бібліотеці відображення або збереження як необробленого RGB-файлу працює без будь-якого додаткового перестановлення.
13.3.1.3.3. Режим необробленої потокової передачі¶
За замовчуванням камера стискає кожен захоплений кадр у JPEG перед розміщенням його в каналі потоку, а read_frame() декомпресує на хості. На камерах без апаратної підтримки JPEG програмне стиснення є найповільнішим кроком у циклі. Передача raw=True пропускає цей крок:
cam.streaming(True, raw=True, resolution=(320, 240))
Тоді камера надсилає піксельний буфер нестисненим. Нестиснені кадри набагато більші за їхні JPEG-еквіваленти, тому камера масштабує кожен захоплений кадр, щоб він вмістився в канал потоку перед надсиланням; аргумент resolution=(width, height) встановлює цю цільову роздільну здатність. Хост все одно отримує RGB888 у полі data — пакет конвертує з будь-якого піксельного формату, який камера повідомила у format.
13.3.1.3.4. Керування циклом за допомогою подій¶
Цикл опитування, який викликає read_frame() швидше, ніж камера виробляє кадри, витрачає більшу частину часу, отримуючи None. Коли хост також має іншу роботу (UI для оновлення, інші канали для опитування), read_status() є дешевшою перевіркою: вона повертає словник, що відображає кожне зареєстроване ім’я каналу в булеве значення «дані готові»:
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 ...
Це форма циклу, яку використовує сам переглядач CLI.
13.3.1.3.5. Зупинка потоку¶
Викличте streaming() з enable=False, щоб зупинити. Камера продовжує виконувати свій скрипт, але більше не заповнює буфер потоку; read_frame() просто повертає None з цього моменту. Виклик stop() неявно робить те саме, зупиняючи скрипт.