4.18. Кілька датчиків#
Деякі камери OpenMV Cam оснащені двома датчиками зображення на одній платі — найчастіше це кольорова камера разом з тепловізійним датчиком FLIR® Lepton®, але та сама архітектура застосовується до плат з поєднанням кольорового і подієвого датчиків, а також до будь-якого майбутнього двосенсорного обладнання. Кожен датчик має власний масив пікселів, власну шину управління і запускає власний конвеєр із власною частотою кадрів. API CSI охоплює їх, дозволяючи застосунку створювати окремий об’єкт CSI для кожного фізичного датчика.
4.18.1. Вибір датчика#
Конструктор CSI приймає аргумент cid, що вказує конкретний датчик на платі. cid=-1 (за замовчуванням) вибирає первинний датчик; іменовані константи cid вибирають вторинний за ідентифікатором чипа:
import csi
csi_rgb = csi.CSI() # primary colour sensor
csi_thermal = csi.CSI(cid=csi.LEPTON) # FLIR® Lepton®
Кожен екземпляр має власну конфігурацію — формат пікселів, розмір кадру, регулятори витримки/підсилення, пул кадрових буферів — і скидається, налаштовується та зчитується незалежно від іншого. Константи для підтримуваних вторинних датчиків (LEPTON, GENX320 та інші, перелічені в довіднику CSI) вказують чип, який застосунок очікує на вторинному порту; драйвер перериває конструювання, якщо реальний чип не відповідає очікуваному.
4.18.2. Захоплення з обох датчиків#
Кожен датчик запускає свій конвеєр захоплення незалежно від іншого — кольоровий датчик може видавати тридцять кадрів на секунду, тоді як Lepton® видає дев’ять. Простий спосіб впоратися з цим розбіжністю — дозволити швидшому датчику керувати циклом, а повільніший зчитувати без блокування, беручи те, що готове, і пропускаючи ітерацію, коли нічого немає:
import csi
csi_rgb = csi.CSI()
csi_thermal = csi.CSI(cid=csi.LEPTON)
csi_rgb.reset() # powers the rail, pulses RESET
csi_rgb.pixformat(csi.RGB565)
csi_rgb.framesize(csi.QVGA)
csi_thermal.reset(hard=False) # I2C reconfigure only
csi_thermal.pixformat(csi.GRAYSCALE)
csi_thermal.framesize(csi.QQVGA)
while True:
rgb_img = csi_rgb.snapshot() # blocks for next colour frame
thermal_img = csi_thermal.snapshot(blocking=False) # returns None if not ready
if thermal_img is not None:
# process aligned colour + thermal pair
pass
else:
# process colour only on this iteration
pass
Блокуючий snapshot() задає темп циклу; неблокуючий повертає найсвіжіший тепловий кадр, коли він з’явився після попереднього виклику, і None в іншому випадку. Застосунок продовжує працювати зі швидкістю кольорового датчика і отримує тепловий кадр щоразу, коли його видає Lepton®.
Зворотній шаблон — два блокуючих snapshot поспіль — теж працює, але тоді цикл виконується зі швидкістю повільнішого з двох датчиків, а конвеєр швидшого зупиняється між ітераціями. Виберіть ту швидкість, з якою застосунок справді хоче керувати наступною обробкою.
4.18.4. Вибір джерела потоку#
Камери з двома датчиками мають два екземпляри CSI, але між ними лише один потоковий кадровий буфер. Аргумент конструктора визначає, кадри якого датчика подаються на попередній перегляд:
csi_rgb = csi.CSI() # primary
csi_thermal = csi.CSI(cid=csi.LEPTON,
stream=True) # preview source
stream=True робить названий екземпляр джерелом. Без аргументу stream= джерелом є первинний датчик (cid=-1, за замовчуванням); екземпляри, побудовані з cid= вторинного датчика, не виводять нічого на попередній перегляд, якщо stream=True не передано явно. Виклики snapshot() на невибраному датчику продовжують захоплювати кадри у буфери цього датчика в звичайному режимі — вони просто не оновлюють попередній перегляд.