4.18. Senzori multipli¶
Câteva camere OpenMV Cam asociază doi senzori de imagine pe aceeași placă – cel mai frecvent o cameră color alături de un senzor termic FLIR® Lepton®, dar aceeași structură se aplică și plăcilor color-plus-event și oricărui viitor hardware cu doi senzori. Fiecare senzor are propriul său grilaj de pixeli, propria sa magistrală de control și rulează propriul flux la propria rată de cadre. API-ul CSI se extinde pentru a le acoperi, permițând aplicației să instanțieze câte un obiect CSI pentru fiecare senzor fizic.
4.18.1. Selectarea senzorului¶
Constructorul CSI acceptă un argument cid care denumește un senzor specific de pe placă. cid=-1 (valoarea implicită) selectează senzorul principal; constantele cid denumite selectează un senzor secundar după ID-ul cipului:
import csi
csi_rgb = csi.CSI() # primary colour sensor
csi_thermal = csi.CSI(cid=csi.LEPTON) # FLIR® Lepton®
Fiecare instanță deține propria configurație – format de pixel, framesize, comenzi de expunere / amplificare (gain), rezervă de tampoane de cadre – și este resetată, configurată și citită independent de cealaltă. Constantele pentru senzorii secundari acceptați (LEPTON, GENX320 și celelalte enumerate în referința CSI) denumesc cipul pe care aplicația îl așteaptă pe portul secundar; driverul eșuează construcția dacă cipul efectiv nu corespunde.
4.18.2. Captura de la ambii senzori¶
Fiecare senzor își rulează fluxul de captură independent de celălalt – senzorul color ar putea livra treizeci de cadre pe secundă, în timp ce Lepton® livrează nouă. Modalitatea simplă de a gestiona această nepotrivire este de a lăsa senzorul mai rapid să conducă bucla și de a citi senzorul mai lent în mod neblocant, preluând orice este disponibil și sărind peste iterație atunci când nu este nimic:
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
Metoda blocantă snapshot() ritmizează bucla; cea neblocantă returnează cel mai recent cadru termic atunci când a sosit unul nou de la apelul anterior, și None în caz contrar. Aplicația continuă să ruleze la rata de cadre a senzorului color și primește un cadru termic ori de câte ori Lepton® produce unul.
Tiparul opus – două instantanee blocante consecutive – funcționează și el, însă bucla rulează atunci la cea mai lentă dintre ratele celor doi senzori, fluxul senzorului mai rapid stagnând între iterații. Alegeți rata pe care procesarea ulterioară a aplicației dorește cu adevărat să o impună.
4.18.4. Selectarea sursei fluxului¶
Camerele cu doi senzori au două instanțe CSI, dar tot un singur tampon de cadre pentru flux între ele. Un argument al constructorului alege cadrele cărui senzor alimentează previzualizarea:
csi_rgb = csi.CSI() # primary
csi_thermal = csi.CSI(cid=csi.LEPTON,
stream=True) # preview source
stream=True face din instanța denumită sursa. Fără argumentul stream=, senzorul principal (cid=-1, valoarea implicită) este sursa; instanțele construite cu cid= al unui senzor secundar rămân tăcute în previzualizare, cu excepția cazului în care stream=True este transmis explicit. Apelurile snapshot() pe senzorul neselectat capturează în continuare cadre în tampoanele de cadre ale acelui senzor în mod normal – doar că nu actualizează previzualizarea.